This source file includes following definitions.
- gf_laser_encoder_new
- gf_laser_encoder_del
- lsr_get_stream
- gf_laser_encoder_new_stream
- gf_laser_encoder_get_config
- gf_laser_encode_au
- gf_laser_encoder_get_rap
- lsr_write_vluimsbf5
- lsr_write_vluimsbf5_ex
- lsr_get_vluimsbf5_size
- lsr_write_vluimsbf8
- lsr_write_extension
- lsr_write_codec_IDREF
- lsr_write_codec_IDREF_Node
- lsr_get_IDREF_nb_bits
- lsr_write_fixed_16_8
- lsr_write_fixed_16_8i
- lsr_get_font_index
- lsr_get_col_index
- lsr_write_line_increment_type
- lsr_write_byte_align_string
- lsr_write_byte_align_string_list
- lsr_write_any_uri
- lsr_write_paint
- lsr_write_private_element_container
- lsr_write_private_att_class
- lsr_write_extend_class
- lsr_write_private_attr_container
- lsr_float_list_equal
- lsr_write_any_attribute
- lsr_write_private_attributes
- lsr_write_string_attribute
- lsr_write_id
- lsr_translate_coords
- lsr_translate_scale
- lsr_write_matrix
- lsr_write_fixed_clamp
- dom_to_lsr_key
- lsr_write_event_type
- lsr_write_smil_time
- lsr_write_smil_times
- lsr_write_duration_ex
- lsr_write_focus
- lsr_elt_has_same_base
- lsr_write_rare
- lsr_write_fill
- lsr_write_stroke
- lsr_write_href
- lsr_write_accumulate
- lsr_write_additive
- lsr_write_calc_mode
- lsr_write_animatable
- lsr_write_anim_fill
- lsr_write_anim_repeat
- lsr_write_repeat_duration
- lsr_write_anim_restart
- svg_type_to_lsr_anim
- lsr_write_coordinate
- lsr_write_coordinate_ptr
- lsr_write_an_anim_value
- lsr_write_anim_value
- lsr_write_anim_values
- lsr_write_fraction_12
- lsr_write_float_list
- lsr_get_bit_size
- lsr_write_point_sequence
- lsr_write_path_type
- lsr_write_rotate_type
- lsr_write_sync_behavior
- lsr_write_sync_tolerance
- lsr_write_coord_list
- lsr_write_transform_behavior
- lsr_write_gradient_units
- lsr_write_content_type
- lsr_write_script_type
- lsr_write_value_with_units
- lsr_write_clip_time
- lsr_write_href_anim
- lsr_write_attribute_type
- lsr_write_preserve_aspect_ratio
- lsr_write_a
- lsr_write_animate
- lsr_write_animateMotion
- lsr_write_animateTransform
- lsr_write_audio
- lsr_write_circle
- lsr_write_conditional
- lsr_write_cursorManager
- lsr_write_data
- lsr_write_defs
- lsr_write_ellipse
- lsr_write_foreignObject
- lsr_write_g
- lsr_write_image
- lsr_write_line
- lsr_write_linearGradient
- lsr_write_mpath
- lsr_write_path
- lsr_write_polygon
- lsr_write_radialGradient
- lsr_write_rect
- lsr_write_rectClip
- lsr_write_script
- lsr_write_selector
- lsr_write_set
- lsr_write_simpleLayout
- lsr_write_stop
- lsr_write_svg
- lsr_write_switch
- lsr_write_text
- lsr_write_tspan
- lsr_write_use
- lsr_write_video
- lsr_write_listener
- lsr_write_scene_content_model
- lsr_write_update_content_model
- lsr_write_group_content
- lsr_write_update_value
- lsr_write_add_replace_insert
- lsr_write_command_list
- lsr_add_color
- lsr_check_col_index
- lsr_check_font_index
- lsr_check_font_and_color
- lsr_write_laser_unit
#include <gpac/internal/laser_dev.h>
#include <gpac/internal/scenegraph_dev.h>
#include <gpac/bitstream.h>
#ifndef GPAC_DISABLE_LASER
#include <gpac/events.h>
#define GF_LSR_WRITE_INT(_codec, _val, _nbBits, _str) {\
gf_bs_write_int(_codec->bs, _val, _nbBits); \
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] %s\t\t%d\t\t%d\n", _str, _nbBits, _val)); \
}\
static void lsr_write_group_content(GF_LASeRCodec *lsr, SVG_Element *elt, Bool skip_object_content);
static GF_Err lsr_write_command_list(GF_LASeRCodec *lsr, GF_List *comList, SVG_Element *script, Bool first_implicit);
static GF_Err lsr_write_laser_unit(GF_LASeRCodec *lsr, GF_List *com_list, Bool reset_encoding_context);
static void lsr_write_point_sequence(GF_LASeRCodec *lsr, GF_List **pts, const char *name);
static void lsr_write_path_type(GF_LASeRCodec *lsr, SVG_PathData *path, const char *name);
GF_LASeRCodec *gf_laser_encoder_new(GF_SceneGraph *graph)
{
GF_LASeRCodec *tmp;
GF_SAFEALLOC(tmp, GF_LASeRCodec);
if (!tmp) return NULL;
tmp->streamInfo = gf_list_new();
tmp->font_table = gf_list_new();
tmp->sg = graph;
return tmp;
}
void gf_laser_encoder_del(GF_LASeRCodec *codec)
{
while (gf_list_count(codec->streamInfo)) {
LASeRStreamInfo *p = (LASeRStreamInfo *)gf_list_last(codec->streamInfo);
gf_free(p);
gf_list_rem_last(codec->streamInfo);
}
gf_list_del(codec->streamInfo);
if (codec->col_table) gf_free(codec->col_table);
while (gf_list_count(codec->font_table)) {
char *ft = (char *)gf_list_last(codec->font_table);
gf_free(ft);
gf_list_rem_last(codec->font_table);
}
gf_list_del(codec->font_table);
gf_free(codec);
}
static LASeRStreamInfo *lsr_get_stream(GF_LASeRCodec *codec, u16 ESID)
{
LASeRStreamInfo *ptr;
u32 i = 0;
while ((ptr = (LASeRStreamInfo *)gf_list_enum(codec->streamInfo, &i))) {
if(ptr->ESID==ESID) return ptr;
}
return NULL;
}
GF_Err gf_laser_encoder_new_stream(GF_LASeRCodec *codec, u16 ESID, GF_LASERConfig *cfg)
{
LASeRStreamInfo *pInfo;
if (lsr_get_stream(codec, ESID) != NULL) return GF_BAD_PARAM;
GF_SAFEALLOC(pInfo, LASeRStreamInfo);
if (!pInfo) return GF_OUT_OF_MEM;
pInfo->ESID = ESID;
memcpy(&pInfo->cfg, cfg, sizeof(GF_LASERConfig));
if (!pInfo->cfg.time_resolution) pInfo->cfg.time_resolution = 1000;
if (!pInfo->cfg.colorComponentBits) pInfo->cfg.colorComponentBits = 8;
if (!pInfo->cfg.coord_bits) pInfo->cfg.coord_bits = 12;
if (pInfo->cfg.resolution<-8) pInfo->cfg.resolution = (s8) -8;
else if (pInfo->cfg.resolution>7) pInfo->cfg.resolution=7;
gf_list_add(codec->streamInfo, pInfo);
return GF_OK;
}
GF_Err gf_laser_encoder_get_config(GF_LASeRCodec *codec, u16 ESID, char **out_data, u32 *out_data_length)
{
GF_BitStream *bs;
if (!codec || !out_data || !out_data_length) return GF_BAD_PARAM;
codec->info = lsr_get_stream(codec, ESID);
if (!codec->info) return GF_BAD_PARAM;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_bs_write_int(bs, codec->info->cfg.profile, 8);
gf_bs_write_int(bs, codec->info->cfg.level, 8);
gf_bs_write_int(bs, 0 , 3);
gf_bs_write_int(bs, codec->info->cfg.pointsCodec, 2);
gf_bs_write_int(bs, codec->info->cfg.pathComponents, 4);
gf_bs_write_int(bs, codec->info->cfg.fullRequestHost, 1);
if (codec->info->cfg.time_resolution != 1000) {
gf_bs_write_int(bs, 1, 1);
gf_bs_write_int(bs, codec->info->cfg.time_resolution , 16);
} else {
gf_bs_write_int(bs, 0, 1);
}
gf_bs_write_int(bs, codec->info->cfg.colorComponentBits - 1, 4);
if (codec->info->cfg.resolution<0)
gf_bs_write_int(bs, 16 + codec->info->cfg.resolution, 4);
else
gf_bs_write_int(bs, codec->info->cfg.resolution, 4);
gf_bs_write_int(bs, codec->info->cfg.coord_bits, 5);
gf_bs_write_int(bs, codec->info->cfg.scale_bits_minus_coord_bits, 4);
gf_bs_write_int(bs, codec->info->cfg.newSceneIndicator ? 1 : 0, 1);
gf_bs_write_int(bs, 0, 3);
gf_bs_write_int(bs, codec->info->cfg.extensionIDBits, 4);
gf_bs_write_int(bs, 0, 1);
gf_bs_write_int(bs, 0, 1);
gf_bs_align(bs);
gf_bs_get_content(bs, out_data, out_data_length);
gf_bs_del(bs);
return GF_OK;
}
GF_Err gf_laser_encode_au(GF_LASeRCodec *codec, u16 ESID, GF_List *command_list, Bool reset_context, char **out_data, u32 *out_data_length)
{
GF_Err e;
if (!codec || !command_list || !out_data || !out_data_length) return GF_BAD_PARAM;
codec->info = lsr_get_stream(codec, ESID);
if (!codec->info) return GF_BAD_PARAM;
codec->coord_bits = codec->info->cfg.coord_bits;
codec->scale_bits = codec->info->cfg.scale_bits_minus_coord_bits;
codec->time_resolution = codec->info->cfg.time_resolution;
codec->color_scale = (1<<codec->info->cfg.colorComponentBits) - 1;
if (codec->info->cfg.resolution>=0)
codec->res_factor = gf_divfix(FIX_ONE, INT2FIX(1<<codec->info->cfg.resolution) );
else
codec->res_factor = INT2FIX(1 << (-codec->info->cfg.resolution));
codec->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
e = lsr_write_laser_unit(codec, command_list, reset_context);
if (!e) {
gf_bs_align(codec->bs);
gf_bs_get_content(codec->bs, out_data, out_data_length);
}
gf_bs_del(codec->bs);
codec->bs = NULL;
return e;
}
GF_Err gf_laser_encoder_get_rap(GF_LASeRCodec *codec, char **out_data, u32 *out_data_length)
{
GF_Err e;
if (!codec->info) codec->info = (LASeRStreamInfo*)gf_list_get(codec->streamInfo, 0);
codec->coord_bits = codec->info->cfg.coord_bits;
codec->scale_bits = codec->info->cfg.scale_bits_minus_coord_bits;
codec->time_resolution = codec->info->cfg.time_resolution;
codec->color_scale = (1<<codec->info->cfg.colorComponentBits) - 1;
if (codec->info->cfg.resolution>=0)
codec->res_factor = gf_divfix(FIX_ONE, INT2FIX(1<<codec->info->cfg.resolution) );
else
codec->res_factor = INT2FIX(1 << (-codec->info->cfg.resolution));
codec->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
e = lsr_write_laser_unit(codec, NULL, GF_FALSE);
if (e == GF_OK) gf_bs_get_content(codec->bs, out_data, out_data_length);
gf_bs_del(codec->bs);
codec->bs = NULL;
return e;
}
static void lsr_write_vluimsbf5(GF_LASeRCodec *lsr, u32 val, const char *name)
{
u32 nb_words;
u32 nb_bits = val ? gf_get_bit_size(val) : 1;
nb_words = nb_bits / 4;
if (nb_bits%4) nb_words++;
assert(nb_words * 4 >= nb_bits);
nb_bits = 4*nb_words;
while (nb_words) {
nb_words--;
gf_bs_write_int(lsr->bs, nb_words ? 1 : 0, 1);
}
gf_bs_write_int(lsr->bs, val, nb_bits);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] %s\t\t%d\t\t%d\n", name, nb_bits + (nb_bits/4), val));
}
static void lsr_write_vluimsbf5_ex(GF_LASeRCodec *lsr, u32 val, u32 extra_words, const char *name)
{
u32 nb_words;
u32 nb_bits = val ? gf_get_bit_size(val) : 1;
nb_words = nb_bits / 4;
if (nb_bits%4) nb_words++;
nb_words += extra_words;
assert(nb_words * 4 >= nb_bits);
nb_bits = 4*nb_words;
while (nb_words) {
nb_words--;
gf_bs_write_int(lsr->bs, nb_words ? 1 : 0, 1);
}
gf_bs_write_int(lsr->bs, val, nb_bits);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] %s\t\t%d\t\t%d\n", name, nb_bits + (nb_bits/4), val));
}
static u32 lsr_get_vluimsbf5_size(u32 val, u32 extra_words)
{
u32 nb_words;
u32 nb_bits = val ? gf_get_bit_size(val) : 1;
nb_words = nb_bits / 4;
if (nb_bits%4) nb_words++;
nb_words += extra_words;
return 4*nb_words + nb_words;
}
static void lsr_write_vluimsbf8(GF_LASeRCodec *lsr, u32 val, const char *name)
{
u32 nb_words;
u32 nb_tot, nb_bits = val ? gf_get_bit_size(val) : 1;
nb_words = nb_bits / 7;
if (nb_bits%7) nb_words++;
assert(nb_words * 7 >= nb_bits);
nb_bits = nb_words * 7;
nb_tot = nb_words+nb_bits;
while (nb_words) {
nb_words--;
gf_bs_write_int(lsr->bs, nb_words ? 1 : 0, 1);
}
gf_bs_write_int(lsr->bs, val, nb_bits);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] %s\t\t%d\t\t%d\n", name, nb_tot, val));
}
static void lsr_write_extension(GF_LASeRCodec *lsr, char *data, u32 len, const char *name)
{
if (!len) len = (u32) strlen(name);
lsr_write_vluimsbf5(lsr, len, name);
gf_bs_write_data(lsr->bs, data, len);
}
static void lsr_write_codec_IDREF(GF_LASeRCodec *lsr, XMLRI *href, const char *name)
{
u32 nID = 0;
if (href && href->target) nID = gf_node_get_id((GF_Node *)href->target);
else if (name[0]=='#') {
GF_Node *n = gf_sg_find_node_by_name(lsr->sg, (char *) name + 1);
if (n) nID = gf_node_get_id((GF_Node *)href->target);
}
else nID = 1+href->lsr_stream_id;
assert(nID);
lsr_write_vluimsbf5(lsr, nID-1, name);
GF_LSR_WRITE_INT(lsr, 0, 1, "reserved");
}
static void lsr_write_codec_IDREF_Node(GF_LASeRCodec *lsr, GF_Node *href, const char *name)
{
u32 nID = gf_node_get_id(href);
assert(nID);
lsr_write_vluimsbf5(lsr, nID-1, name);
GF_LSR_WRITE_INT(lsr, 0, 1, "reserved");
}
static u32 lsr_get_IDREF_nb_bits(GF_LASeRCodec *lsr, GF_Node *href)
{
u32 nb_bits, nb_words, nID;
nID = gf_node_get_id(href);
assert(nID);
nb_bits = nID ? gf_get_bit_size(nID) : 1;
nb_words = nb_bits / 4;
if (nb_bits%4) nb_words++;
assert(nb_words * 4 >= nb_bits);
nb_bits = nb_words * 4;
return nb_words+nb_bits + 1 ;
}
static void lsr_write_fixed_16_8(GF_LASeRCodec *lsr, Fixed fix, const char *name)
{
u32 val;
if (fix<0) {
#ifdef GPAC_FIXED_POINT
val = (1<<24) + fix / 256;
#else
val = (1<<24) + FIX2INT(fix * 256);
#endif
} else {
#ifdef GPAC_FIXED_POINT
val = fix/256;
#else
val = FIX2INT(fix*256);
#endif
}
val &= 0x00FFFFFF;
GF_LSR_WRITE_INT(lsr, val, 24, name);
}
static void lsr_write_fixed_16_8i(GF_LASeRCodec *lsr, SVG_Number *n, const char *name)
{
if (n->type==SVG_NUMBER_INHERIT) {
GF_LSR_WRITE_INT(lsr, 1, 1, name);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
lsr_write_fixed_16_8(lsr, n->value, name);
}
}
static s32 lsr_get_font_index(GF_LASeRCodec *lsr, SVG_FontFamily *font)
{
u32 i, count;
if ((font->type!=SVG_FONTFAMILY_VALUE) || !font->value) return -1;
count = gf_list_count(lsr->font_table);
for (i=0; i<count; i++) {
char *n = (char *)gf_list_get(lsr->font_table, i);
if (!strcmp(n, font->value)) return (s32) i;
}
return -2;
}
static s32 lsr_get_col_index(GF_LASeRCodec *lsr, SVG_Color *color)
{
u16 r, g, b;
u32 i;
if (color->type!=SVG_COLOR_RGBCOLOR) return -1;
r = FIX2INT(color->red*lsr->color_scale);
g = FIX2INT(color->green*lsr->color_scale);
b = FIX2INT(color->blue*lsr->color_scale);
for (i=0; i<lsr->nb_cols; i++) {
LSRCol *c = &lsr->col_table[i];
if ((c->r == r) && (c->g == g) && (c->b == b)) return (s32) i;
}
return -2;
}
static void lsr_write_line_increment_type(GF_LASeRCodec *lsr, SVG_Number *li, const char *name)
{
if (li->type==SVG_NUMBER_INHERIT) {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, 1, 1, "inherit");
} else if (li->type==SVG_NUMBER_AUTO) {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, 0, 1, "auto");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
lsr_write_fixed_16_8(lsr, li->value, "line-increment-value");
}
}
static void lsr_write_byte_align_string(GF_LASeRCodec *lsr, char *str, const char *name)
{
u32 len = str ? (u32) strlen(str) : 0;
gf_bs_align(lsr->bs);
lsr_write_vluimsbf8(lsr, len, "len");
if (len) gf_bs_write_data(lsr->bs, str, len);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] %s\t\t%d\t\t%s\n", name, 8*len, str ? str : ""));
}
static void lsr_write_byte_align_string_list(GF_LASeRCodec *lsr, GF_List *l, const char *name, Bool is_iri)
{
char text[4096];
u32 i, count = gf_list_count(l);
text[0] = 0;
for (i=0; i<count; i++) {
char *str;
if (is_iri) {
XMLRI *iri = (XMLRI *)gf_list_get(l, i);
str = iri->string;
} else {
str = (char*)gf_list_get(l, i);
}
strcat(text, str);
if (i+1<count) strcat(text, ";");
}
lsr_write_byte_align_string(lsr, text, name);
}
static void lsr_write_any_uri(GF_LASeRCodec *lsr, XMLRI *iri, const char *name)
{
Bool is_iri = GF_FALSE;
if (iri->type==XMLRI_STRING) {
is_iri = GF_TRUE;
if (iri->string[0]=='#') {
iri->target = (SVG_Element*)gf_sg_find_node_by_name(lsr->sg, iri->string+1);
if (iri->target) {
is_iri = GF_FALSE;
iri->type = XMLRI_ELEMENTID;
}
}
}
GF_LSR_WRITE_INT(lsr, is_iri, 1, "hasUri");
if (is_iri) {
if (!iri->string || strnicmp(iri->string, "data:", 5)) {
lsr_write_byte_align_string(lsr, iri->string, "uri");
GF_LSR_WRITE_INT(lsr, 0, 1, "hasData");
} else {
u32 len;
char *sep = strchr(iri->string, ',');
sep[0] = 0;
lsr_write_byte_align_string(lsr, iri->string, "uri");
sep[0] = ',';
len = (u32) strlen(sep+1);
GF_LSR_WRITE_INT(lsr, 1, 1, "hasData");
lsr_write_vluimsbf5(lsr, len, "len");
gf_bs_write_data(lsr->bs, sep+1, len);
}
}
GF_LSR_WRITE_INT(lsr, (iri->type==XMLRI_ELEMENTID) ? 1 : 0, 1, "hasID");
if (iri->type==XMLRI_ELEMENTID) lsr_write_codec_IDREF(lsr, iri, "idref");
GF_LSR_WRITE_INT(lsr, (iri->type==XMLRI_STREAMID) ? 1 : 0, 1, "hasID");
if (iri->type==XMLRI_STREAMID)
lsr_write_codec_IDREF(lsr, iri, "ref");
}
static void lsr_write_paint(GF_LASeRCodec *lsr, SVG_Paint *paint, const char *name)
{
if ((paint->type==SVG_PAINT_COLOR) && (paint->color.type==SVG_COLOR_RGBCOLOR)) {
s32 idx;
GF_LSR_WRITE_INT(lsr, 1, 1, "hasIndex");
idx = lsr_get_col_index(lsr, &paint->color);
if (idx<0) {
idx = 0;
GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[LASeR] color not in colorTable\n"));
}
GF_LSR_WRITE_INT(lsr, (u32) idx, lsr->colorIndexBits, name);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasIndex");
switch (paint->type) {
case SVG_PAINT_INHERIT:
GF_LSR_WRITE_INT(lsr, 0, 2, "enum");
GF_LSR_WRITE_INT(lsr, 0, 2, "choice");
break;
case SVG_PAINT_NONE:
GF_LSR_WRITE_INT(lsr, 0, 2, "enum");
GF_LSR_WRITE_INT(lsr, 2, 2, "choice");
break;
case SVG_PAINT_COLOR:
if (paint->color.type == SVG_COLOR_CURRENTCOLOR) {
GF_LSR_WRITE_INT(lsr, 0, 2, "enum");
GF_LSR_WRITE_INT(lsr, 1, 2, "choice");
} else {
GF_LSR_WRITE_INT(lsr, 2, 2, "enum");
lsr_write_byte_align_string(lsr, (char*)gf_svg_get_system_paint_server_name(paint->color.type), "systemsPaint");
}
break;
case SVG_PAINT_URI:
GF_LSR_WRITE_INT(lsr, 1, 2, "enum");
lsr_write_any_uri(lsr, &paint->iri, "uri");
break;
default:
GF_LSR_WRITE_INT(lsr, 3, 2, "enum");
lsr_write_extension(lsr, "ERROR", 5, "colorExType0");
break;
}
}
}
#ifdef GPAC_UNUSED_FUNC
static void lsr_write_private_element_container(GF_LASeRCodec *lsr)
{
assert(0);
}
static void lsr_write_private_att_class(GF_LASeRCodec *lsr)
{
assert(0);
}
static void lsr_write_extend_class(GF_LASeRCodec *lsr, char *data, u32 len, const char *name)
{
u32 i=0;
GF_LSR_WRITE_INT(lsr, 0, lsr->info->cfg.extensionIDBits, "reserved");
lsr_write_vluimsbf5(lsr, len, "len");
while (i<len) {
gf_bs_write_int(lsr->bs, data[i], 8);
i++;
}
}
static void lsr_write_private_attr_container(GF_LASeRCodec *lsr, u32 index, const char *name)
{
assert(0);
}
static Bool lsr_float_list_equal(GF_List *l1, GF_List *l2)
{
u32 i, count = gf_list_count(l1);
if (count != gf_list_count(l2)) return 0;
for (i=0; i<count; i++) {
Fixed *v1 = (Fixed *)gf_list_get(l1, i);
Fixed *v2 = (Fixed *)gf_list_get(l2, i);
if (*v1 != *v2) return 0;
}
return 1;
}
#endif
static void lsr_write_any_attribute(GF_LASeRCodec *lsr, SVG_Element *node, Bool skippable)
{
if (1) {
if (skippable) GF_LSR_WRITE_INT(lsr, 0, 1, "has_attrs");
} else {
if (skippable) GF_LSR_WRITE_INT(lsr, 1, 1, "has_attrs");
}
}
static void lsr_write_private_attributes(GF_LASeRCodec *lsr, SVG_Element *elt)
{
if (1) {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_private_attr");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_private_attr");
#ifdef GPAC_UNUSED_FUNC
lsr_write_private_att_class(lsr);
#endif
}
}
static void lsr_write_string_attribute(GF_LASeRCodec *lsr, char *class_attr, char *name)
{
if (class_attr) {
GF_LSR_WRITE_INT(lsr, 1, 1, name);
lsr_write_byte_align_string(lsr, class_attr, name);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
}
}
static void lsr_write_id(GF_LASeRCodec *lsr, GF_Node *n)
{
u32 id = gf_node_get_id(n);
if (id) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_id");
lsr_write_vluimsbf5(lsr, id-1, "ID");
#if TODO_LASER_EXTENSIONS
if (0) {
GF_LSR_WRITE_INT(lsr, 1, 1, "reserved");
lsr_write_vluimsbf5(lsr, reserved_len, "len");
GF_LSR_WRITE_INT(lsr, 0, reserved_len, "reserved");
} else
#endif
GF_LSR_WRITE_INT(lsr, 0, 1, "reserved");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_id");
}
}
static u32 lsr_translate_coords(GF_LASeRCodec *lsr, Fixed x, u32 nb_bits)
{
s32 res, max;
res = FIX2INT( gf_divfix(x, lsr->res_factor) );
if (!res && x) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] resolution factor %g too small to allow coding of %g - adjusting to smallest integer!\n", lsr->res_factor, FIX2FLT(x) ));
res = (x>0) ? 1 : -1;
}
max = (1<<(nb_bits-1)) - 1;
if (res>=0) {
if (res > max) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] nb_bits %d not large enough to encode positive number %g!\n", nb_bits, FIX2FLT(x) ));
res = max;
}
assert( ! (res & (1<<(nb_bits-1)) ));
return (u32) res;
}
res += 1<<(nb_bits);
if (res<=max) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] nb_bits %d not large enough to encode negative number %g!\n", nb_bits, FIX2FLT(x) ));
res = max+1;
}
assert( res & (1<<(nb_bits-1)) );
return res;
}
static u32 lsr_translate_scale(GF_LASeRCodec *lsr, Fixed v)
{
s32 res;
if (ABS(v) * 256 < 1) v = 0;
v = v*256;
if (v<0) {
res = FIX2INT(v) + (1<<lsr->coord_bits);
if (res<0) GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[LASeR] nb_bits %d not large enough to encode negative number %d!\n", lsr->coord_bits, res));
return res;
}
res = FIX2INT(v);
if (res & (1<<(lsr->coord_bits-1)) ) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[LASeR] nb_bits %d not large enough to encode positive number %d!\n", lsr->coord_bits, res));
}
return res;
}
static void lsr_write_matrix(GF_LASeRCodec *lsr, SVG_Transform *mx)
{
u32 res;
if (mx->is_ref) {
GF_LSR_WRITE_INT(lsr, 1, 1, "isNotMatrix");
GF_LSR_WRITE_INT(lsr, 1, 1, "isRef");
GF_LSR_WRITE_INT(lsr, 1, 1, "hasXY");
lsr_write_fixed_16_8(lsr, mx->mat.m[2], "valueX");
lsr_write_fixed_16_8(lsr, mx->mat.m[5], "valueY");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "isNotMatrix");
lsr->coord_bits += lsr->scale_bits;
if ((mx->mat.m[0]!=FIX_ONE) || (mx->mat.m[4]!=FIX_ONE)) {
GF_LSR_WRITE_INT(lsr, 1, 1, "xx_yy_present");
res = lsr_translate_scale(lsr, mx->mat.m[0]);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, "xx");
res = lsr_translate_scale(lsr, mx->mat.m[4]);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, "yy");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "xx_yy_present");
}
if (mx->mat.m[1] || mx->mat.m[3]) {
GF_LSR_WRITE_INT(lsr, 1, 1, "xy_yx_present");
res = lsr_translate_scale(lsr, mx->mat.m[1]);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, "xy");
res = lsr_translate_scale(lsr, mx->mat.m[3]);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, "yx");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "xy_yx_present");
}
if (mx->mat.m[2] || mx->mat.m[5]) {
GF_LSR_WRITE_INT(lsr, 1, 1, "xz_yz_present");
res = lsr_translate_coords(lsr, mx->mat.m[2], lsr->coord_bits);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, "xz");
res = lsr_translate_coords(lsr, mx->mat.m[5], lsr->coord_bits);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, "yz");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "xz_yz_present");
}
lsr->coord_bits -= lsr->scale_bits;
}
}
static void lsr_write_fixed_clamp(GF_LASeRCodec *lsr, Fixed f, const char *name)
{
#ifdef GPAC_FIXED_POINT
s32 val = f >> 8;
#else
s32 val = (u32) (255 * f);
#endif
if (val<0) val = 0;
else if (val>255) val = 255;
GF_LSR_WRITE_INT(lsr, (u32) val, 8, name);
}
u32 dom_to_lsr_key(u32 dom_k)
{
switch (dom_k) {
case GF_KEY_STAR:
return 0;
case GF_KEY_0:
return 1;
case GF_KEY_1:
return 2;
case GF_KEY_2:
return 3;
case GF_KEY_3:
return 4;
case GF_KEY_4:
return 5;
case GF_KEY_5:
return 6;
case GF_KEY_6:
return 7;
case GF_KEY_7:
return 8;
case GF_KEY_8:
return 9;
case GF_KEY_9:
return 10;
case GF_KEY_DOWN:
return 12;
case GF_KEY_LEFT:
return 14;
case GF_KEY_RIGHT:
return 16;
case GF_KEY_UP:
return 20;
case GF_KEY_ENTER:
case GF_KEY_EXECUTE:
return 13;
case GF_KEY_ESCAPE:
return 15;
case GF_KEY_NUMBER:
return 17;
case GF_KEY_CELL_SOFT1:
return 18;
case GF_KEY_CELL_SOFT2:
return 19;
default:
return 100;
}
}
static void lsr_write_event_type(GF_LASeRCodec *lsr, u32 evtType, u32 evtParam)
{
u32 force_string = 0;
switch (evtType) {
case GF_EVENT_KEYDOWN:
case GF_EVENT_LONGKEYPRESS:
case GF_EVENT_REPEAT_KEY:
case GF_EVENT_SHORT_ACCESSKEY:
if (dom_to_lsr_key(evtParam)==100) force_string = 2;
break;
case GF_EVENT_BEGIN:
case GF_EVENT_END:
force_string = 1;
break;
case GF_EVENT_REPEAT:
force_string = 1;
break;
}
if (force_string) {
char szName[1024];
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
if (evtParam) {
if (force_string==2) {
sprintf(szName, "%s(%s)", gf_dom_event_get_name(evtType), gf_dom_get_key_name(evtParam) );
} else {
sprintf(szName, "%s(%d)", gf_dom_event_get_name(evtType), evtParam);
}
} else {
sprintf(szName, "%s", gf_dom_event_get_name(evtType));
}
lsr_write_byte_align_string(lsr, szName, "evtString");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
switch (evtType) {
case GF_EVENT_ABORT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_abort, 6, "event");
break;
case GF_EVENT_ACTIVATE:
GF_LSR_WRITE_INT(lsr, LSR_EVT_activate, 6, "event");
break;
case GF_EVENT_ACTIVATED:
GF_LSR_WRITE_INT(lsr, LSR_EVT_activatedEvent, 6, "event");
break;
case GF_EVENT_BEGIN:
case GF_EVENT_BEGIN_EVENT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_beginEvent, 6, "event");
break;
case GF_EVENT_CLICK:
GF_LSR_WRITE_INT(lsr, LSR_EVT_click, 6, "event");
break;
case GF_EVENT_DEACTIVATED:
GF_LSR_WRITE_INT(lsr, LSR_EVT_deactivatedEvent, 6, "event");
break;
case GF_EVENT_END:
case GF_EVENT_END_EVENT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_endEvent, 6, "event");
break;
case GF_EVENT_ERROR:
GF_LSR_WRITE_INT(lsr, LSR_EVT_error, 6, "event");
break;
case GF_EVENT_EXECUTION_TIME:
GF_LSR_WRITE_INT(lsr, LSR_EVT_executionTime, 6, "event");
break;
case GF_EVENT_FOCUSIN:
GF_LSR_WRITE_INT(lsr, LSR_EVT_focusin, 6, "event");
break;
case GF_EVENT_FOCUSOUT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_focusout, 6, "event");
break;
case GF_EVENT_KEYDOWN:
GF_LSR_WRITE_INT(lsr, evtParam ? LSR_EVT_accessKey : LSR_EVT_keydown, 6, "event");
break;
case GF_EVENT_KEYUP:
GF_LSR_WRITE_INT(lsr, LSR_EVT_keyup, 6, "event");
break;
case GF_EVENT_LOAD:
GF_LSR_WRITE_INT(lsr, LSR_EVT_load, 6, "event");
break;
case GF_EVENT_LONGKEYPRESS:
GF_LSR_WRITE_INT(lsr, LSR_EVT_longAccessKey, 6, "event");
break;
case GF_EVENT_MOUSEDOWN:
GF_LSR_WRITE_INT(lsr, LSR_EVT_mousedown, 6, "event");
break;
case GF_EVENT_MOUSEMOVE:
GF_LSR_WRITE_INT(lsr, LSR_EVT_mousemove, 6, "event");
break;
case GF_EVENT_MOUSEOUT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_mouseout, 6, "event");
break;
case GF_EVENT_MOUSEOVER:
GF_LSR_WRITE_INT(lsr, LSR_EVT_mouseover, 6, "event");
break;
case GF_EVENT_MOUSEUP:
GF_LSR_WRITE_INT(lsr, LSR_EVT_mouseup, 6, "event");
break;
case GF_EVENT_PAUSE:
GF_LSR_WRITE_INT(lsr, LSR_EVT_pause, 6, "event");
break;
case GF_EVENT_PAUSED_EVENT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_pausedEvent, 6, "event");
break;
case GF_EVENT_PLAY:
GF_LSR_WRITE_INT(lsr, LSR_EVT_play, 6, "event");
break;
case GF_EVENT_REPEAT_EVENT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_repeatEvent, 6, "event");
break;
case GF_EVENT_REPEAT_KEY:
GF_LSR_WRITE_INT(lsr, LSR_EVT_repeatKey, 6, "event");
break;
case GF_EVENT_RESIZE:
GF_LSR_WRITE_INT(lsr, LSR_EVT_resize, 6, "event");
break;
case GF_EVENT_RESUME_EVENT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_resumedEvent, 6, "event");
break;
case GF_EVENT_SCROLL:
GF_LSR_WRITE_INT(lsr, LSR_EVT_scroll, 6, "event");
break;
case GF_EVENT_SHORT_ACCESSKEY:
GF_LSR_WRITE_INT(lsr, LSR_EVT_shortAccessKey, 6, "event");
break;
case GF_EVENT_TEXTINPUT:
GF_LSR_WRITE_INT(lsr, LSR_EVT_textinput, 6, "event");
break;
case GF_EVENT_UNLOAD:
GF_LSR_WRITE_INT(lsr, LSR_EVT_unload, 6, "event");
break;
case GF_EVENT_ZOOM:
GF_LSR_WRITE_INT(lsr, LSR_EVT_zoom, 6, "event");
break;
default:
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] Unsupported LASER event %d\n", evtType) );
GF_LSR_WRITE_INT(lsr, 0, 6, "event");
break;
return;
}
switch (evtType) {
case GF_EVENT_KEYDOWN:
if (!evtParam) break;
case GF_EVENT_LONGKEYPRESS:
case GF_EVENT_REPEAT_KEY:
case GF_EVENT_SHORT_ACCESSKEY:
lsr_write_vluimsbf5(lsr, dom_to_lsr_key(evtParam), "keyCode");
break;
}
}
}
static void lsr_write_smil_time(GF_LASeRCodec *lsr, SMIL_Time *t)
{
s32 now;
if (t->type==GF_SMIL_TIME_EVENT) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasEvent");
if (t->element && gf_node_get_id((GF_Node*)t->element) ) {
XMLRI iri;
GF_LSR_WRITE_INT(lsr, 1, 1, "hasIdentifier");
iri.string = NULL;
iri.type = XMLRI_ELEMENTID;
iri.target = t->element;
lsr_write_codec_IDREF(lsr, &iri, "idref");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasIdentifier");
}
lsr_write_event_type(lsr, t->event.type, t->event.parameter);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasEvent");
}
if (!t->clock) {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasClock");
return;
}
GF_LSR_WRITE_INT(lsr, 1, 1, "hasClock");
now = (s32) (t->clock * lsr->time_resolution);
if (now<0) {
now = -now;
GF_LSR_WRITE_INT(lsr, 1, 1, "sign");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "sign");
}
lsr_write_vluimsbf5(lsr, now, "value");
}
static void lsr_write_smil_times(GF_LASeRCodec *lsr, GF_List **l, const char *name, Bool skipable)
{
SMIL_Time *v;
u32 r_count, i, count;
Bool indef = GF_FALSE;
count = l ? gf_list_count(*l) : 0;
r_count = 0;
for (i=0; i<count; i++) {
v = (SMIL_Time*)gf_list_get(*l, i);
if (v->type==GF_SMIL_TIME_INDEFINITE) {
indef = GF_TRUE;
break;
}
else if (v->type!=GF_SMIL_TIME_EVENT_RESOLVED) r_count++;
}
if (skipable && !r_count && !indef) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
return;
}
if (skipable) GF_LSR_WRITE_INT(lsr, 1, 1, name);
GF_LSR_WRITE_INT(lsr, indef, 1, "choice");
if (indef) return;
lsr_write_vluimsbf5(lsr, r_count, "count");
for (i=0; i<count; i++) {
v = (SMIL_Time*)gf_list_get(*l, i);
lsr_write_smil_time(lsr, v);
}
}
static void lsr_write_duration_ex(GF_LASeRCodec *lsr, SMIL_Duration *v, const char *name, Bool skipable)
{
if (skipable) {
if (!v || !v->type) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
return;
}
GF_LSR_WRITE_INT(lsr, 1, 1, name);
}
if (v->type==SMIL_DURATION_DEFINED) {
s32 now = (s32) (v->clock_value * lsr->time_resolution);
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
GF_LSR_WRITE_INT(lsr, (now<0) ? 1 : 0, 1, "sign");
if (now<0) now = -now;
lsr_write_vluimsbf5(lsr, now, "value");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, v->type, 2, "time");
}
}
#define lsr_write_duration(a, b, c) lsr_write_duration_ex(a, b, c, 1)
static void lsr_write_focus(GF_LASeRCodec *lsr, SVG_Focus *foc, const char *name)
{
if (foc->type==SVG_FOCUS_IRI) {
GF_LSR_WRITE_INT(lsr, 0, 1, "isEnum");
lsr_write_codec_IDREF(lsr, &foc->target, "id");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "isEnum");
GF_LSR_WRITE_INT(lsr, foc->type, 1, "enum");
}
}
static Bool lsr_elt_has_same_base(GF_LASeRCodec *lsr, SVGAllAttributes *atts, SVG_Element *base, Bool *same_fill, Bool *same_stroke, Bool no_stroke_check)
{
SVGAllAttributes base_atts;
GF_FieldInfo info, base_info;
if (same_stroke) *same_stroke = GF_FALSE;
if (same_fill) *same_fill = GF_FALSE;
if (!base) return GF_FALSE;
gf_svg_flatten_attributes(base, &base_atts);
if (atts->externalResourcesRequired != base_atts.externalResourcesRequired) return GF_FALSE;
info.fieldType = base_info.fieldType = SVG_Paint_datatype;
info.far_ptr = atts->stroke;
base_info.far_ptr = base_atts.stroke;
if (!gf_svg_attributes_equal(&info, &base_info)) {
if (!no_stroke_check) return GF_FALSE;
} else {
if (same_stroke) *same_stroke = GF_TRUE;
}
if (same_fill) {
info.fieldType = base_info.fieldType = SVG_Paint_datatype;
info.far_ptr = atts->fill;
base_info.far_ptr = base_atts.fill;
*same_fill = gf_svg_attributes_equal(&info, &base_info) ? GF_TRUE : GF_FALSE;
}
switch (gf_node_get_tag((GF_Node*) base)) {
case TAG_SVG_path:
info.fieldType = base_info.fieldType = SVG_Number_datatype;
info.far_ptr = atts->pathLength;
base_info.far_ptr = base_atts.pathLength;
if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE;
break;
case TAG_SVG_rect:
info.fieldType = base_info.fieldType = SVG_Length_datatype;
info.far_ptr = atts->rx;
base_info.far_ptr = base_atts.rx;
if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE;
info.fieldType = base_info.fieldType = SVG_Length_datatype;
info.far_ptr = atts->ry;
base_info.far_ptr = base_atts.ry;
if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE;
break;
case TAG_SVG_use:
info.fieldType = base_info.fieldType = SVG_Coordinate_datatype;
info.far_ptr = atts->x;
base_info.far_ptr = base_atts.x;
if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE;
info.fieldType = base_info.fieldType = SVG_Coordinate_datatype;
info.far_ptr = atts->y;
base_info.far_ptr = base_atts.y;
if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE;
break;
case TAG_SVG_text:
info.fieldType = base_info.fieldType = SVG_Boolean_datatype;
info.far_ptr = atts->editable;
base_info.far_ptr = base_atts.editable;
if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE;
info.fieldType = base_info.fieldType = SVG_Numbers_datatype;
info.far_ptr = atts->text_rotate;
base_info.far_ptr = base_atts.text_rotate;
if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE;
break;
}
return gf_lsr_same_rare(atts, &base_atts);
}
static void lsr_write_rare(GF_LASeRCodec *lsr, GF_Node *n)
{
u32 i, nb_rare;
s32 field_rare;
SVGAttribute *att;
nb_rare = 0;
att = ((SVG_Element*)n)->attributes;
while (att) {
field_rare = gf_lsr_rare_type_from_attribute(att->tag);
if (field_rare>=0) nb_rare++;
att = att->next;
}
GF_LSR_WRITE_INT(lsr, nb_rare ? 1 : 0, 1, "has_rare");
if (!nb_rare) return;
GF_LSR_WRITE_INT(lsr, nb_rare, 6, "nbOfAttributes");
att = ((SVG_Element*)n)->attributes;
while (att) {
field_rare = gf_lsr_rare_type_from_attribute(att->tag);
if (field_rare==-1) {
att = att->next;
continue;
}
if (field_rare==49) {
Bool is_string = GF_FALSE;
u32 size, cur_bits;
u32 len = 2+3;
switch (att->tag) {
case TAG_SVG_ATT_syncMaster:
len +=1;
break;
case TAG_SVG_ATT_requiredFonts:
len += 8 * (u32) strlen(*(SVG_String*)att->data);
size = lsr_get_vluimsbf5_size(len, 1);
cur_bits = gf_bs_get_bit_position(lsr->bs) + lsr->info->cfg.extensionIDBits + size + 5;
while (cur_bits%8) {
len++;
cur_bits++;
}
is_string = GF_TRUE;
break;
default:
len +=2;
break;
}
GF_LSR_WRITE_INT(lsr, 49, 6, "attributeRARE");
GF_LSR_WRITE_INT(lsr, 2, lsr->info->cfg.extensionIDBits, "extensionID");
if (is_string) {
lsr_write_vluimsbf5_ex(lsr, len, 1, "len");
} else {
lsr_write_vluimsbf5(lsr, len, "len");
}
GF_LSR_WRITE_INT(lsr, 1, 2, "nbOfAttributes");
switch (att->tag) {
case TAG_SVG_ATT_syncMaster:
GF_LSR_WRITE_INT(lsr, 0, 3, "attributeRARE");
GF_LSR_WRITE_INT(lsr, *(SVG_Boolean *)att->data ? 1 : 0, 1, "syncMaster");
break;
case TAG_SVG_ATT_focusHighlight:
GF_LSR_WRITE_INT(lsr, 1, 3, "attributeRARE");
GF_LSR_WRITE_INT(lsr, *(SVG_FocusHighlight*)att->data, 2, "focusHighlight");
break;
case TAG_SVG_ATT_initialVisibility:
GF_LSR_WRITE_INT(lsr, 2, 3, "attributeRARE");
GF_LSR_WRITE_INT(lsr, *(SVG_InitialVisibility*)att->data, 2, "initialVisibility");
break;
case TAG_SVG_ATT_fullscreen:
GF_LSR_WRITE_INT(lsr, 3, 3, "attributeRARE");
GF_LSR_WRITE_INT(lsr, *(SVG_Boolean *)att->data ? 1 : 0, 2, "fullscreen");
break;
case TAG_SVG_ATT_requiredFonts:
GF_LSR_WRITE_INT(lsr, 4, 3, "attributeRARE");
lsr_write_byte_align_string(lsr, *(SVG_String*)att->data, "requiredFonts");
break;
}
GF_LSR_WRITE_INT(lsr, 0, 1, "hasNextExtension");
att = att->next;
continue;
}
GF_LSR_WRITE_INT(lsr, (u32)field_rare, 6, "attributeRARE");
switch (att->tag) {
case TAG_SVG_ATT__class:
lsr_write_byte_align_string(lsr, *(SVG_String *)att->data, "class");
break;
case TAG_SVG_ATT_audio_level:
lsr_write_fixed_clamp(lsr, ((SVG_Number *) att->data)->value, "audio-level");
break;
case TAG_SVG_ATT_color:
lsr_write_paint(lsr, (SVG_Paint*) att->data, "color");
break;
case TAG_SVG_ATT_color_rendering:
GF_LSR_WRITE_INT(lsr, *(SVG_RenderingHint*)att->data, 2, "color-rendering");
break;
case TAG_SVG_ATT_display:
GF_LSR_WRITE_INT(lsr, *(SVG_Display*)att->data, 5, "display");
break;
case TAG_SVG_ATT_display_align:
GF_LSR_WRITE_INT(lsr, *(SVG_DisplayAlign*)att->data, 3, "display-align");
break;
case TAG_SVG_ATT_fill_opacity:
lsr_write_fixed_clamp(lsr, ((SVG_Number *)att->data)->value, "fill-opacity");
break;
case TAG_SVG_ATT_fill_rule:
GF_LSR_WRITE_INT(lsr, *(SVG_FillRule*)att->data, 2, "fill-rule");
break;
case TAG_SVG_ATT_image_rendering:
GF_LSR_WRITE_INT(lsr, *(SVG_RenderingHint*)att->data, 2, "image-rendering");
break;
case TAG_SVG_ATT_line_increment:
lsr_write_line_increment_type(lsr, (SVG_Number*)att->data, "lineIncrement");
break;
case TAG_SVG_ATT_pointer_events:
GF_LSR_WRITE_INT(lsr, *(SVG_PointerEvents*)att->data, 4, "pointer-events");
break;
case TAG_SVG_ATT_shape_rendering:
GF_LSR_WRITE_INT(lsr, *(SVG_RenderingHint*)att->data, 3, "shape-rendering");
break;
case TAG_SVG_ATT_solid_color:
lsr_write_paint(lsr, (SVG_Paint*)att->data, "solid-color");
break;
case TAG_SVG_ATT_solid_opacity:
lsr_write_fixed_clamp(lsr, ((SVG_Number *)att->data)->value, "solid-opacity");
break;
case TAG_SVG_ATT_stop_color:
lsr_write_paint(lsr, (SVG_Paint*)att->data, "stop-color");
break;
case TAG_SVG_ATT_stop_opacity:
lsr_write_fixed_clamp(lsr, ((SVG_Number *)att->data)->value, "stop-opacity");
break;
case TAG_SVG_ATT_stroke_dasharray:
{
u32 j;
SVG_StrokeDashArray *da = (SVG_StrokeDashArray*)att->data;
if (da->type==SVG_STROKEDASHARRAY_INHERIT) {
GF_LSR_WRITE_INT(lsr, 1, 1, "dashArray");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "dashArray");
lsr_write_vluimsbf5(lsr, da->array.count, "len");
for (j=0; j<da->array.count; j++) {
lsr_write_fixed_16_8(lsr, da->array.vals[j], "dash");
}
}
}
break;
case TAG_SVG_ATT_stroke_dashoffset:
lsr_write_fixed_16_8i(lsr, (SVG_Number*)att->data, "dashOffset");
break;
case TAG_SVG_ATT_stroke_linecap:
GF_LSR_WRITE_INT(lsr, *(SVG_StrokeLineCap*)att->data, 2, "stroke-linecap");
break;
case TAG_SVG_ATT_stroke_linejoin:
GF_LSR_WRITE_INT(lsr, *(SVG_StrokeLineJoin*)att->data, 2, "stroke-linejoin");
break;
case TAG_SVG_ATT_stroke_miterlimit:
lsr_write_fixed_16_8i(lsr, (SVG_Number*)att->data, "miterLimit");
break;
case TAG_SVG_ATT_stroke_opacity:
lsr_write_fixed_clamp(lsr, ((SVG_Number *)att->data)->value, "stroke-opacity");
break;
case TAG_SVG_ATT_stroke_width:
lsr_write_fixed_16_8i(lsr, (SVG_Number*)att->data, "strokeWidth");
break;
case TAG_SVG_ATT_text_anchor:
GF_LSR_WRITE_INT(lsr, *(SVG_TextAnchor*)att->data, 2, "text-achor");
break;
case TAG_SVG_ATT_text_rendering:
GF_LSR_WRITE_INT(lsr, *(SVG_RenderingHint*)att->data, 3, "text-rendering");
break;
case TAG_SVG_ATT_viewport_fill:
lsr_write_paint(lsr, (SVG_Paint*)att->data, "viewport-fill");
break;
case TAG_SVG_ATT_viewport_fill_opacity:
lsr_write_fixed_clamp(lsr, ((SVG_Number *)att->data)->value, "viewport-fill-opacity");
break;
case TAG_SVG_ATT_vector_effect:
GF_LSR_WRITE_INT(lsr, *(SVG_VectorEffect*)att->data, 4, "vector-effect");
break;
case TAG_SVG_ATT_visibility:
GF_LSR_WRITE_INT(lsr, *(SVG_PointerEvents*)att->data, 2, "visibility");
break;
case TAG_SVG_ATT_requiredExtensions:
lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "requiredExtensions", GF_TRUE);
break;
case TAG_SVG_ATT_requiredFormats:
lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "requiredFormats", GF_FALSE);
break;
case TAG_SVG_ATT_requiredFeatures:
{
GF_List *l = *(GF_List **)att->data;
u32 j, tot_count, count = gf_list_count(l);
u8 *vals = (u8*)gf_malloc(sizeof(u8)*count);
tot_count = 0;
for (i=0; i<count; i++) {
char *ext;
XMLRI *iri = (XMLRI*)gf_list_get(l, i);
if (iri->type != XMLRI_STRING) continue;
ext = strchr(iri->string, '#');
if (!ext) continue;
if (!stricmp(ext, "Animation")) {
vals[tot_count] = 0;
tot_count++;
}
else if (!stricmp(ext, "Audio")) {
vals[tot_count] = 1;
tot_count++;
}
else if (!stricmp(ext, "ComposedVideo")) {
vals[tot_count] = 2;
tot_count++;
}
else if (!stricmp(ext, "ConditionalProcessing")) {
vals[tot_count] = 3;
tot_count++;
}
else if (!stricmp(ext, "ConditionalProcessingAttribute")) {
vals[tot_count] = 4;
tot_count++;
}
else if (!stricmp(ext, "CoreAttribute")) {
vals[tot_count] = 5;
tot_count++;
}
else if (!stricmp(ext, "Extensibility")) {
vals[tot_count] = 6;
tot_count++;
}
else if (!stricmp(ext, "ExternalResourcesRequired")) {
vals[tot_count] = 7;
tot_count++;
}
else if (!stricmp(ext, "Font")) {
vals[tot_count] = 8;
tot_count++;
}
else if (!stricmp(ext, "Gradient")) {
vals[tot_count] = 9;
tot_count++;
}
else if (!stricmp(ext, "GraphicsAttribute")) {
vals[tot_count] = 10;
tot_count++;
}
else if (!stricmp(ext, "Handler")) {
vals[tot_count] = 11;
tot_count++;
}
else if (!stricmp(ext, "Hyperlinking")) {
vals[tot_count] = 12;
tot_count++;
}
else if (!stricmp(ext, "Image")) {
vals[tot_count] = 13;
tot_count++;
}
else if (!stricmp(ext, "OpacityAttribute")) {
vals[tot_count] = 14;
tot_count++;
}
else if (!stricmp(ext, "PaintAttribute")) {
vals[tot_count] = 15;
tot_count++;
}
else if (!stricmp(ext, "Prefetch")) {
vals[tot_count] = 16;
tot_count++;
}
else if (!stricmp(ext, "SVG")) {
vals[tot_count] = 17;
tot_count++;
}
else if (!stricmp(ext, "SVG-animation")) {
vals[tot_count] = 18;
tot_count++;
}
else if (!stricmp(ext, "SVG-dynamic")) {
vals[tot_count] = 19;
tot_count++;
}
else if (!stricmp(ext, "SVG-static")) {
vals[tot_count] = 20;
tot_count++;
}
else if (!stricmp(ext, "SVGDOM")) {
vals[tot_count] = 21;
tot_count++;
}
else if (!stricmp(ext, "SVGDOM-animation")) {
vals[tot_count] = 22;
tot_count++;
}
else if (!stricmp(ext, "SVGDOM-dynamic")) {
vals[tot_count] = 23;
tot_count++;
}
else if (!stricmp(ext, "SVGDOM-static")) {
vals[tot_count] = 24;
tot_count++;
}
else if (!stricmp(ext, "Script")) {
vals[tot_count] = 25;
tot_count++;
}
else if (!stricmp(ext, "Shape")) {
vals[tot_count] = 26;
tot_count++;
}
else if (!stricmp(ext, "SolidColor")) {
vals[tot_count] = 27;
tot_count++;
}
else if (!stricmp(ext, "Structure")) {
vals[tot_count] = 28;
tot_count++;
}
else if (!stricmp(ext, "Text")) {
vals[tot_count] = 29;
tot_count++;
}
else if (!stricmp(ext, "TimedAnimation")) {
vals[tot_count] = 30;
tot_count++;
}
else if (!stricmp(ext, "TransformedVideo")) {
vals[tot_count] = 31;
tot_count++;
}
else if (!stricmp(ext, "Video")) {
vals[tot_count] = 32;
tot_count++;
}
else if (!stricmp(ext, "XlinkAttribute")) {
vals[tot_count] = 33;
tot_count++;
}
}
lsr_write_vluimsbf5(lsr, tot_count, "len");
for (j=0; j<tot_count; j++) {
GF_LSR_WRITE_INT(lsr, vals[j], 6, "feature");
}
gf_free(vals);
}
break;
case TAG_SVG_ATT_systemLanguage:
lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "systemLanguage", GF_FALSE);
break;
case TAG_XML_ATT_base:
lsr_write_byte_align_string(lsr, ((XMLRI*)att->data)->string, "xml:base");
break;
case TAG_XML_ATT_lang:
lsr_write_byte_align_string(lsr, *(SVG_String *)att->data, "xml:lang");
break;
case TAG_XML_ATT_space:
GF_LSR_WRITE_INT(lsr, *(XML_Space *)att->data, 1, "xml:space");
break;
case TAG_SVG_ATT_nav_next:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusNext");
break;
case TAG_SVG_ATT_nav_up:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusNorth");
break;
case TAG_SVG_ATT_nav_up_left:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusNorthEast");
break;
case TAG_SVG_ATT_nav_up_right:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusNorthWest");
break;
case TAG_SVG_ATT_nav_prev:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusPrev");
break;
case TAG_SVG_ATT_nav_down:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusSouth");
break;
case TAG_SVG_ATT_nav_down_left:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusSouthEast");
break;
case TAG_SVG_ATT_nav_down_right:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusSouthWest");
break;
case TAG_SVG_ATT_nav_right:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusWest");
break;
case TAG_SVG_ATT_nav_left:
lsr_write_focus(lsr, (SVG_Focus*)att->data, "focusEast");
break;
case TAG_SVG_ATT_font_variant:
GF_LSR_WRITE_INT(lsr, *(SVG_FontVariant *)att->data, 2, "font-variant");
break;
case TAG_SVG_ATT_font_family:
{
s32 idx = lsr_get_font_index(lsr, (SVG_FontFamily*)att->data);
if (idx<0) {
GF_LSR_WRITE_INT(lsr, 1, 1, "isInherit");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "isInherit");
GF_LSR_WRITE_INT(lsr, idx, lsr->fontIndexBits, "fontIndex");
}
}
break;
case TAG_SVG_ATT_font_size:
lsr_write_fixed_16_8i(lsr, (SVG_Number*)att->data, "fontSize");
break;
case TAG_SVG_ATT_font_style:
GF_LSR_WRITE_INT(lsr, *((SVG_FontStyle *)att->data), 3, "fontStyle");
break;
case TAG_SVG_ATT_font_weight:
GF_LSR_WRITE_INT(lsr, *((SVG_FontWeight *)att->data), 4, "fontWeight");
break;
case TAG_XLINK_ATT_title:
lsr_write_byte_align_string(lsr, *(SVG_String *)att->data, "xlink:title");
break;
case TAG_XLINK_ATT_type:
GF_LSR_WRITE_INT(lsr, 0, 3, "xlink:type");
break;
case TAG_XLINK_ATT_role:
lsr_write_any_uri(lsr, (XMLRI*)att->data, "xlink:role");
break;
case TAG_XLINK_ATT_arcrole:
lsr_write_any_uri(lsr, (XMLRI*)att->data, "xlink:arcrole");
break;
case TAG_XLINK_ATT_actuate:
GF_LSR_WRITE_INT(lsr, 0, 2, "xlink:actuate");
break;
case TAG_XLINK_ATT_show:
GF_LSR_WRITE_INT(lsr, 0, 3, "xlink:show");
break;
case TAG_SVG_ATT_end:
lsr_write_smil_times(lsr, (GF_List **)att->data, "end", GF_FALSE);
break;
case TAG_SVG_ATT_min:
lsr_write_duration_ex(lsr, (SMIL_Duration*)att->data, "min", GF_FALSE);
break;
case TAG_SVG_ATT_max:
lsr_write_duration_ex(lsr, (SMIL_Duration*)att->data, "max", GF_FALSE);
break;
case TAG_SVG_ATT_transform:
lsr_write_matrix(lsr, (SVG_Transform*)att->data);
break;
case TAG_SVG_ATT_focusable:
GF_LSR_WRITE_INT(lsr, *(SVG_Focusable*)att->data, 2, "focusable");
break;
default:
GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[LASeR Enc] Rare Field declared but not encoded\n"));
break;
}
att = att->next;
}
}
static void lsr_write_fill(GF_LASeRCodec *lsr, SVG_Element *n, SVGAllAttributes *atts)
{
if (atts->fill) {
GF_LSR_WRITE_INT(lsr, 1, 1, "fill");
lsr_write_paint(lsr, atts->fill, "fill");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "fill");
}
}
static void lsr_write_stroke(GF_LASeRCodec *lsr, SVG_Element *n, SVGAllAttributes *atts)
{
if (atts->stroke) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_stroke");
lsr_write_paint(lsr, atts->stroke, "stroke");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_stroke");
}
}
static void lsr_write_href(GF_LASeRCodec *lsr, XMLRI *iri)
{
Bool has_href = iri ? GF_TRUE : GF_FALSE;
if (iri) {
if (iri->type==XMLRI_ELEMENTID) {
if (!iri->target && iri->string) iri->target = (SVG_Element *)gf_sg_find_node_by_name(lsr->sg, iri->string+1);
if (!iri->target || !gf_node_get_id((GF_Node *)iri->target)) has_href = GF_FALSE;
}
else if (iri->type==XMLRI_STREAMID) {
if (!iri->lsr_stream_id) has_href = GF_FALSE;
}
else if (!iri->string) has_href = GF_FALSE;
}
GF_LSR_WRITE_INT(lsr, has_href, 1, "has_href");
if (has_href) lsr_write_any_uri(lsr, iri, "href");
}
static void lsr_write_accumulate(GF_LASeRCodec *lsr, SMIL_Accumulate *accum_type)
{
GF_LSR_WRITE_INT(lsr, accum_type ? 1 : 0, 1, "has_accumulate");
if (accum_type) GF_LSR_WRITE_INT(lsr, *accum_type, 1, "accumulate");
}
static void lsr_write_additive(GF_LASeRCodec *lsr, SMIL_Additive *add_type)
{
GF_LSR_WRITE_INT(lsr, add_type ? 1 : 0, 1, "has_additive");
if (add_type) GF_LSR_WRITE_INT(lsr, *add_type, 1, "additive");
}
static void lsr_write_calc_mode(GF_LASeRCodec *lsr, u8 *calc_mode)
{
GF_LSR_WRITE_INT(lsr, (!calc_mode || (*calc_mode==SMIL_CALCMODE_LINEAR)) ? 0 : 1, 1, "has_calcMode");
if (calc_mode && (*calc_mode!=SMIL_CALCMODE_LINEAR)) {
GF_LSR_WRITE_INT(lsr, *calc_mode, 2, "calcMode");
}
}
static void lsr_write_animatable(GF_LASeRCodec *lsr, SMIL_AttributeName *anim_type, XMLRI *iri, const char *name)
{
s32 a_type = -1;
if (!anim_type || !iri || !iri->target) {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasAttributeName");
return;
}
assert(anim_type->name || anim_type->tag);
if (!anim_type->tag) anim_type->tag = gf_xml_get_attribute_tag((GF_Node*)iri->target, anim_type->name, 0);
if (!anim_type->type) anim_type->type = gf_xml_get_attribute_type(anim_type->tag);
a_type = gf_lsr_anim_type_from_attribute(anim_type->tag);
if (a_type<0) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] Unsupported attributeName %s\n", anim_type->name));
}
GF_LSR_WRITE_INT(lsr, 1, 1, "hasAttributeName");
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
GF_LSR_WRITE_INT(lsr, (u8) a_type, 8, "attributeType");
}
static void lsr_write_anim_fill(GF_LASeRCodec *lsr, u8 *animFreeze)
{
GF_LSR_WRITE_INT(lsr, animFreeze ? 1 : 0, 1, "has_smil_fill");
if (animFreeze) GF_LSR_WRITE_INT(lsr, *animFreeze, 1, "smil_fill");
}
static void lsr_write_anim_repeat(GF_LASeRCodec *lsr, SMIL_RepeatCount *repeat)
{
GF_LSR_WRITE_INT(lsr, repeat ? 1 : 0, 1, "has_repeatCount");
if (!repeat) return;
if (repeat->type==SMIL_REPEATCOUNT_DEFINED) {
GF_LSR_WRITE_INT(lsr, 0, 1, "repeatCount");
lsr_write_fixed_16_8(lsr, repeat->count, "repeatCount");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "repeatCount");
}
}
static void lsr_write_repeat_duration(GF_LASeRCodec *lsr, SMIL_Duration *smil)
{
GF_LSR_WRITE_INT(lsr, smil ? 1 : 0, 1, "has_repeatDur");
if (!smil) return;
if (smil->type==SMIL_DURATION_DEFINED) {
u32 now = (u32) (smil->clock_value * lsr->time_resolution);
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
lsr_write_vluimsbf5(lsr, now, "value");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
}
}
static void lsr_write_anim_restart(GF_LASeRCodec *lsr, u8 *animRestart)
{
GF_LSR_WRITE_INT(lsr, animRestart ? 1 : 0, 1, "has_restart");
if (animRestart) GF_LSR_WRITE_INT(lsr, *animRestart, 2, "restart");
}
static u32 svg_type_to_lsr_anim(u32 svg_type, u32 transform_type, GF_List *vals, void *a_val)
{
switch (svg_type) {
case DOM_String_datatype:
return 0;
case SVG_Number_datatype:
case SVG_FontSize_datatype:
case SVG_Length_datatype:
case SVG_Coordinate_datatype:
return 1;
case SVG_PathData_datatype:
return 2;
case SMIL_KeyPoints_datatype:
case SVG_Points_datatype:
return 3;
case SVG_Paint_datatype:
return 5;
case SVG_FillRule_datatype:
case SVG_StrokeLineJoin_datatype:
case SVG_StrokeLineCap_datatype:
case SVG_FontStyle_datatype:
case SVG_FontWeight_datatype:
case SVG_FontVariant_datatype:
case SVG_TextAnchor_datatype:
case SVG_TransformType_datatype:
case SVG_Display_datatype:
case SVG_Visibility_datatype:
case SVG_Overflow_datatype:
case SVG_ZoomAndPan_datatype:
case SVG_DisplayAlign_datatype:
case SVG_TextAlign_datatype:
case SVG_PointerEvents_datatype:
case SVG_RenderingHint_datatype:
case SVG_VectorEffect_datatype:
case SVG_PlaybackOrder_datatype:
case SVG_TimelineBegin_datatype:
return 6;
case SVG_StrokeDashArray_datatype:
case SVG_ViewBox_datatype:
case SVG_Coordinates_datatype:
return 8;
case SVG_FontFamily_datatype:
return 11;
case XMLRI_datatype:
return 12;
case SVG_Motion_datatype:
return 9;
case SVG_Transform_Translate_datatype:
return 9;
case SVG_Transform_Scale_datatype:
return 8;
case SVG_Transform_Rotate_datatype:
if (vals) {
u32 i=0;
SVG_Point_Angle *pt;
while ((pt = (SVG_Point_Angle *) gf_list_enum(vals, &i))) {
if (pt->x || pt->y) return 8;
}
} else if (a_val) {
SVG_Point_Angle *pt = (SVG_Point_Angle *) a_val;
if (pt->x || pt->y) return 8;
}
return 1;
case SVG_Transform_SkewX_datatype:
return 1;
case SVG_Transform_SkewY_datatype:
return 1;
default:
return 255;
}
}
static void lsr_write_coordinate(GF_LASeRCodec *lsr, Fixed val, Bool skipable, const char *name)
{
if (skipable && !val) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
} else {
u32 res = lsr_translate_coords(lsr, val, lsr->coord_bits);
if (skipable) GF_LSR_WRITE_INT(lsr, 1, 1, name);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, name);
}
}
static void lsr_write_coordinate_ptr(GF_LASeRCodec *lsr, SVG_Coordinate *val, Bool skipable, const char *name)
{
if (skipable && !val) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
} else {
u32 res = lsr_translate_coords(lsr, val ? val->value : 0, lsr->coord_bits);
if (skipable) GF_LSR_WRITE_INT(lsr, 1, 1, name);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, name);
}
}
static void lsr_write_an_anim_value(GF_LASeRCodec *lsr, void *val, u32 lsr_type, u32 svg_type, u32 transform_type, const char *name)
{
if ((lsr_type==1) || (lsr_type==4)) {
switch (svg_type) {
case SVG_Transform_Rotate_datatype:
case SVG_Transform_SkewX_datatype:
case SVG_Transform_SkewY_datatype:
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
break;
default:
{
SVG_Number *n = (SVG_Number *) val;
if (n->type != SVG_NUMBER_VALUE) {
u8 val = 0;
if (n->type==SVG_NUMBER_INHERIT) val=1;
GF_LSR_WRITE_INT(lsr, 1, 1, "escapeFlag");
GF_LSR_WRITE_INT(lsr, val, 2, "escapeEnum");
return;
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
}
}
break;
}
} else if (svg_type==SVG_StrokeDashArray_datatype) {
SVG_StrokeDashArray *da = (SVG_StrokeDashArray *)val;
if (da->type==SVG_STROKEDASHARRAY_INHERIT) {
GF_LSR_WRITE_INT(lsr, 1, 1, "escapeFlag");
GF_LSR_WRITE_INT(lsr, 0, 2, "escapeEnum");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
}
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
}
switch(lsr_type) {
case 0:
lsr_write_byte_align_string(lsr, *(DOM_String *)val, name);
break;
case 1:
if (svg_type==SVG_Transform_Rotate_datatype) {
Fixed angle = ((SVG_Point_Angle *) val)->angle;
angle = gf_muldiv(angle, INT2FIX(180), GF_PI);
lsr_write_fixed_16_8(lsr, angle, name);
} else if ((svg_type==SVG_Transform_SkewX_datatype) || (svg_type==SVG_Transform_SkewY_datatype)) {
lsr_write_fixed_16_8(lsr, *(Fixed *)val, name);
} else {
lsr_write_fixed_16_8(lsr, ((SVG_Number *) val)->value, name);
}
break;
case 12:
lsr_write_any_uri(lsr, (XMLRI*)val, name);
break;
case 2:
lsr_write_path_type(lsr, (SVG_PathData*)val, name);
break;
case 3:
lsr_write_point_sequence(lsr, (GF_List **)val, name);
break;
case 4:
lsr_write_fixed_clamp(lsr, ((SVG_Number *) val)->value, name);
break;
case 5:
lsr_write_paint(lsr, (SVG_Paint*)val, name);
break;
case 6:
lsr_write_vluimsbf5(lsr, (u32) *(u8 *) val, name);
break;
case 10:
lsr_write_vluimsbf5(lsr, *(u32 *) val, name);
break;
case 11:
{
s32 idx = lsr_get_font_index(lsr, (SVG_FontFamily*)val);
if (idx<0) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] corrupted font table while encoding anim value\n"));
idx=0;
}
lsr_write_vluimsbf5(lsr, idx, name);
}
break;
case 7:
{
GF_List *l = *(GF_List **)val;
u32 i, count = gf_list_count(l);
lsr_write_vluimsbf5(lsr, count, "count");
for (i=0; i<count; i++) {
u8 *v = (u8 *)gf_list_get(l, i);
lsr_write_vluimsbf5(lsr, *v, "val");
}
}
break;
case 8:
{
u32 i, count;
if (svg_type==SVG_StrokeDashArray_datatype) {
SVG_StrokeDashArray *da = (SVG_StrokeDashArray *)val;
lsr_write_vluimsbf5(lsr, da->array.count, "count");
for (i=0; i<da->array.count; i++) {
lsr_write_fixed_16_8(lsr, da->array.vals[i], "val");
}
} else if (svg_type==SVG_ViewBox_datatype) {
SVG_ViewBox *vb = (SVG_ViewBox *)val;
lsr_write_vluimsbf5(lsr, 4, "count");
lsr_write_fixed_16_8(lsr, vb->x, "val");
lsr_write_fixed_16_8(lsr, vb->y, "val");
lsr_write_fixed_16_8(lsr, vb->width, "val");
lsr_write_fixed_16_8(lsr, vb->height, "val");
} else if (svg_type==SVG_Coordinates_datatype) {
GF_List *l = *(GF_List **)val;
count = gf_list_count(l);
lsr_write_vluimsbf5(lsr, count, "count");
for (i=0; i<count; i++) {
SVG_Coordinate *v = (SVG_Coordinate *)gf_list_get(l, i);
lsr_write_fixed_16_8(lsr, v->value, "val");
}
} else if (svg_type==SVG_Transform_Rotate_datatype) {
SVG_Point_Angle *p = (SVG_Point_Angle *)val;
Fixed angle = gf_muldiv(p->angle, INT2FIX(180), GF_PI);
count = (p->x || p->y) ? 3 : 1;
lsr_write_vluimsbf5(lsr, count, "count");
lsr_write_fixed_16_8(lsr, angle, "val");
if (count==3) {
lsr_write_fixed_16_8(lsr, p->x, "val");
lsr_write_fixed_16_8(lsr, p->y, "val");
}
} else if (svg_type==SVG_Transform_Scale_datatype) {
SVG_Point *pt = (SVG_Point *)val;
count = (pt->x == pt->y) ? 1 : 2;
lsr_write_vluimsbf5(lsr, count, "count");
lsr_write_fixed_16_8(lsr, pt->x, "val");
if (count==2) lsr_write_fixed_16_8(lsr, pt->y, "val");
} else {
GF_List *l = *(GF_List **)val;
count = gf_list_count(l);
lsr_write_vluimsbf5(lsr, count, "count");
for (i=0; i<count; i++) {
Fixed *v = (Fixed *)gf_list_get(l, i);
lsr_write_fixed_16_8(lsr, *v, "val");
}
}
}
break;
case 9:
if (svg_type==SVG_Motion_datatype) {
lsr_write_coordinate(lsr, ((GF_Matrix2D*)val)->m[2], GF_FALSE, "valX");
lsr_write_coordinate(lsr, ((GF_Matrix2D*)val)->m[5], GF_FALSE, "valY");
} else {
lsr_write_coordinate(lsr, ((SVG_Point *)val)->x, GF_FALSE, "valX");
lsr_write_coordinate(lsr, ((SVG_Point *)val)->y, GF_FALSE, "valY");
}
break;
default:
lsr_write_extension(lsr, NULL, 0, name);
break;
}
}
static void lsr_write_anim_value(GF_LASeRCodec *lsr, SMIL_AnimateValue *val, const char *name)
{
if (!val || !val->type) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
} else {
u32 type = svg_type_to_lsr_anim(val->type, 0, NULL, val->value);
if (type==255) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] unsupported anim type %d - skipping\n", val->type ));
GF_LSR_WRITE_INT(lsr, 0, 1, name);
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, name);
GF_LSR_WRITE_INT(lsr, type, 4, "type");
lsr_write_an_anim_value(lsr, val->value, type, val->type, 0, name);
}
}
}
static void lsr_write_anim_values(GF_LASeRCodec *lsr, SMIL_AnimateValues *anims, const char *name)
{
u32 type, i, count = 0;
if (anims && anims->type) count = gf_list_count(anims->values);
if (!count) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
return;
}
type = svg_type_to_lsr_anim(anims->type, 0, anims->values, NULL);
if (type==255) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] unsupported anim type %d - skipping\n", anims->type ));
GF_LSR_WRITE_INT(lsr, 0, 1, name);
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, name);
GF_LSR_WRITE_INT(lsr, type, 4, "type");
lsr_write_vluimsbf5(lsr, count, "count");
for (i=0; i<count; i++) {
void *att = gf_list_get(anims->values, i);
lsr_write_an_anim_value(lsr, att, type, anims->type, 0, "a_value");
}
}
}
static void lsr_write_fraction_12(GF_LASeRCodec *lsr, GF_List **l, const char *name)
{
u32 i, count;
count = l ? gf_list_count(*l) : 0;
if (!count) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
return;
}
GF_LSR_WRITE_INT(lsr, 1, 1, name);
lsr_write_vluimsbf5(lsr, count, "name");
for (i=0; i<count; i++) {
Fixed f = * (Fixed *) gf_list_get(*l, i);
if (!f || (f == FIX_ONE)) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasShort");
GF_LSR_WRITE_INT(lsr, f ? 0 : 1, 1, "isZero");
} else {
u32 ft = (u32) ( FIX2FLT(f) * 4096 );
GF_LSR_WRITE_INT(lsr, 0, 1, "hasShort");
GF_LSR_WRITE_INT(lsr, ft, 12, "val");
}
}
}
static void lsr_write_float_list(GF_LASeRCodec *lsr, GF_List **l, const char *name)
{
u32 i, count = l ? gf_list_count(*l) : 0;
if (!count) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
return;
}
GF_LSR_WRITE_INT(lsr, 1, 1, name);
lsr_write_vluimsbf5(lsr, count, "count");
for (i=0; i<count; i++) {
Fixed *v = (Fixed *)gf_list_get(*l, i);
lsr_write_fixed_16_8(lsr, *v, "val");
}
}
static u32 lsr_get_bit_size(GF_LASeRCodec *lsr, Fixed v)
{
u32 val;
v = gf_divfix(v, lsr->res_factor);
val = (v<0) ? FIX2INT(-v) : FIX2INT(v);
return 1 + gf_get_bit_size(val);
}
static void lsr_write_point_sequence(GF_LASeRCodec *lsr, GF_List **pts, const char *name)
{
u32 i, count = pts ? gf_list_count(*pts) : 0;
lsr_write_vluimsbf5(lsr, count, "nbPoints");
if (!count) return;
GF_LSR_WRITE_INT(lsr, 0, 1, "flag");
if (1) {
if (count < 3) {
u32 nb_bits = 0;
for (i=0; i<count; i++) {
u32 k;
SVG_Point *pt = (SVG_Point *)gf_list_get(*pts, i);
k = lsr_get_bit_size(lsr, pt->x);
if (k>nb_bits) nb_bits = k;
k = lsr_get_bit_size(lsr, pt->y);
if (k>nb_bits) nb_bits = k;
}
GF_LSR_WRITE_INT(lsr, nb_bits, 5, "bits");
for (i=0; i<count; i++) {
SVG_Point *pt = (SVG_Point *)gf_list_get(*pts, i);
u32 v = lsr_translate_coords(lsr, pt->x, nb_bits);
GF_LSR_WRITE_INT(lsr, v, nb_bits, "x");
v = lsr_translate_coords(lsr, pt->y, nb_bits);
GF_LSR_WRITE_INT(lsr, v, nb_bits, "y");
}
} else {
Fixed c_x, c_y;
u32 k, nb_dx, nb_dy;
SVG_Point *pt = (SVG_Point *)gf_list_get(*pts, 0);
nb_dx = 0;
k = lsr_get_bit_size(lsr, pt->x);
if (k>nb_dx) nb_dx = k;
k = lsr_get_bit_size(lsr, pt->y);
if (k>nb_dx) nb_dx = k;
GF_LSR_WRITE_INT(lsr, nb_dx, 5, "bits");
k = lsr_translate_coords(lsr, pt->x, nb_dx);
GF_LSR_WRITE_INT(lsr, k, nb_dx, "x");
k = lsr_translate_coords(lsr, pt->y, nb_dx);
GF_LSR_WRITE_INT(lsr, k, nb_dx, "y");
c_x = pt->x;
c_y = pt->y;
nb_dx = nb_dy = 0;
for (i=1; i<count; i++) {
SVG_Point *pt = (SVG_Point *)gf_list_get(*pts, i);
k = lsr_get_bit_size(lsr, pt->x - c_x);
if (k>nb_dx) nb_dx = k;
k = lsr_get_bit_size(lsr, pt->y - c_y);
if (k>nb_dy) nb_dy = k;
c_x = pt->x;
c_y = pt->y;
}
GF_LSR_WRITE_INT(lsr, nb_dx, 5, "bitsx");
GF_LSR_WRITE_INT(lsr, nb_dy, 5, "bitsy");
c_x = pt->x;
c_y = pt->y;
for (i=1; i<count; i++) {
SVG_Point *pt = (SVG_Point *)gf_list_get(*pts, i);
k = lsr_translate_coords(lsr, pt->x - c_x, nb_dx);
GF_LSR_WRITE_INT(lsr, k, nb_dx, "dx");
k = lsr_translate_coords(lsr, pt->y - c_y, nb_dy);
GF_LSR_WRITE_INT(lsr, k, nb_dy, "dy");
c_x = pt->x;
c_y = pt->y;
}
}
}
}
static void lsr_write_path_type(GF_LASeRCodec *lsr, SVG_PathData *path, const char *name)
{
#if USE_GF_PATH
u32 i, *contour, nb_types;
GF_List *pts = gf_list_new();
contour = path->contours;
nb_types = 0;
for (i=0; i<path->n_points; ) {
switch (path->tags[i]) {
case GF_PATH_CURVE_ON:
gf_list_add(pts, &path->points[i]);
nb_types++;
i++;
break;
case GF_PATH_CLOSE:
nb_types++;
i++;
break;
case GF_PATH_CURVE_CONIC:
gf_list_add(pts, &path->points[i]);
gf_list_add(pts, &path->points[i+1]);
i+=2;
nb_types++;
break;
case GF_PATH_CURVE_CUBIC:
gf_list_add(pts, &path->points[i]);
gf_list_add(pts, &path->points[i+1]);
gf_list_add(pts, &path->points[i+2]);
i+=3;
nb_types++;
break;
}
}
lsr_write_point_sequence(lsr, &pts, "seq");
gf_list_del(pts);
lsr_write_vluimsbf5(lsr, nb_types-1, "nbOfTypes");
for (i=0; i<path->n_points; ) {
switch (path->tags[i]) {
case GF_PATH_CLOSE:
GF_LSR_WRITE_INT(lsr, LSR_PATH_COM_Z, 5, name);
i++;
break;
case GF_PATH_CURVE_ON:
if (!i) {
} else if (*contour == i-1) {
GF_LSR_WRITE_INT(lsr, LSR_PATH_COM_M, 5, name);
} else {
GF_LSR_WRITE_INT(lsr, LSR_PATH_COM_L, 5, name);
}
i++;
break;
case GF_PATH_CURVE_CONIC:
GF_LSR_WRITE_INT(lsr, LSR_PATH_COM_Q, 5, name);
i+=2;
break;
case GF_PATH_CURVE_CUBIC:
GF_LSR_WRITE_INT(lsr, LSR_PATH_COM_C, 5, name);
i+=3;
break;
}
}
#else
u32 i, count;
lsr_write_point_sequence(lsr, path->points, "seq");
count = gf_list_count(path->commands);
lsr_write_vluimsbf5(lsr, count, "nbOfTypes");
for (i; i<count; i++) {
u8 type = *(u8 *) gf_list_get(path->commands, i);
GF_LSR_WRITE_INT(lsr, type, 5, name);
}
#endif
}
static void lsr_write_rotate_type(GF_LASeRCodec *lsr, SVG_Rotate *rotate, const char *name)
{
GF_LSR_WRITE_INT(lsr, rotate ? 1 : 0, 1, name);
if (!rotate) return;
if ((rotate->type == SVG_NUMBER_AUTO) || (rotate->type == SVG_NUMBER_AUTO_REVERSE)) {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, (rotate->type == SVG_NUMBER_AUTO) ? 0 : 1, 1, "rotate");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
lsr_write_fixed_16_8(lsr, rotate->value, "rotate");
}
}
static void lsr_write_sync_behavior(GF_LASeRCodec *lsr, SMIL_SyncBehavior *sync, const char *name)
{
GF_LSR_WRITE_INT(lsr, sync ? 1 : 0, 1, name);
if (!sync) return;
assert(*sync!=SMIL_SYNCBEHAVIOR_INHERIT);
GF_LSR_WRITE_INT(lsr, *sync-1, 2, name);
}
static void lsr_write_sync_tolerance(GF_LASeRCodec *lsr, SMIL_SyncTolerance *sync, const char *name)
{
GF_LSR_WRITE_INT(lsr, sync ? 1 : 0, 1, name);
if (!sync) return;
assert(sync->type!=SMIL_SYNCTOLERANCE_INHERIT);
if (sync->type==SMIL_SYNCTOLERANCE_DEFAULT) {
GF_LSR_WRITE_INT(lsr, 1, 1, name);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
lsr_write_vluimsbf5(lsr, (u32) (sync->value*lsr->time_resolution), "value");
}
}
static void lsr_write_coord_list(GF_LASeRCodec *lsr, GF_List **coords, const char *name)
{
u32 i, count = coords ? gf_list_count(*coords) : 0;
if (!count) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, name);
lsr_write_vluimsbf5(lsr, count, "nb_coords");
for (i=0; i<count; i++) {
SVG_Coordinate *c = (SVG_Coordinate *)gf_list_get(*coords, i);
u32 res = lsr_translate_coords(lsr, c->value, lsr->coord_bits);
GF_LSR_WRITE_INT(lsr, res, lsr->coord_bits, name);
}
}
}
static void lsr_write_transform_behavior(GF_LASeRCodec *lsr, SVG_TransformBehavior *type)
{
GF_LSR_WRITE_INT(lsr, type ? 1 : 0, 1, "hasTransformBehavior");
if (!type) return;
GF_LSR_WRITE_INT(lsr, *type, 4, "transformBehavior");
}
static void lsr_write_gradient_units(GF_LASeRCodec *lsr, SVG_GradientUnit *type)
{
GF_LSR_WRITE_INT(lsr, type ? 1 : 0, 1, "hasGradientUnits");
if (!type) return;
GF_LSR_WRITE_INT(lsr, *type ? 1 : 0, 1, "gradientUnits");
}
static void lsr_write_content_type(GF_LASeRCodec *lsr, SVG_String *type, const char *name)
{
if (type) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasType");
lsr_write_byte_align_string(lsr, *type, "type");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasType");
}
}
static void lsr_write_script_type(GF_LASeRCodec *lsr, SVG_String *type)
{
GF_LSR_WRITE_INT(lsr, type ? 1 : 0, 1, "hasType");
if (!type) return;
if (!strcmp(*type, "application/ecmascript")) {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, 0, 1, "script");
} else if (!strcmp(*type, "application/jar-archive")) {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, 1, 1, "script");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
lsr_write_byte_align_string(lsr, *type, "type");
}
}
static void lsr_write_value_with_units(GF_LASeRCodec *lsr, SVG_Number *n, const char *name)
{
#ifdef GPAC_FIXED_POINT
s32 val = n->value >> 8;
#else
s32 val = (s32) (n->value * (1<<8) );
#endif
GF_LSR_WRITE_INT(lsr, val, 32, name);
switch (n->type) {
case SVG_NUMBER_IN:
GF_LSR_WRITE_INT(lsr, 1, 3, "units");
break;
case SVG_NUMBER_CM:
GF_LSR_WRITE_INT(lsr, 2, 3, "units");
break;
case SVG_NUMBER_MM:
GF_LSR_WRITE_INT(lsr, 3, 3, "units");
break;
case SVG_NUMBER_PT:
GF_LSR_WRITE_INT(lsr, 4, 3, "units");
break;
case SVG_NUMBER_PC:
GF_LSR_WRITE_INT(lsr, 5, 3, "units");
break;
case SVG_NUMBER_PERCENTAGE:
GF_LSR_WRITE_INT(lsr, 6, 3, "units");
break;
default:
GF_LSR_WRITE_INT(lsr, 0, 3, "units");
break;
}
}
static void lsr_write_clip_time(GF_LASeRCodec *lsr, SVG_Clock *clock, const char *name)
{
if (!clock || *clock <= 0) {
GF_LSR_WRITE_INT(lsr, 0, 1, name);
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, name);
GF_LSR_WRITE_INT(lsr, 0, 1, "isEnum");
GF_LSR_WRITE_INT(lsr, 0, 1, "sign");
lsr_write_vluimsbf5(lsr, (u32) (lsr->time_resolution**clock), "val");
}
}
static void lsr_write_href_anim(GF_LASeRCodec *lsr, XMLRI *href, SVG_Element *parent)
{
if (!href || (href->target && (href->target==parent))) {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_href");
} else {
lsr_write_href(lsr, href);
}
}
static void lsr_write_attribute_type(GF_LASeRCodec *lsr, SVGAllAttributes *atts)
{
if (!atts->attributeType) {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasAttributeType");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasAttributeType");
GF_LSR_WRITE_INT(lsr, (*atts->attributeType), 2, "attributeType");
}
}
static void lsr_write_preserve_aspect_ratio(GF_LASeRCodec *lsr, SVG_PreserveAspectRatio *preserveAspectRatio)
{
GF_LSR_WRITE_INT(lsr, preserveAspectRatio ? 1 : 0, 1, "hasPreserveAspectRatio");
if (!preserveAspectRatio) return;
GF_LSR_WRITE_INT(lsr, 0, 1, "choice (meetOrSlice)");
GF_LSR_WRITE_INT(lsr, preserveAspectRatio->defer ? 1 : 0, 1, "choice (defer)");
switch (preserveAspectRatio->align) {
case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
GF_LSR_WRITE_INT(lsr, 1, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMAXYMID:
GF_LSR_WRITE_INT(lsr, 2, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
GF_LSR_WRITE_INT(lsr, 3, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
GF_LSR_WRITE_INT(lsr, 4, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMIDYMID:
GF_LSR_WRITE_INT(lsr, 5, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
GF_LSR_WRITE_INT(lsr, 6, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMINYMAX:
GF_LSR_WRITE_INT(lsr, 7, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMINYMID:
GF_LSR_WRITE_INT(lsr, 8, 4, "alignXandY");
break;
case SVG_PRESERVEASPECTRATIO_XMINYMIN:
GF_LSR_WRITE_INT(lsr, 9, 4, "alignXandY");
break;
default:
GF_LSR_WRITE_INT(lsr, 0, 4, "alignXandY");
break;
}
}
#define lsr_write_err() GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired")
static void lsr_write_a(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_err();
GF_LSR_WRITE_INT(lsr, (atts.target!=NULL) ? 1 : 0, 1, "hasTarget");
if (atts.target) lsr_write_byte_align_string(lsr, *(SVG_String*)atts.target, "target");
lsr_write_href(lsr, atts.xlink_href);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_animate(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *parent)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_animatable(lsr, atts.attributeName, atts.xlink_href, "attributeName");
lsr_write_accumulate(lsr, atts.accumulate);
lsr_write_additive(lsr, atts.additive);
lsr_write_anim_value(lsr, atts.by, "by");
lsr_write_calc_mode(lsr, atts.calcMode);
lsr_write_anim_value(lsr, atts.from, "from");
lsr_write_fraction_12(lsr, atts.keySplines, "keySplines");
lsr_write_fraction_12(lsr, atts.keyTimes, "keyTimes");
lsr_write_anim_values(lsr, atts.values, "values");
lsr_write_attribute_type(lsr, &atts);
lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE);
lsr_write_duration(lsr, atts.dur, "dur");
lsr_write_anim_fill(lsr, atts.smil_fill);
lsr_write_anim_repeat(lsr, atts.repeatCount);
lsr_write_repeat_duration(lsr, atts.repeatDur);
lsr_write_anim_restart(lsr, atts.restart);
lsr_write_anim_value(lsr, atts.to, "to");
lsr_write_href_anim(lsr, atts.xlink_href, parent);
GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_animateMotion(GF_LASeRCodec *lsr, SVG_Element*elt, SVG_Element *parent)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_accumulate(lsr, atts.accumulate);
lsr_write_additive(lsr, atts.additive);
lsr_write_anim_value(lsr, atts.by, "by");
lsr_write_calc_mode(lsr, atts.calcMode);
lsr_write_anim_value(lsr, atts.from, "from");
lsr_write_fraction_12(lsr, atts.keySplines, "keySplines");
lsr_write_fraction_12(lsr, atts.keyTimes, "keyTimes");
lsr_write_anim_values(lsr, atts.values, "values");
lsr_write_attribute_type(lsr, &atts);
lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE);
lsr_write_duration(lsr, atts.dur, "dur");
lsr_write_anim_fill(lsr, atts.smil_fill);
lsr_write_anim_repeat(lsr, atts.repeatCount);
lsr_write_repeat_duration(lsr, atts.repeatDur);
lsr_write_anim_restart(lsr, atts.restart);
lsr_write_anim_value(lsr, atts.to, "to");
lsr_write_float_list(lsr, atts.keyPoints, "keyPoints");
if (atts.path) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasPath");
lsr_write_path_type(lsr, atts.path, "path");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasPath");
}
lsr_write_rotate_type(lsr, atts.rotate, "rotate");
lsr_write_href_anim(lsr, atts.xlink_href, parent);
GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_animateTransform(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *parent)
{
u32 type;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_animatable(lsr, atts.attributeName, atts.xlink_href, "attributeName");
type = atts.transform_type ? *atts.transform_type : SVG_TRANSFORM_TRANSLATE;
switch (type) {
case SVG_TRANSFORM_ROTATE:
GF_LSR_WRITE_INT(lsr, 0, 3, "rotscatra");
break;
case SVG_TRANSFORM_SCALE:
GF_LSR_WRITE_INT(lsr, 1, 3, "rotscatra");
break;
case SVG_TRANSFORM_SKEWX:
GF_LSR_WRITE_INT(lsr, 2, 3, "rotscatra");
break;
case SVG_TRANSFORM_SKEWY:
GF_LSR_WRITE_INT(lsr, 3, 3, "rotscatra");
break;
case SVG_TRANSFORM_TRANSLATE:
GF_LSR_WRITE_INT(lsr, 4, 3, "rotscatra");
break;
}
lsr_write_accumulate(lsr, atts.accumulate);
lsr_write_additive(lsr, atts.additive);
lsr_write_anim_value(lsr, atts.by, "by");
lsr_write_calc_mode(lsr, atts.calcMode);
lsr_write_anim_value(lsr, atts.from, "from");
lsr_write_fraction_12(lsr, atts.keySplines, "keySplines");
lsr_write_fraction_12(lsr, atts.keyTimes, "keyTimes");
lsr_write_anim_values(lsr, atts.values, "values");
lsr_write_attribute_type(lsr, &atts);
lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE);
lsr_write_duration(lsr, atts.dur, "dur");
lsr_write_anim_fill(lsr, atts.smil_fill);
lsr_write_anim_repeat(lsr, atts.repeatCount);
lsr_write_repeat_duration(lsr, atts.repeatDur);
lsr_write_anim_restart(lsr, atts.restart);
lsr_write_anim_value(lsr, atts.to, "to");
lsr_write_href_anim(lsr, atts.xlink_href, parent);
GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_audio(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE);
lsr_write_duration(lsr, atts.dur, "dur");
GF_LSR_WRITE_INT(lsr, atts.externalResourcesRequired ? *atts.externalResourcesRequired : 0, 1, "externalResourcesRequired");
lsr_write_anim_repeat(lsr, atts.repeatCount);
lsr_write_repeat_duration(lsr, atts.repeatDur);
lsr_write_anim_restart(lsr, atts.restart);
lsr_write_sync_behavior(lsr, atts.syncBehavior, "syncBehavior");
lsr_write_sync_tolerance(lsr, atts.syncTolerance, "syncBehavior");
lsr_write_content_type(lsr, atts.xlink_type, "type");
lsr_write_href(lsr, atts.xlink_href);
lsr_write_clip_time(lsr, atts.clipBegin, "clipBegin");
lsr_write_clip_time(lsr, atts.clipEnd, "clipEnd");
GF_LSR_WRITE_INT(lsr, atts.syncReference ? 1 : 0, 1, "hasSyncReference");
if (atts.syncReference) lsr_write_any_uri(lsr, atts.syncReference, "syncReference");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_circle(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
lsr_write_coordinate_ptr(lsr, atts.cx, GF_TRUE, "cx");
lsr_write_coordinate_ptr(lsr, atts.cy, GF_TRUE, "cy");
lsr_write_coordinate_ptr(lsr, atts.r, GF_FALSE, "r");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_conditional(GF_LASeRCodec *lsr, SVG_Element *elt)
{
GF_DOMUpdates *up;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_smil_times(lsr, atts.begin, "begin", 1);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
up = elt->children ? (GF_DOMUpdates*)elt->children->node : NULL;
lsr_write_command_list(lsr, up ? up->updates : NULL, elt, GF_FALSE);
lsr_write_private_attributes(lsr, elt);
}
static void lsr_write_cursorManager(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x");
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "y");
lsr_write_href(lsr, atts.xlink_href);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_data(GF_LASeRCodec *lsr, SVG_Element *elt)
{
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_defs(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_ellipse(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
lsr_write_coordinate_ptr(lsr, atts.cx, GF_TRUE, "cx");
lsr_write_coordinate_ptr(lsr, atts.cy, GF_TRUE, "cy");
lsr_write_coordinate_ptr(lsr, atts.rx, GF_FALSE, "rx");
lsr_write_coordinate_ptr(lsr, atts.ry, GF_FALSE, "ry");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_foreignObject(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired&&*atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_coordinate_ptr(lsr, atts.height, GF_FALSE, "height");
lsr_write_coordinate_ptr(lsr, atts.width, GF_FALSE, "width");
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x");
lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
GF_LSR_WRITE_INT(lsr, 0, 1, "opt_group");
}
static void lsr_write_g(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag)
{
Bool is_same = GF_FALSE;
Bool same_fill;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
if (!ommit_tag
&& lsr_elt_has_same_base(lsr, &atts, lsr->prev_g, &same_fill, NULL, GF_FALSE)
&& same_fill
) {
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sameg, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
is_same = GF_TRUE;
} else {
if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_g, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr->prev_g = elt;
}
lsr_write_group_content(lsr, elt, is_same);
}
static void lsr_write_image(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_coordinate_ptr(lsr, atts.height, GF_TRUE, "height");
if (atts.opacity && (atts.opacity->type == SVG_NUMBER_VALUE)) {
GF_LSR_WRITE_INT(lsr, 1, 1, "opacity");
lsr_write_fixed_clamp(lsr, atts.opacity->value, "opacity");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "opacity");
}
lsr_write_preserve_aspect_ratio(lsr, atts.preserveAspectRatio);
lsr_write_content_type(lsr, atts.xlink_type, "type");
lsr_write_coordinate_ptr(lsr, atts.width, GF_TRUE, "width");
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x");
lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y");
lsr_write_href(lsr, atts.xlink_href);
lsr_write_transform_behavior(lsr, atts.transformBehavior);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_line(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag)
{
Bool same_fill;
Bool is_same = GF_FALSE;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_line, &same_fill, NULL, GF_FALSE)
&& same_fill
) {
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sameline, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
is_same = GF_TRUE;
} else {
if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_line, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
}
lsr_write_coordinate_ptr(lsr, atts.x1, GF_TRUE, "x1");
lsr_write_coordinate_ptr(lsr, atts.x2, GF_FALSE, "x2");
lsr_write_coordinate_ptr(lsr, atts.y1, GF_TRUE, "y1");
lsr_write_coordinate_ptr(lsr, atts.y2, GF_FALSE, "y2");
if (!is_same) {
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr->prev_line = elt;
}
lsr_write_group_content(lsr, elt, is_same);
}
static void lsr_write_linearGradient(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_gradient_units(lsr, atts.gradientUnits);
lsr_write_coordinate_ptr(lsr, atts.x1, GF_TRUE, "x1");
lsr_write_coordinate_ptr(lsr, atts.x2, GF_TRUE, "x2");
lsr_write_coordinate_ptr(lsr, atts.y1, GF_TRUE, "y1");
lsr_write_coordinate_ptr(lsr, atts.y2, GF_TRUE, "y2");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_mpath(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_href(lsr, atts.xlink_href);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_path(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag)
{
Bool same_fill;
Bool is_same = GF_FALSE;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_path, &same_fill, NULL, GF_FALSE) ) {
is_same = GF_TRUE;
if (!same_fill) {
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_samepathfill, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
} else {
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_samepath, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
}
lsr_write_path_type(lsr, atts.d, "d");
} else {
if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_path, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_path_type(lsr, atts.d, "d");
if (atts.pathLength) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasPathLength");
lsr_write_fixed_16_8(lsr, atts.pathLength->value, "pathLength");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasPathLength");
}
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr->prev_path = elt;
}
lsr_write_group_content(lsr, elt, is_same);
}
static void lsr_write_polygon(GF_LASeRCodec *lsr, SVG_Element *elt, Bool is_polyline, Bool ommit_tag)
{
Bool same_fill, same_stroke;
u32 same_type = 0;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_polygon, &same_fill, &same_stroke, GF_TRUE)
) {
if (same_fill && same_stroke) same_type = 1;
else if (same_fill) same_type = 3;
else if (same_stroke) same_type = 2;
}
if (same_type) {
u8 type = is_polyline ? LSR_SCENE_CONTENT_MODEL_samepolyline : LSR_SCENE_CONTENT_MODEL_samepolygon;
if (same_type==2) type = is_polyline ? LSR_SCENE_CONTENT_MODEL_samepolylinefill : LSR_SCENE_CONTENT_MODEL_samepolygonfill;
else if (same_type==3) type = is_polyline ? LSR_SCENE_CONTENT_MODEL_samepolylinestroke : LSR_SCENE_CONTENT_MODEL_samepolygonstroke;
GF_LSR_WRITE_INT(lsr, type, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
if (same_type==2) lsr_write_fill(lsr, elt, &atts);
else if (same_type==3) lsr_write_stroke(lsr, elt, &atts);
lsr_write_point_sequence(lsr, atts.points, "points");
} else {
if (!ommit_tag) GF_LSR_WRITE_INT(lsr, is_polyline ? LSR_SCENE_CONTENT_MODEL_polyline : LSR_SCENE_CONTENT_MODEL_polygon, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_point_sequence(lsr, atts.points, "points");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr->prev_polygon = elt;
}
lsr_write_group_content(lsr, elt, same_type);
}
static void lsr_write_radialGradient(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_coordinate_ptr(lsr, atts.cx, GF_TRUE, "cx");
lsr_write_coordinate_ptr(lsr, atts.cy, GF_TRUE, "cy");
lsr_write_gradient_units(lsr, atts.gradientUnits);
lsr_write_coordinate_ptr(lsr, atts.r, GF_TRUE, "r");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_rect(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag)
{
u32 same_type = 0;
Bool same_fill;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_rect, &same_fill, NULL, GF_FALSE)
) {
if (!same_fill) {
same_type = 2;
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_samerectfill, 6, "ch4");
} else {
same_type = 1;
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_samerect, 6, "ch4");
}
lsr_write_id(lsr, (GF_Node *) elt);
if (same_type==2) lsr_write_fill(lsr, elt, &atts);
lsr_write_coordinate_ptr(lsr, atts.height, GF_FALSE, "height");
lsr_write_coordinate_ptr(lsr, atts.width, GF_FALSE, "width");
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x");
lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y");
} else {
if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_rect, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_coordinate_ptr(lsr, atts.height, GF_FALSE, "height");
lsr_write_coordinate_ptr(lsr, atts.rx, GF_TRUE, "rx");
lsr_write_coordinate_ptr(lsr, atts.ry, GF_TRUE, "ry");
lsr_write_coordinate_ptr(lsr, atts.width, GF_FALSE, "width");
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x");
lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr->prev_rect = elt;
}
lsr_write_group_content(lsr, elt, same_type);
}
static void lsr_write_rectClip(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
if (atts.size) {
GF_LSR_WRITE_INT(lsr, 1, 1, "size");
lsr_write_coordinate(lsr, atts.size->width, GF_FALSE, "width");
lsr_write_coordinate(lsr, atts.size->height, GF_FALSE, "height");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "size");
}
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_script(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_script_type(lsr, atts.xlink_type);
lsr_write_href(lsr, atts.xlink_href);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_selector(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
GF_LSR_WRITE_INT(lsr, atts.choice ? 1 : 0, 1, "hasChoice");
if (atts.choice) {
if (atts.choice->type==LASeR_CHOICE_N) {
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
GF_LSR_WRITE_INT(lsr, atts.choice->choice_index, 8, "value");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, atts.choice->type, 1, "type");
}
}
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_set(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *parent)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_animatable(lsr, atts.attributeName, atts.xlink_href, "attributeName");
lsr_write_attribute_type(lsr, &atts);
lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE);
lsr_write_duration(lsr, atts.dur, "dur");
lsr_write_anim_fill(lsr, atts.smil_fill);
lsr_write_anim_repeat(lsr, atts.repeatCount);
lsr_write_repeat_duration(lsr, atts.repeatDur);
lsr_write_anim_restart(lsr, atts.restart);
lsr_write_anim_value(lsr, atts.to, "to");
lsr_write_href_anim(lsr, atts.xlink_href, parent);
GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_simpleLayout(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
if (atts.delta) {
GF_LSR_WRITE_INT(lsr, 1, 1, "delta");
lsr_write_coordinate(lsr, atts.delta->width, GF_FALSE, "width");
lsr_write_coordinate(lsr, atts.delta->height, GF_FALSE, "height");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "delta");
}
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_stop(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_fixed_16_8(lsr, atts.offset ? atts.offset->value : 0, "offset");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_svg(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SMIL_Duration snap;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
lsr_write_stroke(lsr, elt, &atts);
lsr_write_string_attribute(lsr, atts.baseProfile ? *atts.baseProfile : NULL, "baseProfile");
lsr_write_string_attribute(lsr, atts.contentScriptType ? *atts.contentScriptType : NULL, "contentScriptType");
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_value_with_units(lsr, atts.height, "height");
GF_LSR_WRITE_INT(lsr, atts.playbackOrder ? 1 : 0, 1, "hasPlaybackOrder");
if (atts.playbackOrder) GF_LSR_WRITE_INT(lsr, *atts.playbackOrder, 1, "playbackOrder");
lsr_write_preserve_aspect_ratio(lsr, atts.preserveAspectRatio);
snap.clock_value = atts.snapshotTime ? *atts.snapshotTime : 0;
snap.type = snap.clock_value ? SMIL_DURATION_DEFINED : SMIL_DURATION_INDEFINITE;
lsr_write_duration(lsr, atts.snapshotTime ? &snap : NULL, "has_snapshotTime");
GF_LSR_WRITE_INT(lsr, atts.syncBehaviorDefault ? 1 : 0, 1, "hasSyncBehavior");
if (atts.syncBehaviorDefault) {
switch (*atts.syncBehaviorDefault) {
case SMIL_SYNCBEHAVIOR_CANSLIP:
GF_LSR_WRITE_INT(lsr, 0, 2, "syncBehavior");
break;
case SMIL_SYNCBEHAVIOR_INDEPENDENT:
GF_LSR_WRITE_INT(lsr, 1, 2, "syncBehavior");
break;
case SMIL_SYNCBEHAVIOR_LOCKED:
GF_LSR_WRITE_INT(lsr, 3, 2, "syncBehavior");
break;
default:
GF_LSR_WRITE_INT(lsr, 2, 2, "syncBehavior");
break;
}
}
GF_LSR_WRITE_INT(lsr, atts.syncToleranceDefault ? 1 : 0, 1, "hasSyncToleranceDefault");
if (atts.syncToleranceDefault) {
if (atts.syncToleranceDefault->type==SMIL_SYNCTOLERANCE_VALUE) {
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
lsr_write_vluimsbf5(lsr, (u32) (atts.syncToleranceDefault->value*lsr->time_resolution), "value");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
}
}
GF_LSR_WRITE_INT(lsr, atts.timelineBegin ? 1 : 0, 1, "hasTimelineBegin");
if (atts.timelineBegin) GF_LSR_WRITE_INT(lsr, *atts.timelineBegin, 1, "timelineBegin");
lsr_write_string_attribute(lsr, atts.version ? *atts.version : NULL, "version");
GF_LSR_WRITE_INT(lsr, atts.viewBox ? 1 : 0, 1, "hasViewBox");
if (atts.viewBox) {
lsr_write_fixed_16_8(lsr, atts.viewBox->x, "viewbox.x");
lsr_write_fixed_16_8(lsr, atts.viewBox->y, "viewbox.y");
lsr_write_fixed_16_8(lsr, atts.viewBox->width, "viewbox.width");
lsr_write_fixed_16_8(lsr, atts.viewBox->height, "viewbox.height");
}
lsr_write_value_with_units(lsr, atts.width, "width");
GF_LSR_WRITE_INT(lsr, atts.zoomAndPan ? 1 : 0, 1, "hasZoomAndPan");
if (atts.zoomAndPan) {
GF_LSR_WRITE_INT(lsr, (*atts.zoomAndPan==SVG_ZOOMANDPAN_MAGNIFY) ? 1 : 0, 1, "zoomAndPan");
}
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_switch(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, 0);
}
static void lsr_write_text(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag)
{
Bool same_fill;
u32 same_type = 0;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_text, &same_fill, NULL, 0) ) {
if (!same_fill) {
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sametextfill, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, elt, &atts);
} else {
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sametext, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
}
lsr_write_coord_list(lsr, atts.text_x, "x");
lsr_write_coord_list(lsr, atts.text_y, "y");
same_type = 1;
} else {
if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_text, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
GF_LSR_WRITE_INT(lsr, (atts.editable && *atts.editable) ? 1 : 0, 1, "editable");
lsr_write_float_list(lsr, atts.text_rotate, "rotate");
lsr_write_coord_list(lsr, atts.text_x, "x");
lsr_write_coord_list(lsr, atts.text_y, "y");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr->prev_text = elt;
}
lsr_write_group_content(lsr, elt, same_type);
}
static void lsr_write_tspan(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_use(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag)
{
SVGAllAttributes atts;
Bool is_same = GF_FALSE;
gf_svg_flatten_attributes(elt, &atts);
if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_use, NULL, NULL, GF_FALSE)
) {
is_same = GF_TRUE;
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sameuse, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_href(lsr, atts.xlink_href);
} else {
if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_use, 6, "ch4");
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_fill(lsr, (SVG_Element*)elt, &atts);
lsr_write_stroke(lsr, (SVG_Element*)elt, &atts);
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
GF_LSR_WRITE_INT(lsr, atts.overflow ? 1 : 0, 1, "hasOverflow");
if (atts.overflow) GF_LSR_WRITE_INT(lsr, 0, 2, "overflow");
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x");
lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y");
lsr_write_href(lsr, atts.xlink_href);
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr->prev_use = elt;
}
lsr_write_group_content(lsr, elt, is_same);
}
static void lsr_write_video(GF_LASeRCodec *lsr, SVG_Element *elt)
{
u32 fs_value;
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
fs_value = 0;
if (atts.fullscreen) {
fs_value = *atts.fullscreen + 1;
atts.fullscreen = NULL;
}
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE);
lsr_write_duration(lsr, atts.dur, "dur");
GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired");
lsr_write_coordinate_ptr(lsr, atts.height, GF_TRUE, "height");
GF_LSR_WRITE_INT(lsr, atts.overlay ? 1 : 0, 1, "hasOverlay");
if (atts.overlay) {
GF_LSR_WRITE_INT(lsr, 1, 1, "choice");
GF_LSR_WRITE_INT(lsr, *atts.overlay, 1, "overlay");
}
lsr_write_preserve_aspect_ratio(lsr, atts.preserveAspectRatio);
lsr_write_anim_repeat(lsr, atts.repeatCount);
lsr_write_repeat_duration(lsr, atts.repeatDur);
lsr_write_anim_restart(lsr, atts.restart);
lsr_write_sync_behavior(lsr, atts.syncBehavior, "syncBehavior");
lsr_write_sync_tolerance(lsr, atts.syncTolerance, "syncBehavior");
lsr_write_transform_behavior(lsr, atts.transformBehavior);
lsr_write_content_type(lsr, atts.xlink_type, "type");
lsr_write_coordinate_ptr(lsr, atts.width, GF_TRUE, "width");
lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x");
lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y");
lsr_write_href(lsr, atts.xlink_href);
lsr_write_clip_time(lsr, atts.clipBegin, "clipBegin");
lsr_write_clip_time(lsr, atts.clipEnd, "clipEnd");
GF_LSR_WRITE_INT(lsr, fs_value ? 1 : 0, 1, "hasFullscreen");
if (atts.fullscreen) GF_LSR_WRITE_INT(lsr, fs_value - 1, 1, "fullscreen");
GF_LSR_WRITE_INT(lsr, atts.syncReference ? 1 : 0, 1, "hasSyncReference");
if (atts.syncReference) lsr_write_any_uri(lsr, atts.syncReference, "syncReference");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_listener(GF_LASeRCodec *lsr, SVG_Element *elt)
{
SVGAllAttributes atts;
gf_svg_flatten_attributes(elt, &atts);
lsr_write_id(lsr, (GF_Node *) elt);
lsr_write_rare(lsr, (GF_Node *) elt);
GF_LSR_WRITE_INT(lsr, atts.defaultAction ? 1 : 0, 1, "hasDefaultAction");
if (atts.defaultAction) GF_LSR_WRITE_INT(lsr, *atts.defaultAction ? 1 : 0, 1, "defaultAction");
if (atts.event) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasEvent");
lsr_write_event_type(lsr, atts.event->type, atts.event->parameter);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasEvent");
}
if (atts.handler && (atts.handler->string || (atts.handler->target && gf_node_get_id((GF_Node *)atts.handler->target) ) )) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasHandler");
lsr_write_any_uri(lsr, atts.handler, "handler");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasHandler");
}
if (atts.observer && atts.observer->target && gf_node_get_id((GF_Node *)atts.observer->target) ) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasObserver");
lsr_write_codec_IDREF(lsr, atts.observer, "observer");
} else {
if (atts.observer) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] listener.observer %s not found in scene - skipping it\n", atts.observer->string ));
}
GF_LSR_WRITE_INT(lsr, 0, 1, "hasObserver");
}
GF_LSR_WRITE_INT(lsr, atts.phase ? 1 : 0, 1, "hasPhase");
if (atts.phase) GF_LSR_WRITE_INT(lsr, *atts.phase, 1, "phase");
GF_LSR_WRITE_INT(lsr, atts.propagate ? 1 : 0, 1, "hasPropagate");
if (atts.propagate) GF_LSR_WRITE_INT(lsr, *atts.propagate, 1, "propagate");
if (atts.listener_target && atts.listener_target->target && gf_node_get_id((GF_Node *)atts.listener_target->target) ) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasTarget");
lsr_write_codec_IDREF(lsr, atts.listener_target, "target");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasTarget");
}
GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled");
lsr_write_any_attribute(lsr, elt, GF_TRUE);
lsr_write_group_content(lsr, elt, GF_FALSE);
}
static void lsr_write_scene_content_model(GF_LASeRCodec *lsr, SVG_Element *parent, void *node)
{
u32 tag = gf_node_get_tag((GF_Node*)node);
switch(tag) {
case TAG_SVG_a:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_a, 6, "ch4");
lsr_write_a(lsr, node);
break;
case TAG_SVG_animate:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_animate, 6, "ch4");
lsr_write_animate(lsr, node, parent);
break;
case TAG_SVG_animateColor:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_animateColor, 6, "ch4");
lsr_write_animate(lsr, node, parent);
break;
case TAG_SVG_animateMotion:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_animateMotion, 6, "ch4");
lsr_write_animateMotion(lsr, node, parent);
break;
case TAG_SVG_animateTransform:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_animateTransform, 6, "ch4");
lsr_write_animateTransform(lsr, node, parent);
break;
case TAG_SVG_audio:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_audio, 6, "ch4");
lsr_write_audio(lsr, node);
break;
case TAG_SVG_circle:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_circle, 6, "ch4");
lsr_write_circle(lsr, node);
break;
case TAG_LSR_cursorManager:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_cursorManager, 6, "ch4");
lsr_write_cursorManager(lsr, node);
break;
case TAG_SVG_defs:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_defs, 6, "ch4");
lsr_write_defs(lsr, node);
break;
case TAG_SVG_desc:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_desc, 6, "ch4");
lsr_write_data(lsr, node);
break;
case TAG_SVG_ellipse:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_ellipse, 6, "ch4");
lsr_write_ellipse(lsr, node);
break;
case TAG_SVG_foreignObject:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_foreignObject, 6, "ch4");
lsr_write_foreignObject(lsr, node);
break;
case TAG_SVG_g:
lsr_write_g(lsr, node, 0);
break;
case TAG_SVG_image:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_image, 6, "ch4");
lsr_write_image(lsr, node);
break;
case TAG_SVG_line:
lsr_write_line(lsr, node, 0);
break;
case TAG_SVG_linearGradient:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_linearGradient, 6, "ch4");
lsr_write_linearGradient(lsr, node);
break;
case TAG_SVG_metadata:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_metadata, 6, "ch4");
lsr_write_data(lsr, node);
break;
case TAG_SVG_mpath:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_mpath, 6, "ch4");
lsr_write_mpath(lsr, node);
break;
case TAG_SVG_path:
lsr_write_path(lsr, node, 0);
break;
case TAG_SVG_polygon:
lsr_write_polygon(lsr, node, 0, 0);
break;
case TAG_SVG_polyline:
lsr_write_polygon(lsr, node, 1, 0);
break;
case TAG_SVG_radialGradient:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_radialGradient, 6, "ch4");
lsr_write_radialGradient(lsr, node);
break;
case TAG_SVG_rect:
lsr_write_rect(lsr, node, 0);
break;
case TAG_SVG_script:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_script, 6, "ch4");
lsr_write_script(lsr, node);
break;
case TAG_SVG_set:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_set, 6, "ch4");
lsr_write_set(lsr, node, parent);
break;
case TAG_SVG_stop:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_stop, 6, "ch4");
lsr_write_stop(lsr, node);
break;
case TAG_SVG_switch:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_switch, 6, "ch4");
lsr_write_switch(lsr, node);
break;
case TAG_SVG_text:
lsr_write_text(lsr, node, 0);
break;
case TAG_SVG_title:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_title, 6, "ch4");
lsr_write_data(lsr, node);
break;
case TAG_SVG_tspan:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_tspan, 6, "ch4");
lsr_write_tspan(lsr, node);
break;
case TAG_SVG_use:
lsr_write_use(lsr, node, 0);
break;
case TAG_SVG_video:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_video, 6, "ch4");
lsr_write_video(lsr, node);
break;
case TAG_SVG_listener:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_listener, 6, "ch4");
lsr_write_listener(lsr, node);
break;
case TAG_LSR_conditional:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_conditional, 6, "ch4");
lsr_write_conditional(lsr, node);
break;
case TAG_LSR_rectClip:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_rectClip, 6, "ch4");
lsr_write_rectClip(lsr, node);
break;
case TAG_LSR_selector:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_selector, 6, "ch4");
lsr_write_selector(lsr, node);
break;
case TAG_LSR_simpleLayout:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_simpleLayout, 6, "ch4");
lsr_write_simpleLayout(lsr, node);
break;
#if 0
case TAG_SVG_extendElement:
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_privateContainer, 6, "ch4");
lsr_write_private_element_container(lsr);
break;
#endif
default:
#if 0
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_element_any, 6, "ch4");
lsr_write_extend_class(lsr, NULL, 0, node);
break;
#else
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] node %s not part of LASeR children nodes - skipping\n", gf_node_get_class_name((GF_Node*)node)));
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_textContent, 6, "ch4");
lsr_write_byte_align_string(lsr, "", "textContent");
break;
#endif
}
}
static void lsr_write_update_content_model(GF_LASeRCodec *lsr, SVG_Element *parent, void *node)
{
u32 tag = gf_node_get_tag((GF_Node*)node);
if (tag==TAG_LSR_conditional) {
GF_LSR_WRITE_INT(lsr, 1, 1, "ch4");
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL2_conditional, 3, "ch61");
lsr_write_conditional(lsr, node);
} else if (tag==TAG_LSR_cursorManager) {
GF_LSR_WRITE_INT(lsr, 1, 1, "ch4");
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL2_cursorManager, 3, "ch61");
lsr_write_cursorManager(lsr, node);
} else if (tag==TAG_LSR_rectClip) {
GF_LSR_WRITE_INT(lsr, 1, 1, "ch4");
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL2_rectClip, 3, "ch61");
lsr_write_rectClip(lsr, node);
} else if (tag==TAG_LSR_selector) {
GF_LSR_WRITE_INT(lsr, 1, 1, "ch4");
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL2_selector, 3, "ch61");
lsr_write_selector(lsr, node);
} else if (tag==TAG_LSR_simpleLayout) {
GF_LSR_WRITE_INT(lsr, 1, 1, "ch4");
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL2_simpleLayout, 3, "ch61");
lsr_write_simpleLayout(lsr, node);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "ch4");
switch(tag) {
case TAG_SVG_a:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_a, 6, "ch6");
lsr_write_a(lsr, node);
break;
case TAG_SVG_animate:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_animate, 6, "ch6");
lsr_write_animate(lsr, node, parent);
break;
case TAG_SVG_animateColor:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_animateColor, 6, "ch6");
lsr_write_animate(lsr, node, parent);
break;
case TAG_SVG_animateMotion:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_animateMotion, 6, "ch6");
lsr_write_animateMotion(lsr, node, parent);
break;
case TAG_SVG_animateTransform:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_animateTransform, 6, "ch6");
lsr_write_animateTransform(lsr, node, parent);
break;
case TAG_SVG_audio:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_audio, 6, "ch6");
lsr_write_audio(lsr, node);
break;
case TAG_SVG_circle:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_circle, 6, "ch6");
lsr_write_circle(lsr, node);
break;
case TAG_SVG_defs:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_defs, 6, "ch6");
lsr_write_defs(lsr, node);
break;
case TAG_SVG_desc:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_desc, 6, "ch6");
lsr_write_data(lsr, node);
break;
case TAG_SVG_ellipse:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_ellipse, 6, "ch6");
lsr_write_ellipse(lsr, node);
break;
case TAG_SVG_foreignObject:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_foreignObject, 6, "ch6");
lsr_write_foreignObject(lsr, node);
break;
case TAG_SVG_g:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_g, 6, "ch6");
lsr_write_g(lsr, node, 1);
break;
case TAG_SVG_image:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_image, 6, "ch6");
lsr_write_image(lsr, node);
break;
case TAG_SVG_line:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_line, 6, "ch6");
lsr_write_line(lsr, node, 1);
break;
case TAG_SVG_linearGradient:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_linearGradient, 6, "ch6");
lsr_write_linearGradient(lsr, node);
break;
case TAG_SVG_metadata:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_metadata, 6, "ch6");
lsr_write_data(lsr, node);
break;
case TAG_SVG_mpath:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_mpath, 6, "ch6");
lsr_write_mpath(lsr, node);
break;
case TAG_SVG_path:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_path, 6, "ch6");
lsr_write_path(lsr, node, 1);
break;
case TAG_SVG_polygon:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_polygon, 6, "ch6");
lsr_write_polygon(lsr, node, 0, 1);
break;
case TAG_SVG_polyline:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_polyline, 6, "ch6");
lsr_write_polygon(lsr, node, 1, 1);
break;
case TAG_SVG_radialGradient:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_radialGradient, 6, "ch6");
lsr_write_radialGradient(lsr, node);
break;
case TAG_SVG_rect:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_rect, 6, "ch6");
lsr_write_rect(lsr, node, 1);
break;
case TAG_SVG_script:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_script, 6, "ch6");
lsr_write_script(lsr, node);
break;
case TAG_SVG_set:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_set, 6, "ch6");
lsr_write_set(lsr, node, parent);
break;
case TAG_SVG_stop:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_stop, 6, "ch6");
lsr_write_stop(lsr, node);
break;
case TAG_SVG_svg:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_svg, 6, "ch6");
lsr_write_svg(lsr, node);
break;
case TAG_SVG_switch:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_switch, 6, "ch6");
lsr_write_switch(lsr, node);
break;
case TAG_SVG_text:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_text, 6, "ch6");
lsr_write_text(lsr, node, 1);
break;
case TAG_SVG_title:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_title, 6, "ch6");
lsr_write_data(lsr, node);
break;
case TAG_SVG_tspan:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_tspan, 6, "ch6");
lsr_write_tspan(lsr, node);
break;
case TAG_SVG_use:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_use, 6, "ch6");
lsr_write_use(lsr, node, 1);
break;
case TAG_SVG_video:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_video, 6, "ch6");
lsr_write_video(lsr, node);
break;
case TAG_SVG_listener:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_CONTENT_MODEL_listener, 6, "ch6");
lsr_write_listener(lsr, node);
break;
}
}
}
static void lsr_write_group_content(GF_LASeRCodec *lsr, SVG_Element *elt, Bool skip_object_content)
{
GF_ChildNodeItem *l;
u32 count;
if (!skip_object_content) lsr_write_private_attributes(lsr, elt);
count = gf_node_list_get_count(elt->children);
l = elt->children;
if (!count) {
GF_LSR_WRITE_INT(lsr, 0, 1, "opt_group");
return;
}
GF_LSR_WRITE_INT(lsr, 1, 1, "opt_group");
lsr_write_vluimsbf5(lsr, count, "occ0");
while (l) {
if (gf_node_get_tag(l->node)==TAG_DOMText) {
GF_DOMText *txt = (GF_DOMText *)l->node;
GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_textContent, 6, "ch4");
lsr_write_byte_align_string(lsr, txt->textContent, "textContent");
} else {
lsr_write_scene_content_model(lsr, elt, l->node);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] ############## end %s ###########\n", gf_node_get_class_name((GF_Node*)l->node)));
}
l = l->next;
}
}
static void lsr_write_update_value(GF_LASeRCodec *lsr, SVG_Element *elt, u32 fieldType, u32 att_tag, u32 transformType, void *val, Bool is_indexed)
{
SVG_Number *n;
if (is_indexed) {
assert(gf_list_count(*(GF_List **)val));
switch (fieldType) {
case SVG_Points_datatype:
{
GF_Point2D *pt = (GF_Point2D*)gf_list_get(*(GF_List **)val, 0);
lsr_write_coordinate(lsr, pt->x, GF_FALSE, "x");
lsr_write_coordinate(lsr, pt->y, GF_FALSE, "y");
}
break;
case SMIL_Times_datatype:
{
SMIL_Time *st = (SMIL_Time*)gf_list_get(*(GF_List **)val, 0);
lsr_write_smil_time(lsr, st);
}
break;
case SMIL_KeyPoints_datatype:
{
Fixed *f = (Fixed*)gf_list_get(*(GF_List **)val, 0);
lsr_write_fixed_clamp(lsr, *f, "v");
}
break;
case SMIL_KeySplines_datatype:
{
Fixed *f = (Fixed*)gf_list_get(*(GF_List **)val, 0);
lsr_write_fixed_16_8(lsr, *f, "v");
}
break;
case SMIL_KeyTimes_datatype:
{
Fixed *v = (Fixed*)gf_list_get(*(GF_List **)val, 0);
Fixed f = *v;
if ((f==0) || (f==FIX_ONE)) {
GF_LSR_WRITE_INT(lsr, 1, 1, "hasShort");
GF_LSR_WRITE_INT(lsr, (f==0) ? 0 : 1, 1, "isZero");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "hasShort");
lsr_write_fixed_clamp(lsr, f, "timevalue");
}
}
break;
case SVG_StrokeDashArray_datatype:
case SVG_ViewBox_datatype:
break;
case DOM_StringList_datatype:
if (att_tag==TAG_SVG_ATT_requiredFeatures) {
}
break;
}
} else {
switch (fieldType) {
case SVG_Boolean_datatype:
GF_LSR_WRITE_INT(lsr, *(SVG_Boolean*)val ? 1 : 0, 1, "val");
break;
case SVG_Paint_datatype:
lsr_write_paint(lsr, (SVG_Paint *)val, "val");
break;
case SVG_Transform_datatype:
lsr_write_matrix(lsr, (SVG_Transform*)val);
break;
case SVG_Transform_Scale_datatype:
lsr_write_fixed_16_8(lsr, ((SVG_Point *)val)->x, "scale_x");
lsr_write_fixed_16_8(lsr, ((SVG_Point *)val)->y, "scale_y");
break;
case LASeR_Size_datatype:
case SVG_Transform_Translate_datatype:
lsr_write_coordinate(lsr, ((SVG_Point *)val)->x, GF_FALSE, "translation_x");
lsr_write_coordinate(lsr, ((SVG_Point *)val)->y, GF_FALSE, "translation_y");
break;
case SVG_Transform_Rotate_datatype:
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefaultValue");
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
lsr_write_fixed_16_8(lsr, ((SVG_Point_Angle*)val)->angle, "rotate");
break;
case SVG_Number_datatype:
case SVG_FontSize_datatype:
case SVG_Length_datatype:
n = (SVG_Number*)val;
switch (att_tag) {
case TAG_SVG_ATT_audio_level:
case TAG_SVG_ATT_fill_opacity:
case TAG_SVG_ATT_offset:
case TAG_SVG_ATT_opacity:
case TAG_SVG_ATT_solid_opacity:
case TAG_SVG_ATT_stop_opacity:
case TAG_SVG_ATT_stroke_opacity:
case TAG_SVG_ATT_viewport_fill_opacity:
if (n->type==SVG_NUMBER_INHERIT) {
GF_LSR_WRITE_INT(lsr, 1, 1, "isDefaultValue");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefaultValue");
lsr_write_fixed_clamp(lsr, n->value, "val");
}
break;
case TAG_SVG_ATT_width:
case TAG_SVG_ATT_height:
if (elt->sgprivate->tag==TAG_SVG_svg) {
lsr_write_value_with_units(lsr, n, "val");
} else {
lsr_write_coordinate(lsr, n->value, GF_FALSE, "val");
}
break;
default:
if (n->type==SVG_NUMBER_INHERIT) {
GF_LSR_WRITE_INT(lsr, 1, 1, "isDefaultValue");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefaultValue");
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
lsr_write_fixed_16_8(lsr, n->value, "val");
}
}
break;
case SVG_Rotate_datatype:
n = (SVG_Number*)val;
if (n->type==SVG_NUMBER_INHERIT) {
GF_LSR_WRITE_INT(lsr, 1, 1, "isDefaultValue");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefaultValue");
if ((n->type == SVG_NUMBER_AUTO) || (n->type == SVG_NUMBER_AUTO_REVERSE)) {
GF_LSR_WRITE_INT(lsr, 1, 1, "escapeFlag");
GF_LSR_WRITE_INT(lsr, (n->type == SVG_NUMBER_AUTO) ? 0 : 1, 2, "rotate");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
lsr_write_fixed_16_8(lsr, n->value, "rotate");
}
}
break;
case SVG_Coordinate_datatype:
n = (SVG_Number*)val;
lsr_write_coordinate(lsr, n->value, GF_FALSE, "val");
break;
case SVG_Coordinates_datatype:
GF_LSR_WRITE_INT(lsr, 0, 1, "isInherit");
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
lsr_write_float_list(lsr, (GF_List **)val, "val");
break;
case XMLRI_datatype:
if ((att_tag==TAG_XLINK_ATT_href) || (att_tag==TAG_SVG_ATT_syncReference)) {
lsr_write_any_uri(lsr, (XMLRI*)val, "val");
} else if (((XMLRI*)val)->target) {
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefault");
GF_LSR_WRITE_INT(lsr, 0, 1, "isEscape");
lsr_write_vluimsbf5(lsr, gf_node_get_id( ((XMLRI*)val)->target) - 1, "ID");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "isDefault");
}
break;
case SVG_Focus_datatype:
if ( (((SVG_Focus*)val)->type == SVG_FOCUS_AUTO) || !((SVG_Focus*)val)->target.target) {
GF_LSR_WRITE_INT(lsr, 1, 1, "isDefault");
} else if (((SVG_Focus*)val)->type == SVG_FOCUS_SELF) {
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefault");
GF_LSR_WRITE_INT(lsr, 1, 1, "isEscape");
GF_LSR_WRITE_INT(lsr, 1, 2, "escapeEnumVal");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefault");
GF_LSR_WRITE_INT(lsr, 0, 1, "isEscape");
lsr_write_vluimsbf5(lsr, gf_node_get_id( ((SVG_Focus*)val)->target.target) - 1, "ID");
}
break;
case DOM_String_datatype:
case SVG_ContentType_datatype:
case SVG_LanguageID_datatype:
lsr_write_byte_align_string(lsr, val ? *(DOM_String *)val : (char *)"", "val");
break;
case SVG_Motion_datatype:
lsr_write_coordinate(lsr, ((GF_Matrix2D *)val)->m[2], GF_FALSE, "pointValueX");
lsr_write_coordinate(lsr, ((GF_Matrix2D *)val)->m[5], GF_FALSE, "pointValueY");
break;
case SVG_Points_datatype:
lsr_write_point_sequence(lsr, (GF_List **)val, "val");
break;
case SVG_PathData_datatype:
lsr_write_path_type(lsr, (SVG_PathData*)val, "val");
break;
case LASeR_Choice_datatype:
{
LASeR_Choice *ch = (LASeR_Choice *)val;
GF_LSR_WRITE_INT(lsr, (ch->type==LASeR_CHOICE_ALL) ? 1 : 0, 1, "isDefaultValue");
if (ch->type!=LASeR_CHOICE_ALL) {
GF_LSR_WRITE_INT(lsr, (ch->type==LASeR_CHOICE_NONE) ? 1 : 0, 1, "escapeFlag");
if (ch->type==LASeR_CHOICE_NONE) {
GF_LSR_WRITE_INT(lsr, LASeR_CHOICE_NONE, 2, "escapeEnum");
} else {
lsr_write_vluimsbf5(lsr, ((LASeR_Choice *)val)->choice_index, "value");
}
}
}
break;
case SVG_ViewBox_datatype:
{
SVG_ViewBox *b = (SVG_ViewBox *)val;
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefaultValue");
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
lsr_write_vluimsbf5(lsr, 4, "nb1");
lsr_write_fixed_16_8(lsr, b->x, "x");
lsr_write_fixed_16_8(lsr, b->y, "y");
lsr_write_fixed_16_8(lsr, b->width, "width");
lsr_write_fixed_16_8(lsr, b->width, "height");
}
break;
case SVG_FontFamily_datatype:
{
SVG_FontFamily *ff = (SVG_FontFamily *)val;
GF_LSR_WRITE_INT(lsr, (ff->type == SVG_FONTFAMILY_INHERIT) ? 1 : 0, 1, "isDefaultValue");
if (ff->type != SVG_FONTFAMILY_INHERIT) {
s32 idx = lsr_get_font_index(lsr, ff);
if (idx==-1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] corrupted font table while encoding update value\n"));
idx=0;
}
GF_LSR_WRITE_INT(lsr, 0, 1, "escapeFlag");
lsr_write_vluimsbf5(lsr, (u32) idx, "nb1");
}
}
break;
default:
if ((fieldType>=SVG_FillRule_datatype) && (fieldType<=SVG_LAST_U8_PROPERTY)) {
u8 v = *(u8 *)val;
if (!v) {
GF_LSR_WRITE_INT(lsr, 1, 1, "isDefaultValue");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "isDefaultValue");
lsr_write_vluimsbf5(lsr, v, "val");
}
} else {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] update value not implemented for type %d - please fix or report\n", fieldType));
}
}
}
}
static GF_Err lsr_write_add_replace_insert(GF_LASeRCodec *lsr, GF_Command *com)
{
GF_CommandField *field;
u8 type = 0;
Bool is_text_node = GF_FALSE;
u32 field_type, tr_type = 0;
if (com->tag==GF_SG_LSR_REPLACE) type = LSR_UPDATE_REPLACE;
else if (com->tag==GF_SG_LSR_ADD) type = LSR_UPDATE_ADD;
else if (com->tag==GF_SG_LSR_INSERT) type = LSR_UPDATE_INSERT;
else return GF_BAD_PARAM;
GF_LSR_WRITE_INT(lsr, type, 4, "ch4");
field = (GF_CommandField*)gf_list_get(com->command_fields, 0);
field_type = 0;
if (field && ( !field->new_node || (field->fieldIndex==TAG_LSR_ATT_children) ) && !field->node_list) {
s32 attType = 0;
field_type = field->fieldType;
attType = gf_lsr_anim_type_from_attribute(field->fieldIndex);
if (attType== -1) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[LASeR] Attribute %s of element %s is not updatable\n", gf_svg_get_attribute_name(com->node, field->fieldIndex), gf_node_get_class_name(com->node) ));
return lsr->last_error = GF_BAD_PARAM;
}
GF_LSR_WRITE_INT(lsr, 1, 1, "has_attributeName");
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
GF_LSR_WRITE_INT(lsr, attType, 8, "attributeName");
}
else if (field && field->new_node && field->new_node->sgprivate->tag==TAG_DOMText) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_attributeName");
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_TYPE_TEXT_CONTENT, 8, "attributeName");
is_text_node = GF_TRUE;
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_attributeName");
}
if (type!=LSR_UPDATE_ADD) {
if (!field || field->pos<0) {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_index");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_index");
lsr_write_vluimsbf5(lsr, (u32) field->pos, "index");
}
}
if (type!=LSR_UPDATE_INSERT) {
if (com->fromNodeID) {
u8 opAttType;
opAttType = gf_lsr_anim_type_from_attribute(com->fromFieldIndex);
GF_LSR_WRITE_INT(lsr, 1, 1, "has_operandAttribute");
GF_LSR_WRITE_INT(lsr, opAttType, 8, "operandAttribute");
GF_LSR_WRITE_INT(lsr, 1, 1, "has_operandElementId");
lsr_write_vluimsbf5(lsr, com->fromNodeID-1, "operandElementId");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_operandAttribute");
GF_LSR_WRITE_INT(lsr, 0, 1, "has_operandElementId");
}
}
lsr_write_codec_IDREF_Node(lsr, com->node, "ref");
if (field && !field->new_node && !field->node_list && !com->fromNodeID) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_value");
lsr_write_update_value(lsr, (SVG_Element *)com->node, field_type, field->fieldIndex, tr_type, field->field_ptr, (field->pos>=0) ? GF_TRUE : GF_FALSE);
} else if (is_text_node) {
GF_DOMText *t = (GF_DOMText *)field->new_node;
GF_LSR_WRITE_INT(lsr, 1, 1, "has_value");
lsr_write_update_value(lsr, (SVG_Element *)com->node, DOM_String_datatype, field->fieldIndex, 0, &t->textContent, (field->pos>=0) ? GF_TRUE : GF_FALSE);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_value");
}
lsr_write_any_attribute(lsr, NULL, GF_TRUE);
if (type!=LSR_UPDATE_ADD) {
if (field && field->node_list && !com->fromNodeID) {
GF_ChildNodeItem *l = field->node_list;
u32 count = gf_node_list_get_count(l);
GF_LSR_WRITE_INT(lsr, 1, 1, "opt_group");
if (type==LSR_UPDATE_REPLACE) lsr_write_vluimsbf5(lsr, count, "count");
while (l) {
lsr_write_update_content_model(lsr, (SVG_Element*) com->node, l->node);
l = l->next;
if (type==LSR_UPDATE_INSERT) break;
}
} else if (field && field->new_node && !is_text_node) {
GF_LSR_WRITE_INT(lsr, 1, 1, "opt_group");
if (type==LSR_UPDATE_REPLACE) lsr_write_vluimsbf5(lsr, 1, "count");
lsr_write_update_content_model(lsr, (SVG_Element*) com->node, field->new_node);
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "opt_group");
}
}
return GF_OK;
}
static GF_Err lsr_write_command_list(GF_LASeRCodec *lsr, GF_List *com_list, SVG_Element *cond, Bool first_implicit)
{
GF_CommandField *field;
u32 i, count;
u32 detail;
GF_BitStream *old_bs;
count = com_list ? gf_list_count(com_list) : 0;
old_bs = NULL;
if (cond) {
old_bs = lsr->bs;
lsr->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
}
assert(count>= (u32) (first_implicit ? 1 : 0) );
lsr_write_vluimsbf5(lsr, count-first_implicit, "occ0");
if (!com_list) goto exit;
count = gf_list_count(com_list);
for (i=0; i<count; i++) {
GF_Command *com = (GF_Command *)gf_list_get(com_list, i);
switch (com->tag) {
case GF_SG_LSR_NEW_SCENE:
case GF_SG_LSR_REFRESH_SCENE:
GF_LSR_WRITE_INT(lsr, (com->tag==GF_SG_LSR_REFRESH_SCENE) ? LSR_UPDATE_REFRESH_SCENE : LSR_UPDATE_NEW_SCENE, 4, "ch4");
if (com->tag==GF_SG_LSR_REFRESH_SCENE) lsr_write_vluimsbf5(lsr, 0, "time");
lsr_write_any_attribute(lsr, NULL, 1);
lsr_write_svg(lsr, (SVG_Element*)com->node);
break;
case GF_SG_LSR_REPLACE:
case GF_SG_LSR_ADD:
case GF_SG_LSR_INSERT:
lsr_write_add_replace_insert(lsr, com);
break;
case GF_SG_LSR_CLEAN:
break;
case GF_SG_LSR_DELETE:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_DELETE, 4, "ch4");
field = (GF_CommandField*)gf_list_get(com->command_fields, 0);
if (field && field->fieldType) {
u8 attType;
attType = gf_lsr_anim_type_from_attribute(field->fieldIndex);
GF_LSR_WRITE_INT(lsr, 1, 1, "has_attributeName");
GF_LSR_WRITE_INT(lsr, 0, 1, "choice");
GF_LSR_WRITE_INT(lsr, attType, 8, "attributeName");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_attributeName");
}
if (!field || (field->pos<0) ) {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_index");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_index");
lsr_write_vluimsbf5(lsr, (u32) field->pos, "index");
}
lsr_write_codec_IDREF_Node(lsr, com->node, "ref");
lsr_write_any_attribute(lsr, NULL, 1);
break;
case GF_SG_LSR_RESTORE:
return GF_NOT_SUPPORTED;
case GF_SG_LSR_SAVE:
return GF_NOT_SUPPORTED;
case GF_SG_LSR_SEND_EVENT:
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_SEND_EVENT, 4, "ch4");
detail = com->send_event_integer;
switch (com->send_event_name) {
case GF_EVENT_KEYDOWN:
case GF_EVENT_LONGKEYPRESS:
case GF_EVENT_REPEAT_KEY:
case GF_EVENT_SHORT_ACCESSKEY:
detail = dom_to_lsr_key(detail);
if (detail==100) detail = 0;
break;
}
lsr_write_event_type(lsr, com->send_event_name, com->send_event_integer);
if (detail && com->send_event_integer) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_intvalue");
GF_LSR_WRITE_INT(lsr, (com->send_event_integer<0) ? 1 : 0, 1, "sign");
lsr_write_vluimsbf5(lsr, ABS(com->send_event_integer), "value");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_intvalue");
}
if (com->send_event_name<=GF_EVENT_MOUSEWHEEL) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_pointvalue");
lsr_write_coordinate(lsr, INT2FIX(com->send_event_x), 0, "x");
lsr_write_coordinate(lsr, INT2FIX(com->send_event_y), 0, "y");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_pointvalue");
}
lsr_write_codec_IDREF_Node(lsr, com->node, "ref");
if (com->send_event_string) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_stringvalue");
lsr_write_byte_align_string(lsr, com->send_event_string, "stringvalue");
} else if (!detail && com->send_event_integer) {
GF_LSR_WRITE_INT(lsr, 1, 1, "has_stringvalue");
lsr_write_byte_align_string(lsr, (char *)gf_dom_get_key_name(com->send_event_integer), "stringvalue");
} else {
GF_LSR_WRITE_INT(lsr, 0, 1, "has_stringvalue");
}
GF_LSR_WRITE_INT(lsr, 0, 1, "has_attr_any");
return GF_OK;
case GF_SG_LSR_ACTIVATE:
case GF_SG_LSR_DEACTIVATE:
{
u32 update_size = lsr_get_IDREF_nb_bits(lsr, com->node);
GF_LSR_WRITE_INT(lsr, LSR_UPDATE_EXTEND, 4, "ch4");
GF_LSR_WRITE_INT(lsr, 2, lsr->info->cfg.extensionIDBits, "extensionID");
lsr_write_vluimsbf5(lsr, 10 + 5 + 2 + 5 + 2 + update_size, "len");
lsr_write_vluimsbf5(lsr, 87, "reserved");
lsr_write_vluimsbf5(lsr, 1, "occ2");
GF_LSR_WRITE_INT(lsr, 1, 2, "reserved");
lsr_write_vluimsbf5(lsr, 1, "occ3");
GF_LSR_WRITE_INT(lsr, (com->tag==GF_SG_LSR_ACTIVATE) ? 1 : 2, 2, "ch5");
lsr_write_codec_IDREF_Node(lsr, com->node, "ref");
}
break;
default:
return GF_BAD_PARAM;
}
lsr->prev_g = NULL;
lsr->prev_line = NULL;
lsr->prev_path = NULL;
lsr->prev_polygon = NULL;
lsr->prev_rect = NULL;
lsr->prev_text = NULL;
lsr->prev_use = NULL;
if (lsr->last_error) break;
}
exit:
if (cond) {
char *data;
u32 data_size;
gf_bs_get_content(lsr->bs, &data, &data_size);
gf_bs_del(lsr->bs);
lsr->bs = old_bs;
lsr_write_vluimsbf5(lsr, data_size, NULL);
gf_bs_align(lsr->bs);
gf_bs_write_data(lsr->bs, data, data_size);
gf_free(data);
}
return lsr->last_error;
}
static void lsr_add_color(GF_LASeRCodec *lsr, SVG_Color *color)
{
lsr->col_table = (LSRCol*)gf_realloc(lsr->col_table, sizeof(LSRCol)*(lsr->nb_cols+1));
lsr->col_table[lsr->nb_cols].r = FIX2INT(color->red*lsr->color_scale);
lsr->col_table[lsr->nb_cols].g = FIX2INT(color->green*lsr->color_scale);
lsr->col_table[lsr->nb_cols].b = FIX2INT(color->blue*lsr->color_scale);
lsr->nb_cols++;
}
static void lsr_check_col_index(GF_LASeRCodec *lsr, SVG_Color *color, SVG_Paint *paint)
{
s32 idx;
if (color) {
idx = lsr_get_col_index(lsr, color);
if (idx==-2) lsr_add_color(lsr, color);
}
else if (paint && (paint->type==SVG_PAINT_COLOR) ) {
idx = lsr_get_col_index(lsr, &paint->color);
if (idx==-2) lsr_add_color(lsr, &paint->color);
}
}
static void lsr_check_font_index(GF_LASeRCodec *lsr, SVG_FontFamily *font)
{
u32 count, i;
if (font && (font->type == SVG_FONTFAMILY_VALUE) && font->value) {
Bool found = 0;
count = gf_list_count(lsr->font_table);
for (i=0; i<count; i++) {
char *ff = (char *)gf_list_get(lsr->font_table, i);
if (!strcmp(ff, font->value)) {
found = 1;
break;
}
}
if (!found) gf_list_add(lsr->font_table, gf_strdup(font->value));
}
}
static void lsr_check_font_and_color(GF_LASeRCodec *lsr, SVG_Element *elt)
{
GF_ChildNodeItem *l;
SVGAttribute *att;
u32 i, count, tag;
u32 check_anim_font, check_anim_col;
tag = gf_node_get_tag((GF_Node*)elt);
if (tag < GF_NODE_FIRST_DOM_NODE_TAG) goto check_children;
check_anim_font = check_anim_col = 0;
att = elt->attributes;
while (att) {
switch (att->data_type) {
case SVG_Paint_datatype:
lsr_check_col_index(lsr, NULL, att->data);
break;
case SVG_FontFamily_datatype:
lsr_check_font_index(lsr, att->data);
break;
case SMIL_AttributeName_datatype:
{
SMIL_AttributeName *an = (SMIL_AttributeName*)att->data;
if (an->name) {
if (!strcmp(an->name, "fill")) check_anim_col = 1;
else if (!strcmp(an->name, "stroke")) check_anim_col = 1;
else if (!strcmp(an->name, "color")) check_anim_col = 1;
else if (!strcmp(an->name, "solid-olor")) check_anim_col = 2;
else if (!strcmp(an->name, "stop-color")) check_anim_col = 2;
else if (!strcmp(an->name, "font-family")) check_anim_font = 1;
}
}
break;
}
att = att->next;
}
if (check_anim_font || check_anim_col) {
att = elt->attributes;
while (att) {
switch (att->data_type) {
case SMIL_AnimateValue_datatype:
if (check_anim_font) lsr_check_font_index(lsr, ((SMIL_AnimateValue*)att->data)->value);
else if (check_anim_col == 1) lsr_check_col_index(lsr, NULL, ((SMIL_AnimateValue*)att->data)->value);
else if (check_anim_col == 2) lsr_check_col_index(lsr, ((SMIL_AnimateValue*)att->data)->value, NULL);
break;
case SMIL_AnimateValues_datatype:
{
SMIL_AnimateValues *vals = (SMIL_AnimateValues*)att->data;
count = gf_list_count(vals->values);
for (i=0; i<count; i++) {
if (check_anim_font) lsr_check_font_index(lsr, (SVG_FontFamily*)gf_list_get(vals->values, i));
else if (check_anim_col == 1) lsr_check_col_index(lsr, NULL, (SVG_Paint*)gf_list_get(vals->values, i) );
else if (check_anim_col == 2) lsr_check_col_index(lsr, (SVG_Color*)gf_list_get(vals->values, i), NULL);
}
}
break;
}
att = att->next;
}
}
check_children:
l = elt->children;
while (l) {
if (l->node->sgprivate->tag==TAG_DOMUpdates) {
GF_DOMUpdates *up = (GF_DOMUpdates *)l->node;
count = gf_list_count(up->updates);
for (i=0; i<count; i++) {
u32 j, c2;
GF_Command *com = gf_list_get(up->updates, i);
c2 = gf_list_count(com->command_fields);
for (j=0; j<c2; j++) {
GF_CommandField *field = (GF_CommandField *)gf_list_get(com->command_fields, j);
if (field->new_node) {
lsr_check_font_and_color(lsr, (SVG_Element*)field->new_node);
}
else if (field->field_ptr) {
switch (field->fieldType) {
case SVG_Paint_datatype:
lsr_check_col_index(lsr, NULL, (SVG_Paint*)field->field_ptr);
break;
case SVG_Color_datatype:
lsr_check_col_index(lsr, (SVG_Color*)field->field_ptr, NULL);
break;
case SVG_FontFamily_datatype:
lsr_check_font_index(lsr, (SVG_FontFamily*)field->field_ptr);
break;
}
}
}
}
} else {
lsr_check_font_and_color(lsr, (SVG_Element*)l->node);
}
l = l->next;
}
}
static GF_Err lsr_write_laser_unit(GF_LASeRCodec *lsr, GF_List *com_list, Bool reset_encoding_context)
{
u32 i, count, prev_col_count, prev_font_count;
if (!com_list) {
if (gf_sg_get_root_node(lsr->sg) == NULL) return GF_BAD_PARAM;
GF_LSR_WRITE_INT(lsr, 1, 1, "resetEncodingContext");
} else {
GF_LSR_WRITE_INT(lsr, reset_encoding_context ? 1 : 0, 1, "resetEncodingContext");
}
GF_LSR_WRITE_INT(lsr, 0, 1, "opt_group");
if (0) lsr_write_extension(lsr, NULL, 0, "ext");
if (reset_encoding_context) {
lsr->nb_cols = 0;
if (lsr->col_table) gf_free(lsr->col_table);
lsr->col_table = NULL;
while (gf_list_count(lsr->font_table)) {
char *ft = (char *)gf_list_last(lsr->font_table);
gf_free(ft);
gf_list_rem_last(lsr->font_table);
}
}
prev_col_count = lsr->nb_cols;
prev_font_count = gf_list_count(lsr->font_table);
if (!com_list) {
prev_col_count = prev_font_count = 0;
lsr_check_font_and_color(lsr, (SVG_Element *)gf_sg_get_root_node(lsr->sg));
} else {
count = gf_list_count(com_list);
for (i=0; i<count; i++) {
GF_Command *com = (GF_Command *)gf_list_get(com_list, i);
if (gf_list_count(com->command_fields)) {
GF_CommandField *field = (GF_CommandField *)gf_list_get(com->command_fields, 0);
if (field->fieldType==SVG_Paint_datatype) lsr_check_col_index(lsr, NULL, (SVG_Paint*)field->field_ptr);
else if (field->fieldType==SVG_FontFamily_datatype) lsr_check_font_index(lsr, (SVG_FontFamily*)field->field_ptr);
else if (field->new_node) lsr_check_font_and_color(lsr, (SVG_Element*)field->new_node);
else if (field->node_list) {
GF_ChildNodeItem *l = field->node_list;
while (l) {
lsr_check_font_and_color(lsr, (SVG_Element*)l->node);
l = l->next;
}
}
} else if (com->node && (com->tag!=GF_SG_LSR_DELETE) ) {
lsr_check_font_and_color(lsr, (SVG_Element *)com->node);
}
}
}
if (prev_col_count == lsr->nb_cols) {
GF_LSR_WRITE_INT(lsr, 0, 1, "colorInitialisation");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "colorInitialisation");
lsr_write_vluimsbf5(lsr, lsr->nb_cols - prev_col_count, "count");
for (i=prev_col_count; i<lsr->nb_cols; i++) {
GF_LSR_WRITE_INT(lsr, lsr->col_table[i].r, lsr->info->cfg.colorComponentBits, "red");
GF_LSR_WRITE_INT(lsr, lsr->col_table[i].g, lsr->info->cfg.colorComponentBits, "green");
GF_LSR_WRITE_INT(lsr, lsr->col_table[i].b, lsr->info->cfg.colorComponentBits, "blue");
}
}
lsr->colorIndexBits = gf_get_bit_size(lsr->nb_cols);
count = gf_list_count(lsr->font_table);
if (prev_font_count == count) {
GF_LSR_WRITE_INT(lsr, 0, 1, "fontInitialisation");
} else {
GF_LSR_WRITE_INT(lsr, 1, 1, "fontInitialisation");
lsr_write_vluimsbf5(lsr, count - prev_font_count, "count");
for (i=prev_font_count; i<count; i++) {
char *ft = (char *)gf_list_get(lsr->font_table, i);
lsr_write_byte_align_string(lsr, ft, "font");
}
}
lsr->fontIndexBits = gf_get_bit_size(count);
GF_LSR_WRITE_INT(lsr, 0, 1, "privateDataIdentifierInitialisation");
GF_LSR_WRITE_INT(lsr, 0, 1, "anyXMLInitialisation");
lsr_write_vluimsbf5(lsr, 0, "countG");
GF_LSR_WRITE_INT(lsr, 0, 1, "hasExtension");
if (!com_list) {
lsr_write_vluimsbf5(lsr, 0, "occ0");
GF_LSR_WRITE_INT(lsr, 4, 4, "ch4");
lsr_write_any_attribute(lsr, NULL, 1);
lsr_write_svg(lsr, (SVG_Element *)gf_sg_get_root_node(lsr->sg) );
} else {
GF_Err e = lsr_write_command_list(lsr, com_list, NULL, 1);
if (e) return e;
}
GF_LSR_WRITE_INT(lsr, 0, 1, "opt_group");
if (0) lsr_write_extension(lsr, NULL, 0, "ext");
return GF_OK;
}
#endif