static void _rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx, gdouble * x, gdouble * y, gboolean * lastwasspace) { guint i; rsvg_push_discrete_layer (ctx); for (i = 0; i < self->children->len; i++) { RsvgNode *node = g_ptr_array_index (self->children, i); if (!strcmp (node->type->str, "RSVG_NODE_CHARS")) { RsvgNodeChars *chars = (RsvgNodeChars *) node; GString *str = _rsvg_text_chomp (rsvg_current_state (ctx), chars->contents, lastwasspace); rsvg_text_render_text (ctx, str->str, x, y); g_string_free (str, TRUE); } else if (!strcmp (node->type->str, "tspan")) { RsvgNodeText *tspan = (RsvgNodeText *) node; rsvg_state_push (ctx); _rsvg_node_text_type_tspan (tspan, ctx, x, y, lastwasspace); rsvg_state_pop (ctx); } else if (!strcmp (node->type->str, "tref")) { RsvgNodeTref *tref = (RsvgNodeTref *) node; _rsvg_node_text_type_tref (tref, ctx, x, y, lastwasspace); } } rsvg_pop_discrete_layer (ctx); }
static int _rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx, gdouble * x, gboolean * lastwasspace) { guint i; int out = FALSE; for (i = 0; i < self->children->len; i++) { RsvgNode *node = g_ptr_array_index (self->children, i); rsvg_state_push (ctx); rsvg_state_reinherit_top (ctx, node->state, 0); if (!strcmp (node->type->str, "RSVG_NODE_CHARS")) { RsvgNodeChars *chars = (RsvgNodeChars *) node; GString *str = _rsvg_text_chomp (rsvg_current_state (ctx), chars->contents, lastwasspace); *x += rsvg_text_length_text_as_string (ctx, str->str); g_string_free (str, TRUE); } else if (!strcmp (node->type->str, "tspan")) { RsvgNodeText *tspan = (RsvgNodeText *) node; out = _rsvg_node_text_length_tspan (tspan, ctx, x, lastwasspace); } else if (!strcmp (node->type->str, "tref")) { RsvgNodeTref *tref = (RsvgNodeTref *) node; out = _rsvg_node_text_length_tref (tref, ctx, x, lastwasspace); } rsvg_state_pop (ctx); if (out) break; } return out; }
/* generic function for drawing all of the children of a particular node */ void _rsvg_node_draw_children (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate) { guint i; if (dominate != -1) { rsvg_state_reinherit_top (ctx, self->state, dominate); rsvg_push_discrete_layer (ctx); } for (i = 0; i < self->children->len; i++) { rsvg_state_push (ctx); rsvg_node_draw (g_ptr_array_index (self->children, i), ctx, 0); rsvg_state_pop (ctx); } if (dominate != -1) rsvg_pop_discrete_layer (ctx); }
static int _rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx, gdouble * length, gboolean * lastwasspace, gboolean usetextonly) { guint i; int out = FALSE; for (i = 0; i < self->children->len; i++) { RsvgNode *node = g_ptr_array_index (self->children, i); RsvgNodeType type = RSVG_NODE_TYPE (node); rsvg_state_push (ctx); rsvg_state_reinherit_top (ctx, node->state, 0); if (type == RSVG_NODE_TYPE_CHARS) { RsvgNodeChars *chars = (RsvgNodeChars *) node; GString *str = _rsvg_text_chomp (rsvg_current_state (ctx), chars->contents, lastwasspace); *length += rsvg_text_length_text_as_string (ctx, str->str); g_string_free (str, TRUE); } else { if (usetextonly || type == RSVG_NODE_TYPE_TEXT_PATH) { out = _rsvg_node_text_length_children(node, ctx, length, lastwasspace, usetextonly); } else { if (type == RSVG_NODE_TYPE_TSPAN) { RsvgNodeText *tspan = (RsvgNodeText *) node; out = _rsvg_node_text_length_tspan (tspan, ctx, length, lastwasspace, usetextonly); } else if (type == RSVG_NODE_TYPE_TREF) { RsvgNodeTref *tref = (RsvgNodeTref *) node; out = _rsvg_node_text_length_tref (tref, ctx, length, lastwasspace, usetextonly); } } } rsvg_state_pop (ctx); if (out) break; } return out; }
static void _rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx, gdouble * x, gdouble * y, gboolean * lastwasspace, gboolean usetextonly) { guint i; rsvg_push_discrete_layer (ctx); for (i = 0; i < self->children->len; i++) { RsvgNode *node = g_ptr_array_index (self->children, i); RsvgNodeType type = RSVG_NODE_TYPE (node); if (type == RSVG_NODE_TYPE_CHARS) { RsvgNodeChars *chars = (RsvgNodeChars *) node; GString *str = _rsvg_text_chomp (rsvg_current_state (ctx), chars->contents, lastwasspace); rsvg_text_render_text (ctx, str->str, x, y); g_string_free (str, TRUE); } else { if (usetextonly) { _rsvg_node_text_type_children (node, ctx, x, y, lastwasspace, usetextonly); } else { if (type == RSVG_NODE_TYPE_TSPAN) { RsvgNodeText *tspan = (RsvgNodeText *) node; rsvg_state_push (ctx); _rsvg_node_text_type_tspan (tspan, ctx, x, y, lastwasspace, usetextonly); rsvg_state_pop (ctx); } else if (type == RSVG_NODE_TYPE_TREF) { RsvgNodeTref *tref = (RsvgNodeTref *) node; _rsvg_node_text_type_tref (tref, ctx, x, y, lastwasspace, usetextonly); } else if (type == RSVG_NODE_TYPE_TEXT_PATH) { RsvgNodeTextPath *textpath = (RsvgNodeTextPath *) node; _rsvg_node_text_type_text_path(textpath, ctx, x, y, lastwasspace, usetextonly); } } } } rsvg_pop_discrete_layer (ctx); }
void rsvg_cairo_clip (RsvgDrawingCtx * ctx, RsvgClipPath * clip, RsvgBbox * bbox) { RsvgCairoClipRender *clip_render; RsvgCairoRender *save = RSVG_CAIRO_RENDER (ctx->render); cairo_t *cr; cairo_matrix_t affinesave; cr = save->cr; clip_render = RSVG_CAIRO_CLIP_RENDER (rsvg_cairo_clip_render_new (cr, save)); ctx->render = &clip_render->super.super; /* Horribly dirty hack to have the bbox premultiplied to everything */ if (clip->units == objectBoundingBox) { cairo_matrix_t bbtransform; cairo_matrix_init (&bbtransform, bbox->rect.width, 0, 0, bbox->rect.height, bbox->rect.x, bbox->rect.y); affinesave = clip->super.state->affine; cairo_matrix_multiply (&clip->super.state->affine, &bbtransform, &clip->super.state->affine); } rsvg_state_push (ctx); _rsvg_node_draw_children ((RsvgNode *) clip, ctx, 0); rsvg_state_pop (ctx); if (clip->units == objectBoundingBox) clip->super.state->affine = affinesave; g_assert (clip_render->super.cr_stack == NULL); g_assert (clip_render->super.bb_stack == NULL); g_assert (clip_render->super.surfaces_stack == NULL); g_free (ctx->render); cairo_clip (cr); ctx->render = &save->super; }
/** * rsvg_handle_render_cairo_sub: * @handle: A RsvgHandle * @cr: A Cairo renderer * @id: An element's id within the SVG, or %NULL to render the whole SVG. For * example, if you have a layer called "layer1" that you wish to render, pass * "##layer1" as the id. * * Draws a subset of a SVG to a Cairo surface * * Returns: %TRUE if drawing succeeded. * * Since: 2.14 */ gboolean rsvg_handle_render_cairo_sub (RsvgHandle * handle, cairo_t * cr, const char *id) { RsvgDrawingCtx *draw; RsvgNode *drawsub = NULL; g_return_val_if_fail (handle != NULL, FALSE); if (!handle->priv->finished) return FALSE; if (id && *id) drawsub = rsvg_defs_lookup (handle->priv->defs, id); if (drawsub == NULL && id != NULL) { /* todo: there's no way to signal that @id doesn't exist */ return FALSE; } draw = rsvg_cairo_new_drawing_ctx (cr, handle); if (!draw) return FALSE; while (drawsub != NULL) { draw->drawsub_stack = g_slist_prepend (draw->drawsub_stack, drawsub); drawsub = drawsub->parent; } rsvg_state_push (draw); cairo_save (cr); rsvg_node_draw ((RsvgNode *) handle->priv->treebase, draw, 0); cairo_restore (cr); rsvg_state_pop (draw); rsvg_drawing_ctx_free (draw); return TRUE; }
static void _rsvg_node_switch_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate) { guint i; rsvg_state_reinherit_top (ctx, self->state, dominate); rsvg_push_discrete_layer (ctx); for (i = 0; i < self->children->len; i++) { RsvgNode *drawable = g_ptr_array_index (self->children, i); if (drawable->state->cond_true) { rsvg_state_push (ctx); rsvg_node_draw (g_ptr_array_index (self->children, i), ctx, 0); rsvg_state_pop (ctx); break; /* only render the 1st one */ } } rsvg_pop_discrete_layer (ctx); }
static void rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate) { RsvgNodeSvg *sself; RsvgState *state; gdouble affine[6], affine_old[6], affine_new[6]; guint i; double nx, ny, nw, nh; sself = (RsvgNodeSvg *) self; nx = _rsvg_css_normalize_length (&sself->x, ctx, 'h'); ny = _rsvg_css_normalize_length (&sself->y, ctx, 'v'); nw = _rsvg_css_normalize_length (&sself->w, ctx, 'h'); nh = _rsvg_css_normalize_length (&sself->h, ctx, 'v'); rsvg_state_reinherit_top (ctx, self->state, dominate); state = rsvg_current_state (ctx); for (i = 0; i < 6; i++) affine_old[i] = state->affine[i]; if (sself->vbox.active) { double x = nx, y = ny, w = nw, h = nh; rsvg_preserve_aspect_ratio (sself->preserve_aspect_ratio, sself->vbox.w, sself->vbox.h, &w, &h, &x, &y); affine[0] = w / sself->vbox.w; affine[1] = 0; affine[2] = 0; affine[3] = h / sself->vbox.h; affine[4] = x - sself->vbox.x * w / sself->vbox.w; affine[5] = y - sself->vbox.y * h / sself->vbox.h; _rsvg_affine_multiply (state->affine, affine, state->affine); _rsvg_push_view_box (ctx, sself->vbox.w, sself->vbox.h); } else { affine[0] = 1; affine[1] = 0; affine[2] = 0; affine[3] = 1; affine[4] = nx; affine[5] = ny; _rsvg_affine_multiply (state->affine, affine, state->affine); _rsvg_push_view_box (ctx, nw, nh); } for (i = 0; i < 6; i++) affine_new[i] = state->affine[i]; rsvg_push_discrete_layer (ctx); /* Bounding box addition must be AFTER the discrete layer push, which must be AFTER the transformation happens. */ if (!state->overflow && self->parent) { for (i = 0; i < 6; i++) state->affine[i] = affine_old[i]; rsvg_add_clipping_rect (ctx, nx, ny, nw, nh); for (i = 0; i < 6; i++) state->affine[i] = affine_new[i]; } for (i = 0; i < self->children->len; i++) { rsvg_state_push (ctx); rsvg_node_draw (g_ptr_array_index (self->children, i), ctx, 0); rsvg_state_pop (ctx); } rsvg_pop_discrete_layer (ctx); _rsvg_pop_view_box (ctx); }
static void rsvg_node_use_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate) { RsvgNodeUse *use = (RsvgNodeUse *) self; RsvgNode *child; RsvgState *state; double affine[6]; double x, y, w, h; x = _rsvg_css_normalize_length (&use->x, ctx, 'h'); y = _rsvg_css_normalize_length (&use->y, ctx, 'v'); w = _rsvg_css_normalize_length (&use->w, ctx, 'h'); h = _rsvg_css_normalize_length (&use->h, ctx, 'v'); rsvg_state_reinherit_top (ctx, self->state, dominate); child = use->link; /* If it can find nothing to draw... draw nothing */ if (!child) return; else if (rsvg_node_is_ancestor (child, self)) /* or, if we're <use>'ing ourself */ return; state = rsvg_current_state (ctx); if (strcmp (child->type->str, "symbol")) { _rsvg_affine_translate (affine, x, y); _rsvg_affine_multiply (state->affine, affine, state->affine); rsvg_push_discrete_layer (ctx); rsvg_state_push (ctx); rsvg_node_draw (child, ctx, 1); rsvg_state_pop (ctx); rsvg_pop_discrete_layer (ctx); } else { RsvgNodeSymbol *symbol = (RsvgNodeSymbol *) child; if (symbol->vbox.active) { rsvg_preserve_aspect_ratio (symbol->preserve_aspect_ratio, symbol->vbox.w, symbol->vbox.h, &w, &h, &x, &y); _rsvg_affine_translate (affine, x, y); _rsvg_affine_multiply (state->affine, affine, state->affine); _rsvg_affine_scale (affine, w / symbol->vbox.w, h / symbol->vbox.h); _rsvg_affine_multiply (state->affine, affine, state->affine); _rsvg_affine_translate (affine, -symbol->vbox.x, -symbol->vbox.y); _rsvg_affine_multiply (state->affine, affine, state->affine); _rsvg_push_view_box (ctx, symbol->vbox.w, symbol->vbox.h); rsvg_push_discrete_layer (ctx); if (!state->overflow || (!state->has_overflow && child->state->overflow)) rsvg_add_clipping_rect (ctx, symbol->vbox.x, symbol->vbox.y, symbol->vbox.w, symbol->vbox.h); } else { _rsvg_affine_translate (affine, x, y); _rsvg_affine_multiply (state->affine, affine, state->affine); rsvg_push_discrete_layer (ctx); } rsvg_state_push (ctx); _rsvg_node_draw_children (child, ctx, 1); rsvg_state_pop (ctx); rsvg_pop_discrete_layer (ctx); if (symbol->vbox.active) _rsvg_pop_view_box (ctx); } }
void rsvg_marker_render (RsvgMarker * self, gdouble x, gdouble y, gdouble orient, gdouble linewidth, RsvgDrawingCtx * ctx) { cairo_matrix_t affine, taffine; unsigned int i; gdouble rotation; RsvgState *state = rsvg_current_state (ctx); cairo_matrix_init_translate (&taffine, x, y); cairo_matrix_multiply (&affine, &taffine, &state->affine); if (self->orientAuto) rotation = orient; else rotation = self->orient * M_PI / 180.; cairo_matrix_init_rotate (&taffine, rotation); cairo_matrix_multiply (&affine, &taffine, &affine); if (self->bbox) { cairo_matrix_init_scale (&taffine, linewidth, linewidth); cairo_matrix_multiply (&affine, &taffine, &affine); } if (self->vbox.active) { double w, h, x, y; w = _rsvg_css_normalize_length (&self->width, ctx, 'h'); h = _rsvg_css_normalize_length (&self->height, ctx, 'v'); x = 0; y = 0; rsvg_preserve_aspect_ratio (self->preserve_aspect_ratio, self->vbox.rect.width, self->vbox.rect.height, &w, &h, &x, &y); x = -self->vbox.rect.x * w / self->vbox.rect.width; y = -self->vbox.rect.y * h / self->vbox.rect.height; cairo_matrix_init (&taffine, w / self->vbox.rect.width, 0, 0, h / self->vbox.rect.height, x, y); cairo_matrix_multiply (&affine, &taffine, &affine); _rsvg_push_view_box (ctx, self->vbox.rect.width, self->vbox.rect.height); } cairo_matrix_init_translate (&taffine, -_rsvg_css_normalize_length (&self->refX, ctx, 'h'), -_rsvg_css_normalize_length (&self->refY, ctx, 'v')); cairo_matrix_multiply (&affine, &taffine, &affine); rsvg_state_push (ctx); state = rsvg_current_state (ctx); rsvg_state_reinit (state); rsvg_state_reconstruct (state, &self->super); state->affine = affine; rsvg_push_discrete_layer (ctx); state = rsvg_current_state (ctx); if (!state->overflow) { if (self->vbox.active) rsvg_add_clipping_rect (ctx, self->vbox.rect.x, self->vbox.rect.y, self->vbox.rect.width, self->vbox.rect.height); else rsvg_add_clipping_rect (ctx, 0, 0, _rsvg_css_normalize_length (&self->width, ctx, 'h'), _rsvg_css_normalize_length (&self->height, ctx, 'v')); } for (i = 0; i < self->super.children->len; i++) { rsvg_state_push (ctx); rsvg_node_draw (g_ptr_array_index (self->super.children, i), ctx, 0); rsvg_state_pop (ctx); } rsvg_pop_discrete_layer (ctx); rsvg_state_pop (ctx); if (self->vbox.active) _rsvg_pop_view_box (ctx); }