LCOV - code coverage report
Current view: top level - compositor - mpeg4_text.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 329 371 88.7 %
Date: 2021-04-29 23:48:07 Functions: 10 10 100.0 %

          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 "visual_manager.h"
      28             : #include "mpeg4_grouping.h"
      29             : #include "texturing.h"
      30             : #include <gpac/utf.h>
      31             : #include <gpac/options.h>
      32             : 
      33             : #ifndef GPAC_DISABLE_VRML
      34             : 
      35             : /*default value when no fontStyle*/
      36             : #define FSFAMILY        (fs && fs->family.count) ? (const char *)fs->family.vals[0]       : ""
      37             : 
      38             : /*here it's tricky since it depends on our metric system...*/
      39             : #define FSSIZE          (fs ? fs->size : -1)
      40             : #define FSSTYLE         (fs && fs->style.buffer) ? (const char *)fs->style.buffer : ""
      41             : #define FSMAJOR         ( (fs && fs->justify.count && fs->justify.vals[0]) ? (const char *)fs->justify.vals[0] : "FIRST")
      42             : #define FSMINOR         ( (fs && (fs->justify.count>1) && fs->justify.vals[1]) ? (const char *)fs->justify.vals[1] : "FIRST")
      43             : #define FSHORIZ         (fs ? fs->horizontal : 1)
      44             : #define FSLTR           (fs ? fs->leftToRight : 1)
      45             : #define FSTTB           (fs ? fs->topToBottom : 1)
      46             : #define FSLANG          (fs ? fs->language : "")
      47             : #define FSSPACE         (fs ? fs->spacing : 1)
      48             : 
      49             : 
      50             : /*exported to access the strike list ...*/
      51             : typedef struct
      52             : {
      53             :         struct _drawable s_graph;
      54             :         Fixed ascent, descent;
      55             :         GF_List *spans;
      56             :         GF_Rect bounds;
      57             :         u32 texture_text_flag;
      58             :         Bool is_dirty;
      59             :         GF_Compositor *compositor;
      60             : } TextStack;
      61             : 
      62        3316 : void text_clean_paths(GF_Compositor *compositor, TextStack *stack)
      63             : {
      64             :         /*delete all path objects*/
      65       12807 :         while (gf_list_count(stack->spans)) {
      66        6175 :                 GF_TextSpan *span = (GF_TextSpan*) gf_list_get(stack->spans, 0);
      67        6175 :                 gf_list_rem(stack->spans, 0);
      68        6175 :                 gf_font_manager_delete_span(compositor->font_manager, span);
      69             :         }
      70        3316 :         stack->bounds.width = stack->bounds.height = 0;
      71        3316 :         drawable_reset_path(&stack->s_graph);
      72        3316 : }
      73             : 
      74             : 
      75         507 : static void build_text_split(TextStack *st, M_Text *txt, GF_TraverseState *tr_state)
      76             : {
      77             :         u32 i, j, k, len, styles, idx, first_char;
      78             :         Bool split_words = GF_FALSE;
      79             :         GF_Font *font;
      80             :         GF_TextSpan *tspan;
      81         507 :         GF_FontManager *ft_mgr = tr_state->visual->compositor->font_manager;
      82             :         Fixed fontSize, start_y;
      83         507 :         M_FontStyle *fs = (M_FontStyle *)txt->fontStyle;
      84             : 
      85         507 :         fontSize = FSSIZE;
      86         507 :         if (fontSize <= 0) {
      87             :                 fontSize = INT2FIX(12);
      88           0 :                 if (!tr_state->pixel_metrics) fontSize = gf_divfix(fontSize, tr_state->visual->compositor->output_width);
      89             :         }
      90             : 
      91             :         styles = 0;
      92         507 :         if (fs && fs->style.buffer) {
      93         507 :                 if (strstr(fs->style.buffer, "BOLD") || strstr(fs->style.buffer, "bold")) styles |= GF_FONT_WEIGHT_BOLD;
      94         507 :                 if (strstr(fs->style.buffer, "ITALIC") || strstr(fs->style.buffer, "italic")) styles |= GF_FONT_ITALIC;
      95         507 :                 if (strstr(fs->style.buffer, "UNDERLINED") || strstr(fs->style.buffer, "underlined")) styles |= GF_FONT_UNDERLINED;
      96         507 :                 if (strstr(fs->style.buffer, "STRIKETHROUGH") || strstr(fs->style.buffer, "strikethrough")) styles |= GF_FONT_STRIKEOUT;
      97             :         }
      98             : 
      99         507 :         font = gf_font_manager_set_font(ft_mgr, fs ? fs->family.vals : NULL, fs ? fs->family.count : 0, styles);
     100         507 :         if (!font) return;
     101             : 
     102         507 :         st->ascent = (fontSize*font->ascent) / font->em_size;
     103         507 :         st->descent = -(fontSize*font->descent) / font->em_size;
     104             : 
     105         507 :         if (!strcmp(FSMINOR, "MIDDLE")) {
     106           0 :                 start_y = (st->descent + st->ascent)/2;
     107             :         }
     108         507 :         else if (!strcmp(FSMINOR, "BEGIN")) {
     109             :                 start_y = st->descent;
     110             :         }
     111         507 :         else if (!strcmp(FSMINOR, "END")) {
     112           0 :                 start_y = st->descent + st->ascent;
     113             :         }
     114             :         else {
     115             :                 start_y = st->ascent;
     116             :         }
     117             : 
     118         507 :         st->bounds.width = st->bounds.x = st->bounds.height = 0;
     119             :         idx = 0;
     120         507 :         split_words = (tr_state->text_split_mode==1) ? GF_TRUE : GF_FALSE;
     121             : 
     122        1014 :         for (i=0; i < txt->string.count; i++) {
     123             : 
     124         507 :                 char *str = txt->string.vals[i];
     125         507 :                 if (!str || !strlen(str)) continue;
     126             : 
     127         507 :                 tspan = gf_font_manager_create_span(ft_mgr, font, str, fontSize, GF_FALSE, GF_FALSE, GF_FALSE, NULL, GF_FALSE, styles, (GF_Node*)txt);
     128         507 :                 if (!tspan) continue;
     129             : 
     130         507 :                 len = tspan->nb_glyphs;
     131         507 :                 tspan->flags |= GF_TEXT_SPAN_HORIZONTAL;
     132             : 
     133             :                 first_char = 0;
     134        5421 :                 for (j=0; j<len; j++) {
     135             :                         u32 is_space = 0;
     136             :                         GF_TextSpan *span;
     137             : 
     138        4914 :                         if (!tspan->glyphs[j]) continue;
     139             : 
     140             :                         /*we currently only split sentences at spaces*/
     141        4914 :                         if (tspan->glyphs[j]->utf_name == (unsigned short) ' ') is_space = 1;
     142        4148 :                         else if (tspan->glyphs[j]->utf_name == (unsigned short) '\n')
     143             :                                 is_space = 2;
     144        4914 :                         if (split_words && (j+1!=len) && !is_space)
     145        1166 :                                 continue;
     146             : 
     147        3748 :                         span = (GF_TextSpan*) gf_malloc(sizeof(GF_TextSpan));
     148             :                         memcpy(span, tspan, sizeof(GF_TextSpan));
     149             : 
     150        3748 :                         span->nb_glyphs = split_words ? (j - first_char) : 1;
     151        3748 :                         if (split_words && !is_space) span->nb_glyphs++;
     152        3748 :                         span->glyphs = (GF_Glyph**)gf_malloc(sizeof(void *)*span->nb_glyphs);
     153             : 
     154        3748 :                         span->bounds.height = st->ascent + st->descent;
     155             :                         span->bounds.y = start_y;
     156        3748 :                         span->bounds.x = 0;
     157        3748 :                         span->bounds.width = 0;
     158        3748 :                         span->bounds.y += 2;
     159        3748 :                         span->bounds.height += 4;
     160             : 
     161        3748 :                         if (split_words) {
     162        1343 :                                 for (k=0; k<span->nb_glyphs; k++) {
     163        1343 :                                         span->glyphs[k] = tspan->glyphs[FSLTR ? (first_char+k) : (len - first_char - k - 1)];
     164        1343 :                                         span->bounds.width += tspan->font_scale * (span->glyphs[k] ? span->glyphs[k]->horiz_advance : tspan->font->max_advance_h);
     165             :                                 }
     166             :                         } else {
     167             :                                 //span->glyphs[0] = tspan->glyphs[FSLTR ? j : (len - j - 1) ];
     168        3465 :                                 span->glyphs[0] = tspan->glyphs[j];
     169        3465 :                                 span->bounds.width = tspan->font_scale * (span->glyphs[0] ? span->glyphs[0]->horiz_advance : tspan->font->max_advance_h);
     170             :                         }
     171             : 
     172        3748 :                         gf_list_add(st->spans, span);
     173             : 
     174             :                         /*request a context (first one is always valid when entering sort phase)*/
     175        3748 :                         if (idx) parent_node_start_group(tr_state->parent, NULL, GF_FALSE);
     176             : 
     177        3748 :                         idx++;
     178        3748 :                         parent_node_end_text_group(tr_state->parent, &span->bounds, st->ascent, st->descent, idx);
     179             : 
     180        3748 :                         if (is_space && split_words) {
     181         106 :                                 span = (GF_TextSpan*) gf_malloc(sizeof(GF_TextSpan));
     182             :                                 memcpy(span, tspan, sizeof(GF_TextSpan));
     183         106 :                                 span->nb_glyphs = 1;
     184         106 :                                 span->glyphs = (GF_Glyph**)gf_malloc(sizeof(void *));
     185             : 
     186         106 :                                 gf_list_add(st->spans, span);
     187         106 :                                 span->bounds.height = st->ascent + st->descent;
     188             :                                 span->bounds.y = start_y;
     189         106 :                                 span->bounds.x = 0;
     190         106 :                                 span->bounds.y += 2;
     191         106 :                                 span->bounds.height += 4;
     192         106 :                                 k = (j - first_char);
     193         106 :                                 span->glyphs[0] = tspan->glyphs[FSLTR ? (first_char+k) : (len - first_char - k - 1)];
     194         106 :                                 span->bounds.width = tspan->font_scale * (span->glyphs[0] ? span->glyphs[0]->horiz_advance : tspan->font->max_advance_h);
     195         106 :                                 parent_node_start_group(tr_state->parent, NULL, is_space);
     196         106 :                                 idx++;
     197         106 :                                 parent_node_end_text_group(tr_state->parent, &span->bounds, st->ascent, st->descent, idx);
     198             :                         }
     199        3748 :                         first_char = j+1;
     200             :                 }
     201         507 :                 gf_font_manager_delete_span(ft_mgr, tspan);
     202             :         }
     203             : }
     204             : 
     205             : 
     206        1804 : static void build_text(TextStack *st, M_Text *txt, GF_TraverseState *tr_state)
     207             : {
     208             :         u32 i, j, int_major, k, styles, count;
     209             :         Fixed fontSize, start_x, start_y, line_spacing, tot_width, tot_height, max_scale, maxExtent;
     210             :         u32 size, trim_size;
     211             :         GF_Font *font;
     212             :         Bool horizontal;
     213             :         GF_TextSpan *trim_tspan = NULL;
     214        1804 :         GF_FontManager *ft_mgr = tr_state->visual->compositor->font_manager;
     215        1804 :         M_FontStyle *fs = (M_FontStyle *)txt->fontStyle;
     216             : 
     217        1804 :         fontSize = FSSIZE;
     218        1804 :         if (fontSize <= 0) {
     219             :                 fontSize = INT2FIX(12);
     220           0 :                 if (!tr_state->pixel_metrics) fontSize = gf_divfix(fontSize, tr_state->visual->compositor->output_width);
     221             :         }
     222        1804 :         horizontal = FSHORIZ;
     223             :         start_x = start_y = 0;
     224             : 
     225             :         styles = 0;
     226        1804 :         if (fs && fs->style.buffer) {
     227        1804 :                 if (strstr(fs->style.buffer, "BOLD") || strstr(fs->style.buffer, "bold")) styles |= GF_FONT_WEIGHT_BOLD;
     228        1804 :                 if (strstr(fs->style.buffer, "ITALIC") || strstr(fs->style.buffer, "italic")) styles |= GF_FONT_ITALIC;
     229        1804 :                 if (strstr(fs->style.buffer, "UNDERLINED") || strstr(fs->style.buffer, "underlined")) styles |= GF_FONT_UNDERLINED;
     230        1804 :                 if (strstr(fs->style.buffer, "STRIKETHROUGH") || strstr(fs->style.buffer, "strikethrough")) styles |= GF_FONT_STRIKEOUT;
     231             :         }
     232             : 
     233        1804 :         font = gf_font_manager_set_font(ft_mgr, fs ? fs->family.vals : NULL, fs ? fs->family.count : 0, styles);
     234        1804 :         if (!font) return;
     235             : 
     236             :         /*NOTA: we could use integer maths here but we have a risk of overflow with large fonts, so use fixed maths*/
     237        1804 :         st->ascent = gf_muldiv(fontSize, INT2FIX(font->ascent), INT2FIX(font->em_size));
     238        1804 :         st->descent = -gf_muldiv(fontSize, INT2FIX(font->descent), INT2FIX(font->em_size));
     239        1804 :         line_spacing = gf_mulfix(FSSPACE, fontSize);
     240             : 
     241        1804 :         maxExtent = txt->maxExtent;
     242             :         trim_size = 0;
     243             : 
     244        1804 :         if (maxExtent<0) {
     245         112 :                 trim_tspan = gf_font_manager_create_span(ft_mgr, font, "...", fontSize, GF_FALSE, GF_FALSE, GF_FALSE, NULL, GF_FALSE, styles, (GF_Node*)txt);
     246         336 :                 for (i=0; i<trim_tspan->nb_glyphs; i++) {
     247         336 :                         if (horizontal) {
     248         336 :                                 trim_size += trim_tspan->glyphs[i] ? trim_tspan->glyphs[i]->horiz_advance : trim_tspan->font->max_advance_h;
     249             :                         } else {
     250           0 :                                 trim_size += trim_tspan->glyphs[i] ? trim_tspan->glyphs[i]->vert_advance : trim_tspan->font->max_advance_v;
     251             :                         }
     252             :                 }
     253             :         }
     254             : 
     255             :         tot_width = tot_height = 0;
     256        2379 :         for (i=0; i < txt->string.count; i++) {
     257             :                 GF_TextSpan *tspan;
     258        2379 :                 char *str = txt->string.vals[i];
     259        2379 :                 if (!str) continue;
     260             : 
     261        2337 :                 tspan = gf_font_manager_create_span(ft_mgr, font, txt->string.vals[i], fontSize, GF_FALSE, GF_FALSE, GF_FALSE, NULL, GF_FALSE, styles, (GF_Node*)txt);
     262        2337 :                 if (!tspan) continue;
     263             : 
     264        2321 :                 if (horizontal) tspan->flags |= GF_TEXT_SPAN_HORIZONTAL;
     265             : 
     266             :                 size = 0;
     267        2321 :                 if (trim_size) {
     268        1155 :                         for (j=0; j<tspan->nb_glyphs; j++) {
     269        1155 :                                 if (horizontal) {
     270        1155 :                                         size += tspan->glyphs[j] ? tspan->glyphs[j]->horiz_advance : tspan->font->max_advance_h;
     271             :                                 } else {
     272           0 :                                         size += tspan->glyphs[j] ? tspan->glyphs[j]->vert_advance : tspan->font->max_advance_v;
     273             :                                 }
     274             :                                 /*word is bigger than allowed extent, rewrite 3 previous chars*/
     275        1155 :                                 if ((s32)size*tspan->font_scale >= -maxExtent) {
     276           0 :                                         u32 nb_chars = (j<2) ? j : 3;
     277             : 
     278           0 :                                         for (k=0; k<nb_chars; k++) {
     279           0 :                                                 u32 idx = nb_chars-k-1;
     280           0 :                                                 if (horizontal) {
     281           0 :                                                         size -= tspan->glyphs[j-k] ? tspan->glyphs[j-k]->horiz_advance : tspan->font->max_advance_h;
     282           0 :                                                         size += trim_tspan->glyphs[idx] ? trim_tspan->glyphs[idx]->horiz_advance : tspan->font->max_advance_h;
     283             :                                                 } else {
     284           0 :                                                         size -= tspan->glyphs[j-k] ? tspan->glyphs[j-k]->vert_advance : tspan->font->max_advance_v;
     285           0 :                                                         size += trim_tspan->glyphs[idx] ? trim_tspan->glyphs[idx]->vert_advance : tspan->font->max_advance_v;
     286             :                                                 }
     287           0 :                                                 tspan->glyphs[j-k] = trim_tspan->glyphs[idx];
     288             :                                         }
     289           0 :                                         tspan->nb_glyphs = j+1;
     290             :                                         break;
     291             :                                 }
     292             :                         }
     293             :                 }
     294             : 
     295        2321 :                 if ((horizontal && !FSLTR) || (!horizontal && !FSTTB)) {
     296         288 :                         for (k=0; k<tspan->nb_glyphs/2; k++) {
     297         288 :                                 GF_Glyph *g = tspan->glyphs[k];
     298         288 :                                 tspan->glyphs[k] = tspan->glyphs[tspan->nb_glyphs-1-k];
     299         288 :                                 tspan->glyphs[tspan->nb_glyphs-k-1] = g;
     300             :                         }
     301             :                 }
     302             : 
     303        2321 :                 if (!size) {
     304       27752 :                         for (j=0; j<tspan->nb_glyphs; j++) {
     305       27752 :                                 if (horizontal) {
     306       27234 :                                         size += tspan->glyphs[j] ? tspan->glyphs[j]->horiz_advance : tspan->font->max_advance_h;
     307             :                                 } else {
     308         518 :                                         size += tspan->glyphs[j] ? tspan->glyphs[j]->vert_advance : tspan->font->max_advance_v;
     309             :                                 }
     310             :                         }
     311             :                 }
     312        2321 :                 gf_list_add(st->spans, tspan);
     313             : 
     314        2321 :                 if (horizontal) {
     315        2227 :                         tspan->bounds.width = tspan->font_scale * size;
     316             :                         /*apply length*/
     317        2227 :                         if ((txt->length.count>i) && (txt->length.vals[i]>0)) {
     318           9 :                                 tspan->x_scale = gf_divfix(txt->length.vals[i], tspan->bounds.width);
     319           9 :                                 tspan->bounds.width = txt->length.vals[i];
     320             :                         }
     321        2227 :                         if (tot_width < tspan->bounds.width ) tot_width = tspan->bounds.width;
     322             :                 } else {
     323          94 :                         tspan->bounds.height = tspan->font_scale * size;
     324             : 
     325             :                         /*apply length*/
     326          94 :                         if ((txt->length.count>i) && (txt->length.vals[i]>0)) {
     327           9 :                                 tspan->y_scale = gf_divfix(txt->length.vals[i], tspan->bounds.height);
     328           9 :                                 tspan->bounds.height = txt->length.vals[i];
     329             :                         }
     330          94 :                         if (tot_height < tspan->bounds.height) tot_height = tspan->bounds.height;
     331             :                 }
     332             :         }
     333        1804 :         if (trim_tspan) gf_font_manager_delete_span(ft_mgr, trim_tspan);
     334             : 
     335             : 
     336             :         max_scale = FIX_ONE;
     337        1804 :         if (horizontal) {
     338        1757 :                 if ((maxExtent > 0) && (tot_width>maxExtent)) {
     339           1 :                         max_scale = gf_divfix(maxExtent, tot_width);
     340             :                 }
     341        1757 :                 tot_height = (txt->string.count-1) * line_spacing + (st->ascent + st->descent);
     342        1757 :                 st->bounds.height = tot_height;
     343             : 
     344        1757 :                 if (!strcmp(FSMINOR, "MIDDLE")) {
     345        1029 :                         if (FSTTB) {
     346        1021 :                                 start_y = tot_height/2;
     347        1021 :                                 st->bounds.y = start_y;
     348             :                         } else {
     349           8 :                                 start_y = st->descent + st->ascent - tot_height/2;
     350           8 :                                 st->bounds.y = tot_height/2;
     351             :                         }
     352             :                 }
     353         728 :                 else if (!strcmp(FSMINOR, "BEGIN")) {
     354          43 :                         if (FSTTB) {
     355             :                                 start_y = 0;
     356          35 :                                 st->bounds.y = start_y;
     357             :                         } else {
     358           8 :                                 st->bounds.y = st->bounds.height;
     359             :                                 start_y = st->descent + st->ascent;
     360             :                         }
     361             :                 }
     362         685 :                 else if (!strcmp(FSMINOR, "END")) {
     363          18 :                         if (FSTTB) {
     364             :                                 start_y = tot_height;
     365          10 :                                 st->bounds.y = start_y;
     366             :                         } else {
     367           8 :                                 start_y = -tot_height + 2*st->descent + st->ascent;
     368           8 :                                 st->bounds.y = start_y - (st->descent + st->ascent) + tot_height;
     369             :                         }
     370             :                 }
     371             :                 else {
     372             :                         start_y = st->ascent;
     373         667 :                         st->bounds.y = FSTTB ? start_y : (tot_height - st->descent);
     374             :                 }
     375             :         } else {
     376          47 :                 if ((maxExtent > 0) && (tot_height>maxExtent) ) {
     377           1 :                         max_scale = gf_divfix(maxExtent, tot_height);
     378             :                 }
     379          47 :                 tot_width = txt->string.count * line_spacing;
     380          47 :                 st->bounds.width = tot_width;
     381             : 
     382          47 :                 if (!strcmp(FSMINOR, "MIDDLE")) {
     383          23 :                         if (FSLTR) {
     384          17 :                                 start_x = -tot_width/2;
     385          17 :                                 st->bounds.x = start_x;
     386             :                         } else {
     387           6 :                                 start_x = tot_width/2 - line_spacing;
     388           6 :                                 st->bounds.x = - tot_width + line_spacing;
     389             :                         }
     390             :                 }
     391          24 :                 else if (!strcmp(FSMINOR, "END")) {
     392          12 :                         if (FSLTR) {
     393           6 :                                 start_x = -tot_width;
     394           6 :                                 st->bounds.x = start_x;
     395             :                         } else {
     396           6 :                                 start_x = tot_width-line_spacing;
     397           6 :                                 st->bounds.x = 0;
     398             :                         }
     399             :                 }
     400             :                 else {
     401          12 :                         if (FSLTR) {
     402             :                                 start_x = 0;
     403           6 :                                 st->bounds.x = start_x;
     404             :                         } else {
     405           6 :                                 start_x = -line_spacing;
     406           6 :                                 st->bounds.x = -tot_width;
     407             :                         }
     408             :                 }
     409             :         }
     410             : 
     411             : 
     412             :         /*major-justification*/
     413        1804 :         if (!strcmp(FSMAJOR, "MIDDLE") ) {
     414             :                 int_major = 0;
     415         242 :         } else if (!strcmp(FSMAJOR, "END") ) {
     416             :                 int_major = 1;
     417             :         } else {
     418             :                 int_major = 2;
     419             :         }
     420             : 
     421        1804 :         st->bounds.width = st->bounds.height = 0;
     422             : 
     423        1804 :         count = gf_list_count(st->spans);
     424        2321 :         for (i=0; i < count; i++) {
     425        2321 :                 GF_TextSpan *span = (GF_TextSpan*)gf_list_get(st->spans, i);
     426        2321 :                 switch (int_major) {
     427             :                 /*major-justification MIDDLE*/
     428        1955 :                 case 0:
     429        1955 :                         if (horizontal) {
     430        1909 :                                 start_x = -span->bounds.width/2;
     431             :                         } else {
     432             :                                 //start_y = FSTTB ? span->bounds.height/2 : (-span->bounds.height/2 + space);
     433          46 :                                 start_y = span->bounds.height/2;
     434             :                         }
     435             :                         break;
     436             :                 /*major-justification END*/
     437         103 :                 case 1:
     438         103 :                         if (horizontal) {
     439          79 :                                 start_x = (FSLTR) ? -span->bounds.width : 0;
     440             :                         } else {
     441             :                                 //start_y = FSTTB ? span->bounds.height : (-span->bounds.height + space);
     442          24 :                                 start_y = FSTTB ? span->bounds.height : 0;
     443             :                         }
     444             :                         break;
     445             :                 /*BEGIN, FIRST or default*/
     446         263 :                 default:
     447         263 :                         if (horizontal) {
     448         239 :                                 start_x = (FSLTR) ? 0 : -span->bounds.width;
     449             :                         } else {
     450             :                                 //start_y = FSTTB ? 0 : space;
     451          24 :                                 start_y = FSTTB ? 0 : span->bounds.height;
     452             :                         }
     453             :                         break;
     454             :                 }
     455        2321 :                 span->off_x = start_x;
     456        2321 :                 span->bounds.x = start_x;
     457        2321 :                 if (horizontal) {
     458        2227 :                         span->off_y = start_y - st->ascent;
     459        2227 :                         span->x_scale = gf_mulfix(span->x_scale, max_scale);
     460        2227 :                         span->bounds.y = start_y;
     461             :                 } else {
     462          94 :                         span->y_scale = gf_mulfix(span->y_scale, max_scale);
     463          94 :                         span->off_y = start_y - gf_mulfix(st->ascent, span->y_scale);
     464          94 :                         span->bounds.y = start_y;
     465             :                 }
     466        2321 :                 span->off_x = gf_mulfix(span->off_x, max_scale);
     467        2321 :                 span->off_y = gf_mulfix(span->off_y, max_scale);
     468             : 
     469        2321 :                 if (horizontal) {
     470        2227 :                         start_y += FSTTB ? -line_spacing : line_spacing;
     471        2227 :                         span->bounds.height = st->descent + st->ascent;
     472             :                 } else {
     473          94 :                         start_x += FSLTR ? line_spacing : -line_spacing;
     474          94 :                         span->bounds.width = line_spacing;
     475             :                 }
     476        2321 :                 gf_rect_union(&st->bounds, &span->bounds);
     477             :         }
     478             : }
     479             : 
     480       26200 : static void text_get_draw_opt(GF_Node *node, TextStack *st, Bool *force_texture, u32 *hl_color, DrawAspect2D *asp)
     481             : {
     482             :         const char *fs_style;
     483             :         char *hlight;
     484       26200 :         M_FontStyle *fs = (M_FontStyle *) ((M_Text *) node)->fontStyle;
     485             : 
     486       26200 :         *hl_color = 0;
     487             : 
     488       26200 :         fs_style = FSSTYLE;
     489       26200 :         hlight = strstr(fs_style, "HIGHLIGHT");
     490       26200 :         if (hlight) hlight = strchr(hlight, '#');
     491       26200 :         if (hlight) {
     492           0 :                 hlight += 1;
     493           0 :                 if (!strnicmp(hlight, "RV", 2)) *hl_color = 0x00FFFFFF;
     494             :                 else {
     495           0 :                         sscanf(hlight, "%x", hl_color);
     496           0 :                         if (strlen(hlight)!=8) *hl_color |= 0xFF000000;
     497             :                 }
     498             :         }
     499       26200 :         *force_texture = st->texture_text_flag;
     500       26200 :         if (strstr(fs_style, "TEXTURED")) *force_texture = GF_TRUE;
     501       26200 :         if (strstr(fs_style, "OUTLINED")) {
     502           0 :                 if (asp && !asp->pen_props.width) {
     503           0 :                         asp->pen_props.width = FIX_ONE/2;
     504           0 :                         asp->pen_props.align = GF_PATH_LINE_OUTSIDE;
     505           0 :                         asp->line_scale=FIX_ONE;
     506           0 :                         asp->line_color = 0xFF000000;
     507             :                 }
     508             :         }
     509       26200 : }
     510             : 
     511             : 
     512             : #ifndef GPAC_DISABLE_3D
     513             : 
     514             : 
     515             : static Bool text_is_3d_material(GF_TraverseState *tr_state)
     516             : {
     517             :         GF_Node *__mat;
     518        2535 :         if (!tr_state->appear) return GF_FALSE;
     519        2399 :         __mat = ((M_Appearance *)tr_state->appear)->material;
     520        2399 :         if (!__mat) return GF_FALSE;
     521        2399 :         if (gf_node_get_tag(__mat)==TAG_MPEG4_Material2D) return GF_FALSE;
     522             :         return GF_TRUE;
     523             : }
     524             : 
     525        2535 : static void text_draw_3d(GF_TraverseState *tr_state, GF_Node *node, TextStack *st)
     526             : {
     527             :         DrawAspect2D the_asp, *asp;
     528             :         Bool is_3d, force_texture;
     529             :         u32 hl_color;
     530             : 
     531        2535 :         is_3d = text_is_3d_material(tr_state);
     532             :         asp = NULL;
     533             :         if (!is_3d) {
     534             :                 memset(&the_asp, 0, sizeof(DrawAspect2D));
     535             :                 asp = &the_asp;
     536        2496 :                 drawable_get_aspect_2d_mpeg4(node, asp, tr_state);
     537             :         }
     538        2535 :         text_get_draw_opt(node, st, &force_texture, &hl_color, asp);
     539        2535 :         gf_font_spans_draw_3d(st->spans, tr_state, asp, hl_color, force_texture);
     540        2535 : }
     541             : 
     542             : #endif
     543             : 
     544             : 
     545             : 
     546             : 
     547       23665 : void text_draw_2d(GF_Node *node, GF_TraverseState *tr_state)
     548             : {
     549             :         Bool force_texture;
     550             :         u32 hl_color;
     551       23665 :         TextStack *st = (TextStack *) gf_node_get_private((GF_Node *) node);
     552             : 
     553       23665 :         if (!GF_COL_A(tr_state->ctx->aspect.fill_color) && !tr_state->ctx->aspect.pen_props.width) return;
     554             : 
     555       23665 :         text_get_draw_opt(node, st, &force_texture, &hl_color, &tr_state->ctx->aspect);
     556             : 
     557       23665 :         tr_state->text_parent = node;
     558       23665 :         gf_font_spans_draw_2d(st->spans, tr_state, hl_color, force_texture, &st->bounds);
     559       23665 :         tr_state->text_parent = NULL;
     560             : }
     561             : 
     562             : 
     563             : 
     564       61803 : static void text_check_changes(GF_Node *node, TextStack *stack, GF_TraverseState *tr_state)
     565             : {
     566       61803 :         if (gf_node_dirty_get(node) || tr_state->visual->compositor->reset_fonts) {
     567        1804 :                 text_clean_paths(tr_state->visual->compositor, stack);
     568        1804 :                 build_text(stack, (M_Text*)node, tr_state);
     569        1804 :                 gf_node_dirty_clear(node, 0);
     570        1804 :                 drawable_mark_modified(&stack->s_graph, tr_state);
     571             :         }
     572             : 
     573       61803 :         if (tr_state->visual->compositor->edited_text && (tr_state->visual->compositor->focus_node==node)) {
     574           0 :                 drawable_mark_modified(&stack->s_graph, tr_state);
     575           0 :                 tr_state->visual->has_text_edit = GF_TRUE;
     576           0 :                 if (!stack->bounds.width) stack->bounds.width = INT2FIX(1)/100;
     577           0 :                 if (!stack->bounds.height) stack->bounds.height = INT2FIX(1)/100;
     578             :         }
     579       61803 : }
     580             : 
     581             : 
     582       63400 : static void Text_Traverse(GF_Node *n, void *rs, Bool is_destroy)
     583             : {
     584             :         DrawableContext *ctx;
     585             :         M_Text *txt = (M_Text *) n;
     586       63400 :         TextStack *st = (TextStack *) gf_node_get_private(n);
     587             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     588             : 
     589       63400 :         if (is_destroy) {
     590        1005 :                 GF_Compositor *compositor = gf_sc_get_compositor(n);
     591        1005 :                 text_clean_paths(compositor, st);
     592        1005 :                 drawable_del_ex(&st->s_graph, compositor, GF_TRUE);
     593        1005 :                 gf_list_del(st->spans);
     594        1005 :                 gf_free(st);
     595        1005 :                 return;
     596             :         }
     597             : 
     598       62395 :         if (!txt->string.count) return;
     599             : 
     600       62310 :         if (tr_state->text_split_mode) {
     601         507 :                 st->is_dirty = gf_node_dirty_get(n) ? GF_TRUE : GF_FALSE;
     602         507 :                 gf_node_dirty_clear(n, 0);
     603         507 :                 text_clean_paths(tr_state->visual->compositor, st);
     604         507 :                 build_text_split(st, txt, tr_state);
     605         507 :                 return;
     606             :         }
     607             : 
     608       61803 :         text_check_changes(n, st, tr_state);
     609             : 
     610       61803 :         switch (tr_state->traversing_mode) {
     611       23665 :         case TRAVERSE_DRAW_2D:
     612       23665 :                 text_draw_2d(n, tr_state);
     613       23665 :                 return;
     614             : #ifndef GPAC_DISABLE_3D
     615        2535 :         case TRAVERSE_DRAW_3D:
     616        2535 :                 text_draw_3d(tr_state, n, st);
     617        2535 :                 return;
     618             : #endif
     619        7494 :         case TRAVERSE_PICK:
     620        7494 :                 tr_state->text_parent = n;
     621        7494 :                 gf_font_spans_pick(n, st->spans, tr_state, &st->bounds, GF_FALSE, NULL);
     622        7494 :                 tr_state->text_parent = NULL;
     623        7494 :                 return;
     624         315 :         case TRAVERSE_GET_BOUNDS:
     625         315 :                 tr_state->bounds = st->bounds;
     626         315 :                 return;
     627           0 :         case TRAVERSE_GET_TEXT:
     628           0 :                 tr_state->text_parent = n;
     629           0 :                 gf_font_spans_get_selection(n, st->spans, tr_state);
     630           0 :                 tr_state->text_parent = NULL;
     631           0 :                 return;
     632             :         case TRAVERSE_SORT:
     633             :                 break;
     634             :         default:
     635             :                 return;
     636             :         }
     637             : 
     638             : #ifndef GPAC_DISABLE_3D
     639       27794 :         if (tr_state->visual->type_3d) return;
     640             : #endif
     641             : 
     642       27794 :         ctx = drawable_init_context_mpeg4(&st->s_graph, tr_state);
     643       27794 :         if (!ctx) return;
     644       27772 :         ctx->sub_path_index = tr_state->text_split_idx;
     645             : 
     646       27772 :         ctx->flags |= CTX_IS_TEXT;
     647       27772 :         if (!GF_COL_A(ctx->aspect.fill_color)) {
     648             :                 /*override line join*/
     649         302 :                 ctx->aspect.pen_props.join = GF_LINE_JOIN_MITER;
     650         302 :                 ctx->aspect.pen_props.cap = GF_LINE_CAP_FLAT;
     651             :         }
     652             : 
     653             :         /*if text selection mode, we must force redraw of the entire text span because we don't
     654             :         if glyphs have been (un)selected*/
     655       54288 :         if (!tr_state->immediate_draw &&
     656             :                 /*text selection on*/
     657       26516 :                 (tr_state->visual->compositor->text_selection
     658             :                  /*text sel release*/
     659       26157 :                  || (tr_state->visual->compositor->store_text_state==GF_SC_TSEL_RELEASED))
     660         750 :            ) {
     661             :                 GF_TextSpan *span;
     662         750 :                 u32 i = 0;
     663         750 :                 Bool unselect = (tr_state->visual->compositor->store_text_state==GF_SC_TSEL_RELEASED) ? GF_TRUE : GF_FALSE;
     664        2583 :                 while ((span = (GF_TextSpan*)gf_list_enum(st->spans, &i))) {
     665        1083 :                         if (span->flags & GF_TEXT_SPAN_SELECTED) {
     666         392 :                                 if (unselect) span->flags &= ~GF_TEXT_SPAN_SELECTED;
     667         392 :                                 ctx->flags |= CTX_APP_DIRTY;
     668             :                         }
     669             :                 }
     670       27022 :         } else if (st->is_dirty) {
     671          93 :                 ctx->flags |= CTX_APP_DIRTY;
     672             :         }
     673             : 
     674       27772 :         if (ctx->sub_path_index) {
     675        3299 :                 GF_TextSpan *span = (GF_TextSpan *)gf_list_get(st->spans, ctx->sub_path_index-1);
     676        3299 :                 if (span) drawable_finalize_sort(ctx, tr_state, &span->bounds);
     677             :         } else {
     678       24473 :                 drawable_finalize_sort(ctx, tr_state, &st->bounds);
     679             :         }
     680             : }
     681             : 
     682             : 
     683        1005 : void compositor_init_text(GF_Compositor *compositor, GF_Node *node)
     684             : {
     685             :         TextStack *stack;
     686        1005 :         GF_SAFEALLOC(stack, TextStack);
     687        1005 :         if (!stack) {
     688           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate text stack\n"));
     689             :                 return;
     690             :         }
     691        1005 :         drawable_init_ex(&stack->s_graph);
     692        1005 :         stack->s_graph.node = node;
     693        1005 :         stack->s_graph.flags = DRAWABLE_USE_TRAVERSE_DRAW;
     694        1005 :         stack->ascent = stack->descent = 0;
     695        1005 :         stack->spans = gf_list_new();
     696        1005 :         stack->texture_text_flag = 0;
     697             : 
     698        1005 :         stack->compositor = compositor;
     699        1005 :         gf_node_set_private(node, stack);
     700        1005 :         gf_node_set_callback_function(node, Text_Traverse);
     701             : }
     702             : 
     703             : #ifndef GPAC_DISABLE_3D
     704           1 : void compositor_extrude_text(GF_Node *node, GF_TraverseState *tr_state, GF_Mesh *mesh, MFVec3f *thespine, Fixed creaseAngle, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool txAlongSpine)
     705             : {
     706             :         u32 i, count;
     707             :         Fixed min_cx, min_cy, width_cx, width_cy;
     708           1 :         TextStack *st = (TextStack *) gf_node_get_private(node);
     709             : 
     710             :         /*rebuild text node*/
     711           1 :         if (gf_node_dirty_get(node)) {
     712           0 :                 ParentNode2D *parent = tr_state->parent;
     713           0 :                 tr_state->parent = NULL;
     714           0 :                 text_clean_paths(tr_state->visual->compositor, st);
     715           0 :                 drawable_reset_path(&st->s_graph);
     716           0 :                 gf_node_dirty_clear(node, 0);
     717           0 :                 build_text(st, (M_Text *)node, tr_state);
     718           0 :                 tr_state->parent = parent;
     719             :         }
     720             : 
     721           1 :         min_cx = st->bounds.x;
     722           1 :         min_cy = st->bounds.y - st->bounds.height;
     723           1 :         width_cx = st->bounds.width;
     724             :         width_cy = st->bounds.height;
     725             : 
     726           1 :         mesh_reset(mesh);
     727           1 :         count = gf_list_count(st->spans);
     728           2 :         for (i=0; i<count; i++) {
     729           1 :                 GF_TextSpan *span = (GF_TextSpan *)gf_list_get(st->spans, i);
     730           1 :                 GF_Path *span_path = gf_font_span_create_path(span);
     731           1 :                 mesh_extrude_path_ext(mesh, span_path, thespine, creaseAngle, min_cx, min_cy, width_cx, width_cy, begin_cap, end_cap, spine_ori, spine_scale, txAlongSpine);
     732           1 :                 gf_path_del(span_path);
     733             :         }
     734           1 :         mesh_update_bounds(mesh);
     735           1 :         gf_mesh_build_aabbtree(mesh);
     736           1 : }
     737             : 
     738             : #endif /*GPAC_DISABLE_3D*/
     739             : 
     740             : 
     741             : #endif /*GPAC_DISABLE_VRML*/
     742             : 
     743             : 

Generated by: LCOV version 1.13