Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Compositor sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 :
28 : #include "nodes_stacks.h"
29 : #include "mpeg4_grouping.h"
30 : #include "visual_manager.h"
31 :
32 : #ifndef GPAC_DISABLE_VRML
33 :
34 :
35 : typedef struct
36 : {
37 : PARENT_MPEG4_STACK_2D
38 :
39 : GF_List *grouplist;
40 : GF_Rect clip;
41 : } FormStack;
42 :
43 : /*storage of group info*/
44 : typedef struct
45 : {
46 : GF_List *children;
47 : GF_Rect origin, final;
48 : } FormGroup;
49 :
50 :
51 188 : static void form_reset(FormStack *st)
52 : {
53 1213 : while (gf_list_count(st->grouplist)) {
54 1025 : FormGroup * fg = (FormGroup *) gf_list_get(st->grouplist, 0);
55 1025 : gf_list_rem(st->grouplist, 0);
56 1025 : gf_list_del(fg->children);
57 1025 : gf_free(fg);
58 : }
59 188 : }
60 :
61 1025 : static FormGroup *form_new_group(FormStack *st)
62 : {
63 : FormGroup *fg;
64 1025 : GF_SAFEALLOC(fg, FormGroup);
65 1025 : if (!fg) {
66 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate form group\n"));
67 : return NULL;
68 : }
69 1025 : fg->children = gf_list_new();
70 1025 : gf_list_add(st->grouplist, fg);
71 : return fg;
72 : }
73 :
74 : static GFINLINE FormGroup *form_get_group(FormStack *st, u32 i)
75 : {
76 4306 : return (FormGroup *) gf_list_get(st->grouplist, i);
77 : }
78 :
79 9165 : static void fg_compute_bounds(FormGroup *fg)
80 : {
81 : ChildGroup *cg;
82 9165 : u32 i=0;
83 9165 : memset(&fg->origin, 0, sizeof(GF_Rect));
84 24889 : while ((cg = (ChildGroup *)gf_list_enum(fg->children, &i))) {
85 15724 : gf_rect_union(&fg->origin, &cg->final);
86 : }
87 9165 : fg->final = fg->origin;
88 9165 : }
89 961 : static void fg_update_bounds(FormGroup *fg)
90 : {
91 : ChildGroup *cg;
92 961 : u32 i=0;
93 : Fixed x, y;
94 961 : x = fg->final.x - fg->origin.x;
95 961 : y = fg->final.y - fg->origin.y;
96 3522 : while ((cg = (ChildGroup *)gf_list_enum(fg->children, &i))) {
97 1600 : cg->final.x += x;
98 1600 : cg->final.y += y;
99 : }
100 961 : fg_compute_bounds(fg);
101 961 : }
102 :
103 :
104 : static void shin_apply(FormStack *st, u32 *group_idx, u32 count);
105 : static void sh_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
106 : static void svin_apply(FormStack *st, u32 *group_idx, u32 count);
107 : static void sv_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
108 : static void al_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
109 : static void ar_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
110 : static void at_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
111 : static void ab_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count);
112 : static void ah_apply(FormStack *st, u32 *group_idx, u32 count);
113 : static void av_apply(FormStack *st, u32 *group_idx, u32 count);
114 :
115 260 : static void form_apply(FormStack *st, const char *constraint, u32 *group_idx, u32 count)
116 : {
117 : Float val;
118 520 : if (!constraint || !strlen(constraint)) return;
119 :
120 : /*SHin*/
121 260 : if (!strnicmp(constraint, "SHin", 4)) {
122 96 : shin_apply(st, group_idx, count);
123 96 : return;
124 : }
125 : /*SH*/
126 164 : if (!strnicmp(constraint, "SH", 2)) {
127 15 : if (sscanf(constraint, "SH %f", &val)==1) {
128 14 : sh_apply(st, FLT2FIX(val), group_idx, count);
129 : } else {
130 1 : sh_apply(st, -FIX_ONE, group_idx, count);
131 : }
132 : return;
133 : }
134 : /*SVin*/
135 149 : if (!strnicmp(constraint, "SVin", 4)) {
136 16 : svin_apply(st, group_idx, count);
137 16 : return;
138 : }
139 : /*SV*/
140 133 : if (!strnicmp(constraint, "SV", 2)) {
141 35 : if (sscanf(constraint, "SV %f", &val)==1) {
142 34 : sv_apply(st, FLT2FIX(val), group_idx, count);
143 : } else {
144 1 : sv_apply(st, -FIX_ONE, group_idx, count);
145 : }
146 : return;
147 : }
148 : /*AL*/
149 98 : if (!strnicmp(constraint, "AL", 2)) {
150 7 : if (sscanf(constraint, "AL %f", &val)==1) {
151 1 : al_apply(st, FLT2FIX(val), group_idx, count);
152 : } else {
153 6 : al_apply(st, -FIX_ONE, group_idx, count);
154 : }
155 : return;
156 : }
157 : /*AR*/
158 91 : if (!strnicmp(constraint, "AR", 2)) {
159 6 : if (sscanf(constraint, "AR %f", &val)==1) {
160 1 : ar_apply(st, FLT2FIX(val), group_idx, count);
161 : } else {
162 5 : ar_apply(st, -FIX_ONE, group_idx, count);
163 : }
164 : return;
165 : }
166 : /*AT*/
167 85 : if (!strnicmp(constraint, "AT", 2)) {
168 7 : if (sscanf(constraint, "AT %f", &val)==1) {
169 1 : at_apply(st, FLT2FIX(val), group_idx, count);
170 : } else {
171 6 : at_apply(st, -FIX_ONE, group_idx, count);
172 : }
173 : return;
174 : }
175 : /*AB*/
176 78 : if (!strnicmp(constraint, "AB", 2)) {
177 39 : if (sscanf(constraint, "AB %f", &val)==1) {
178 1 : ab_apply(st, FLT2FIX(val), group_idx, count);
179 : } else {
180 38 : ab_apply(st, -FIX_ONE, group_idx, count);
181 : }
182 : return;
183 : }
184 : /*AH*/
185 39 : if (!strnicmp(constraint, "AH", 2)) {
186 36 : ah_apply(st, group_idx, count);
187 36 : return;
188 : }
189 : /*AV*/
190 3 : if (!strnicmp(constraint, "AV", 2)) {
191 3 : av_apply(st, group_idx, count);
192 3 : return;
193 : }
194 : }
195 :
196 :
197 : #ifndef MAX_FORM_GROUP_INDEX
198 : #define MAX_FORM_GROUP_INDEX 100
199 : #endif
200 :
201 : /*define to 1 to let the form object clip its children (not specified in spec)*/
202 : #define FORM_CLIPS 1
203 :
204 527 : static void TraverseForm(GF_Node *n, void *rs, Bool is_destroy)
205 : {
206 : #if FORM_CLIPS
207 : GF_Rect prev_clipper;
208 : Bool had_clip;
209 : GF_IRect prev_clip;
210 : #endif
211 : Bool recompute_form;
212 : u32 idx[MAX_FORM_GROUP_INDEX];
213 : u32 i, index, last_ind, j;
214 : u32 mode_bckup;
215 : ParentNode2D *parent_bck;
216 : FormGroup *fg;
217 : ChildGroup *cg;
218 : M_Form *fm = (M_Form *) n;
219 527 : FormStack *st = (FormStack *)gf_node_get_private(n);
220 : GF_TraverseState *tr_state = (GF_TraverseState *) rs;
221 :
222 527 : if (is_destroy) {
223 48 : form_reset(st);
224 48 : gf_list_del(st->grouplist);
225 48 : parent_node_predestroy((ParentNode2D *)st);
226 48 : gf_free(st);
227 569 : return;
228 : }
229 : /*update cliper*/
230 479 : if ((gf_node_dirty_get(n) & GF_SG_NODE_DIRTY)) {
231 : /*get visual size*/
232 48 : visual_get_size_info(tr_state, &st->clip.width, &st->clip.height);
233 : /*setup bounds in local coord system*/
234 48 : if (fm->size.x>=0) st->clip.width = fm->size.x;
235 48 : if (fm->size.y>=0) st->clip.height = fm->size.y;
236 48 : st->bounds = st->clip = gf_rect_center(st->clip.width, st->clip.height);
237 : }
238 : recompute_form = GF_FALSE;
239 479 : if (gf_node_dirty_get(n)) recompute_form = GF_TRUE;
240 :
241 : #if FORM_CLIPS
242 479 : if ((tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) && !tr_state->for_node) {
243 0 : tr_state->bounds = st->clip;
244 : #ifndef GPAC_DISABLE_3D
245 0 : gf_bbox_from_rect(&tr_state->bbox, &st->clip);
246 : #endif
247 0 : return;
248 : }
249 : #endif
250 :
251 479 : if (recompute_form) {
252 : GF_Rect bounds;
253 70 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Form] Recomputing positions\n"));
254 :
255 70 : parent_node_reset((ParentNode2D*)st);
256 :
257 70 : bounds.width = bounds.height = 0;
258 :
259 : /*init traversing state*/
260 70 : parent_bck = tr_state->parent;
261 70 : mode_bckup = tr_state->traversing_mode;
262 70 : tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
263 70 : tr_state->parent = (ParentNode2D *) st;
264 :
265 70 : parent_node_traverse(n, (ParentNode2D *)st, tr_state);
266 :
267 : /*restore traversing state*/
268 70 : tr_state->parent = parent_bck;
269 70 : tr_state->traversing_mode = mode_bckup;
270 :
271 : /*center all nodes*/
272 70 : i=0;
273 918 : while ((cg = (ChildGroup *)gf_list_enum(st->groups, &i))) {
274 778 : cg->final.x = - cg->final.width/2;
275 778 : cg->final.y = cg->final.height/2;
276 : }
277 : /*build groups*/
278 70 : form_reset(st);
279 70 : fg = form_new_group(st);
280 70 : fg->origin = fg->final = st->clip;
281 : fg = NULL;
282 2594 : for (i=0; i<fm->groups.count; i++) {
283 2530 : if (!fg) {
284 955 : fg = form_new_group(st);
285 : }
286 2530 : if (fm->groups.vals[i]==-1) {
287 949 : fg_compute_bounds(fg);
288 : fg = NULL;
289 949 : continue;
290 : }
291 : /*broken form*/
292 1581 : if ((u32) fm->groups.vals[i]>gf_list_count(st->groups)) goto err_exit;
293 1575 : cg = (ChildGroup *)gf_list_get(st->groups, fm->groups.vals[i]-1);
294 1575 : gf_list_add(fg->children, cg);
295 : }
296 :
297 : memset(idx, 0, sizeof(u32)*MAX_FORM_GROUP_INDEX);
298 : last_ind = 0;
299 260 : for (i=0; i<fm->constraints.count; i++) {
300 : index = 0;
301 : while (1) {
302 2470 : if (last_ind+index > fm->groupsIndex.count) goto err_exit;
303 1365 : if (fm->groupsIndex.vals[last_ind+index]==-1) break;
304 1105 : if (index>=MAX_FORM_GROUP_INDEX) goto err_exit;
305 1105 : idx[index] = fm->groupsIndex.vals[last_ind+index];
306 1105 : index++;
307 : }
308 : /*apply*/
309 260 : form_apply(st, fm->constraints.vals[i], idx, index);
310 260 : index++;
311 260 : last_ind += index;
312 :
313 : /*refresh all group bounds*/
314 260 : j=1;
315 7775 : while ((fg = (FormGroup*)gf_list_enum(st->grouplist, &j))) {
316 7255 : fg_compute_bounds(fg);
317 7255 : gf_rect_union(&bounds, &fg->final);
318 : }
319 : /*done*/
320 260 : if (last_ind>=fm->groupsIndex.count) break;
321 : }
322 64 : form_reset(st);
323 :
324 : #if !FORM_CLIPS
325 : st->clip = bounds;
326 : #endif
327 : }
328 :
329 : /*check picking*/
330 473 : if ((tr_state->traversing_mode==TRAVERSE_PICK) && !gf_sc_pick_in_clipper(tr_state, &st->clip))
331 : return;
332 :
333 : #if !FORM_CLIPS
334 : if ((tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) && !tr_state->for_node) {
335 : tr_state->bounds = st->clip;
336 : gf_bbox_from_rect(&tr_state->bbox, &st->clip);
337 : return;
338 : }
339 : #endif
340 : /*According to the spec clipping is not required on form so we don't do it*/
341 : #if FORM_CLIPS
342 : /*update clipper*/
343 454 : if (tr_state->traversing_mode==TRAVERSE_SORT) {
344 286 : prev_clip = tr_state->visual->top_clipper;
345 286 : compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, GF_FALSE);
346 286 : if (tr_state->has_clip) {
347 286 : tr_state->visual->top_clipper = gf_rect_pixelize(&tr_state->clipper);
348 286 : gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip);
349 : }
350 :
351 : #ifndef GPAC_DISABLE_3D
352 286 : if (tr_state->visual->type_3d)
353 140 : visual_3d_reset_clipper_2d(tr_state->visual);
354 : #endif
355 :
356 286 : i=0;
357 1800 : while ((cg = (ChildGroup*)gf_list_enum(st->groups, &i))) {
358 1228 : parent_node_child_traverse(cg, tr_state);
359 : }
360 :
361 : #ifndef GPAC_DISABLE_3D
362 286 : if (tr_state->visual->type_3d)
363 140 : visual_3d_reset_clipper_2d(tr_state->visual);
364 : #endif
365 286 : tr_state->visual->top_clipper = prev_clip;
366 286 : if (had_clip) tr_state->clipper = prev_clipper;
367 286 : tr_state->has_clip = had_clip;
368 : } else
369 : #endif
370 : {
371 168 : i=0;
372 7730 : while ((cg = (ChildGroup*)gf_list_enum(st->groups, &i))) {
373 7394 : parent_node_child_traverse(cg, tr_state);
374 : }
375 : }
376 :
377 : return;
378 :
379 : err_exit:
380 6 : parent_node_reset((ParentNode2D*)st);
381 6 : form_reset(st);
382 : }
383 :
384 48 : void compositor_init_form(GF_Compositor *compositor, GF_Node *node)
385 : {
386 : FormStack *stack;
387 48 : GF_SAFEALLOC(stack, FormStack);
388 48 : if (!stack) {
389 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate form stack\n"));
390 : return;
391 : }
392 :
393 48 : parent_node_setup((ParentNode2D*)stack);
394 48 : stack->grouplist = gf_list_new();
395 48 : gf_node_set_private(node, stack);
396 48 : gf_node_set_callback_function(node, TraverseForm);
397 : }
398 :
399 :
400 : /*
401 : FORM CONSTRAINTS
402 : */
403 :
404 :
405 96 : static void shin_apply(FormStack *st, u32 *group_idx, u32 count)
406 : {
407 : u32 i, len;
408 : Fixed tot_len, inter_space;
409 : tot_len = 0;
410 96 : inter_space = st->clip.width;
411 :
412 : len = 0;
413 783 : for (i=0; i<count; i++) {
414 687 : if (group_idx[i] != 0) {
415 1374 : tot_len += form_get_group(st, group_idx[i])->final.width;
416 687 : len++;
417 : }
418 : }
419 96 : inter_space -= tot_len;
420 96 : inter_space /= (len+1);
421 :
422 783 : for (i=0; i<count; i++) {
423 687 : if(group_idx[i] == 0) continue;
424 687 : if (!i) {
425 192 : form_get_group(st, group_idx[0])->final.x = st->clip.x + inter_space;
426 : } else {
427 1182 : form_get_group(st, group_idx[i])->final.x =
428 1773 : form_get_group(st, group_idx[i-1])->final.x + form_get_group(st, group_idx[i-1])->final.width
429 591 : + inter_space;
430 : }
431 1374 : fg_update_bounds(form_get_group(st, group_idx[i]));
432 : }
433 96 : }
434 :
435 15 : static void sh_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
436 : {
437 : u32 i, k;
438 : GF_Rect *l, *r;
439 : Fixed inter_space, tot_len;
440 :
441 : tot_len = 0;
442 15 : if (space == -FIX_ONE) {
443 1 : r = &form_get_group(st, group_idx[count-1])->final;
444 1 : l = &form_get_group(st, group_idx[0])->final;
445 1 : inter_space = r->x - l->x;
446 1 : if(group_idx[0] != 0) inter_space -= l->width;
447 2 : for (i=1; i<count-1; i++) tot_len += form_get_group(st, group_idx[i])->final.width;
448 1 : inter_space -= tot_len;
449 1 : inter_space /= (count-1);
450 : } else {
451 : inter_space = space;
452 : }
453 :
454 15 : k = count - 1;
455 15 : if (space != -1) k += 1;
456 31 : for (i=1; i<k; i++) {
457 16 : if (group_idx[i] ==0) continue;
458 16 : l = &form_get_group(st, group_idx[i-1])->final;
459 16 : r = &form_get_group(st, group_idx[i])->final;
460 16 : r->x = l->x + inter_space;
461 16 : if(group_idx[i-1] != 0) r->x += l->width;
462 32 : fg_update_bounds(form_get_group(st, group_idx[i]));
463 : }
464 15 : }
465 :
466 16 : static void svin_apply(FormStack *st, u32 *group_idx, u32 count)
467 : {
468 : u32 i, len;
469 : Fixed tot_len, inter_space;
470 : tot_len = 0;
471 16 : inter_space = st->clip.height;
472 : len = 0;
473 114 : for (i=0; i<count; i++) {
474 98 : if (group_idx[i] != 0) {
475 196 : tot_len += form_get_group(st, group_idx[i])->final.height;
476 98 : len++;
477 : }
478 : }
479 16 : inter_space -= tot_len;
480 16 : inter_space /= (len+1);
481 :
482 114 : for (i=0; i<count; i++) {
483 98 : if (group_idx[i] == 0) continue;
484 98 : if (!i) {
485 32 : form_get_group(st, group_idx[0])->final.y = st->clip.y - inter_space;
486 : } else {
487 164 : form_get_group(st, group_idx[i])->final.y =
488 328 : form_get_group(st, group_idx[i-1])->final.y - form_get_group(st, group_idx[i-1])->final.height -
489 : inter_space;
490 : }
491 196 : fg_update_bounds(form_get_group(st, group_idx[i]));
492 : }
493 16 : }
494 :
495 35 : static void sv_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
496 : {
497 : u32 i, k;
498 : Fixed tot_len, inter_space;
499 :
500 : tot_len = 0;
501 35 : if(space > -FIX_ONE) {
502 : inter_space = space;
503 : } else {
504 1 : GF_Rect *t = &form_get_group(st, group_idx[count-1])->final;
505 1 : GF_Rect *b = &form_get_group(st, group_idx[0])->final;
506 1 : inter_space = b->y - t->y;
507 1 : if (group_idx[0]!=0) inter_space -= t->height;
508 2 : for (i=1; i<count-1; i++) tot_len += form_get_group(st, group_idx[i])->final.height;
509 1 : inter_space -= tot_len;
510 1 : inter_space /= count-1;
511 : }
512 :
513 35 : k = count-1;
514 35 : if (space > -1) k += 1;
515 81 : for (i=1; i<k; i++) {
516 46 : if (group_idx[i] == 0) continue;
517 138 : form_get_group(st, group_idx[i])->final.y = form_get_group(st, group_idx[i-1])->final.y - inter_space;
518 46 : if (group_idx[i-1] != 0) {
519 39 : form_get_group(st, group_idx[i])->final.y -= form_get_group(st, group_idx[i-1])->final.height;
520 : }
521 92 : fg_update_bounds(form_get_group(st, group_idx[i]));
522 : }
523 35 : }
524 :
525 7 : static void al_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
526 : {
527 : Fixed min_x;
528 : GF_Rect *rc;
529 : u32 i, start;
530 :
531 : start = 0;
532 14 : min_x = form_get_group(st, group_idx[0])->final.x;
533 7 : if (space>-FIX_ONE) {
534 : start = 1;
535 1 : min_x += space;
536 : } else {
537 6 : for (i=1; i<count; i++) {
538 6 : rc = &form_get_group(st, group_idx[0])->final;
539 6 : if (group_idx[i]==0) {
540 0 : min_x = rc->x;
541 0 : break;
542 : }
543 6 : if (rc->x < min_x) min_x = rc->x;
544 : }
545 : }
546 20 : for (i=start; i<count; i++) {
547 13 : if( group_idx[i] == 0) continue;
548 14 : form_get_group(st, group_idx[i])->final.x = min_x;
549 14 : fg_update_bounds(form_get_group(st, group_idx[i]));
550 : }
551 7 : }
552 :
553 6 : static void ar_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
554 : {
555 : Fixed max_x;
556 : u32 i, start;
557 : GF_Rect *rc;
558 :
559 : start = 0;
560 6 : rc = &form_get_group(st, group_idx[0])->final;
561 6 : max_x = rc->x + rc->width;
562 :
563 6 : if(space>-FIX_ONE) {
564 1 : max_x -= space;
565 : start = 1;
566 : } else {
567 5 : for (i=1; i<count; i++) {
568 5 : rc = &form_get_group(st, group_idx[i])->final;
569 5 : if (group_idx[i]==0) {
570 0 : max_x = rc->x + rc->width;
571 0 : break;
572 : }
573 5 : if (rc->x + rc->width > max_x) max_x = rc->x + rc->width;
574 : }
575 : }
576 17 : for (i=start; i<count; i++) {
577 11 : if(group_idx[i] == 0) continue;
578 6 : rc = &form_get_group(st, group_idx[i])->final;
579 6 : rc->x = max_x - rc->width;
580 12 : fg_update_bounds(form_get_group(st, group_idx[i]));
581 : }
582 6 : }
583 :
584 7 : static void at_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
585 : {
586 : Fixed max_y;
587 : u32 i, start;
588 : GF_Rect *rc;
589 :
590 : start = 0;
591 14 : max_y = form_get_group(st, group_idx[0])->final.y;
592 7 : if(space>-FIX_ONE) {
593 : start = 1;
594 1 : max_y -= space;
595 : } else {
596 6 : for (i=1; i<count; i++) {
597 6 : rc = &form_get_group(st, group_idx[i])->final;
598 6 : if (group_idx[i]==0) {
599 0 : max_y = rc->y;
600 0 : break;
601 : }
602 6 : if (rc->y > max_y) max_y = rc->y;
603 : }
604 : }
605 :
606 20 : for (i=start; i<count; i++) {
607 13 : if(group_idx[i] == 0) continue;
608 14 : form_get_group(st, group_idx[i])->final.y = max_y;
609 14 : fg_update_bounds(form_get_group(st, group_idx[i]));
610 : }
611 7 : }
612 :
613 39 : static void ab_apply(FormStack *st, Fixed space, u32 *group_idx, u32 count)
614 : {
615 : Fixed min_y;
616 : u32 i, start;
617 : GF_Rect *rc;
618 :
619 : start = 0;
620 39 : rc = &form_get_group(st, group_idx[0])->final;
621 39 : min_y = rc->y - rc->height;
622 39 : if(space>-FIX_ONE) {
623 : start = 1;
624 1 : min_y += space;
625 : } else {
626 38 : for (i=1; i<count; i++) {
627 38 : rc = &form_get_group(st, group_idx[i])->final;
628 38 : if (group_idx[i]==0) {
629 0 : min_y = rc->y - rc->height;
630 0 : break;
631 : }
632 38 : if (rc->y - rc->height < min_y) min_y = rc->y - rc->height;
633 : }
634 : }
635 116 : for (i=start; i<count; i++) {
636 77 : if(group_idx[i] == 0) continue;
637 39 : rc = &form_get_group(st, group_idx[i])->final;
638 39 : rc->y = min_y + rc->height;
639 78 : fg_update_bounds(form_get_group(st, group_idx[i]));
640 : }
641 39 : }
642 :
643 36 : static void ah_apply(FormStack *st, u32 *group_idx, u32 count)
644 : {
645 : GF_Rect *rc;
646 : u32 i;
647 : Fixed left, right, center;
648 : left = right = center = 0;
649 :
650 42 : for (i=0; i<count; i++) {
651 39 : rc = &form_get_group(st, group_idx[i])->final;
652 39 : if(group_idx[i] == 0) {
653 33 : center = rc->x + rc->width / 2;
654 33 : break;
655 : }
656 6 : if (left > rc->x) left = rc->x;
657 6 : if (right < rc->x + rc->width) right = rc->x + rc->width;
658 6 : center = (left+right)/2;
659 : }
660 :
661 118 : for (i=0; i<count; i++) {
662 82 : if(group_idx[i] == 0) continue;
663 49 : rc = &form_get_group(st, group_idx[i])->final;
664 49 : rc->x = center - rc->width/2;
665 98 : fg_update_bounds(form_get_group(st, group_idx[i]));
666 : }
667 36 : }
668 :
669 3 : static void av_apply(FormStack *st, u32 *group_idx, u32 count)
670 : {
671 : u32 i;
672 : Fixed top, bottom, center;
673 : GF_Rect *rc;
674 : top = bottom = center = 0;
675 :
676 9 : for (i=0; i<count; i++) {
677 6 : rc = &form_get_group(st, group_idx[i])->final;
678 6 : if (group_idx[i] == 0) {
679 0 : center = rc->y - rc->height / 2;
680 0 : break;
681 : }
682 6 : if (top < rc->y) top = rc->y;
683 6 : if (bottom > rc->y - rc->height) bottom = rc->y - rc->height;
684 6 : center = (top+bottom)/2;
685 : }
686 :
687 9 : for (i=0; i<count; i++) {
688 6 : if(group_idx[i] == 0) continue;
689 6 : rc = &form_get_group(st, group_idx[i])->final;
690 6 : rc->y = center + rc->height/2;
691 12 : fg_update_bounds(form_get_group(st, group_idx[i]));
692 : }
693 3 : }
694 :
695 : #endif /*GPAC_DISABLE_VRML*/
|