📄 svg_base_sani.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Authors: Cyril Concolato - Jean le Feuvre * Copyright (c) 2005-200X ENST * All rights reserved * * This file is part of GPAC / SVG Rendering sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "visualsurface2d.h"#ifndef GPAC_DISABLE_SVG#include "svg_stacks.h"#ifdef GPAC_ENABLE_SVG_SANI/* This is the generic routine for child traversing - note we are not duplicating the effect*/void gf_svg_sani_apply_local_transformation(RenderEffect2D *eff, GF_Node *node, GF_Matrix2D *backup_matrix){ gf_mx2d_copy(*backup_matrix, eff->transform); if (((SVG_SANI_TransformableElement *)node)->transform.is_ref) gf_mx2d_copy(eff->transform, eff->vb_transform); if (((SVG_SANI_TransformableElement *)node)->motionTransform) gf_mx2d_pre_multiply(&eff->transform, ((SVG_SANI_TransformableElement *)node)->motionTransform); gf_mx2d_pre_multiply(&eff->transform, &((SVG_SANI_TransformableElement *)node)->transform.mat);}void gf_svg_sani_restore_parent_transformation(RenderEffect2D *eff, GF_Matrix2D *backup_matrix){ gf_mx2d_copy(eff->transform, *backup_matrix); }/* Set the viewport of the renderer based on the element that contains a viewport TODO: change the SVG_SANI_svgElement into an element that has a viewport (more generic)*/static void gf_svg_sani_set_viewport_transformation(RenderEffect2D *eff, SVG_SANI_svgElement *svg, Bool is_root) { GF_Matrix2D mat; Fixed real_width, real_height; gf_mx2d_init(mat); if (is_root) { u32 scene_width = eff->surface->render->compositor->scene_width; u32 scene_height = eff->surface->render->compositor->scene_height; u32 dpi = 90; /* Should retrieve the dpi from the system */ switch (svg->width.type) { case SVG_NUMBER_VALUE: case SVG_NUMBER_PX: real_width = INT2FIX(scene_width); break; case SVG_NUMBER_PERCENTAGE: /*u32 * fixed / u32*/ real_width = scene_width*svg->width.value/100; break; case SVG_NUMBER_IN: real_width = dpi * svg->width.value; break; case SVG_NUMBER_CM: real_width = gf_mulfix(dpi*FLT2FIX(0.39), svg->width.value); break; case SVG_NUMBER_MM: real_width = gf_mulfix(dpi*FLT2FIX(0.039), svg->width.value); break; case SVG_NUMBER_PT: real_width = dpi/12 * svg->width.value; break; case SVG_NUMBER_PC: real_width = dpi/6 * svg->width.value; break; default: real_width = INT2FIX(scene_width); break; } switch (svg->height.type) { case SVG_NUMBER_VALUE: case SVG_NUMBER_PX: real_height = INT2FIX(scene_height); break; case SVG_NUMBER_PERCENTAGE: real_height = scene_height*svg->height.value/100; break; case SVG_NUMBER_IN: real_height = dpi * svg->height.value; break; case SVG_NUMBER_CM: real_height = gf_mulfix(dpi*FLT2FIX(0.39), svg->height.value); break; case SVG_NUMBER_MM: real_height = gf_mulfix(dpi*FLT2FIX(0.039), svg->height.value); break; case SVG_NUMBER_PT: real_height = dpi/12 * svg->height.value; break; case SVG_NUMBER_PC: real_height = dpi/6 * svg->height.value; break; default: real_height = INT2FIX(scene_height); break; } } else { real_width = real_height = 0; switch (svg->width.type) { case SVG_NUMBER_VALUE: case SVG_NUMBER_PX: real_width = svg->width.value; break; default: break; } switch (svg->height.type) { case SVG_NUMBER_VALUE: case SVG_NUMBER_PX: real_height = svg->height.value; break; default: break; } } if (!real_width || !real_height) return; if (svg->viewBox.is_set && svg->viewBox.width != 0 && svg->viewBox.height != 0) { Fixed scale, vp_w, vp_h; if (svg->preserveAspectRatio.meetOrSlice==SVG_MEETORSLICE_MEET) { if (gf_divfix(real_width, svg->viewBox.width) > gf_divfix(real_height, svg->viewBox.height)) { scale = gf_divfix(real_height, svg->viewBox.height); vp_w = gf_mulfix(svg->viewBox.width, scale); vp_h = real_height; } else { scale = gf_divfix(real_width, svg->viewBox.width); vp_w = real_width; vp_h = gf_mulfix(svg->viewBox.height, scale); } } else { if (gf_divfix(real_width, svg->viewBox.width) < gf_divfix(real_height, svg->viewBox.height)) { scale = gf_divfix(real_height, svg->viewBox.height); vp_w = gf_mulfix(svg->viewBox.width, scale); vp_h = real_height; } else { scale = gf_divfix(real_width, svg->viewBox.width); vp_w = real_width; vp_h = gf_mulfix(svg->viewBox.height, scale); } } if (svg->preserveAspectRatio.align==SVG_PRESERVEASPECTRATIO_NONE) { mat.m[0] = gf_divfix(real_width, svg->viewBox.width); mat.m[4] = gf_divfix(real_height, svg->viewBox.height); mat.m[2] = - gf_muldiv(svg->viewBox.x, real_width, svg->viewBox.width); mat.m[5] = - gf_muldiv(svg->viewBox.y, real_height, svg->viewBox.height); } else { Fixed dx, dy; mat.m[0] = mat.m[4] = scale; mat.m[2] = - gf_mulfix(svg->viewBox.x, scale); mat.m[5] = - gf_mulfix(svg->viewBox.y, scale); dx = dy = 0; switch (svg->preserveAspectRatio.align) { case SVG_PRESERVEASPECTRATIO_XMINYMIN: break; case SVG_PRESERVEASPECTRATIO_XMIDYMIN: dx = ( real_width - vp_w) / 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMIN: dx = real_width - vp_w; break; case SVG_PRESERVEASPECTRATIO_XMINYMID: dy = ( real_height - vp_h) / 2; break; case SVG_PRESERVEASPECTRATIO_XMIDYMID: dx = ( real_width - vp_w) / 2; dy = ( real_height - vp_h) / 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMID: dx = real_width - vp_w; dy = ( real_height - vp_h) / 2; break; case SVG_PRESERVEASPECTRATIO_XMINYMAX: dy = real_height - vp_h; break; case SVG_PRESERVEASPECTRATIO_XMIDYMAX: dx = (real_width - vp_w) / 2; dy = real_height - vp_h; break; case SVG_PRESERVEASPECTRATIO_XMAXYMAX: dx = real_width - vp_w; dy = real_height - vp_h; break; } mat.m[2] += dx; mat.m[5] += dy; /*we need a clipper*/ if (svg->preserveAspectRatio.meetOrSlice==SVG_MEETORSLICE_SLICE) { GF_Rect rc; rc.width = real_width; rc.height = real_height; if (!is_root) { rc.x = 0; rc.y = real_height; gf_mx2d_apply_rect(&eff->vb_transform, &rc); } else { rc.x = dx; rc.y = dy + real_height; } eff->surface->top_clipper = gf_rect_pixelize(&rc); } } } gf_mx2d_pre_multiply(&eff->vb_transform, &mat);}/* Node specific rendering functions All the nodes follow the same principles: * Check if the display property is not set to none, otherwise do not render * Back-up of the coordinate system & apply geometric transformation if any * Render the children if any or the shape if leaf node * Restore coordinate system */static void svg_sani_render_svg(GF_Node *node, void *rs, Bool is_destroy){ u32 viewport_color; GF_Matrix2D backup_matrix; GF_IRect top_clip; Bool is_root_svg = 1; SVG_SANI_svgElement *svg = (SVG_SANI_svgElement *)node; RenderEffect2D *eff = (RenderEffect2D *) rs; if (is_destroy) return; /*enable or disable navigation*/ eff->surface->render->navigation_disabled = (svg->zoomAndPan == SVG_ZOOMANDPAN_DISABLE) ? 1 : 0; svg_sani_render_base(node, eff); if (svg->display == SVG_DISPLAY_NONE) return; top_clip = eff->surface->top_clipper; gf_mx2d_copy(backup_matrix, eff->transform); gf_mx2d_init(eff->vb_transform); gf_svg_sani_set_viewport_transformation(eff, svg, is_root_svg); gf_mx2d_pre_multiply(&eff->transform, &eff->vb_transform); if (!is_root_svg && (svg->x.value || svg->y.value)) gf_mx2d_add_translation(&eff->transform, svg->x.value, svg->y.value); /* TODO: FIX ME: this only works for single SVG element in the doc*/ if (is_root_svg && svg->viewport_fill.type != SVG_PAINT_NONE) { viewport_color = GF_COL_ARGB_FIXED(svg->viewport_fill_opacity.value, svg->viewport_fill.color.red, svg->viewport_fill.color.green, svg->viewport_fill.color.blue); if (eff->surface->render->compositor->back_color != viewport_color) { eff->invalidate_all = 1; eff->surface->render->compositor->back_color = viewport_color; } } if (eff->traversing_mode == TRAVERSE_GET_BOUNDS) { svg_get_nodes_bounds(node, svg->children, eff); } else { svg_render_node_list(svg->children, eff); } gf_svg_sani_restore_parent_transformation(eff, &backup_matrix); eff->surface->top_clipper = top_clip;}void svg_sani_init_svg(Render2D *sr, GF_Node *node){ gf_node_set_callback_function(node, svg_sani_render_svg);}static void svg_sani_render_g(GF_Node *node, void *rs, Bool is_destroy){ GF_Matrix2D backup_matrix; SVG_SANI_gElement *g = (SVG_SANI_gElement *)node; RenderEffect2D *eff = (RenderEffect2D *) rs; if (is_destroy) return; svg_sani_render_base(node, eff); if (g->display == SVG_DISPLAY_NONE) { u32 prev_flags = eff->trav_flags; eff->trav_flags |= GF_SR_TRAV_SWITCHED_OFF; svg_render_node_list(g->children, eff); eff->trav_flags = prev_flags; return; } gf_svg_sani_apply_local_transformation(eff, node, &backup_matrix); if (eff->traversing_mode == TRAVERSE_GET_BOUNDS) { svg_get_nodes_bounds(node, g->children, eff); } else { svg_render_node_list(g->children, eff); } gf_svg_sani_restore_parent_transformation(eff, &backup_matrix);}void svg_sani_init_g(Render2D *sr, GF_Node *node){ gf_node_set_callback_function(node, svg_sani_render_g);}static Bool svg_sani_eval_conditional(GF_Renderer *sr, SVG_SANI_Element *elt){ u32 i, count; Bool found; const char *lang_3cc, *lang_2cc; if (!elt->conditional) return 1; count = gf_list_count(elt->conditional->requiredFeatures); for (i=0;i<count;i++) { XMLRI *iri = (XMLRI *)gf_list_get(elt->conditional->requiredFeatures, i); if (!iri->string) continue; /*TODO FIXME: be a bit more precise :)*/ if (!strnicmp(iri->string, "http://www.w3.org/", 18)) { char *feat = strrchr(iri->string, '#'); if (!feat) continue; feat++; if (!strcmp(feat, "SVGDOM")) return 0; if (!strcmp(feat, "Font")) return 0; continue; } return 0; } count = gf_list_count(elt->conditional->requiredExtensions); if (count) return 0; lang_3cc = gf_cfg_get_key(sr->user->config, "Systems", "Language3CC"); if (!lang_3cc) lang_3cc = "und"; lang_2cc = gf_cfg_get_key(sr->user->config, "Systems", "Language2CC"); if (!lang_2cc) lang_2cc = "un"; count = gf_list_count(elt->conditional->systemLanguage); found = count ? 0 : 1; for (i=0;i<count;i++) { char *lang = (char*)gf_list_get(elt->conditional->systemLanguage, i); /*3 char-code*/ if (strlen(lang)==3) { if (!stricmp(lang, lang_3cc)) { found = 1; break; } } /*2 char-code, only check first 2 chars - TODO FIXME*/ else if (!strnicmp(lang, lang_2cc, 2)) { found = 1; break; } } if (!found) return 0; return 1;}static void svg_sani_render_switch(GF_Node *node, void *rs, Bool is_destroy){ GF_Matrix2D backup_matrix; SVG_SANI_switchElement *s = (SVG_SANI_switchElement *)node; RenderEffect2D *eff = (RenderEffect2D *) rs; if (is_destroy) return; svg_sani_render_base(node, eff); if (s->display == SVG_DISPLAY_NONE) { gf_svg_sani_restore_parent_transformation(eff, &backup_matrix);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -