rsvg-cairo-clip.c 7.48 KB
Newer Older
1 2
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 sts=4 expandtab: */
Caleb Michael Moore's avatar
Caleb Michael Moore committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
   rsvg-shapes.c: Draw shapes with cairo

   Copyright (C) 2005 Dom Lachowicz <cinamod@hotmail.com>
   Copyright (C) 2005 Caleb Moore <c.moore@student.unsw.edu.au>
   Copyright (C) 2005 Red Hat, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Authors: Dom Lachowicz <cinamod@hotmail.com>, 
            Caleb Moore <c.moore@student.unsw.edu.au>
            Carl Worth <cworth@cworth.org>
*/

30 31
#include "config.h"

Caleb Michael Moore's avatar
Caleb Michael Moore committed
32 33 34 35
#include "rsvg-cairo-draw.h"
#include "rsvg-cairo-clip.h"
#include "rsvg-cairo-render.h"
#include "rsvg-styles.h"
36
#include "rsvg-path-builder.h"
37
#include "rsvg-structure.h"
Caleb Michael Moore's avatar
Caleb Michael Moore committed
38 39 40

#include <math.h>
#include <string.h>
41
#include <pango/pangocairo.h>
Caleb Michael Moore's avatar
Caleb Michael Moore committed
42 43 44 45

typedef struct RsvgCairoClipRender RsvgCairoClipRender;

struct RsvgCairoClipRender {
46
    RsvgCairoRender super;
47
    RsvgCairoRender *parent;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
48 49
};

50 51
#define RSVG_CAIRO_CLIP_RENDER(render) (_RSVG_RENDER_CIC ((render), RSVG_RENDER_TYPE_CAIRO_CLIP, RsvgCairoClipRender))

