LCOV - code coverage report
Current view: top level - compositor - mpeg4_layout.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 330 431 76.6 %
Date: 2021-04-29 23:48:07 Functions: 10 13 76.9 %

          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             : #include "nodes_stacks.h"
      27             : #include "mpeg4_grouping.h"
      28             : #include "visual_manager.h"
      29             : 
      30             : #ifndef GPAC_DISABLE_VRML
      31             : 
      32             : typedef struct
      33             : {
      34             :         PARENT_MPEG4_STACK_2D
      35             : 
      36             :         Bool is_scrolling;
      37             :         u32 start_scroll_type;
      38             :         Double start_time, pause_time;
      39             :         GF_List *lines;
      40             :         GF_Rect clip;
      41             :         Fixed last_scroll, prev_rate, scroll_rate, scale_scroll, scroll_len, scroll_min, scroll_max;
      42             : 
      43             :         /*for keyboard navigation*/
      44             :         GF_SensorHandler hdl;
      45             :         s32 key_scroll;
      46             :         Bool keys_active;
      47             : } LayoutStack;
      48             : 
      49             : typedef struct
      50             : {
      51             :         Fixed width, height, ascent, descent;
      52             :         u32 first_child, nb_children;
      53             :         Bool line_break;
      54             : } LineInfo;
      55             : 
      56         348 : static void layout_reset_lines(LayoutStack *st)
      57             : {
      58         612 :         while (gf_list_count(st->lines)) {
      59         264 :                 LineInfo *li = (LineInfo *)gf_list_get(st->lines, 0);
      60         264 :                 gf_list_rem(st->lines, 0);
      61         264 :                 gf_free(li);
      62             :         }
      63         348 : }
      64             : 
      65         264 : static LineInfo *new_line_info(LayoutStack *st)
      66             : {
      67             :         LineInfo *li;
      68         264 :         GF_SAFEALLOC(li, LineInfo);
      69         264 :         if (li)
      70         264 :                 gf_list_add(st->lines, li);
      71         264 :         return li;
      72             : }
      73             : 
      74             : 
      75             : enum
      76             : {
      77             :         L_FIRST,
      78             :         L_BEGIN,
      79             :         L_MIDDLE,
      80             :         L_END,
      81             :         L_JUSTIFY,
      82             : };
      83             : 
      84         388 : static u32 get_justify(M_Layout *l, u32 i)
      85             : {
      86         388 :         if (l->justify.count <= i) return L_BEGIN;
      87         379 :         if (!strcmp(l->justify.vals[i], "END")) return L_END;
      88         283 :         if (!strcmp(l->justify.vals[i], "MIDDLE")) return L_MIDDLE;
      89         188 :         if (!strcmp(l->justify.vals[i], "FIRST")) return L_FIRST;
      90         164 :         if (!strcmp(l->justify.vals[i], "SPREAD")) return L_JUSTIFY;
      91         164 :         if (!strcmp(l->justify.vals[i], "JUSTIFY")) return L_JUSTIFY;
      92             :         return L_BEGIN;
      93             : }
      94             : 
      95         178 : static void get_lines_info(LayoutStack *st, M_Layout *l)
      96             : {
      97             :         Fixed prev_discard_width;
      98             :         u32 i, count;
      99             :         LineInfo *li;
     100             :         Fixed max_w, max_h;
     101             : 
     102         178 :         max_w = st->clip.width;
     103         178 :         max_h = st->clip.height;
     104         178 :         layout_reset_lines(st);
     105             : 
     106         178 :         count = gf_list_count(st->groups);
     107         178 :         if (!count) return;
     108             : 
     109         172 :         li = new_line_info(st);
     110         172 :         li->first_child = 0;
     111             :         prev_discard_width = 0;
     112             : 
     113         797 :         for (i=0; i<count; i++) {
     114         797 :                 ChildGroup *cg = (ChildGroup *)gf_list_get(st->groups, i);
     115         797 :                 if (!l->horizontal) {
     116             :                         /*check if exceed column size or not - if so, move to next column or clip given wrap mode*/
     117         298 :                         if (cg->final.height + li->height > max_h) {
     118          40 :                                 if (l->wrap) {
     119          40 :                                         li = new_line_info(st);
     120          40 :                                         li->first_child = i;
     121             :                                 }
     122             :                         }
     123         298 :                         if (cg->final.width > li->width) li->width = cg->final.width;
     124         298 :                         li->height += cg->final.height;
     125         298 :                         li->nb_children ++;
     126             :                 } else {
     127         499 :                         if ((cg->text_type==2) || (i && (cg->final.width + li->width> max_w))) {
     128          52 :                                 if (cg->text_type==2) li->line_break = 1;
     129          52 :                                 if (l->wrap) {
     130          52 :                                         if (!li->ascent) {
     131           1 :                                                 li->ascent = li->height;
     132           1 :                                                 li->descent = 0;
     133             :                                         }
     134             :                                         /*previous word is discardable (' ')*/
     135          52 :                                         if (prev_discard_width) {
     136           3 :                                                 li->width -= prev_discard_width;
     137           3 :                                                 li->nb_children--;
     138             :                                         }
     139          52 :                                         if ((cg->text_type==1) && (i+1==count)) break;
     140             : 
     141          52 :                                         li = new_line_info(st);
     142          52 :                                         li->first_child = i;
     143          52 :                                         if (cg->text_type) {
     144           0 :                                                 li->first_child++;
     145           0 :                                                 continue;
     146             :                                         }
     147             :                                 }
     148             :                         }
     149             : 
     150             :                         /*get ascent/descent for text or height for non-text*/
     151         499 :                         if (cg->ascent) {
     152         233 :                                 if (li->ascent < cg->ascent) li->ascent = cg->ascent;
     153         233 :                                 if (li->descent < cg->descent) li->descent = cg->descent;
     154         233 :                                 if (li->height < li->ascent + li->descent) li->height = li->ascent + li->descent;
     155         266 :                         } else if (cg->final.height > li->height) {
     156         158 :                                 li->height = cg->final.height;
     157             :                         }
     158         499 :                         li->width += cg->final.width;
     159         499 :                         li->nb_children ++;
     160             : 
     161         499 :                         prev_discard_width = (cg->text_type==1) ? cg->final.width : 0;
     162             : 
     163             :                 }
     164             :         }
     165             : }
     166             : 
     167             : 
     168         178 : static void layout_justify(LayoutStack *st, M_Layout *l)
     169             : {
     170             :         u32 first, minor, major, i, k, nbLines;
     171             :         Fixed current_top, current_left, h;
     172             :         LineInfo *li;
     173             :         ChildGroup *cg, *prev;
     174         178 :         get_lines_info(st, l);
     175         178 :         major = get_justify(l, 0);
     176         178 :         minor = get_justify(l, 1);
     177             : 
     178         178 :         st->scroll_len = 0;
     179         178 :         nbLines = gf_list_count(st->lines);
     180         178 :         if (l->horizontal) {
     181         116 :                 if (l->wrap && !l->topToBottom) {
     182          24 :                         li = (LineInfo*)gf_list_get(st->lines, 0);
     183          24 :                         current_top = st->clip.y - st->clip.height;
     184          24 :                         if (li) current_top += li->height;
     185             :                 } else {
     186          92 :                         current_top = st->clip.y;
     187             :                 }
     188             : 
     189             :                 /*for each line perform adjustment*/
     190         162 :                 for (k=0; k<nbLines; k++) {
     191             :                         Fixed spacing = 0;
     192         162 :                         li = (LineInfo*)gf_list_get(st->lines, k);
     193         162 :                         first = li->first_child;
     194         162 :                         if (!l->leftToRight) first += li->nb_children - 1;
     195             : 
     196         162 :                         if (!l->topToBottom && k) current_top += li->height;
     197             : 
     198             :                         /*set major alignment (X) */
     199         162 :                         cg = (ChildGroup *)gf_list_get(st->groups, first);
     200         162 :                         if (!cg) continue;
     201         162 :                         switch (major) {
     202          49 :                         case L_END:
     203          49 :                                 cg->final.x = st->clip.x + st->clip.width - li->width;
     204          49 :                                 break;
     205          49 :                         case L_MIDDLE:
     206          49 :                                 cg->final.x = st->clip.x + (st->clip.width - li->width)/2;
     207          49 :                                 break;
     208          64 :                         case L_FIRST:
     209             :                         case L_BEGIN:
     210          64 :                                 cg->final.x = st->clip.x;
     211          64 :                                 break;
     212           0 :                         case L_JUSTIFY:
     213           0 :                                 cg->final.x = st->clip.x;
     214           0 :                                 if (li->nb_children>1) {
     215           0 :                                         cg = (ChildGroup *)gf_list_get(st->groups, li->nb_children-1);
     216           0 :                                         spacing = (st->clip.width - li->width) / (li->nb_children-1) ;
     217           0 :                                         if (spacing<0) spacing = 0;
     218           0 :                                         else if (cg->ascent) {
     219             :                                                 /*disable spacing for last text line and line breaks*/
     220           0 :                                                 if ( (k+1==nbLines) || li->line_break) {
     221             :                                                         spacing = 0;
     222             :                                                 }
     223             :                                         }
     224             :                                 }
     225             :                                 break;
     226             :                         }
     227             : 
     228             : 
     229             :                         /*for each in the run */
     230             :                         i = first;
     231             :                         while (1) {
     232         496 :                                 cg = (ChildGroup *)gf_list_get(st->groups, i);
     233         496 :                                 if (!cg) break;
     234         496 :                                 h = MAX(li->ascent, li->height);
     235         496 :                                 switch (minor) {
     236         108 :                                 case L_FIRST:
     237         108 :                                         cg->final.y = current_top - h;
     238         108 :                                         if (cg->ascent) {
     239          48 :                                                 cg->final.y += cg->ascent;
     240             :                                         } else {
     241          60 :                                                 cg->final.y += cg->final.height;
     242             :                                         }
     243             :                                         break;
     244         108 :                                 case L_MIDDLE:
     245         108 :                                         cg->final.y = current_top - (h - cg->final.height)/2;
     246         108 :                                         break;
     247         134 :                                 case L_END:
     248         134 :                                         cg->final.y = current_top;
     249         134 :                                         break;
     250         146 :                                 case L_BEGIN:
     251             :                                 default:
     252         146 :                                         cg->final.y = current_top - h + cg->final.height;
     253         146 :                                         break;
     254             :                                 }
     255             :                                 /*update left for non-first children in line*/
     256         496 :                                 if (i != first) {
     257         334 :                                         if (l->leftToRight) {
     258         214 :                                                 prev = (ChildGroup *)gf_list_get(st->groups, i-1);
     259             :                                         } else {
     260         120 :                                                 prev = (ChildGroup *)gf_list_get(st->groups, i+1);
     261             :                                         }
     262         334 :                                         cg->final.x = prev->final.x + prev->final.width + spacing;
     263             :                                 }
     264         496 :                                 i += l->leftToRight ? +1 : -1;
     265         496 :                                 if (l->leftToRight && (i==li->first_child + li->nb_children))
     266             :                                         break;
     267         394 :                                 else if (!l->leftToRight && (i==li->first_child - 1))
     268             :                                         break;
     269             :                         }
     270         162 :                         if (l->topToBottom) {
     271         114 :                                 current_top -= gf_mulfix(l->spacing, li->height);
     272             :                         } else {
     273          48 :                                 current_top += gf_mulfix(l->spacing - FIX_ONE, li->height);
     274             :                         }
     275         162 :                         if (l->scrollVertical) {
     276         156 :                                 st->scroll_len += li->height;
     277             :                         } else {
     278           6 :                                 if (st->scroll_len < li->width) st->scroll_len = li->width;
     279             :                         }
     280             :                 }
     281             :                 return;
     282             :         }
     283             : 
     284             :         /*Vertical aligment*/
     285          62 :         li = (LineInfo*)gf_list_get(st->lines, 0);
     286          62 :         if (l->wrap && !l->leftToRight) {
     287          18 :                 current_left = st->clip.x + st->clip.width;
     288          18 :                 if (li) current_left -= li->width;
     289             :         } else {
     290          44 :                 current_left = st->clip.x;
     291             :         }
     292             : 
     293             :         /*for all columns in run*/
     294         102 :         for (k=0; k<nbLines; k++) {
     295             :                 Fixed spacing = 0;
     296         102 :                 li = (LineInfo*)gf_list_get(st->lines, k);
     297             : 
     298         102 :                 first = li->first_child;
     299         102 :                 if (!l->topToBottom) first += li->nb_children - 1;
     300             : 
     301             :                 /*set major alignment (Y) */
     302         102 :                 cg = (ChildGroup *)gf_list_get(st->groups, first);
     303         102 :                 switch (major) {
     304          30 :                 case L_END:
     305          30 :                         cg->final.y = st->clip.y - st->clip.height + li->height;
     306          30 :                         break;
     307          30 :                 case L_MIDDLE:
     308          30 :                         cg->final.y = st->clip.y - st->clip.height/2 + li->height/2;
     309          30 :                         break;
     310          42 :                 case L_FIRST:
     311             :                 case L_BEGIN:
     312          42 :                         cg->final.y = st->clip.y;
     313          42 :                         break;
     314           0 :                 case L_JUSTIFY:
     315           0 :                         cg->final.y = st->clip.y;
     316           0 :                         if (li->nb_children>1) {
     317           0 :                                 spacing = (st->clip.height - li->height) / (li->nb_children-1) ;
     318           0 :                                 if (spacing<0) spacing = 0;
     319             :                         }
     320             :                         break;
     321             :                 }
     322             : 
     323             :                 /*for each in the run */
     324             :                 i = first;
     325             :                 while (1) {
     326         298 :                         cg = (ChildGroup *)gf_list_get(st->groups, i);
     327         298 :                         switch (minor) {
     328          90 :                         case L_MIDDLE:
     329          90 :                                 cg->final.x = current_left + li->width/2 - cg->final.width/2;
     330          90 :                                 break;
     331          90 :                         case L_END:
     332          90 :                                 cg->final.x = current_left + li->width - cg->final.width;
     333          90 :                                 break;
     334         118 :                         case L_BEGIN:
     335             :                         case L_FIRST:
     336             :                         default:
     337         118 :                                 cg->final.x = current_left;
     338         118 :                                 break;
     339             :                         }
     340             :                         /*update top for non-first children in line*/
     341         298 :                         if (i != first) {
     342         196 :                                 if (l->topToBottom) {
     343         106 :                                         prev = (ChildGroup *)gf_list_get(st->groups, i-1);
     344             :                                 } else {
     345          90 :                                         prev = (ChildGroup *)gf_list_get(st->groups, i+1);
     346             :                                 }
     347         196 :                                 cg->final.y = prev->final.y - prev->final.height + spacing;
     348             :                         }
     349         298 :                         i += l->topToBottom ? +1 : -1;
     350         298 :                         if (l->topToBottom && (i==li->first_child + li->nb_children))
     351             :                                 break;
     352         241 :                         else if (!l->topToBottom && (i==li->first_child - 1))
     353             :                                 break;
     354             :                 }
     355         102 :                 if (l->leftToRight) {
     356          66 :                         current_left += gf_mulfix(l->spacing, li->width);
     357          36 :                 } else if (k < nbLines - 1) {
     358          18 :                         li = (LineInfo*)gf_list_get(st->lines, k+1);
     359          18 :                         current_left -= gf_mulfix(l->spacing, li->width);
     360             :                 }
     361         102 :                 if (l->scrollVertical) {
     362          96 :                         if (st->scroll_len < li->height) st->scroll_len = li->height;
     363             :                 } else {
     364           6 :                         st->scroll_len += li->width;
     365             :                 }
     366             :         }
     367             : }
     368             : 
     369          25 : static void layout_setup_scroll_bounds(LayoutStack *st, M_Layout *l)
     370             : {
     371             :         u32 minor_justify = 0;
     372             : 
     373          25 :         st->scroll_min = st->scroll_max = 0;
     374             : 
     375          25 :         if (l->horizontal) minor_justify = l->scrollVertical ? 1 : 0;
     376          11 :         else minor_justify = l->scrollVertical ? 0 : 1;
     377             : 
     378             :         /*update scroll-out max limit*/
     379          25 :         if (l->scrollMode != -1) {
     380             :                 /*set max limit*/
     381          13 :                 switch( get_justify(l, minor_justify)) {
     382           0 :                 case L_END:
     383           0 :                         if (l->scrollVertical) {
     384           0 :                                 if (st->scale_scroll<0) st->scroll_max = - st->scroll_len;
     385           0 :                                 else st->scroll_max = st->clip.height;
     386             :                         } else {
     387           0 :                                 if (st->scale_scroll<0) st->scroll_max = - st->clip.width;
     388           0 :                                 else st->scroll_max = st->scroll_len;
     389             :                         }
     390             :                         break;
     391           0 :                 case L_MIDDLE:
     392           0 :                         if (l->scrollVertical) {
     393           0 :                                 if (st->scale_scroll<0) st->scroll_max = - (st->clip.height + st->scroll_len)/2;
     394           0 :                                 else st->scroll_max = (st->clip.height + st->scroll_len)/2;
     395             :                         } else {
     396           0 :                                 if (st->scale_scroll<0) st->scroll_max = - (st->clip.width + st->scroll_len)/2;
     397           0 :                                 else st->scroll_max = (st->clip.width + st->scroll_len)/2;
     398             :                         }
     399             :                         break;
     400          13 :                 default:
     401          13 :                         if (l->scrollVertical) {
     402           8 :                                 if (st->scale_scroll<0) st->scroll_max = - st->clip.height;
     403           4 :                                 else st->scroll_max = st->scroll_len;
     404             :                         } else {
     405           5 :                                 if (st->scale_scroll<0) st->scroll_max = - st->scroll_len;
     406           3 :                                 else st->scroll_max = st->clip.width;
     407             :                         }
     408             :                         break;
     409             :                 }
     410             :         }
     411             :         /*scroll-in only*/
     412             :         else {
     413             :                 st->scroll_max = 0;
     414             :         }
     415             : 
     416             :         /*scroll-out only*/
     417          25 :         if (l->scrollMode==1) {
     418             :                 st->scroll_min = 0;
     419             :                 return;
     420             :         }
     421             : 
     422             :         /*when vertically scrolling an horizontal layout, don't use vertical justification, only justify top/bottom lines*/
     423          25 :         if (l->horizontal && l->scrollVertical) {
     424           6 :                 if (st->scale_scroll<0) {
     425           3 :                         st->scroll_min = st->scroll_len;
     426             :                 } else {
     427           3 :                         st->scroll_min = - st->clip.height;
     428             :                 }
     429             :                 return;
     430             :         }
     431             : 
     432             :         /*update scroll-in offset*/
     433          19 :         switch( get_justify(l, minor_justify)) {
     434           2 :         case L_END:
     435           2 :                 if (l->scrollVertical) {
     436           0 :                         if (st->scale_scroll<0) st->scroll_min = st->clip.height;
     437           0 :                         else st->scroll_min = - st->scroll_len;
     438             :                 } else {
     439           2 :                         if (st->scale_scroll<0) st->scroll_min = st->scroll_len;
     440           2 :                         else st->scroll_min = -st->clip.width;
     441             :                 }
     442             :                 break;
     443           2 :         case L_MIDDLE:
     444           2 :                 if (l->scrollVertical) {
     445           0 :                         if (st->scale_scroll<0) st->scroll_min = (st->clip.height + st->scroll_len)/2;
     446           0 :                         else st->scroll_min = - (st->clip.height + st->scroll_len)/2;
     447             :                 } else {
     448           2 :                         if (st->scale_scroll<0) st->scroll_min = (st->clip.width + st->scroll_len)/2;
     449           2 :                         else st->scroll_min = - (st->clip.width + st->scroll_len)/2;
     450             :                 }
     451             :                 break;
     452          15 :         default:
     453          15 :                 if (l->scrollVertical) {
     454           6 :                         if (st->scale_scroll<0) st->scroll_min = st->scroll_len;
     455           5 :                         else st->scroll_min = - st->clip.height;
     456             :                 } else {
     457           9 :                         if (st->scale_scroll<0) st->scroll_min = st->clip.width;
     458           7 :                         else st->scroll_min = - st->scroll_len;
     459             :                 }
     460             :                 break;
     461             :         }
     462             : }
     463             : 
     464             : 
     465         879 : static void layout_scroll(GF_TraverseState *tr_state, LayoutStack *st, M_Layout *l)
     466             : {
     467             :         u32 i, nb_lines;
     468             :         Fixed scrolled, rate, elapsed, scroll_diff;
     469             :         Bool smooth, do_scroll, stop_anim;
     470             :         Double time = 0;
     471             :         ChildGroup *cg;
     472             : 
     473             :         /*not scrolling*/
     474        1757 :         if (!st->scale_scroll && !st->is_scrolling && !st->key_scroll) return;
     475             : 
     476         433 :         if (st->key_scroll) {
     477           0 :                 if (!st->is_scrolling) {
     478           0 :                         layout_setup_scroll_bounds(st, l);
     479           0 :                         st->is_scrolling = 1;
     480             :                 }
     481             : 
     482           0 :                 scrolled = st->last_scroll + INT2FIX(st->key_scroll);
     483             :         } else {
     484             : 
     485         433 :                 time = gf_node_get_scene_time((GF_Node *)l);
     486             : 
     487             :                 //      if (st->scale_scroll && (st->prev_rate!=st->scale_scroll)) st->start_scroll_type = 1;
     488             : 
     489             :                 /*if scroll rate changed to previous non-zero value, this is a
     490             :                 scroll restart, don't re-update bounds*/
     491         433 :                 if ((st->start_scroll_type==2) && (st->prev_rate==st->scale_scroll)) st->start_scroll_type = 0;
     492             : 
     493         433 :                 if (st->start_scroll_type) {
     494          19 :                         st->start_time = time;
     495          19 :                         st->is_scrolling = 1;
     496          19 :                         st->prev_rate = st->scale_scroll;
     497             : 
     498             :                         /*continuous restart: use last scroll to update the start time. We must recompute scroll bounds
     499             :                         since switching from scroll_rate >0 to <0 changes the bounds !*/
     500          19 :                         if ((st->start_scroll_type==2) && st->scale_scroll) {
     501           2 :                                 Fixed cur_pos = st->scroll_min + st->last_scroll;
     502           2 :                                 layout_setup_scroll_bounds(st, l);
     503           2 :                                 cur_pos -= st->scroll_min;
     504           2 :                                 st->start_time = time - FIX2FLT(gf_divfix(cur_pos, st->scale_scroll));
     505             :                         } else {
     506          17 :                                 layout_setup_scroll_bounds(st, l);
     507             :                         }
     508          19 :                         st->last_scroll = 0;
     509          19 :                         st->start_scroll_type = 0;
     510             :                 }
     511             : 
     512             :                 /*handle pause/resume*/
     513         433 :                 rate = st->scale_scroll;
     514         433 :                 if (!rate) {
     515          41 :                         if (!st->pause_time) {
     516           1 :                                 st->pause_time = time;
     517             :                         } else {
     518             :                                 time = st->pause_time;
     519             :                         }
     520          41 :                         rate = st->prev_rate;
     521         392 :                 } else if (st->pause_time) {
     522           1 :                         st->start_time += (time - st->pause_time);
     523           1 :                         st->pause_time = 0;
     524             :                 }
     525             : 
     526             :                 /*compute advance in pixels for smooth scroll*/
     527         433 :                 elapsed = FLT2FIX((Float) (time - st->start_time));
     528         433 :                 scrolled = gf_mulfix(elapsed, rate);
     529             :         }
     530             : 
     531         433 :         smooth = l->smoothScroll;
     532             :         /*if the scroll is in the same direction as the layout, there is no notion of line or column to scroll
     533             :         so move to smooth mode*/
     534         433 :         if (!l->horizontal && l->scrollVertical) smooth = 1;
     535         366 :         else if (l->horizontal && !l->scrollVertical) smooth = 1;
     536             : 
     537             : 
     538             :         stop_anim = 0;
     539             :         /*compute scroll diff for non-smooth mode*/
     540         200 :         if (smooth) {
     541             :                 do_scroll = 1;
     542             :         } else {
     543             :                 Fixed dim;
     544           0 :                 scroll_diff = scrolled - st->last_scroll;
     545             :                 do_scroll = 0;
     546             : 
     547           0 :                 nb_lines = gf_list_count(st->lines);
     548           0 :                 for (i=0; i < nb_lines; i++) {
     549           0 :                         LineInfo *li = (LineInfo*)gf_list_get(st->lines, i);
     550           0 :                         dim = l->scrollVertical ? li->height : li->width;
     551           0 :                         if (st->key_scroll) {
     552           0 :                                 if (st->key_scroll<0) dim = -dim;
     553           0 :                                 scrolled = dim + st->last_scroll;
     554             :                                 /*in key mode we must handle the min ourselves since we can go below the scroll limit*/
     555           0 :                                 if (st->scroll_min > st->scroll_len + scrolled) {
     556           0 :                                         scrolled = st->scroll_min - st->scroll_len;
     557             :                                 } else {
     558             :                                         do_scroll = 1;
     559             :                                 }
     560             :                                 break;
     561           0 :                         } else if (ABS(scroll_diff) >= dim) {
     562             : //                              if (scroll_diff<0) scroll_diff = -dim;
     563             : //                              else scroll_diff = dim;
     564             :                                 do_scroll = 1;
     565             :                                 break;
     566             :                         }
     567             :                 }
     568             :         }
     569             : 
     570         433 :         scroll_diff = st->scroll_max - st->scroll_min;
     571         433 :         if ((scroll_diff<0) && (scrolled<=scroll_diff)) {
     572             :                 stop_anim = 1;
     573             :                 scrolled = scroll_diff;
     574             :         }
     575         433 :         else if ((scroll_diff>0) && (scrolled>=scroll_diff)) {
     576             :                 stop_anim = 1;
     577             :                 scrolled = scroll_diff;
     578             :         }
     579             : 
     580         433 :         if (do_scroll)
     581         433 :                 st->last_scroll = scrolled;
     582             :         else
     583           0 :                 scrolled = st->last_scroll;
     584             : 
     585         433 :         i=0;
     586        1347 :         while ((cg = (ChildGroup *)gf_list_enum(st->groups, &i))) {
     587         914 :                 if (l->scrollVertical) {
     588         376 :                         cg->scroll_y = st->scroll_min + scrolled;
     589         376 :                         cg->scroll_x = 0;
     590             :                 } else {
     591         538 :                         cg->scroll_x = st->scroll_min + scrolled;
     592         538 :                         cg->scroll_y = 0;
     593             :                 }
     594             :         }
     595             : 
     596         433 :         if (st->key_scroll) {
     597           0 :                 st->key_scroll = 0;
     598             :                 return;
     599             :         }
     600             :         /*draw next frame*/
     601         433 :         if (!stop_anim) {
     602         432 :                 tr_state->visual->compositor->force_next_frame_redraw = GF_TRUE;
     603             :                 return;
     604             :         }
     605             : 
     606             :         /*done*/
     607           1 :         if (!l->loop) return;
     608             : 
     609             :         /*restart*/
     610           1 :         st->start_time = time;
     611           1 :         gf_sc_invalidate(tr_state->visual->compositor, NULL);
     612             : }
     613             : 
     614             : 
     615        1156 : static void TraverseLayout(GF_Node *node, void *rs, Bool is_destroy)
     616             : {
     617             :         Bool recompute_layout;
     618             :         u32 i;
     619             :         ChildGroup *cg;
     620             :         GF_IRect prev_clip;
     621        1156 :         Bool mode_bckup, had_clip=GF_FALSE;
     622             :         ParentNode2D *parent_bck;
     623             :         GF_Rect prev_clipper;
     624             :         M_Layout *l = (M_Layout *)node;
     625        1156 :         LayoutStack *st = (LayoutStack *) gf_node_get_private(node);
     626             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     627             : 
     628        1156 :         if (is_destroy) {
     629         170 :                 layout_reset_lines(st);
     630         170 :                 parent_node_predestroy((ParentNode2D *)st);
     631         170 :                 gf_list_del(st->lines);
     632         170 :                 gf_free(st);
     633         170 :                 return;
     634             :         }
     635             : 
     636             :         /*note we don't clear dirty flag, this is done in traversing*/
     637         986 :         if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
     638             : 
     639             :                 /*TO CHANGE IN BIFS - scroll_rate is quite unusable*/
     640         179 :                 st->scale_scroll = st->scroll_rate = l->scrollRate;
     641             :                 /*move to pixel metrics*/
     642         179 :                 if (visual_get_size_info(tr_state, &st->clip.width, &st->clip.height)) {
     643         179 :                         st->scale_scroll = gf_mulfix(st->scale_scroll, l->scrollVertical ? st->clip.height : st->clip.width);
     644             :                 }
     645             :                 /*setup bounds in local coord system*/
     646         179 :                 if (l->size.x>=0) st->clip.width = l->size.x;
     647         179 :                 if (l->size.y>=0) st->clip.height = l->size.y;
     648         179 :                 st->bounds = st->clip = gf_rect_center(st->clip.width, st->clip.height);
     649             : 
     650         179 :                 if (st->scale_scroll && !st->start_scroll_type) st->start_scroll_type = 1;
     651             : 
     652         179 :                 drawable_reset_group_highlight(tr_state, node);
     653             :         }
     654             : 
     655             :         /*don't waste time traversing is pick ray not in clipper*/
     656         986 :         if ((tr_state->traversing_mode==TRAVERSE_PICK) && !gf_sc_pick_in_clipper(tr_state, &st->clip))
     657             :                 goto layout_exit;
     658             : 
     659         880 :         if ((tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) && !tr_state->for_node) {
     660           1 :                 tr_state->bounds = st->clip;
     661             : #ifndef GPAC_DISABLE_3D
     662           1 :                 gf_bbox_from_rect(&tr_state->bbox, &st->clip);
     663             : #endif
     664           1 :                 goto layout_exit;
     665             :         }
     666             : 
     667             :         recompute_layout = 0;
     668         879 :         if (gf_node_dirty_get(node))
     669             :                 recompute_layout = 1;
     670             : 
     671             :         /*setup clipping*/
     672         879 :         prev_clip = tr_state->visual->top_clipper;
     673         879 :         if (tr_state->traversing_mode==TRAVERSE_SORT) {
     674         871 :                 compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, 0);
     675         871 :                 if (tr_state->has_clip) {
     676         871 :                         tr_state->visual->top_clipper = gf_rect_pixelize(&tr_state->clipper);
     677         871 :                         gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip);
     678             :                 }
     679             :         }
     680         879 :         if (recompute_layout) {
     681         178 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layout] recomputing positions\n"));
     682             : 
     683         178 :                 parent_node_reset((ParentNode2D*)st);
     684             : 
     685             :                 /*setup traversing state*/
     686         178 :                 parent_bck = tr_state->parent;
     687         178 :                 mode_bckup = tr_state->traversing_mode;
     688         178 :                 tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
     689         178 :                 tr_state->parent = (ParentNode2D *) st;
     690             : 
     691         178 :                 if (l->wrap) tr_state->text_split_mode = 1;
     692         178 :                 parent_node_traverse(node, (ParentNode2D *)st, tr_state);
     693             :                 /*restore traversing state*/
     694         178 :                 tr_state->parent = parent_bck;
     695         178 :                 tr_state->traversing_mode = mode_bckup;
     696         178 :                 if (l->wrap) tr_state->text_split_mode = 0;
     697             : 
     698             :                 /*center all nodes*/
     699         178 :                 i=0;
     700        1153 :                 while ((cg = (ChildGroup *)gf_list_enum(st->groups, &i))) {
     701         797 :                         cg->final.x = - cg->final.width/2;
     702         797 :                         cg->final.y = cg->final.height/2;
     703             :                 }
     704             : 
     705             :                 /*apply justification*/
     706         178 :                 layout_justify(st, l);
     707             : 
     708             :                 /*if scrolling, update bounds*/
     709         178 :                 if (l->scrollRate && st->is_scrolling) {
     710           6 :                         layout_setup_scroll_bounds(st, l);
     711             :                 }
     712             :         }
     713             : 
     714             : 
     715         879 :         if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS)  {
     716           0 :                 tr_state->bounds = st->bounds;
     717           0 :                 if (l->scrollVertical) {
     718           0 :                         tr_state->bounds.height = st->scroll_len;
     719             :                 } else {
     720           0 :                         tr_state->bounds.width = st->scroll_len;
     721             :                 }
     722             : #ifndef GPAC_DISABLE_3D
     723           0 :                 gf_bbox_from_rect(&tr_state->bbox, &tr_state->bounds);
     724             : #endif
     725           0 :                 goto layout_exit;
     726             :         }
     727             : 
     728             : 
     729             :         /*scroll*/
     730         879 :         layout_scroll(tr_state, st, l);
     731             : 
     732         879 :         i=0;
     733        4138 :         while ((cg = (ChildGroup *)gf_list_enum(st->groups, &i))) {
     734        2380 :                 parent_node_child_traverse(cg, tr_state);
     735             :         }
     736         879 :         tr_state->visual->top_clipper = prev_clip;
     737         879 :         if (tr_state->traversing_mode==TRAVERSE_SORT)  {
     738         871 :                 if (had_clip) tr_state->clipper = prev_clipper;
     739         871 :                 tr_state->has_clip = had_clip;
     740             : 
     741         871 :                 drawable_check_focus_highlight(node, tr_state, &st->clip);
     742             :         }
     743             : 
     744        1100 : layout_exit:
     745         986 :         tr_state->text_split_mode = 0;
     746             : }
     747             : 
     748           0 : static Bool OnLayout(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor)
     749             : {
     750             :         Bool vertical;
     751             :         LayoutStack *st;
     752           0 :         if (!sh || !ev) return GF_FALSE;
     753             : 
     754           0 :         st = (LayoutStack *) gf_node_get_private(sh->sensor);
     755           0 :         vertical = ((M_Layout *)sh->sensor)->scrollVertical;
     756             : 
     757           0 :         if (!is_over) {
     758           0 :                 st->is_scrolling = 0;
     759           0 :                 st->key_scroll = 0;
     760           0 :                 return 0;
     761             :         }
     762           0 :         if (ev->type!=GF_EVENT_KEYDOWN) {
     763           0 :                 st->is_scrolling = 0;
     764           0 :                 st->key_scroll = 0;
     765           0 :                 return 0;
     766             :         }
     767             : 
     768           0 :         switch (ev->key.key_code) {
     769           0 :         case GF_KEY_LEFT:
     770           0 :                 if (!st->keys_active) return 0;
     771             : 
     772           0 :                 if (vertical) return 0;
     773           0 :                 st->key_scroll = -1;
     774           0 :                 break;
     775           0 :         case GF_KEY_RIGHT:
     776           0 :                 if (!st->keys_active) return 0;
     777             : 
     778           0 :                 if (vertical) return 0;
     779           0 :                 st->key_scroll = +1;
     780           0 :                 break;
     781           0 :         case GF_KEY_UP:
     782           0 :                 if (!st->keys_active) return 0;
     783             : 
     784           0 :                 if (!vertical) return 0;
     785           0 :                 st->key_scroll = +1;
     786           0 :                 break;
     787           0 :         case GF_KEY_DOWN:
     788           0 :                 if (!st->keys_active) return 0;
     789             : 
     790           0 :                 if (!vertical) return 0;
     791           0 :                 st->key_scroll = -1;
     792           0 :                 break;
     793           0 :         case GF_KEY_ENTER:
     794           0 :                 st->keys_active = !st->keys_active;
     795           0 :                 break;
     796           0 :         default:
     797           0 :                 st->key_scroll = 0;
     798           0 :                 return 0;
     799             :         }
     800           0 :         gf_sc_invalidate(compositor, NULL);
     801           0 :         return 1;
     802             : }
     803             : 
     804           0 : static Bool layout_is_enabled(GF_Node *node)
     805             : {
     806             :         M_Layout *l = (M_Layout *)node;
     807           0 :         if (node && (l->scrollRate != 0)) return 0;
     808           0 :         return 1;
     809             : }
     810             : 
     811         170 : void compositor_init_layout(GF_Compositor *compositor, GF_Node *node)
     812             : {
     813             :         LayoutStack *stack;
     814         170 :         GF_SAFEALLOC(stack, LayoutStack);
     815         170 :         if (!stack) {
     816           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate layout stack\n"));
     817             :                 return;
     818             :         }
     819             : 
     820         170 :         parent_node_setup((ParentNode2D*)stack);
     821         170 :         stack->lines = gf_list_new();
     822         170 :         gf_node_set_private(node, stack);
     823         170 :         gf_node_set_callback_function(node, TraverseLayout);
     824         170 :         stack->hdl.sensor = node;
     825         170 :         stack->hdl.IsEnabled = layout_is_enabled;
     826         170 :         stack->hdl.OnUserEvent = OnLayout;
     827             : #ifdef GPAC_ENABLE_COVERAGE
     828         170 :         if (gf_sys_is_cov_mode()) {
     829             :                 OnLayout(NULL, GF_FALSE, GF_FALSE, NULL, compositor);
     830             :                 layout_is_enabled(node);
     831             :                 compositor_mpeg4_layout_get_sensor_handler(node);
     832             :         }
     833             : #endif
     834             : 
     835             : }
     836             : 
     837           8 : void compositor_layout_modified(GF_Compositor *compositor, GF_Node *node)
     838             : {
     839           8 :         LayoutStack *st = (LayoutStack *) gf_node_get_private(node);
     840             :         /*if modif other than scrollrate restart scroll*/
     841           8 :         if (st->scroll_rate == ((M_Layout*)node)->scrollRate) {
     842           5 :                 st->start_scroll_type = 1;
     843             :         }
     844             :         /*if modif on scroll rate only, indicate continous restart*/
     845           3 :         else if (((M_Layout*)node)->scrollRate) {
     846           2 :                 st->start_scroll_type = 2;
     847             :         }
     848           8 :         gf_node_dirty_set(node, GF_SG_NODE_DIRTY, 0);
     849           8 :         gf_sc_invalidate(compositor, NULL);
     850           8 : }
     851             : 
     852           0 : GF_SensorHandler *compositor_mpeg4_layout_get_sensor_handler(GF_Node *node)
     853             : {
     854             :         LayoutStack *st;
     855         170 :         if (!node) return NULL;
     856         170 :         st = (LayoutStack *) gf_node_get_private(node);
     857           0 :         return &st->hdl;
     858             : }
     859             : 
     860             : 
     861             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13