This source file includes following definitions.
- form_reset
- form_new_group
- form_get_group
- fg_compute_bounds
- fg_update_bounds
- form_apply
- TraverseForm
- compositor_init_form
- shin_apply
- sh_apply
- svin_apply
- sv_apply
- al_apply
- ar_apply
- at_apply
- ab_apply
- ah_apply
- av_apply
#include "nodes_stacks.h"
#include "mpeg4_grouping.h"
#include "visual_manager.h"
#ifndef GPAC_DISABLE_VRML
typedef struct
{
PARENT_MPEG4_STACK_2D
GF_List *grouplist;
GF_Rect clip;
} FormStack;
typedef struct
{
GF_List *children;
GF_Rect origin, final;
} FormGroup;
static void form_reset(FormStack *st)
{
while (gf_list_count(st->grouplist)) {
FormGroup * fg = (FormGroup *) gf_list_get(st->grouplist, 0);
gf_list_rem(st->grouplist, 0);
gf_list_del(fg->children);
gf_free(fg);
}
}
static FormGroup *form_new_group(FormStack *st)
{
FormGroup *fg;
GF_SAFEALLOC(fg, FormGroup);
if (!fg) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate form group\n"));
return NULL;
}
fg->children = gf_list_new();
gf_list_add(st->grouplist, fg);
return fg;
}
static GFINLINE FormGroup *form_get_group(FormStack *st, u32 i)
{
return (FormGroup *) gf_list_get(st->grouplist, i);
}
static void fg_compute_bounds(FormGroup *fg)
{
ChildGroup *cg;
u32 i=0;
memset(&fg->origin, 0, sizeof(GF_Rect));
while ((cg = (ChildGroup *)gf_list_enum(fg->children, &i))) {
gf_rect_union(&fg->origin, &cg->final);
}
fg->final = fg->origin;
}
static void fg_update_bounds(FormGroup *fg)
{
ChildGroup *cg;
u32 i=0;
Fixed x, y;
x = fg->final.x - fg->origin.x;
y = fg->final.y - fg->origin.y;
while ((cg = (ChildGroup *)gf_list_enum(fg->children, &i))) {
cg->final.x += x;
cg->final.y += y;
}
fg_compute_bounds(fg);
}
static void shin_apply(FormStack *st, u32 *group_idx, u32 count);
static void sh_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
static void svin_apply(FormStack *st, u32 *group_idx, u32 count);
static void sv_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
static void al_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
static void ar_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
static void at_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
static void ab_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
static void ah_apply(FormStack *st, u32 *group_idx, u32 count);
static void av_apply(FormStack *st, u32 *group_idx, u32 count);
static void form_apply(FormStack *st, const char *constraint, u32 *group_idx, u32 count)
{
Float val;
if (!constraint || !strlen(constraint)) return;
if (!strnicmp(constraint, "SHin", 4)) {
shin_apply(st, group_idx, count);
return;
}
if (!strnicmp(constraint, "SH", 2)) {
if (sscanf(constraint, "SH %f", &val)==1) {
sh_apply(st, FLT2FIX(val), group_idx, count);
} else {
sh_apply(st, -FIX_ONE, group_idx, count);
}
return;
}
if (!strnicmp(constraint, "SVin", 4)) {
svin_apply(st, group_idx, count);
return;
}
if (!strnicmp(constraint, "SV", 2)) {
if (sscanf(constraint, "SV %f", &val)==1) {
sv_apply(st, FLT2FIX(val), group_idx, count);
} else {
sv_apply(st, -FIX_ONE, group_idx, count);
}
return;
}
if (!strnicmp(constraint, "AL", 2)) {
if (sscanf(constraint, "AL %f", &val)==1) {
al_apply(st, FLT2FIX(val), group_idx, count);
} else {
al_apply(st, -FIX_ONE, group_idx, count);
}
return;
}
if (!strnicmp(constraint, "AR", 2)) {
if (sscanf(constraint, "AR %f", &val)==1) {
ar_apply(st, FLT2FIX(val), group_idx, count);
} else {
ar_apply(st, -FIX_ONE, group_idx, count);
}
return;
}
if (!strnicmp(constraint, "AT", 2)) {
if (sscanf(constraint, "AT %f", &val)==1) {
at_apply(st, FLT2FIX(val), group_idx, count);
} else {
at_apply(st, -FIX_ONE, group_idx, count);
}
return;
}
if (!strnicmp(constraint, "AB", 2)) {
if (sscanf(constraint, "AB %f", &val)==1) {
ab_apply(st, FLT2FIX(val), group_idx, count);
} else {
ab_apply(st, -FIX_ONE, group_idx, count);
}
return;
}
if (!strnicmp(constraint, "AH", 2)) {
ah_apply(st, group_idx, count);
return;
}
if (!strnicmp(constraint, "AV", 2)) {
av_apply(st, group_idx, count);
return;
}
}
#ifndef MAX_FORM_GROUP_INDEX
#define MAX_FORM_GROUP_INDEX 100
#endif
#define FORM_CLIPS 1
static void TraverseForm(GF_Node *n, void *rs, Bool is_destroy)
{
#if FORM_CLIPS
GF_Rect prev_clipper;
Bool had_clip;
GF_IRect prev_clip;
#endif
Bool recompute_form;
u32 idx[MAX_FORM_GROUP_INDEX];
u32 i, index, last_ind, j;
u32 mode_bckup;
ParentNode2D *parent_bck;
FormGroup *fg;
ChildGroup *cg;
M_Form *fm = (M_Form *) n;
FormStack *st = (FormStack *)gf_node_get_private(n);
GF_TraverseState *tr_state = (GF_TraverseState *) rs;
if (is_destroy) {
form_reset(st);
gf_list_del(st->grouplist);
parent_node_predestroy((ParentNode2D *)st);
gf_free(st);
return;
}
if ((gf_node_dirty_get(n) & GF_SG_NODE_DIRTY)) {
visual_get_size_info(tr_state, &st->clip.width, &st->clip.height);
if (fm->size.x>=0) st->clip.width = fm->size.x;
if (fm->size.y>=0) st->clip.height = fm->size.y;
st->bounds = st->clip = gf_rect_center(st->clip.width, st->clip.height);
}
recompute_form = GF_FALSE;
if (gf_node_dirty_get(n)) recompute_form = GF_TRUE;
#if FORM_CLIPS
if ((tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) && !tr_state->for_node) {
tr_state->bounds = st->clip;
#ifndef GPAC_DISABLE_3D
gf_bbox_from_rect(&tr_state->bbox, &st->clip);
#endif
return;
}
#endif
if (recompute_form) {
GF_Rect bounds;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Form] Recomputing positions\n"));
parent_node_reset((ParentNode2D*)st);
bounds.width = bounds.height = 0;
parent_bck = tr_state->parent;
mode_bckup = tr_state->traversing_mode;
tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
tr_state->parent = (ParentNode2D *) st;
parent_node_traverse(n, (ParentNode2D *)st, tr_state);
tr_state->parent = parent_bck;
tr_state->traversing_mode = mode_bckup;
i=0;
while ((cg = (ChildGroup *)gf_list_enum(st->groups, &i))) {
cg->final.x = - cg->final.width/2;
cg->final.y = cg->final.height/2;
}
form_reset(st);
fg = form_new_group(st);
fg->origin = fg->final = st->clip;
fg = NULL;
for (i=0; i<fm->groups.count; i++) {
if (!fg) {
fg = form_new_group(st);
}
if (fm->groups.vals[i]==-1) {
fg_compute_bounds(fg);
fg = NULL;
continue;
}
if ((u32) fm->groups.vals[i]>gf_list_count(st->groups)) goto err_exit;
cg = (ChildGroup *)gf_list_get(st->groups, fm->groups.vals[i]-1);
gf_list_add(fg->children, cg);
}
memset(idx, 0, sizeof(u32)*MAX_FORM_GROUP_INDEX);
last_ind = 0;
for (i=0; i<fm->constraints.count; i++) {
index = 0;
while (1) {
if (last_ind+index > fm->groupsIndex.count) goto err_exit;
if (fm->groupsIndex.vals[last_ind+index]==-1) break;
if (index>MAX_FORM_GROUP_INDEX) goto err_exit;
idx[index] = fm->groupsIndex.vals[last_ind+index];
index++;
}
form_apply(st, fm->constraints.vals[i], idx, index);
index++;
last_ind += index;
j=1;
while ((fg = (FormGroup*)gf_list_enum(st->grouplist, &j))) {
fg_compute_bounds(fg);
gf_rect_union(&bounds, &fg->final);
}
if (last_ind>=fm->groupsIndex.count) break;
}
form_reset(st);
#if !FORM_CLIPS
st->clip = bounds;
#endif
}
if ((tr_state->traversing_mode==TRAVERSE_PICK) && !gf_sc_pick_in_clipper(tr_state, &st->clip))
return;
#if !FORM_CLIPS
if ((tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) && !tr_state->for_node) {
tr_state->bounds = st->clip;
gf_bbox_from_rect(&tr_state->bbox, &st->clip);
return;
}
#endif
#if FORM_CLIPS
if (tr_state->traversing_mode==TRAVERSE_SORT) {
prev_clip = tr_state->visual->top_clipper;
compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, GF_FALSE);
if (tr_state->has_clip) {
tr_state->visual->top_clipper = gf_rect_pixelize(&tr_state->clipper);
gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip);
}
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d)
visual_3d_reset_clipper_2d(tr_state->visual);
#endif
i=0;
while ((cg = (ChildGroup*)gf_list_enum(st->groups, &i))) {
parent_node_child_traverse(cg, tr_state);
}
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d)
visual_3d_reset_clipper_2d(tr_state->visual);
#endif
tr_state->visual->top_clipper = prev_clip;
if (had_clip) tr_state->clipper = prev_clipper;
tr_state->has_clip = had_clip;
} else
#endif
{
i=0;
while ((cg = (ChildGroup*)gf_list_enum(st->groups, &i))) {
parent_node_child_traverse(cg, tr_state);
}
}
return;
err_exit:
parent_node_reset((ParentNode2D*)st);
form_reset(st);
}
void compositor_init_form(GF_Compositor *compositor, GF_Node *node)
{
FormStack *stack;
GF_SAFEALLOC(stack, FormStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate form stack\n"));
return;
}
parent_node_setup((ParentNode2D*)stack);
stack->grouplist = gf_list_new();
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraverseForm);
}
static void shin_apply(FormStack *st, u32 *group_idx, u32 count)
{
u32 i, len;
Fixed tot_len, inter_space;
tot_len = 0;
inter_space = st->clip.width;
len = 0;
for (i=0; i<count; i++) {
if (group_idx[i] != 0) {
tot_len += form_get_group(st, group_idx[i])->final.width;
len++;
}
}
inter_space -= tot_len;
inter_space /= (len+1);
for (i=0; i<count; i++) {
if(group_idx[i] == 0) continue;
if (!i) {
form_get_group(st, group_idx[0])->final.x = st->clip.x + inter_space;
} else {
form_get_group(st, group_idx[i])->final.x =
form_get_group(st, group_idx[i-1])->final.x + form_get_group(st, group_idx[i-1])->final.width
+ inter_space;
}
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void sh_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
{
u32 i, k;
GF_Rect *l, *r;
Fixed inter_space, tot_len;
tot_len = 0;
if (space == -FIX_ONE) {
r = &form_get_group(st, group_idx[count-1])->final;
l = &form_get_group(st, group_idx[0])->final;
inter_space = r->x - l->x;
if(group_idx[0] != 0) inter_space -= l->width;
for (i=1; i<count-1; i++) tot_len += form_get_group(st, group_idx[i])->final.width;
inter_space -= tot_len;
inter_space /= (count-1);
} else {
inter_space = space;
}
k = count - 1;
if (space != -1) k += 1;
for (i=1; i<k; i++) {
if (group_idx[i] ==0) continue;
l = &form_get_group(st, group_idx[i-1])->final;
r = &form_get_group(st, group_idx[i])->final;
r->x = l->x + inter_space;
if(group_idx[i-1] != 0) r->x += l->width;
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void svin_apply(FormStack *st, u32 *group_idx, u32 count)
{
u32 i, len;
Fixed tot_len, inter_space;
tot_len = 0;
inter_space = st->clip.height;
len = 0;
for (i=0; i<count; i++) {
if (group_idx[i] != 0) {
tot_len += form_get_group(st, group_idx[i])->final.height;
len++;
}
}
inter_space -= tot_len;
inter_space /= (len+1);
for (i=0; i<count; i++) {
if (group_idx[i] == 0) continue;
if (!i) {
form_get_group(st, group_idx[0])->final.y = st->clip.y - inter_space;
} else {
form_get_group(st, group_idx[i])->final.y =
form_get_group(st, group_idx[i-1])->final.y - form_get_group(st, group_idx[i-1])->final.height -
inter_space;
}
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void sv_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
{
u32 i, k;
Fixed tot_len, inter_space;
GF_Rect *t, *b;
tot_len = 0;
if(space > -FIX_ONE) {
inter_space = space;
} else {
t = &form_get_group(st, group_idx[count-1])->final;
b = &form_get_group(st, group_idx[0])->final;
inter_space = b->y - t->y;
if (group_idx[0]!=0) inter_space -= t->height;
for (i=1; i<count-1; i++) tot_len += form_get_group(st, group_idx[i])->final.height;
inter_space -= tot_len;
inter_space /= count-1;
}
k = count-1;
if (space > -1) k += 1;
for (i=1; i<k; i++) {
if (group_idx[i] == 0) continue;
form_get_group(st, group_idx[i])->final.y = form_get_group(st, group_idx[i-1])->final.y - inter_space;
if (group_idx[i-1] != 0) {
form_get_group(st, group_idx[i])->final.y -= form_get_group(st, group_idx[i-1])->final.height;
}
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void al_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
{
Fixed min_x;
GF_Rect *rc;
u32 i, start;
start = 0;
min_x = form_get_group(st, group_idx[0])->final.x;
if (space>-FIX_ONE) {
start = 1;
min_x += space;
} else {
for (i=1; i<count; i++) {
rc = &form_get_group(st, group_idx[0])->final;
if (group_idx[i]==0) {
min_x = rc->x;
break;
}
if (rc->x < min_x) min_x = rc->x;
}
}
for (i=start; i<count; i++) {
if( group_idx[i] == 0) continue;
form_get_group(st, group_idx[i])->final.x = min_x;
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void ar_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
{
Fixed max_x;
u32 i, start;
GF_Rect *rc;
start = 0;
rc = &form_get_group(st, group_idx[0])->final;
max_x = rc->x + rc->width;
if(space>-FIX_ONE) {
max_x -= space;
start = 1;
} else {
for (i=1; i<count; i++) {
rc = &form_get_group(st, group_idx[i])->final;
if (group_idx[i]==0) {
max_x = rc->x + rc->width;
break;
}
if (rc->x + rc->width > max_x) max_x = rc->x + rc->width;
}
}
for (i=start; i<count; i++) {
if(group_idx[i] == 0) continue;
rc = &form_get_group(st, group_idx[i])->final;
rc->x = max_x - rc->width;
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void at_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
{
Fixed max_y;
u32 i, start;
GF_Rect *rc;
start = 0;
max_y = form_get_group(st, group_idx[0])->final.y;
if(space>-FIX_ONE) {
start = 1;
max_y -= space;
} else {
for (i=1; i<count; i++) {
rc = &form_get_group(st, group_idx[i])->final;
if (group_idx[i]==0) {
max_y = rc->y;
break;
}
if (rc->y > max_y) max_y = rc->y;
}
}
for (i=start; i<count; i++) {
if(group_idx[i] == 0) continue;
form_get_group(st, group_idx[i])->final.y = max_y;
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void ab_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
{
Fixed min_y;
u32 i, start;
GF_Rect *rc;
start = 0;
rc = &form_get_group(st, group_idx[0])->final;
min_y = rc->y - rc->height;
if(space>-FIX_ONE) {
start = 1;
min_y += space;
} else {
for (i=1; i<count; i++) {
rc = &form_get_group(st, group_idx[i])->final;
if (group_idx[i]==0) {
min_y = rc->y - rc->height;
break;
}
if (rc->y - rc->height < min_y) min_y = rc->y - rc->height;
}
}
for (i=start; i<count; i++) {
if(group_idx[i] == 0) continue;
rc = &form_get_group(st, group_idx[i])->final;
rc->y = min_y + rc->height;
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void ah_apply(FormStack *st, u32 *group_idx, u32 count)
{
GF_Rect *rc;
u32 i;
Fixed left, right, center;
left = right = center = 0;
for (i=0; i<count; i++) {
rc = &form_get_group(st, group_idx[i])->final;
if(group_idx[i] == 0) {
center = rc->x + rc->width / 2;
break;
}
if (left > rc->x) left = rc->x;
if (right < rc->x + rc->width) right = rc->x + rc->width;
center = (left+right)/2;
}
for (i=0; i<count; i++) {
if(group_idx[i] == 0) continue;
rc = &form_get_group(st, group_idx[i])->final;
rc->x = center - rc->width/2;
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
static void av_apply(FormStack *st, u32 *group_idx, u32 count)
{
u32 i;
Fixed top, bottom, center;
GF_Rect *rc;
top = bottom = center = 0;
for (i=0; i<count; i++) {
rc = &form_get_group(st, group_idx[i])->final;
if (group_idx[i] == 0) {
center = rc->y - rc->height / 2;
break;
}
if (top < rc->y) top = rc->y;
if (bottom > rc->y - rc->height) bottom = rc->y - rc->height;
center = (top+bottom)/2;
}
for (i=0; i<count; i++) {
if(group_idx[i] == 0) continue;
rc = &form_get_group(st, group_idx[i])->final;
rc->y = center + rc->height/2;
fg_update_bounds(form_get_group(st, group_idx[i]));
}
}
#endif