52
static void
Christian Persch's avatar
Christian Persch committed
53
rsvg_cairo_clip_apply_affine (RsvgCairoClipRender *render, cairo_matrix_t *affine)
54
{
55
    RsvgCairoRender *cairo_render = &render->super;
56
    cairo_matrix_t matrix;
57
    gboolean nest = cairo_render->cr != cairo_render->initial_cr;
58 59

    cairo_matrix_init (&matrix,
Christian Persch's avatar
Christian Persch committed
60 61 62 63
                       affine->xx, affine->yx,
                       affine->xy, affine->yy,
                       affine->x0 + (nest ? 0 : render->parent->offset_x),
                       affine->y0 + (nest ? 0 : render->parent->offset_y));
64
    cairo_set_matrix (cairo_render->cr, &matrix);
65 66
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
static void
rsvg_cairo_clip_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, double x, double y)
{
    RsvgCairoClipRender *render = RSVG_CAIRO_CLIP_RENDER (ctx->render);
    RsvgCairoRender *cairo_render = &render->super;
    cairo_matrix_t affine;
    PangoGravity gravity = pango_context_get_gravity (pango_layout_get_context (layout));
    double rotation;

    affine = rsvg_drawing_ctx_get_current_state_affine (ctx);
    rsvg_cairo_clip_apply_affine (render, &affine);

    rotation = pango_gravity_to_rotation (gravity);

    cairo_save (cairo_render->cr);
    cairo_move_to (cairo_render->cr, x, y);
    if (rotation != 0.)
        cairo_rotate (cairo_render->cr, -rotation);

    pango_cairo_update_layout (cairo_render->cr, layout);
    pango_cairo_layout_path (cairo_render->cr, layout);

    cairo_restore (cairo_render->cr);
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
92
static void
93
rsvg_cairo_clip_render_path_builder (RsvgDrawingCtx * ctx, RsvgPathBuilder *builder)
Caleb Michael Moore's avatar
Caleb Michael Moore committed
94
{
95
    RsvgCairoClipRender *render = RSVG_CAIRO_CLIP_RENDER (ctx->render);
96
    RsvgCairoRender *cairo_render = &render->super;
97
    RsvgState *state = rsvg_current_state (ctx);
98 99
    cairo_t *cr;

100
    cr = cairo_render->cr;
101

Christian Persch's avatar
Christian Persch committed
102
    rsvg_cairo_clip_apply_affine (render, &state->affine);
103

104
    cairo_set_fill_rule (cr, rsvg_current_state (ctx)->clip_rule);
105

106
    rsvg_path_builder_add_to_cairo_context (builder, cr);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
107 108
}

109 110 111 112 113 114 115 116 117 118
static void
rsvg_cairo_clip_render_surface (RsvgDrawingCtx *ctx,
                                cairo_surface_t *surface,
                                double src_x,
                                double src_y, 
                                double w, 
                                double h)
{
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
119 120 121 122

static void
rsvg_cairo_clip_render_free (RsvgRender * self)
{
123
    RsvgCairoClipRender *clip_render = RSVG_CAIRO_CLIP_RENDER (self);
124

125
    g_free (clip_render);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
126 127 128
}

static void
129 130 131
rsvg_cairo_clip_push_discrete_layer (RsvgDrawingCtx * ctx)
{
}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
132 133

static void
134 135 136
rsvg_cairo_clip_pop_discrete_layer (RsvgDrawingCtx * ctx)
{
}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
137

138 139 140 141
static void
rsvg_cairo_clip_add_clipping_rect (RsvgDrawingCtx * ctx, double x, double y, double w, double h)
{
}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
142

143
static RsvgRender *
144
rsvg_cairo_clip_render_new (cairo_t *cr, RsvgCairoRender *parent)
Caleb Michael Moore's avatar
Caleb Michael Moore committed
145
{
146 147 148
    RsvgCairoClipRender *clip_render = g_new0 (RsvgCairoClipRender, 1);
    RsvgCairoRender *cairo_render = &clip_render->super;
    RsvgRender *render = &cairo_render->super;
149

150 151
    g_assert (parent->super.type == RSVG_RENDER_TYPE_CAIRO);

152 153 154
    render->type = RSVG_RENDER_TYPE_CAIRO_CLIP;
    render->free = rsvg_cairo_clip_render_free;
    render->create_pango_context = rsvg_cairo_create_pango_context;
155
    render->render_pango_layout = rsvg_cairo_clip_render_pango_layout;
156
    render->render_path_builder = rsvg_cairo_clip_render_path_builder;
157
    render->render_surface = rsvg_cairo_clip_render_surface;
158 159 160
    render->pop_discrete_layer = rsvg_cairo_clip_pop_discrete_layer;
    render->push_discrete_layer = rsvg_cairo_clip_push_discrete_layer;
    render->add_clipping_rect = rsvg_cairo_clip_add_clipping_rect;
161
    render->get_surface_of_node = NULL;
162

163
    cairo_render->initial_cr = parent->cr;
164 165 166 167 168 169 170 171 172 173 174 175 176
    cairo_render->cr         = cr;
    cairo_render->width      = parent->width;
    cairo_render->height     = parent->height;
    cairo_render->offset_x   = parent->offset_x;
    cairo_render->offset_y   = parent->offset_y;
    cairo_render->cr_stack   = NULL;
    cairo_render->bbox       = parent->bbox;
    cairo_render->bb_stack   = NULL;

    /* We don't copy or ref the following two; we just share them */
    cairo_render->font_config_for_testing = parent->font_config_for_testing;
    cairo_render->font_map_for_testing    = parent->font_map_for_testing;

177
    clip_render->parent = parent;
178

179
    return render;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
180 181
}

182
void
183
rsvg_cairo_clip (RsvgDrawingCtx * ctx, RsvgNode *node_clip_path, RsvgBbox * bbox)
Caleb Michael Moore's avatar
Caleb Michael Moore committed
184
{
185
    RsvgClipPath *clip;
186
    RsvgCairoClipRender *clip_render;
187
    RsvgCairoRender *save = RSVG_CAIRO_RENDER (ctx->render);
Christian Persch's avatar
Christian Persch committed
188
    cairo_matrix_t affinesave;
189
    RsvgState *clip_path_state;
190
    cairo_t *cr;
Christian Persch's avatar
Christian Persch committed
191

192 193 194
    g_assert (rsvg_node_get_type (node_clip_path) == RSVG_NODE_TYPE_CLIP_PATH);
    clip = rsvg_rust_cnode_get_impl (node_clip_path);

195 196 197
    cr = save->cr;
    clip_render = RSVG_CAIRO_CLIP_RENDER (rsvg_cairo_clip_render_new (cr, save));
    ctx->render = &clip_render->super.super;
198

199 200
    clip_path_state = rsvg_node_get_state (node_clip_path);

201 202
    /* Horribly dirty hack to have the bbox premultiplied to everything */
    if (clip->units == objectBoundingBox) {
Christian Persch's avatar
Christian Persch committed
203 204 205 206 207 208 209 210
        cairo_matrix_t bbtransform;
        cairo_matrix_init (&bbtransform,
                           bbox->rect.width,
                           0,
                           0,
                           bbox->rect.height,
                           bbox->rect.x,
                           bbox->rect.y);
211 212
        affinesave = clip_path_state->affine;
        cairo_matrix_multiply (&clip_path_state->affine, &bbtransform, &clip_path_state->affine);
213 214 215
    }

    rsvg_state_push (ctx);
216
    rsvg_node_draw_children (node_clip_path, ctx, 0);
217 218 219
    rsvg_state_pop (ctx);

    if (clip->units == objectBoundingBox)
220
        clip_path_state->affine = affinesave;
221

222 223 224 225
    g_assert (clip_render->super.cr_stack == NULL);
    g_assert (clip_render->super.bb_stack == NULL);
    g_assert (clip_render->super.surfaces_stack == NULL);

226
    g_free (ctx->render);
227
    cairo_clip (cr);
228
    ctx->render = &save->super;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
229
}