This source file includes following definitions.
- gf_node_animation_add
- gf_node_animation_del
- gf_node_animation_count
- gf_node_animation_get
- gf_node_animation_rem
- gf_svg_attributes_resolve_unspecified
- gf_svg_attributes_resolve_inherit
- gf_svg_attributes_resolve_currentColor
- gf_smil_anim_set
- gf_smil_anim_use_keypoints_keytimes
- gf_smil_anim_animate_using_values
- gf_smil_anim_animate_from_to
- gf_smil_anim_animate_from_by
- gf_svg_compute_path_anim
- gf_smil_anim_animate_using_path
- gf_smil_anim_compute_interpolation_value
- gf_smil_anim_set_anim_runtime_in_timing
- gf_smil_anim_get_last_specified_value
- gf_smil_anim_apply_accumulate
- gf_smil_apply_additive
- gf_smil_anim_animate
- gf_smil_anim_animate_with_fraction
- gf_smil_anim_reset_variables
- gf_smil_anim_freeze
- gf_smil_anim_remove
- gf_smil_anim_evaluate
- gf_svg_apply_animations
- gf_smil_anim_get_target
- gf_smil_anim_init_runtime_info
- gf_smil_anim_delete_runtime_info
- gf_smil_anim_remove_from_target
- gf_smil_anim_delete_animations
- gf_smil_anim_init_discard
- gf_smil_anim_init_node
#include <gpac/internal/scenegraph_dev.h>
#include <gpac/nodes_svg.h>
#ifndef GPAC_DISABLE_LOG
u32 time_spent_in_anim = 0;
#endif
#ifndef GPAC_DISABLE_SVG
GF_Err gf_node_animation_add(GF_Node *node, void *animation)
{
if (!node || !animation) return GF_BAD_PARAM;
if (!node->sgprivate->interact) {
GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
}
if (!node->sgprivate->interact->animations) node->sgprivate->interact->animations = gf_list_new();
return gf_list_add(node->sgprivate->interact->animations, animation);
}
GF_Err gf_node_animation_del(GF_Node *node)
{
if (!node || !node->sgprivate->interact || !node->sgprivate->interact->animations) return GF_BAD_PARAM;
gf_list_del(node->sgprivate->interact->animations);
node->sgprivate->interact->animations = NULL;
return GF_OK;
}
u32 gf_node_animation_count(GF_Node *node)
{
if (!node || !node->sgprivate->interact|| !node->sgprivate->interact->animations) return 0;
return gf_list_count(node->sgprivate->interact->animations);
}
void *gf_node_animation_get(GF_Node *node, u32 i)
{
if (!node || !node->sgprivate->interact || !node->sgprivate->interact->animations) return 0;
return gf_list_get(node->sgprivate->interact->animations, i);
}
GF_Err gf_node_animation_rem(GF_Node *node, u32 i)
{
if (!node || !node->sgprivate->interact || !node->sgprivate->interact->animations) return GF_OK;
return gf_list_rem(node->sgprivate->interact->animations, i);
}
void gf_svg_attributes_resolve_unspecified(GF_FieldInfo *in, GF_FieldInfo *p, GF_FieldInfo *t)
{
if (in->fieldType == 0) {
if (p->fieldType == SVG_Transform_datatype) {
*in = *t;
} else {
*in = *p;
}
}
}
void gf_svg_attributes_resolve_inherit(GF_FieldInfo *in, GF_FieldInfo *prop)
{
if (gf_svg_is_inherit(in)) *in = *prop;
}
void gf_svg_attributes_resolve_currentColor(GF_FieldInfo *in, GF_FieldInfo *current_color)
{
if ((in->fieldType == SVG_Paint_datatype) && gf_svg_is_current_color(in)) {
*in = *current_color;
}
}
static void gf_smil_anim_set(SMIL_Anim_RTI *rai)
{
GF_FieldInfo to_info;
SMILAnimationAttributesPointers *animp = rai->animp;
if (!animp->to) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL,
("[SMIL Animation] Animation %s - set element without to attribute\n",
gf_node_get_log_name((GF_Node *)rai->anim_elt)));
return;
}
if (!animp->to->type) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL,
("[SMIL Animation] Animation %s - set element with an unparsed to attribute\n",
gf_node_get_log_name((GF_Node *)rai->anim_elt)));
return;
}
if (rai->change_detection_mode) {
if (rai->previous_coef > 0) rai->interpolated_value_changed = 0;
else rai->interpolated_value_changed = 1;
return;
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying set animation\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt),
gf_node_get_log_name((GF_Node *)rai->anim_elt)));
to_info.fieldType = animp->to->type;
to_info.far_ptr = animp->to->value;
gf_svg_attributes_copy(&rai->interpolated_value, &to_info, 0);
rai->previous_coef = FIX_ONE;
}
}
static void gf_smil_anim_use_keypoints_keytimes(SMIL_Anim_RTI *rai, Fixed normalized_simple_time,
Fixed *interpolation_coefficient, u32 *keyValueIndex)
{
SMILAnimationAttributesPointers *animp = rai->animp;
u32 keyTimeIndex = 0;
Fixed interval_duration;
*interpolation_coefficient = normalized_simple_time;
if (rai->key_times_count) {
Fixed keyTimeBefore = 0, keyTimeAfter=0;
for (keyTimeIndex = rai->previous_keytime_index; keyTimeIndex< rai->key_times_count; keyTimeIndex++) {
Fixed *tm1, *t = (Fixed *)gf_list_get(*animp->keyTimes, keyTimeIndex);
if (normalized_simple_time < *t) {
rai->previous_keytime_index = keyTimeIndex;
tm1 = (Fixed *) gf_list_get(*animp->keyTimes, keyTimeIndex-1);
if (tm1) keyTimeBefore = *tm1;
else keyTimeBefore = 0;
keyTimeAfter = *t;
break;
}
}
keyTimeIndex--;
interval_duration = keyTimeAfter - keyTimeBefore;
if (keyValueIndex) *keyValueIndex = keyTimeIndex;
if (interval_duration)
*interpolation_coefficient = gf_divfix(normalized_simple_time - keyTimeBefore, interval_duration);
else
*interpolation_coefficient = FIX_ONE;
if (!rai->change_detection_mode)
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - Using Key Times: index %d, interval duration %.2f, coeff: %.2f\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt),
gf_node_get_log_name((GF_Node *)rai->anim_elt),
keyTimeIndex,
interval_duration,
interpolation_coefficient));
}
if (rai->anim_elt->sgprivate->tag == TAG_SVG_animateMotion && rai->key_points_count) {
Fixed *p1, *p2;
p1 = (Fixed *)gf_list_get(*animp->keyPoints, keyTimeIndex);
if (animp->calcMode && *animp->calcMode == SMIL_CALCMODE_DISCRETE) {
*interpolation_coefficient = *p1;
} else {
p2 = (Fixed *)gf_list_get(*animp->keyPoints, keyTimeIndex+1);
*interpolation_coefficient = gf_mulfix(FIX_ONE - *interpolation_coefficient, *p1)
+ gf_mulfix(*interpolation_coefficient, (p2 ? *p2 : *p1));
}
if (keyValueIndex) *keyValueIndex = 0;
if (!rai->change_detection_mode)
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - Using Key Points: key Point Index %d, coeff: %.2f\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), keyTimeIndex, *interpolation_coefficient));
}
}
static void gf_smil_anim_animate_using_values(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
{
SMILAnimationAttributesPointers *animp = rai->animp;
GF_List *values = NULL;
GF_FieldInfo value_info, value_info_next;
u32 keyValueIndex;
Fixed interpolation_coefficient;
u32 real_calcMode;
values = animp->values->values;
memset(&value_info, 0, sizeof(GF_FieldInfo));
value_info.fieldType = animp->values->type;
value_info_next = value_info;
real_calcMode = (gf_svg_attribute_is_interpolatable(animp->values->type)?
(animp->calcMode ? *animp->calcMode : SMIL_CALCMODE_LINEAR):
SMIL_CALCMODE_DISCRETE
);
if (rai->values_count == 1) {
if (rai->change_detection_mode) {
if (rai->previous_key_index == 0) rai->interpolated_value_changed = 0;
else rai->interpolated_value_changed = 1;
return;
} else {
value_info.far_ptr = gf_list_get(values, 0);
gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
rai->previous_key_index = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - Using values[0] as interpolation value\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt)));
return;
}
}
if (!rai->key_times_count) {
if (real_calcMode == SMIL_CALCMODE_DISCRETE) {
if (normalized_simple_time == FIX_ONE) {
keyValueIndex = rai->values_count-1;
interpolation_coefficient = FIX_ONE;
} else {
Fixed tmp = normalized_simple_time*rai->values_count;
Fixed tmp_floor = gf_floor(tmp);
if ((tmp - tmp_floor) == 0 && tmp) {
keyValueIndex = FIX2INT(tmp_floor) - 1;
} else {
keyValueIndex = FIX2INT(tmp_floor);
}
interpolation_coefficient = tmp - INT2FIX(keyValueIndex);
}
} else {
Fixed tmp = normalized_simple_time*(rai->values_count-1);
if (normalized_simple_time == FIX_ONE) {
keyValueIndex = rai->values_count-2;
} else {
keyValueIndex = FIX2INT(gf_floor(tmp));
}
interpolation_coefficient = tmp - INT2FIX(keyValueIndex);
}
} else {
gf_smil_anim_use_keypoints_keytimes(rai, normalized_simple_time, &interpolation_coefficient, &keyValueIndex);
}
if (rai->change_detection_mode) {
if (real_calcMode == SMIL_CALCMODE_DISCRETE && rai->previous_key_index == (s32)keyValueIndex && rai->previous_coef != -FIX_ONE) {
rai->interpolated_value_changed = 0;
} else if (rai->previous_key_index == (s32)keyValueIndex && rai->previous_coef == interpolation_coefficient)
rai->interpolated_value_changed = 0;
else
rai->interpolated_value_changed = 1;
} else {
rai->previous_key_index = keyValueIndex;
rai->previous_coef = interpolation_coefficient;
switch (real_calcMode) {
case SMIL_CALCMODE_DISCRETE:
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying discrete animation using values (key value index: %d)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), keyValueIndex));
value_info.far_ptr = gf_list_get(values, keyValueIndex);
gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
break;
case SMIL_CALCMODE_PACED:
case SMIL_CALCMODE_SPLINE:
case SMIL_CALCMODE_LINEAR:
if (keyValueIndex == rai->values_count - 1) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying linear animation using values (setting last key value: %d)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), keyValueIndex));
value_info.far_ptr = gf_list_get(values, rai->values_count - 1);
gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying linear animation using values (key value indices: %d, %d / coeff: %f)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), keyValueIndex, keyValueIndex+1, interpolation_coefficient));
value_info.far_ptr = gf_list_get(values, keyValueIndex);
if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(animp->values->type)) {
gf_svg_attributes_resolve_currentColor(&value_info, &rai->owner->current_color_value);
gf_svg_attributes_resolve_inherit(&value_info, &rai->owner->parent_presentation_value);
}
value_info_next.far_ptr = gf_list_get(values, keyValueIndex+1);
if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(animp->values->type)) {
gf_svg_attributes_resolve_currentColor(&value_info_next, &rai->owner->current_color_value);
gf_svg_attributes_resolve_inherit(&value_info_next, &rai->owner->parent_presentation_value);
}
gf_svg_attributes_interpolate(&value_info,
&value_info_next,
&rai->interpolated_value,
interpolation_coefficient, 1);
}
break;
}
}
}
static void gf_smil_anim_animate_from_to(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
{
GF_FieldInfo from_info, to_info;
SMILAnimationAttributesPointers *animp = rai->animp;
Fixed interpolation_coefficient;
s32 useFrom = (normalized_simple_time<=FIX_ONE/2);
u32 real_calcMode;
real_calcMode = (animp->to && gf_svg_attribute_is_interpolatable(animp->to->type)?
(animp->calcMode ? *animp->calcMode : SMIL_CALCMODE_LINEAR):
SMIL_CALCMODE_DISCRETE
);
if (rai->change_detection_mode) {
if (rai->previous_coef == normalized_simple_time)
rai->interpolated_value_changed = 0;
else {
if (real_calcMode == SMIL_CALCMODE_DISCRETE &&
useFrom == rai->previous_key_index) {
rai->interpolated_value_changed = 0;
} else {
rai->interpolated_value_changed = 1;
}
}
} else {
if (animp->from) {
from_info.fieldType = animp->from->type;
from_info.far_ptr = animp->from->value;
} else {
from_info.fieldType = 0;
from_info.far_ptr = NULL;
}
if (rai->is_first_anim)
gf_svg_attributes_resolve_unspecified(&from_info,
&rai->owner->specified_value,
&rai->default_transform_value);
else
gf_svg_attributes_resolve_unspecified(&from_info,
&rai->owner->presentation_value,
&rai->default_transform_value);
if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(from_info.fieldType)) {
gf_svg_attributes_resolve_currentColor(&from_info, &rai->owner->current_color_value);
gf_svg_attributes_resolve_inherit(&from_info, &rai->owner->parent_presentation_value);
}
if (animp->to) {
to_info.fieldType = animp->to->type;
to_info.far_ptr = animp->to->value;
} else {
to_info.fieldType = 0;
to_info.far_ptr = NULL;
}
if (rai->is_first_anim)
gf_svg_attributes_resolve_unspecified(&to_info,
&rai->owner->specified_value,
&rai->default_transform_value);
else
gf_svg_attributes_resolve_unspecified(&to_info,
&rai->owner->presentation_value,
&rai->default_transform_value);
if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(to_info.fieldType)) {
gf_svg_attributes_resolve_currentColor(&to_info, &rai->owner->current_color_value);
gf_svg_attributes_resolve_inherit(&to_info, &rai->owner->parent_presentation_value);
}
gf_smil_anim_use_keypoints_keytimes(rai, normalized_simple_time, &interpolation_coefficient, NULL);
rai->previous_coef = interpolation_coefficient;
switch (real_calcMode) {
case SMIL_CALCMODE_DISCRETE:
{
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying from-to animation (using %s value)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), (useFrom?"from":"to")));
gf_svg_attributes_copy(&rai->interpolated_value, (useFrom?&from_info:&to_info), 0);
rai->previous_key_index = useFrom;
}
break;
case SMIL_CALCMODE_SPLINE:
case SMIL_CALCMODE_PACED:
case SMIL_CALCMODE_LINEAR:
default:
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying from-to animation (linear interpolation, using coefficient %f)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), interpolation_coefficient));
gf_svg_attributes_interpolate(&from_info, &to_info, &rai->interpolated_value, interpolation_coefficient, 1);
break;
}
}
}
static void gf_smil_anim_animate_from_by(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
{
Fixed from_coef;
GF_FieldInfo from_info, by_info;
SMILAnimationAttributesPointers *animp = rai->animp;
s32 useFrom = (normalized_simple_time<=FIX_ONE/2);
if (rai->change_detection_mode) {
if (rai->previous_coef == normalized_simple_time)
rai->interpolated_value_changed = 0;
else {
if (animp->calcMode &&
*animp->calcMode == SMIL_CALCMODE_DISCRETE &&
useFrom == rai->previous_key_index) {
rai->interpolated_value_changed = 0;
} else {
rai->interpolated_value_changed = 1;
}
}
} else {
rai->previous_coef = normalized_simple_time;
if (animp->from) {
from_info.fieldType = animp->from->type;
from_info.far_ptr = animp->from->value;
from_coef = FIX_ONE;
} else {
from_info.fieldType = 0;
from_info.far_ptr = NULL;
from_coef = 0;
}
if (rai->is_first_anim)
gf_svg_attributes_resolve_unspecified(&from_info,
&rai->owner->specified_value,
&rai->default_transform_value);
else
gf_svg_attributes_resolve_unspecified(&from_info,
&rai->owner->presentation_value,
&rai->default_transform_value);
if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(from_info.fieldType)) {
gf_svg_attributes_resolve_currentColor(&from_info, &rai->owner->current_color_value);
gf_svg_attributes_resolve_inherit(&from_info, &rai->owner->parent_presentation_value);
}
if (animp->by) {
by_info.fieldType = animp->by->type;
by_info.far_ptr = animp->by->value;
} else {
by_info.fieldType = 0;
by_info.far_ptr = NULL;
}
if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(from_info.fieldType)) {
gf_svg_attributes_resolve_currentColor(&by_info, &rai->owner->current_color_value);
gf_svg_attributes_resolve_inherit(&by_info, &rai->owner->parent_presentation_value);
}
switch ((animp->calcMode ? *animp->calcMode : SMIL_CALCMODE_LINEAR)) {
case SMIL_CALCMODE_DISCRETE:
{
if (useFrom) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying from-by animation (setting from)",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt)));
gf_svg_attributes_muladd(from_coef, &from_info, 0, &by_info, &rai->interpolated_value, 0);
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying from-by animation (setting from+by)",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt)));
gf_svg_attributes_muladd(from_coef, &from_info, FIX_ONE, &by_info, &rai->interpolated_value, 0);
}
rai->previous_key_index = useFrom;
}
break;
case SMIL_CALCMODE_SPLINE:
case SMIL_CALCMODE_PACED:
case SMIL_CALCMODE_LINEAR:
default:
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying from-by animation (linear interpolation between from and from+by, coef: %f)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), normalized_simple_time));
gf_svg_attributes_muladd(from_coef, &from_info, normalized_simple_time, &by_info, &rai->interpolated_value, 0);
break;
}
}
}
static void gf_svg_compute_path_anim(SMIL_Anim_RTI *rai, GF_Matrix2D *m, Fixed normalized_simple_time)
{
Fixed offset;
offset = gf_mulfix(normalized_simple_time, rai->length);
gf_mx2d_init(*m);
gf_path_iterator_get_transform(rai->path_iterator, offset, 1, m, 1, 0);
switch (rai->rotate) {
case SVG_NUMBER_AUTO:
break;
case SVG_NUMBER_AUTO_REVERSE:
gf_mx2d_add_rotation(m, m->m[2], m->m[5], GF_PI);
break;
default:
m->m[0] = FIX_ONE;
m->m[1] = 0;
m->m[3] = 0;
m->m[4] = FIX_ONE;
}
}
static void gf_smil_anim_animate_using_path(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
{
Fixed interpolation_coefficient;
gf_smil_anim_use_keypoints_keytimes(rai, normalized_simple_time, &interpolation_coefficient, NULL);
if (rai->change_detection_mode) {
if (rai->previous_coef == interpolation_coefficient)
rai->interpolated_value_changed = 0;
else {
rai->interpolated_value_changed = 1;
}
} else {
rai->previous_coef = interpolation_coefficient;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying path animation (coef: %f)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), normalized_simple_time));
gf_svg_compute_path_anim(rai, (GF_Matrix2D*)rai->interpolated_value.far_ptr, interpolation_coefficient);
}
}
static void gf_smil_anim_compute_interpolation_value(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
{
SMILAnimationAttributesPointers *animp = rai->animp;
if (rai->path) {
gf_smil_anim_animate_using_path(rai, normalized_simple_time);
} else if (rai->anim_elt->sgprivate->tag == TAG_SVG_set) {
gf_smil_anim_set(rai);
} else if (rai->values_count) {
gf_smil_anim_animate_using_values(rai, normalized_simple_time);
} else if ((animp->by && animp->by->type) && (!animp->to || animp->to->type == 0)) {
gf_smil_anim_animate_from_by(rai, normalized_simple_time);
} else {
gf_smil_anim_animate_from_to(rai, normalized_simple_time);
}
#ifndef GPAC_DISABLE_LOG
if (0 && gf_log_tool_level_on(GF_LOG_SMIL, GF_LOG_DEBUG)) {
char *str;
gf_log_lt(GF_LOG_DEBUG, GF_LOG_SMIL);
str = gf_svg_dump_attribute(rai->anim_elt, &rai->interpolated_value);
gf_log("[SMIL Animation] Time %f - Animation %s - Interpolation value changed for attribute %s, new value: %s \n",
gf_node_get_scene_time(rai->anim_elt), gf_node_get_log_name(rai->anim_elt),
gf_svg_get_attribute_name(rai->anim_elt, rai->owner->presentation_value.fieldIndex), str);
if (str) gf_free(str);
}
#endif
}
void gf_smil_anim_set_anim_runtime_in_timing(GF_Node *n)
{
u32 i, j;
SVGTimedAnimBaseElement *timed_elt = NULL;
SMIL_Timing_RTI *rti = NULL;
GF_Node *target = NULL;
if (!n) return;
timed_elt = (SVGTimedAnimBaseElement *)n;
if (!gf_svg_is_animation_tag(n->sgprivate->tag)) return;
target = timed_elt->xlinkp->href->target;
if (!target) return;
if (timed_elt->timingp) rti = timed_elt->timingp->runtime;
if (!rti) return;
rti->rai = NULL;
for (i = 0; i < gf_node_animation_count(target); i++) {
SMIL_Anim_RTI *rai_tmp;
SMIL_AttributeAnimations *aa = (SMIL_AttributeAnimations *)gf_node_animation_get(target, i);
j=0;
while ((rai_tmp = (SMIL_Anim_RTI *)gf_list_enum(aa->anims, &j))) {
if (rai_tmp->timingp->runtime == rti) {
rti->rai = rai_tmp;
return;
}
}
}
}
static void gf_smil_anim_get_last_specified_value(SMIL_Anim_RTI *rai)
{
SMILAnimationAttributesPointers *animp = rai->animp;
if (!animp) return;
if (rai->path) {
if (!rai->last_specified_value.far_ptr) rai->last_specified_value.far_ptr = gf_malloc(sizeof(GF_Matrix2D));
gf_svg_compute_path_anim(rai, rai->last_specified_value.far_ptr, FIX_ONE);
return;
} else if (rai->anim_elt->sgprivate->tag == TAG_SVG_set) {
if (animp->to) {
rai->last_specified_value.fieldType = animp->to->type;
rai->last_specified_value.far_ptr = animp->to->value;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL,
("[SMIL Animation] Animation %s - set element without to attribute\n",
gf_node_get_log_name((GF_Node *)rai->anim_elt)));
}
return;
}
if (rai->values_count) {
rai->last_specified_value.fieldType = animp->values->type;
rai->last_specified_value.far_ptr = gf_list_last(animp->values->values);
} else if ((animp->by && animp->by->type) && (!animp->to || animp->to->type == 0)) {
rai->last_specified_value.fieldType = animp->by->type;
rai->last_specified_value.far_ptr = animp->by->value;
} else if (animp->to) {
rai->last_specified_value.fieldType = animp->to->type;
rai->last_specified_value.far_ptr = animp->to->value;
}
if (gf_svg_is_inherit(&rai->last_specified_value)) {
rai->last_specified_value.fieldType = rai->owner->presentation_value.fieldType;
rai->last_specified_value.far_ptr = rai->owner->presentation_value.far_ptr;
}
if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(rai->last_specified_value.fieldType)) {
gf_svg_attributes_resolve_currentColor(&rai->last_specified_value, &rai->owner->current_color_value);
gf_svg_attributes_resolve_inherit(&rai->last_specified_value, &rai->owner->parent_presentation_value);
}
}
static void gf_smil_anim_apply_accumulate(SMIL_Anim_RTI *rai)
{
u32 nb_iterations;
SMILAnimationAttributesPointers *animp = rai->animp;
SMILTimingAttributesPointers *timingp = rai->timingp;
nb_iterations = (timingp->runtime->current_interval ? timingp->runtime->current_interval->nb_iterations : 1);
if (rai->change_detection_mode) {
if ((animp->accumulate && *animp->accumulate == SMIL_ACCUMULATE_SUM)
&& nb_iterations > 0
&& rai->previous_iteration != (s32) nb_iterations) {
rai->interpolated_value_changed = 1;
} else {
}
} else {
if (nb_iterations > 0 && rai->previous_iteration != (s32) nb_iterations) {
rai->previous_iteration = nb_iterations;
}
if ((animp->accumulate && *animp->accumulate == SMIL_ACCUMULATE_SUM) && nb_iterations > 0) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying accumulation (iteration #%d)\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt), nb_iterations));
gf_svg_attributes_muladd(FIX_ONE, &rai->interpolated_value,
INT2FIX(nb_iterations), &rai->last_specified_value,
&rai->interpolated_value, 1);
if ((animp->from) && animp->by && (rai->last_specified_value.far_ptr == animp->by->value)) {
GF_FieldInfo from_info;
from_info.fieldType = rai->animp->from->type;
from_info.far_ptr = rai->animp->from->value;
gf_svg_attributes_muladd(FIX_ONE, &rai->interpolated_value,
INT2FIX(nb_iterations), &from_info,
&rai->interpolated_value, 1);
}
}
}
}
static void gf_smil_apply_additive(SMIL_Anim_RTI *rai)
{
SMILAnimationAttributesPointers *animp = rai->animp;
if (rai->change_detection_mode) return;
else {
if (animp->additive && *animp->additive == SMIL_ADDITIVE_SUM) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying additive behavior\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt)));
gf_svg_attributes_add((rai->is_first_anim ? &rai->owner->specified_value : &rai->owner->presentation_value),
&rai->interpolated_value,
&rai->owner->presentation_value,
1);
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_SMIL, GF_LOG_DEBUG)) {
char *str;
gf_log_lt(GF_LOG_DEBUG, GF_LOG_SMIL);
str = gf_svg_dump_attribute((GF_Node*)rai->anim_elt, &rai->owner->presentation_value);
gf_log("[SMIL Animation] Time %f - Animation %s - Presentation value changed for attribute %s, new value: %s\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node*)rai->anim_elt),
gf_svg_get_attribute_name((GF_Node*)rai->anim_elt, rai->owner->presentation_value.fieldIndex), str);
if (str) gf_free(str);
}
#endif
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying non-additive behavior\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt)));
gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->interpolated_value, 1);
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_SMIL, GF_LOG_DEBUG)) {
char *str;
gf_log_lt(GF_LOG_DEBUG, GF_LOG_SMIL);
str = gf_svg_dump_attribute((GF_Node*)rai->anim_elt, &rai->owner->presentation_value);
gf_log("[SMIL Animation] Time %f - Animation %s - Presentation value changed for attribute %s, new value: %s\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node*)rai->anim_elt),
gf_svg_get_attribute_name((GF_Node*)rai->anim_elt, rai->owner->presentation_value.fieldIndex), str);
if (str) gf_free(str);
}
#endif
}
}
}
static void gf_smil_anim_animate(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
{
SMIL_Anim_RTI *rai = rti->rai;
SMILAnimationAttributesPointers *animp = rai->animp;
if (!rai || !animp) return;
gf_smil_anim_compute_interpolation_value(rai, normalized_simple_time);
gf_smil_anim_apply_accumulate(rai);
gf_smil_apply_additive(rai);
}
static void gf_smil_anim_animate_with_fraction(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
{
gf_smil_anim_animate(rti, rti->fraction);
rti->evaluate_status = SMIL_TIMING_EVAL_NONE;
}
void gf_smil_anim_reset_variables(SMIL_Anim_RTI *rai)
{
if (!rai) return;
rai->interpolated_value_changed = 0;
rai->previous_key_index = -1;
rai->previous_coef = -FIX_ONE;
rai->previous_iteration = -1;
rai->previous_keytime_index = 0;
rai->anim_done = 0;
}
static void gf_smil_anim_freeze(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
{
SMIL_Anim_RTI *rai = rti->rai;
SMILAnimationAttributesPointers *animp = rai->animp;
if (!rai || !animp) return;
if (rai->change_detection_mode) {
if (rai->anim_done == 0)
rai->interpolated_value_changed = 1;
else
rai->interpolated_value_changed = 0;
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying freeze behavior\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt)));
gf_smil_anim_compute_interpolation_value(rai, normalized_simple_time);
gf_smil_anim_apply_accumulate(rai);
gf_smil_apply_additive(rai);
rai->anim_done = 1;
}
}
static void gf_smil_anim_remove(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
{
SMIL_Anim_RTI *rai = rti->rai;
if (!rai) return;
if (rai->change_detection_mode) {
if (rai->anim_done == 0)
rai->interpolated_value_changed = 1;
else
rai->interpolated_value_changed = 0;
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL,
("[SMIL Animation] Time %f - Animation %s - applying remove behavior\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node *)rai->anim_elt)));
gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->owner->specified_value, 0);
rai->anim_done = 1;
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_SMIL, GF_LOG_DEBUG)) {
char *str;
gf_log_lt(GF_LOG_DEBUG, GF_LOG_SMIL);
str = gf_svg_dump_attribute((GF_Node*)rai->anim_elt, &rai->owner->presentation_value);
gf_log("[SMIL Animation] Time %f - Animation %s - Presentation value changed for attribute %s, new value: %s\n",
gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_log_name((GF_Node*)rai->anim_elt),
gf_svg_get_attribute_name((GF_Node*)rai->anim_elt, rai->owner->presentation_value.fieldIndex), str);
if (str) gf_free(str);
}
#endif
}
}
static void gf_smil_anim_evaluate(SMIL_Timing_RTI *rti, Fixed normalized_simple_time, u32 state)
{
SMIL_Anim_RTI *rai = rti->rai;
switch (state) {
case SMIL_TIMING_EVAL_REPEAT:
gf_smil_anim_reset_variables(rai);
case SMIL_TIMING_EVAL_UPDATE:
gf_smil_anim_animate(rti, normalized_simple_time);
break;
case SMIL_TIMING_EVAL_FREEZE:
gf_smil_anim_freeze(rti, normalized_simple_time);
break;
case SMIL_TIMING_EVAL_REMOVE:
gf_smil_anim_remove(rti, normalized_simple_time);
break;
case SMIL_TIMING_EVAL_FRACTION:
gf_smil_anim_animate_with_fraction(rti, normalized_simple_time);
break;
}
}
GF_EXPORT
void gf_svg_apply_animations(GF_Node *node, SVGPropertiesPointers *render_svg_props)
{
u32 count_all, i;
u32 active_anim;
#ifndef GPAC_DISABLE_LOG
u32 time=0;
if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
time = gf_sys_clock();
}
#endif
count_all = gf_node_animation_count(node);
for (i = 0; i < count_all; i++) {
GF_FieldInfo info;
s32 j;
u32 count;
SMIL_AttributeAnimations *aa;
aa = (SMIL_AttributeAnimations *)gf_node_animation_get(node, i);
count = gf_list_count(aa->anims);
if (!count) continue;
aa->presentation_value_changed = 0;
if (aa->is_property) {
aa->parent_presentation_value = aa->presentation_value;
aa->parent_presentation_value.far_ptr =
gf_svg_get_property_pointer((SVG_Element *)node, aa->orig_dom_ptr, render_svg_props);
gf_node_get_attribute_by_tag(node, TAG_SVG_ATT_color, 1, 1, &info);
aa->current_color_value.far_ptr = info.far_ptr;
}
for (j = count-1; j >= 0; j--) {
SMIL_Anim_RTI *rai = (SMIL_Anim_RTI *)gf_list_get(aa->anims, j);
SMIL_Timing_RTI *rti = rai->timingp->runtime;
rai->interpolated_value_changed = 0;
if (rti->evaluate_status) {
rai->change_detection_mode = 1;
rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
aa->presentation_value_changed += rai->interpolated_value_changed;
if (!rai->animp->additive || *rai->animp->additive == SMIL_ADDITIVE_REPLACE) {
j--;
break;
}
}
}
active_anim = 0;
if (aa->presentation_value_changed) {
for (j++; j<(s32)count; j++) {
SMIL_Anim_RTI *rai = (SMIL_Anim_RTI *)gf_list_get(aa->anims, j);
SMIL_Timing_RTI *rti = rai->timingp->runtime;
if (j == 0) rai->is_first_anim = 1;
else rai->is_first_anim = 0;
if (rti->evaluate_status) {
rai->change_detection_mode = 0;
rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
active_anim++;
}
}
}
#ifndef GPAC_DISABLE_LOG
if (aa->presentation_value_changed) {
if (gf_log_tool_level_on(GF_LOG_SMIL, GF_LOG_DEBUG)) {
char *str;
gf_log_lt(GF_LOG_DEBUG, GF_LOG_SMIL);
str = gf_svg_dump_attribute(node, &aa->presentation_value);
gf_log("[SMIL Animation] Time %f - Element %s - Presentation value changed for attribute %s, new value: %s - dirty flags %x\n",
gf_node_get_scene_time(node), gf_node_get_log_name(node),
gf_svg_get_attribute_name(node, aa->presentation_value.fieldIndex), str, aa->dirty_flags);
if (str) gf_free(str);
}
}
#endif
if (aa->dirty_flags) {
if (aa->presentation_value_changed) {
gf_node_dirty_set(node, aa->dirty_flags, aa->dirty_parents);
} else {
if (active_anim) gf_node_dirty_clear(node, aa->dirty_flags);
}
}
}
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
time_spent_in_anim += gf_sys_clock() - time;
}
#endif
}
GF_Node *gf_smil_anim_get_target(GF_Node *e)
{
XLinkAttributesPointers *xlinkp = NULL;
if (!gf_svg_is_animation_tag(e->sgprivate->tag)) return NULL;
xlinkp = ((SVGTimedAnimBaseElement *)e)->xlinkp;
return (xlinkp && xlinkp->href) ? xlinkp->href->target : NULL;
}
void gf_smil_anim_init_runtime_info(GF_Node *e)
{
u32 i;
GF_FieldInfo target_attribute;
SMIL_AttributeAnimations *aa = NULL;
SMIL_Anim_RTI *rai;
XLinkAttributesPointers *xlinkp = NULL;
SMILAnimationAttributesPointers *animp = NULL;
SMILTimingAttributesPointers *timingp = NULL;
GF_Node *target = NULL;
if (!e) return;
animp = ((SVGTimedAnimBaseElement *)e)->animp;
timingp = ((SVGTimedAnimBaseElement *)e)->timingp;
if (!animp || !timingp) return;
xlinkp = ((SVGTimedAnimBaseElement *)e)->xlinkp;
target = xlinkp->href->target;
memset(&target_attribute, 0, sizeof(GF_FieldInfo));
if (animp->attributeName && (animp->attributeName->name || animp->attributeName->tag)) {
if (animp->attributeName->tag) {
gf_node_get_attribute_by_tag(target, animp->attributeName->tag, 1, 1, &target_attribute);
} else {
gf_node_get_field_by_name(target, animp->attributeName->name, &target_attribute);
}
} else {
switch (e->sgprivate->tag) {
case TAG_SVG_animateMotion:
gf_node_get_attribute_by_tag(target, TAG_SVG_ATT_motionTransform, 1, 0, &target_attribute);
gf_mx2d_init(*(GF_Matrix2D *)target_attribute.far_ptr);
break;
default:
GF_LOG(GF_LOG_WARNING, GF_LOG_SMIL,
("[SMIL Animation] Missing attributeName attribute on element %s\n",
gf_node_get_log_name((GF_Node*)e) ));
return;
}
}
if (animp->attributeType && *animp->attributeType == SMIL_ATTRIBUTETYPE_CSS) {
if (!gf_svg_is_property(target, &target_attribute)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_SMIL,
("[SMIL Animation] Using CSS attributeType for an animation on an attribute which is not a property %s\n",
gf_node_get_log_name((GF_Node*)e) ));
return;
}
}
GF_SAFEALLOC(rai, SMIL_Anim_RTI)
if (!rai) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL, ("[SMIL Animation] Failed to allocated SMIL anim RTI\n"));
return;
}
rai->anim_elt = e;
rai->animp = animp;
rai->timingp = timingp;
rai->xlinkp = xlinkp;
gf_mx2d_init(rai->identity);
rai->default_transform_value.far_ptr = &rai->identity;
rai->default_transform_value.fieldType = SVG_Transform_datatype;
rai->interpolated_value = target_attribute;
rai->interpolated_value.far_ptr = gf_svg_create_attribute_value(target_attribute.fieldType);
gf_smil_anim_reset_variables(rai);
rai->values_count = (animp->values ? gf_list_count(animp->values->values) : 0);
rai->key_times_count = (animp->keyTimes ? gf_list_count(*animp->keyTimes) : 0);
rai->key_points_count = (animp->keyPoints ? gf_list_count(*animp->keyPoints) : 0);
rai->key_splines_count = (animp->keySplines ? gf_list_count(*animp->keySplines) : 0);
if (!rai->values_count &&
(!animp->to || animp->to->type == 0) &&
(!animp->from || animp->from->type == 0) &&
(animp->by && animp->by->type != 0)) {
if (!animp->additive) {
GF_FieldInfo info;
gf_node_get_attribute_by_tag(e, TAG_SVG_ATT_additive, 1, 0, &info);
animp->additive = info.far_ptr;
}
if (*animp->additive == SMIL_ADDITIVE_REPLACE) {
GF_LOG(GF_LOG_WARNING, GF_LOG_SMIL, ("[SMIL Animation] Warning: by-animations cannot use additive=\"replace\"\n"));
}
*animp->additive = SMIL_ADDITIVE_SUM;
}
if (e->sgprivate->tag == TAG_SVG_animateMotion) {
GF_Path *the_path = NULL;
GF_ChildNodeItem *child = NULL;
GF_FieldInfo info;
if (gf_node_get_attribute_by_tag(e, TAG_SVG_ATT_rotate, 0, 0, &info) == GF_OK) {
rai->rotate = ((SVG_Rotate *)info.far_ptr)->type;
} else {
rai->rotate = SVG_NUMBER_VALUE;
}
if (gf_node_get_attribute_by_tag(e, TAG_SVG_ATT_path, 0, 0, &info) == GF_OK) {
the_path = ((SVG_PathData *)info.far_ptr);
}
child = ((SVG_Element *)e)->children;
if ((!animp->to || animp->to->type == 0) &&
(!animp->by || animp->by->type == 0) &&
(!animp->values || animp->values->type == 0)) {
#if USE_GF_PATH
if (!gf_path_is_empty(the_path)) {
rai->path = the_path;
rai->path_iterator = gf_path_iterator_new(rai->path);
rai->length = gf_path_iterator_get_length(rai->path_iterator);
}
#else
rai->path = gf_path_new();
if (gf_list_count(the_path->points)) {
gf_svg_path_build(rai->path, the_path->commands, the_path->points);
rai->path_iterator = gf_path_iterator_new(rai->path);
rai->length = gf_path_iterator_get_length(rai->path_iterator);
}
#endif
else {
while (child) {
GF_Node *used_path = NULL;
u32 child_tag = gf_node_get_tag(child->node);
if (child_tag == TAG_SVG_mpath) {
GF_FieldInfo info;
if (gf_node_get_attribute_by_tag(child->node, TAG_XLINK_ATT_href, 0, 0, &info) == GF_OK) {
XMLRI *iri = (XMLRI *)info.far_ptr;
if (iri->target) used_path = iri->target;
else if (iri->string) used_path =
(GF_Node *)gf_sg_find_node_by_name(gf_node_get_graph(child->node), iri->string);
if (used_path && gf_node_get_tag(used_path) == TAG_SVG_path) {
gf_node_get_attribute_by_tag(used_path, TAG_SVG_ATT_d, 1, 0, &info);
#if USE_GF_PATH
rai->path = (SVG_PathData *)info.far_ptr;
#else
gf_svg_path_build(rai->path,
((SVG_PathData *)info.far_ptr)->commands,
((SVG_PathData *)info.far_ptr)->points);
#endif
rai->path_iterator = gf_path_iterator_new(rai->path);
rai->length = gf_path_iterator_get_length(rai->path_iterator);
}
}
break;
}
child = child->next;
}
}
}
}
for (i = 0; i < gf_node_animation_count(target); i++) {
aa = (SMIL_AttributeAnimations *)gf_node_animation_get(target, i);
if (aa->presentation_value.fieldIndex == target_attribute.fieldIndex) {
gf_list_add(aa->anims, rai);
break;
}
aa = NULL;
}
if (!aa) {
GF_SAFEALLOC(aa, SMIL_AttributeAnimations)
if (!aa) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL, ("[SMIL Animation] Failed to allocated SMIL attribue ani\n"));
return;
}
aa->is_property = gf_svg_is_property(target, &target_attribute);
aa->current_color_value.fieldType = SVG_Paint_datatype;
aa->specified_value = target_attribute;
aa->orig_dom_ptr = aa->specified_value.far_ptr;
aa->specified_value.far_ptr = gf_svg_create_attribute_value(target_attribute.fieldType);
gf_svg_attributes_copy(&aa->specified_value, &target_attribute, 0);
aa->presentation_value = target_attribute;
aa->anims = gf_list_new();
gf_list_add(aa->anims, rai);
gf_node_animation_add(target, aa);
aa->dirty_flags = gf_svg_get_modification_flags((SVG_Element *)target, &target_attribute);
aa->dirty_parents = 0;
if (aa->dirty_flags & (GF_SG_SVG_GEOMETRY_DIRTY | GF_SG_SVG_DISPLAY_DIRTY)) aa->dirty_parents = 1;
}
rai->owner = aa;
gf_smil_anim_get_last_specified_value(rai);
timingp->runtime->postpone = 1;
timingp->runtime->evaluate = gf_smil_anim_evaluate;
}
void gf_smil_anim_delete_runtime_info(SMIL_Anim_RTI *rai)
{
gf_svg_delete_attribute_value(rai->interpolated_value.fieldType,
rai->interpolated_value.far_ptr,
rai->anim_elt->sgprivate->scenegraph);
if (rai->path) {
gf_svg_delete_attribute_value(rai->last_specified_value.fieldType,
rai->last_specified_value.far_ptr,
rai->anim_elt->sgprivate->scenegraph);
}
#if USE_GF_PATH
#else
if (rai->path) gf_path_del(rai->path);
#endif
if (rai->path_iterator) gf_path_iterator_del(rai->path_iterator);
gf_free(rai);
}
void gf_smil_anim_remove_from_target(GF_Node *anim, GF_Node *target)
{
u32 i, j;
if (!target) return;
for (i = 0; i < gf_node_animation_count((GF_Node *)target); i ++) {
SMIL_Anim_RTI *rai;
SMIL_AttributeAnimations *aa = (SMIL_AttributeAnimations *)gf_node_animation_get((GF_Node *)target, i);
j=0;
while ((rai = (SMIL_Anim_RTI *)gf_list_enum(aa->anims, &j))) {
if ((GF_Node *)rai->anim_elt == anim) {
gf_list_rem(aa->anims, j-1);
gf_smil_anim_delete_runtime_info(rai);
break;
}
}
if (gf_list_count(aa->anims) == 0) {
gf_list_del(aa->anims);
gf_svg_delete_attribute_value(aa->specified_value.fieldType,
aa->specified_value.far_ptr,
target->sgprivate->scenegraph);
aa->presentation_value.far_ptr = aa->orig_dom_ptr;
gf_node_animation_rem((GF_Node *)target, i);
gf_free(aa);
}
}
}
void gf_smil_anim_delete_animations(GF_Node *e)
{
u32 i, j;
for (i = 0; i < gf_node_animation_count(e); i ++) {
SMIL_Anim_RTI *rai;
SMIL_AttributeAnimations *aa = (SMIL_AttributeAnimations *)gf_node_animation_get(e, i);
gf_svg_delete_attribute_value(aa->specified_value.fieldType,
aa->specified_value.far_ptr,
e->sgprivate->scenegraph);
j=0;
while ((rai = (SMIL_Anim_RTI *)gf_list_enum(aa->anims, &j))) {
rai->xlinkp->href->target = NULL;
gf_smil_anim_delete_runtime_info(rai);
}
gf_list_del(aa->anims);
gf_free(aa);
}
gf_node_animation_del(e);
}
void gf_smil_anim_init_discard(GF_Node *node)
{
SVGAllAttributes all_atts;
XLinkAttributesPointers *xlinkp = NULL;
SVGTimedAnimBaseElement *e = (SVGTimedAnimBaseElement *)node;
gf_smil_timing_init_runtime_info(node);
gf_svg_flatten_attributes((SVG_Element *)e, &all_atts);
GF_SAFEALLOC(e->xlinkp, XLinkAttributesPointers);
if (!e->xlinkp) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL,("[SMIL] Error creating anim xlink attrib\n"));
return;
}
xlinkp = e->xlinkp;
xlinkp->href = all_atts.xlink_href;
xlinkp->type = all_atts.xlink_type;
e->timingp->runtime->evaluate_status = SMIL_TIMING_EVAL_DISCARD;
}
void gf_smil_anim_init_node(GF_Node *node)
{
XLinkAttributesPointers *xlinkp = NULL;
SMILAnimationAttributesPointers *animp = NULL;
SVGAllAttributes all_atts;
SVGTimedAnimBaseElement *e = (SVGTimedAnimBaseElement *)node;
gf_svg_flatten_attributes((SVG_Element *)e, &all_atts);
e->xlinkp = gf_malloc(sizeof(XLinkAttributesPointers));
xlinkp = e->xlinkp;
xlinkp->href = all_atts.xlink_href;
xlinkp->type = all_atts.xlink_type;
if (!xlinkp->href) {
GF_FieldInfo info;
gf_node_get_attribute_by_tag((GF_Node *)node, TAG_XLINK_ATT_href, 1, 0, &info);
xlinkp->href = info.far_ptr;
xlinkp->href->type = XMLRI_ELEMENTID;
xlinkp->href->target = gf_node_get_parent(node, 0);
}
if (xlinkp->href->type == XMLRI_STRING) {
if (!xlinkp->href->string) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL,("Error: IRI not initialized\n"));
return;
} else {
GF_Node *n;
n = (GF_Node*)gf_sg_find_node_by_name(gf_node_get_graph(node), xlinkp->href->string);
if (n) {
xlinkp->href->type = XMLRI_ELEMENTID;
xlinkp->href->target = n;
gf_node_register_iri(node->sgprivate->scenegraph, xlinkp->href);
} else {
return;
}
}
}
if (!xlinkp->href->target) {
GF_LOG(GF_LOG_WARNING, GF_LOG_SMIL,("Trying to initialize an animation when the target is not known\n"));
return;
}
if (node->sgprivate->tag != TAG_SVG_animateMotion && !all_atts.attributeName) {
goto end_init;
}
if ( (all_atts.to && (all_atts.to->type==0))
|| (all_atts.from && (all_atts.from->type==0))
|| (all_atts.by && (all_atts.by->type==0))
) {
GF_FieldInfo info;
if (gf_node_get_attribute_by_name((GF_Node *)xlinkp->href->target, all_atts.attributeName->name, 0, 1, 1, &info)==GF_OK) {
u32 anim_value_type = info.fieldType;
u32 i;
for (i=0; i<3; i++) {
u32 tag = 0;
switch (i) {
case 0:
tag=TAG_SVG_ATT_to;
break;
case 1:
tag=TAG_SVG_ATT_from;
break;
case 2:
tag=TAG_SVG_ATT_by;
break;
}
if (gf_node_get_attribute_by_tag((GF_Node *)node, tag, 0, 0, &info)==GF_OK) {
SMIL_AnimateValue *attval = info.far_ptr;
if (attval->type==0) {
SVG_String string = attval->value;
attval->value = NULL;
if (string) {
gf_svg_parse_attribute((GF_Node *)node, &info, string, anim_value_type);
gf_free(string);
}
}
}
}
}
}
e->animp = gf_malloc(sizeof(SMILAnimationAttributesPointers));
animp = e->animp;
animp->accumulate = all_atts.accumulate;
animp->additive = all_atts.additive;
animp->attributeName = all_atts.attributeName;
animp->attributeType = all_atts.attributeType;
animp->by = all_atts.by;
animp->calcMode = all_atts.calcMode;
animp->from = all_atts.from;
animp->keySplines = all_atts.keySplines;
animp->keyTimes = all_atts.keyTimes;
animp->lsr_enabled = all_atts.lsr_enabled;
animp->to = all_atts.to;
animp->type = all_atts.transform_type;
animp->values = all_atts.values;
if (node->sgprivate->tag == TAG_SVG_animateMotion) {
e->animp->keyPoints = all_atts.keyPoints;
e->animp->origin = all_atts.origin;
e->animp->path = all_atts.path;
e->animp->rotate = all_atts.rotate;
} else {
e->animp->keyPoints = NULL;
e->animp->origin = NULL;
e->animp->path = NULL;
e->animp->rotate = NULL;
}
end_init:
gf_smil_timing_init_runtime_info(node);
gf_smil_anim_init_runtime_info(node);
gf_smil_anim_set_anim_runtime_in_timing(node);
}
#endif