2
* GPAC - Multimedia Framework C SDK
4
* Authors: Cyril Concolato - Jean Le Feuvre
5
* Copyright (c)2004-200X ENST - All rights reserved
7
* This file is part of GPAC / SVG Scene Graph sub-project
9
* GPAC is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU Lesser General Public License as published by
11
* the Free Software Foundation; either version 2, or (at your option)
14
* GPAC is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU Lesser General Public License for more details.
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with this library; see the file COPYING. If not, write to
21
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25
#include <gpac/scenegraph_svg.h>
26
#include <gpac/internal/scenegraph_dev.h>
27
#include <gpac/nodes_svg.h>
29
static void gf_smil_anim_animate_using_values(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
31
SMILAnimationAttributes *anim = rai->anim_elt->anim;
32
GF_List *values = anim->values.values;
34
GF_FieldInfo value_info, value_info_next;
38
Fixed interval_duration;
39
Fixed interpolation_coefficient;
41
memset(&value_info, 0, sizeof(GF_FieldInfo));
42
value_info.fieldType = anim->values.type;
43
value_info.eventType = anim->values.transform_type;
44
value_info_next = value_info;
46
nbValues = gf_list_count(values);
48
if (rai->previous_key_index != 0) {
49
value_info.far_ptr = gf_list_get(values, 0);
50
gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
51
gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
52
rai->previous_key_index = 0;
53
rai->target_value_changed = 1;
58
if (gf_list_count(anim->keyTimes)) {
60
Fixed keyTimeBefore = 0, keyTimeAfter=0;
61
u32 keyTimesCount = gf_list_count(anim->keyTimes);
62
for (keyTimeIndex = rai->previous_keytime_index; keyTimeIndex<keyTimesCount; keyTimeIndex++) {
63
Fixed *tm1, *t = gf_list_get(anim->keyTimes, keyTimeIndex);
64
if (normalized_simple_time < *t) {
65
rai->previous_keytime_index = keyTimeIndex;
66
tm1 = (Fixed *) gf_list_get(anim->keyTimes, keyTimeIndex-1);
67
if (tm1) keyTimeBefore = *tm1;
68
else keyTimeBefore = 0;
74
keyValueIndex = keyTimeIndex;
75
interval_duration = keyTimeAfter - keyTimeBefore;
76
if (interval_duration) interpolation_coefficient = gf_divfix(normalized_simple_time - keyTimeBefore, interval_duration);
77
else interpolation_coefficient = 1;
78
// fprintf(stdout, "Using Key Times: index %d, interval duration %.2f, coeff: %.2f\n", keyTimeIndex, interval_duration, interpolation_coefficient);
80
if (anim->calcMode == SMIL_CALCMODE_DISCRETE) {
81
Fixed tmp = normalized_simple_time*nbValues;
82
keyValueIndex = FIX2INT(gf_floor(tmp));
83
interpolation_coefficient = tmp - INT2FIX(keyValueIndex);
85
Fixed tmp = normalized_simple_time*(nbValues-1);
86
keyValueIndex = FIX2INT(gf_floor(tmp));
87
interpolation_coefficient = tmp - INT2FIX(keyValueIndex);
89
//fprintf(stdout, "No KeyTimes: key index %d, coeff: %.2f\n", keyValueIndex, FIX2FLT(interpolation_coefficient));
92
if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_animateMotion) {
93
SVGanimateMotionElement *am = (SVGanimateMotionElement *)rai->anim_elt;
94
if (gf_list_count(am->keyPoints)) {
95
interpolation_coefficient = *(Fixed *)gf_list_get(am->keyPoints, keyValueIndex);
97
// fprintf(stdout, "Using Key Points: key Value Index %d, coeff: %.2f\n", keyValueIndex, interpolation_coefficient);
101
if (rai->previous_key_index == (s32)keyValueIndex &&
102
rai->previous_coef == interpolation_coefficient) return;
104
rai->previous_key_index = keyValueIndex;
105
rai->previous_coef = interpolation_coefficient;
106
rai->target_value_changed = 1;
108
switch (anim->calcMode) {
109
case SMIL_CALCMODE_DISCRETE:
110
value_info.far_ptr = gf_list_get(values, keyValueIndex);
111
gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
112
gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
114
case SMIL_CALCMODE_PACED:
115
/* TODO: at the moment assume it is linear */
116
case SMIL_CALCMODE_SPLINE:
117
/* TODO: at the moment assume it is linear */
118
case SMIL_CALCMODE_LINEAR:
119
if (keyValueIndex == nbValues - 1) {
120
value_info.far_ptr = gf_list_get(values, nbValues - 1);
121
gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
122
gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
124
value_info.far_ptr = gf_list_get(values, keyValueIndex);
125
gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
126
value_info_next.far_ptr = gf_list_get(values, keyValueIndex+1);
127
gf_svg_attributes_pointer_update(&value_info_next, &rai->owner->presentation_value, &rai->owner->current_color_value);
128
gf_svg_attributes_interpolate(&value_info, &value_info_next, &rai->interpolated_value, interpolation_coefficient, 1);
134
static void gf_smil_anim_set(SMIL_Anim_RTI *rai)
136
GF_FieldInfo to_info;
137
if (!rai->anim_elt->anim->to.type) return;
138
to_info.fieldType = rai->anim_elt->anim->to.type;
139
to_info.eventType = rai->anim_elt->anim->to.transform_type;
140
to_info.far_ptr = rai->anim_elt->anim->to.value;
141
gf_svg_attributes_pointer_update(&to_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
143
gf_svg_attributes_copy(&rai->interpolated_value, &to_info, 0);
144
rai->target_value_changed = 1;
147
static void gf_smil_anim_animate_from_to(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
149
SMILAnimationAttributes *anim = rai->anim_elt->anim;
151
GF_FieldInfo from_info, to_info;
153
if (rai->previous_coef == normalized_simple_time) return;
155
rai->previous_coef = normalized_simple_time;
157
from_info.fieldType = anim->from.type;
158
from_info.eventType = anim->from.transform_type;
159
from_info.far_ptr = anim->from.value;
160
gf_svg_attributes_pointer_update(&from_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
162
to_info.fieldType = anim->to.type;
163
to_info.eventType = anim->to.transform_type;
164
to_info.far_ptr = anim->to.value;
165
gf_svg_attributes_pointer_update(&to_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
167
switch (anim->calcMode) {
168
case SMIL_CALCMODE_DISCRETE:
170
/* before half of the duration stay at 'from' and then switch to 'to' */
171
s32 useFrom = (normalized_simple_time<=FIX_ONE/2);
172
if (useFrom == rai->previous_key_index) return;
173
gf_svg_attributes_copy(&rai->interpolated_value, (useFrom?&from_info:&to_info), 0);
174
rai->previous_key_index = useFrom;
177
case SMIL_CALCMODE_SPLINE:
178
case SMIL_CALCMODE_PACED:
179
case SMIL_CALCMODE_LINEAR:
181
gf_svg_attributes_interpolate(&from_info, &to_info, &rai->interpolated_value, normalized_simple_time, 1);
184
rai->target_value_changed = 1;
187
static void gf_smil_anim_animate_from_by(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
189
SMILAnimationAttributes *anim = rai->anim_elt->anim;
190
GF_FieldInfo from_info, by_info;
192
if (rai->previous_coef == normalized_simple_time) return;
194
rai->previous_coef = normalized_simple_time;
196
from_info.fieldType = anim->from.type;
197
from_info.eventType = anim->from.transform_type;
198
from_info.far_ptr = anim->from.value;
199
gf_svg_attributes_pointer_update(&from_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
201
by_info.fieldType = anim->by.type;
202
by_info.eventType = anim->by.transform_type;
203
by_info.far_ptr = anim->by.value;
204
gf_svg_attributes_pointer_update(&by_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
206
switch (anim->calcMode) {
207
case SMIL_CALCMODE_DISCRETE:
209
/* before half of the duration stay at 'from' and then switch to 'to' */
210
s32 useFrom = (normalized_simple_time<=FIX_ONE/2);
211
if (useFrom == rai->previous_key_index) return;
213
gf_svg_attributes_copy(&rai->interpolated_value, &from_info, 0);
215
gf_svg_attributes_muladd(FIX_ONE, &from_info, FIX_ONE, &by_info, &rai->interpolated_value, 0);
217
rai->previous_key_index = useFrom;
220
case SMIL_CALCMODE_SPLINE:
221
case SMIL_CALCMODE_PACED:
222
case SMIL_CALCMODE_LINEAR:
224
gf_svg_attributes_muladd(FIX_ONE, &from_info, normalized_simple_time, &by_info, &rai->interpolated_value, 0);
227
rai->target_value_changed = 1;
230
static Bool gf_svg_compute_path_anim(SMIL_Anim_RTI *rai, GF_Matrix2D *m, Fixed normalized_simple_time)
234
offset = gf_mulfix(normalized_simple_time, rai->length);
236
res = gf_path_iterator_get_transform(rai->path_iterator, offset, 1, m, 1, 0);
237
// fprintf(stdout, "Time: %f - Offset: %f, Position: %f, %f\n", normalized_simple_time, offset, ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[2], ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[5]);
238
switch (rai->rotate) {
239
case SVG_NUMBER_AUTO:
241
case SVG_NUMBER_AUTO_REVERSE:
242
gf_mx2d_add_rotation(m, m->m[2], m->m[5], GF_PI);
245
((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[0] = 1;
246
((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[1] = 0;
247
((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[3] = 0;
248
((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[4] = 1;
253
static void gf_smil_anim_animate_using_path(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
256
gf_svg_compute_path_anim(rai, rai->interpolated_value.far_ptr, normalized_simple_time);
257
if (res) rai->target_value_changed = 1;
260
static void gf_smil_anim_discard(SMIL_Timing_RTI *rti, Fixed normalized_scene_time)
262
GF_Node *targetNode = (GF_Node *)rti->timed_elt->xlink->href.target;
263
if (!targetNode) return;
264
/* deletes the node and replace all references to that node to NULL */
265
gf_node_replace(targetNode, NULL, 0);
266
/* sets the node to NULL in case of future calls to discard */
267
rti->timed_elt->xlink->href.target = NULL;
268
/* TODO: The animation (discard) does not need to run again */
269
/* TODO: Invalidate the scene ?*/
272
static void gf_smil_anim_get_last_specified_value(SMIL_Anim_RTI *rai)
274
SVGElement *e = rai->anim_elt;
277
/*TODO CHECK WITH CYRIL !! */
278
// if (!rai->last_specified_value.far_ptr) rai->last_specified_value.far_ptr = malloc(sizeof(GF_Matrix2D));
279
// gf_svg_compute_path_anim(rai, rai->last_specified_value.far_ptr, FIX_ONE);
280
} else if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_set) {
281
rai->last_specified_value.fieldType = e->anim->to.type;
282
rai->last_specified_value.eventType = e->anim->to.transform_type;
283
rai->last_specified_value.far_ptr = e->anim->to.value;
287
if (gf_list_count(e->anim->values.values)) {
288
/* Ignore from/to/by*/
289
rai->last_specified_value.fieldType = e->anim->values.type;
290
rai->last_specified_value.eventType = e->anim->values.transform_type;
291
rai->last_specified_value.far_ptr = gf_list_last(e->anim->values.values);
292
} else if (e->anim->by.type && (e->anim->to.type == 0)) {
293
rai->last_specified_value.fieldType = e->anim->by.type;
294
rai->last_specified_value.eventType = e->anim->by.transform_type;
295
rai->last_specified_value.far_ptr = e->anim->by.value;
297
rai->last_specified_value.fieldType = e->anim->to.type;
298
rai->last_specified_value.eventType = e->anim->to.transform_type;
299
rai->last_specified_value.far_ptr = e->anim->to.value;
301
if (gf_svg_is_inherit(&rai->last_specified_value)) {
302
rai->last_specified_value.fieldType = rai->owner->presentation_value.fieldType;
303
rai->last_specified_value.eventType = rai->owner->presentation_value.eventType;
304
rai->last_specified_value.far_ptr = rai->owner->presentation_value.far_ptr;
306
gf_svg_attributes_pointer_update(&rai->last_specified_value, &rai->owner->presentation_value, &rai->owner->current_color_value);
310
/* TODO: fix this ... */
311
static void gf_smil_anim_get_last_nb_iterations(SMIL_Anim_RTI *rai, u32 *nb_iterations)
313
if (rai->anim_elt->timing->repeatCount.type) {
314
*nb_iterations = (u32)rai->anim_elt->timing->repeatCount.count;
316
*nb_iterations = (u32)rai->anim_elt->timing->repeatDur.clock_value;
321
static void gf_smil_anim_apply_accumulate(SMIL_Anim_RTI *rai)
323
u32 nb_iterations = rai->anim_elt->timing->runtime->current_interval->nb_iterations;
324
if (rai->anim_elt->anim->accumulate == SMIL_ACCUMULATE_SUM && nb_iterations > 0) {
325
gf_svg_attributes_muladd(INT2FIX(nb_iterations), &rai->last_specified_value, FIX_ONE, &rai->interpolated_value, &rai->interpolated_value, 1);
329
static SMIL_Anim_RTI *gf_smil_anim_get_anim_runtime_from_timing(SMIL_Timing_RTI *rti)
331
SVGElement *e = rti->timed_elt;
333
if (!e->xlink->href.target) return NULL;
334
for (i = 0; i < gf_node_animation_count((GF_Node *)e->xlink->href.target); i++) {
335
SMIL_Anim_RTI *rai_tmp;
336
SMIL_AttributeAnimations *aa = gf_node_animation_get((GF_Node *)e->xlink->href.target, i);
338
while ((rai_tmp = gf_list_enum(aa->anims, &j))) {
339
if (rai_tmp->anim_elt->timing->runtime == rti) {
347
/* Compute the Animation Value (AV), possibly based on the Underlying Value (read-only) in the case
348
of from-less/to-less/inherit values animations */
349
static void gf_smil_anim_compute_interpolation_value(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
351
SVGElement *e = rai->anim_elt;
353
if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_discard) {
356
} else if (rai->path) {
357
gf_smil_anim_animate_using_path(rai, normalized_simple_time);
359
} else if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_set) {
360
gf_smil_anim_set(rai);
364
if (gf_list_count(e->anim->values.values)) {
365
/* Ignore from/to/by*/
366
gf_smil_anim_animate_using_values(rai, normalized_simple_time);
367
} else if (e->anim->by.type && (e->anim->to.type == 0)) {
368
/* no to but a by, this is a by or a from-by animation */
369
gf_smil_anim_animate_from_by(rai, normalized_simple_time);
371
gf_smil_anim_animate_from_to(rai, normalized_simple_time);
375
static void gf_smil_anim_animate(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
377
SMIL_Anim_RTI *rai = gf_smil_anim_get_anim_runtime_from_timing(rti);
381
// fprintf(stdout, "Animation: %x @ time : %f\n", rti, normalized_simple_time);
383
rai->target_value_changed = 0;
384
gf_smil_anim_compute_interpolation_value(rai, normalized_simple_time);
385
if (rai->target_value_changed) gf_smil_anim_apply_accumulate(rai);
386
/* Apply additive behavior if required
387
PV = (additive == sum ? PV + anim->IV : anim->IV); */
388
if (rai->anim_elt->anim->additive == SMIL_ADDITIVE_SUM) {
389
gf_svg_attributes_add(&rai->owner->presentation_value, &rai->interpolated_value, &rai->owner->presentation_value, 1);
391
gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->interpolated_value, 1);
395
static void gf_smil_anim_freeze(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
397
SMIL_Anim_RTI *rai = gf_smil_anim_get_anim_runtime_from_timing(rti);
400
// fprintf(stdout, "Freeze: %x @ time : %f\n", rti, normalized_simple_time);
402
/* we do the accumulation only once and store the result in interpolated value */
403
if (rti->cycle_number == rti->first_frozen) {
404
rai->target_value_changed = 0;
405
gf_smil_anim_compute_interpolation_value(rai, normalized_simple_time);
406
if (rai->target_value_changed) gf_smil_anim_apply_accumulate(rai);
408
if (rai->anim_elt->anim->additive == SMIL_ADDITIVE_SUM) {
409
gf_svg_attributes_add(&rai->owner->presentation_value, &rai->interpolated_value, &rai->owner->presentation_value, 1);
411
gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->interpolated_value, 1);
415
static void gf_smil_anim_restore(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
417
SMIL_Anim_RTI *rai = gf_smil_anim_get_anim_runtime_from_timing(rti);
420
// fprintf(stdout, "Restore: %x @ time : %f\n", rti, normalized_simple_time);
422
gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->owner->saved_specified_value, 0);
423
//gf_list_del_item(rai->owner->anims, rai);
426
void gf_smil_anim_init_runtime_info(SVGElement *e)
429
GF_FieldInfo target_attribute;
430
SMIL_AttributeAnimations *aa = NULL;
433
if (e->anim->attributeName.name) {
434
gf_node_get_field_by_name((GF_Node *)e->xlink->href.target, e->anim->attributeName.name, &target_attribute);
436
/* if attributeName is not specified it is a transform attribute */
437
gf_node_get_field_by_name((GF_Node *)e->xlink->href.target, "transform", &target_attribute);
440
GF_SAFEALLOC(rai, sizeof(SMIL_Anim_RTI))
442
rai->interpolated_value = target_attribute;
443
rai->interpolated_value.far_ptr = gf_svg_create_attribute_value(target_attribute.fieldType, 0);
444
rai->previous_key_index = -1;
445
rai->previous_coef = -1;
447
if (gf_node_get_tag((GF_Node *)e) == TAG_SVG_animateMotion) {
448
SVGanimateMotionElement *am = (SVGanimateMotionElement *)e;
449
rai->rotate = am->rotate.type;
450
if (e->anim->to.type == 0 && e->anim->by.type == 0 && e->anim->values.type == 0) {
451
rai->path = gf_path_new();
452
if (gf_list_count(am->path.points)) {
453
gf_svg_path_build(rai->path, am->path.commands, am->path.points);
454
rai->path_iterator = gf_path_iterator_new(rai->path);
455
rai->length = gf_path_iterator_get_length(rai->path_iterator);
458
count = gf_list_count(((SVGElement *)e)->children);
459
for (i = 0; i < count; i++) {
460
GF_Node *child = gf_list_get(((SVGElement *)e)->children, i);
461
if (gf_node_get_tag((GF_Node *)child) == TAG_SVG_mpath) {
462
SVGmpathElement *mpath = (SVGmpathElement *)child;
463
GF_Node *used_path = NULL;
464
if (mpath->xlink && mpath->xlink->href.target) used_path = (GF_Node *)mpath->xlink->href.target;
465
else if (mpath->xlink->href.iri) used_path= gf_sg_find_node_by_name(gf_node_get_graph((GF_Node *)mpath), mpath->xlink->href.iri);
466
if (used_path && gf_node_get_tag(used_path) == TAG_SVG_path) {
467
SVGpathElement *used_path_elt = (SVGpathElement *)used_path;
468
gf_svg_path_build(rai->path, used_path_elt->d.commands, used_path_elt->d.points);
469
rai->path_iterator = gf_path_iterator_new(rai->path);
470
rai->length = gf_path_iterator_get_length(rai->path_iterator);
479
/* for all animations, check if there is already one animation on this attribute,
480
if yes, get the list and append the new animation
481
if no, create a list and add the new animation. */
482
for (i = 0; i < gf_node_animation_count((GF_Node *)e->xlink->href.target); i++) {
483
aa = gf_node_animation_get((GF_Node *)e->xlink->href.target, i);
484
if (aa->presentation_value.fieldIndex == target_attribute.fieldIndex) {
485
gf_list_add(aa->anims, rai);
491
GF_SAFEALLOC(aa, sizeof(SMIL_AttributeAnimations))
493
/* Save the DOM value before any animation starts */
494
aa->saved_specified_value = target_attribute;
495
aa->orig_dom_ptr = target_attribute.far_ptr;
496
aa->saved_specified_value.far_ptr = gf_svg_create_attribute_value(target_attribute.fieldType, 0);
497
gf_svg_attributes_copy(&aa->saved_specified_value, &target_attribute, 0);
499
/* Stores the pointer to the presentation value */
500
aa->presentation_value = target_attribute;
502
aa->anims = gf_list_new();
503
gf_list_add(aa->anims, rai);
504
gf_node_animation_add((GF_Node *)e->xlink->href.target, aa);
508
e->timing->runtime->activation = gf_smil_anim_animate;
509
e->timing->runtime->freeze = gf_smil_anim_freeze;
510
e->timing->runtime->restore = gf_smil_anim_restore;
511
gf_smil_anim_get_last_specified_value(rai);
514
void gf_smil_anim_delete_runtime_info(SMIL_Anim_RTI *rai)
516
gf_svg_delete_attribute_value(rai->interpolated_value.fieldType, rai->interpolated_value.far_ptr, rai->anim_elt->sgprivate->scenegraph);
517
if (rai->path) gf_path_del(rai->path);
518
if (rai->path_iterator) gf_path_iterator_del(rai->path_iterator);
522
void gf_smil_anim_delete_animations(SVGElement *e)
525
for (i = 0; i < gf_node_animation_count((GF_Node *)e); i ++) {
527
SMIL_AttributeAnimations *aa = gf_node_animation_get((GF_Node *)e, i);
528
gf_svg_delete_attribute_value(aa->saved_specified_value.fieldType, aa->saved_specified_value.far_ptr, e->sgprivate->scenegraph);
530
while ((rai = gf_list_enum(aa->anims, &j))) {
531
gf_smil_anim_delete_runtime_info(rai);
533
gf_list_del(aa->anims);
536
gf_node_animation_del((GF_Node *)e);
539
void gf_smil_anim_init_node(GF_Node *node)
541
SVGElement *anim_elt = (SVGElement *)node;
543
if (!anim_elt->xlink) return;
544
if (anim_elt->xlink->href.type == SVG_IRI_IRI) {
545
if (!anim_elt->xlink->href.iri) {
546
fprintf(stderr, "Error: IRI not initialized\n");
551
n = gf_sg_find_node_by_name(gf_node_get_graph(node), anim_elt->xlink->href.iri);
553
anim_elt->xlink->href.type = SVG_IRI_ELEMENTID;
554
anim_elt->xlink->href.target = (SVGElement *)n;
555
gf_svg_register_iri(node->sgprivate->scenegraph, &anim_elt->xlink->href);
562
if (!anim_elt->xlink->href.target) return;
564
gf_smil_timing_init_runtime_info(anim_elt);
565
if (anim_elt->anim) gf_smil_anim_init_runtime_info(anim_elt);
566
/*THIS IS A DISCARD OR THIS CRASHES.*/
568
anim_elt->timing->runtime->activation = gf_smil_anim_discard;
573
/* TODO: update for elliptical arcs */
574
void gf_svg_path_build(GF_Path *path, GF_List *commands, GF_List *points)
576
u32 i, j, command_count, points_count;
577
SVG_Point orig, ct_orig, ct_end, end, *tmp;
578
command_count = gf_list_count(commands);
579
points_count = gf_list_count(points);
580
orig.x = orig.y = ct_orig.x = ct_orig.y = 0;
582
for (i=0, j=0; i<command_count; i++) {
583
u8 *command = gf_list_get(commands, i);
585
case SVG_PATHCOMMAND_M: /* Move To */
586
tmp = gf_list_get(points, j);
588
gf_path_add_move_to(path, orig.x, orig.y);
590
/*provision for nextCurveTo when no curve is specified:
591
"If there is no previous command or if the previous command was not an C, c, S or s,
592
assume the first control point is coincident with the current point.
596
case SVG_PATHCOMMAND_L: /* Line To */
597
tmp = gf_list_get(points, j);
600
gf_path_add_line_to(path, end.x, end.y);
606
case SVG_PATHCOMMAND_C: /* Curve To */
607
tmp = gf_list_get(points, j);
609
tmp = gf_list_get(points, j+1);
611
tmp = gf_list_get(points, j+2);
613
gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
618
case SVG_PATHCOMMAND_S: /* Next Curve To */
619
ct_orig.x = 2*orig.x - ct_orig.x;
620
ct_orig.y = 2*orig.y - ct_orig.y;
621
tmp = gf_list_get(points, j);
623
tmp = gf_list_get(points, j+1);
625
gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
630
case SVG_PATHCOMMAND_Q: /* Quadratic Curve To */
631
tmp = gf_list_get(points, j);
633
tmp = gf_list_get(points, j+1);
635
gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
639
case SVG_PATHCOMMAND_T: /* Next Quadratic Curve To */
640
ct_orig.x = 2*orig.x - ct_orig.x;
641
ct_orig.y = 2*orig.y - ct_orig.y;
642
tmp = gf_list_get(points, j);
644
gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
648
case SVG_PATHCOMMAND_Z: /* Close */