@@ -658,7 +658,7 @@ tohex(char c) {
658658}
659659
660660static const char *
661- parse_bracket (struct block_context * ctx , const char * str , int * icon ) {
661+ parse_bracket (struct block_context * ctx , const char * str , int * icon , int * group ) {
662662 char c = * str ;
663663 int hex = -1 ;
664664 if (c == 'i' ) {
@@ -698,11 +698,116 @@ parse_bracket(struct block_context *ctx, const char *str, int *icon) {
698698 } else if (c == 'n' ) {
699699 ctx -> fs = & ctx -> s -> s [0 ];
700700 ctx -> color = ctx -> fs -> color ;
701+ } else if (c == 'w' ) {
702+ ++ str ;
703+ int word_group = 0 ;
704+ while (* str >= '0' && * str <= '9' ) {
705+ word_group = word_group * 10 + (* str - '0' );
706+ ++ str ;
707+ }
708+ * group = word_group ;
701709 }
702710 // todo: other command
703711 return skip_bracket (str );
704712}
705713
714+ enum text_token_type {
715+ TEXT_TOKEN_END ,
716+ TEXT_TOKEN_GROUP ,
717+ TEXT_TOKEN_NEWLINE ,
718+ TEXT_TOKEN_SPACE ,
719+ TEXT_TOKEN_GLYPH ,
720+ };
721+
722+ struct text_token {
723+ enum text_token_type type ;
724+ int advance_x ;
725+ int dy ;
726+ int codepoint ;
727+ int font ;
728+ };
729+
730+ static const char *
731+ next_text_token (const char * str , struct block_context * ctx , int * group ,
732+ struct text_token * token ) {
733+ struct font_manager * mgr = ctx -> s -> font ;
734+ for (;;) {
735+ uint32_t val = 0 ;
736+ str = utf8_decode (str , & val );
737+ if (str == NULL || val == 0 ) {
738+ token -> type = TEXT_TOKEN_END ;
739+ return str ;
740+ }
741+ if (val <= 32 ) {
742+ if (val == '\n' ) {
743+ token -> type = TEXT_TOKEN_NEWLINE ;
744+ return str ;
745+ }
746+ struct font_glyph g , og ;
747+ if (font_manager_glyph (mgr , ctx -> fs -> fontid , ' ' , ctx -> fs -> size , & g , & og ) == NULL ) {
748+ token -> type = TEXT_TOKEN_SPACE ;
749+ token -> advance_x = g .advance_x ;
750+ return str ;
751+ }
752+ continue ;
753+ }
754+
755+ int icon = 0 ;
756+ if (val == '[' ) {
757+ if (* str != '[' ) {
758+ int previous_group = * group ;
759+ str = parse_bracket (ctx , str , & icon , group );
760+ if (* group != previous_group ) {
761+ token -> type = TEXT_TOKEN_GROUP ;
762+ return str ;
763+ }
764+ if (!icon )
765+ continue ;
766+ } else {
767+ ++ str ;
768+ }
769+ }
770+
771+ int codepoint = val ;
772+ int font = ctx -> fs -> fontid ;
773+ int dy = 0 ;
774+ if (icon > 0 ) {
775+ codepoint = icon - 1 ;
776+ font = FONT_ICON ;
777+ dy = - ctx -> fs -> ascent ;
778+ }
779+ struct font_glyph g , og ;
780+ if (font_manager_glyph (mgr , font , codepoint , ctx -> fs -> size , & g , & og ) == NULL ) {
781+ token -> type = TEXT_TOKEN_GLYPH ;
782+ token -> advance_x = g .advance_x ;
783+ token -> dy = dy ;
784+ token -> codepoint = codepoint ;
785+ token -> font = font ;
786+ return str ;
787+ }
788+ }
789+ }
790+
791+ static int
792+ measure_word_group (const char * str , struct block_context * ctx , int group ) {
793+ struct block_context probe = * ctx ;
794+ int current_group = group ;
795+ int width = 0 ;
796+ for (;;) {
797+ struct text_token token ;
798+ str = next_text_token (str , & probe , & current_group , & token );
799+ if (token .type == TEXT_TOKEN_END || token .type == TEXT_TOKEN_GROUP ||
800+ token .type == TEXT_TOKEN_NEWLINE )
801+ break ;
802+ if (token .type == TEXT_TOKEN_SPACE || token .type == TEXT_TOKEN_GLYPH ) {
803+ width += token .advance_x ;
804+ if (width > probe .width )
805+ break ;
806+ }
807+ }
808+ return width ;
809+ }
810+
706811static int
707812ltext_ (lua_State * L , struct styles * s , int gen_layout , int external ) {
708813 const char * str = luaL_checkstring (L , 1 );
@@ -713,7 +818,6 @@ ltext_(lua_State *L, struct styles *s, int gen_layout, int external) {
713818 ctx .width = luaL_optinteger (L , 2 , MAX_WIDTH );
714819 ctx .height = luaL_optinteger (L , 3 , MAX_HEIGHT );
715820
716- struct font_manager * mgr = s -> font ;
717821 ctx .x = 0 ;
718822 ctx .color = s -> s [0 ].color ;
719823 ctx .y = 0 ;
@@ -724,7 +828,6 @@ ltext_(lua_State *L, struct styles *s, int gen_layout, int external) {
724828 ctx .line_height = 0 ;
725829 ctx .alignment = lua_tointeger (L , lua_upvalueindex (5 ));
726830
727- char * buffer = NULL ;
728831 struct text_primitive * prim = NULL ;
729832 struct layout * pos = NULL ;
730833 if (gen_layout ) {
@@ -739,88 +842,76 @@ ltext_(lua_State *L, struct styles *s, int gen_layout, int external) {
739842 pos -> line_count = 0 ;
740843 set_layout_styles (L , pos , s , external );
741844 } else {
742- buffer = (char * )malloc (count * sizeof (struct text_primitive )+1 );
743- prim = (struct text_primitive * )buffer ;
845+ prim = (struct text_primitive * )malloc ((size_t )count * sizeof (* prim ) + 1 );
846+ if (prim == NULL )
847+ return luaL_error (L , "Out of memory" );
744848 }
745849 int n = 0 ;
850+ int group = 0 ;
746851 for (;;) {
747- uint32_t val = 0 ;
748- str = utf8_decode (str , & val );
749- if (str == NULL || val == 0 )
852+ struct text_token token ;
853+ str = next_text_token (str , & ctx , & group , & token );
854+ if (token . type == TEXT_TOKEN_END )
750855 break ;
751- if (val <= 32 ) {
752- if (val == '\n' ) {
753- if (ctx .x > ctx .line_width )
754- ctx .line_width = ctx .x ;
755- if (newline (& ctx , prim , n , pos ))
756- break ;
757- } else {
758- struct font_glyph g , og ;
759- if (font_manager_glyph (mgr , ctx .fs -> fontid , ' ' , ctx .fs -> size , & g , & og ) == NULL ) {
856+ if (token .type == TEXT_TOKEN_GROUP ) {
857+ if (group > 0 && ctx .x > 0 ) {
858+ int group_width = measure_word_group (str , & ctx , group );
859+ if (group_width <= ctx .width &&
860+ ctx .x + group_width > ctx .width ) {
760861 if (ctx .x > ctx .line_width )
761862 ctx .line_width = ctx .x ;
762- if (advance_space (& ctx , prim , pos , & n , g . advance_x ))
863+ if (newline (& ctx , prim , n , pos ))
763864 break ;
764865 }
765866 }
867+ continue ;
868+ }
869+ if (token .type == TEXT_TOKEN_NEWLINE ) {
870+ if (ctx .x > ctx .line_width )
871+ ctx .line_width = ctx .x ;
872+ if (newline (& ctx , prim , n , pos ))
873+ break ;
874+ continue ;
875+ }
876+ if (token .type == TEXT_TOKEN_SPACE ) {
877+ if (ctx .x > ctx .line_width )
878+ ctx .line_width = ctx .x ;
879+ if (advance_space (& ctx , prim , pos , & n , token .advance_x ))
880+ break ;
881+ continue ;
882+ }
883+
884+ if (prim ) {
885+ prim [n ].pos .x = ctx .x * PIXEL_SCALE ;
886+ prim [n ].pos .y = (ctx .y + token .dy ) * PIXEL_SCALE ;
887+ prim [n ].pos .sr = 0 ;
888+ prim [n ].pos .sprite = - material_id ;
766889 } else {
767- int icon = 0 ;
768- if (val == '[' ) {
769- if (* str != '[' ) {
770- str = parse_bracket (& ctx , str , & icon );
771- if (!icon ) {
772- continue ;
773- }
774- } else {
775- ++ str ;
776- }
777- }
778- int dy = 0 ;
779- int codepoint = val ;
780- int font = ctx .fs -> fontid ;
781-
782- if (icon > 0 ) {
783- codepoint = icon - 1 ;
784- font = FONT_ICON ;
785-
786- dy = - ctx .fs -> ascent ;
787- }
788-
890+ // assert(pos != NULL)
891+ set_position (pos , n , & ctx );
892+ }
893+
894+ if (ctx .x > ctx .line_width )
895+ ctx .line_width = ctx .x ;
896+ if (advance (pos , & ctx , token .advance_x )) {
897+ if (newline (& ctx , prim , n , pos ))
898+ break ;
789899 if (prim ) {
790900 prim [n ].pos .x = ctx .x * PIXEL_SCALE ;
791- prim [n ].pos .y = ( ctx .y + dy ) * PIXEL_SCALE ;
792- prim [n ].pos .sr = 0 ;
793- prim [n ].pos .sprite = - material_id ;
901+ prim [n ].pos .y = (ctx .y + token .dy ) * PIXEL_SCALE ;
794902 } else {
795- // assert(pos != NULL)
796903 set_position (pos , n , & ctx );
797904 }
798-
799- struct font_glyph g , og ;
800- if (font_manager_glyph (mgr , font , codepoint , ctx .fs -> size , & g , & og ) == NULL ) {
801- if (ctx .x > ctx .line_width )
802- ctx .line_width = ctx .x ;
803- if (advance (pos , & ctx , g .advance_x )) {
804- if (newline (& ctx , prim , n , pos ))
805- break ;
806- if (prim ) {
807- prim [n ].pos .x = ctx .x * PIXEL_SCALE ;
808- prim [n ].pos .y = ( ctx .y + dy ) * PIXEL_SCALE ;
809- } else {
810- set_position (pos , n , & ctx );
811- }
812- advance (pos , & ctx , g .advance_x );
813- }
814- if (prim ) {
815- prim [n ].u .text .header .sprite = -1 ;
816- prim [n ].u .text .codepoint = codepoint ;
817- prim [n ].u .text .font = font ;
818- prim [n ].u .text .size = ctx .fs -> size ;
819- prim [n ].u .text .color = ctx .color ;
820- }
821- ++ n ;
822- }
905+ advance (pos , & ctx , token .advance_x );
906+ }
907+ if (prim ) {
908+ prim [n ].u .text .header .sprite = -1 ;
909+ prim [n ].u .text .codepoint = token .codepoint ;
910+ prim [n ].u .text .font = token .font ;
911+ prim [n ].u .text .size = ctx .fs -> size ;
912+ prim [n ].u .text .color = ctx .color ;
823913 }
914+ ++ n ;
824915 }
825916 if (ctx .x > ctx .line_width )
826917 ctx .line_width = ctx .x ;
@@ -864,7 +955,8 @@ ltext_(lua_State *L, struct styles *s, int gen_layout, int external) {
864955 prim [i ].pos .y += offy ;
865956 }
866957 }
867- lua_pushexternalstring (L , buffer , n * sizeof (struct text_primitive ), free_primitive , NULL );
958+ lua_pushexternalstring (L , (char * )prim ,
959+ n * sizeof (struct text_primitive ), free_primitive , NULL );
868960 lua_pushinteger (L , height );
869961 return 2 ;
870962 } else {
0 commit comments