diff --git a/inc/hgl/graph/font/TextLayout.h b/inc/hgl/graph/font/TextLayout.h index 881674ee..f4668ccd 100644 --- a/inc/hgl/graph/font/TextLayout.h +++ b/inc/hgl/graph/font/TextLayout.h @@ -75,10 +75,114 @@ namespace hgl bool compress_punctuation =false; ///<压缩标点符号 };//struct TextLayoutAttributes + + using TEXT_COORD_TYPE=int; //字符必须坐标对齐显示才能不模糊,所以这里坐标系全部使用整型坐标 - int TextLayout(RenderableCreater *,const TextLayoutAttributes *,const int max_chars,const UTF16String &); + class TextLayout + { + protected: - int PlaneTextLayout(RenderableCreater *,FontSource *font_source,const int max_chars,const UTF16String &,const uint8 text_direction=0); + struct CharLayoutAttributes + { + u32char ch; ///<字符 + + int size; ///<字符排版尺寸(一般为宽) + + bool visible; ///<是否可显示字符 + + bool is_cjk; ///<是否是中日韩文字 + bool is_emoji; ///<是否是表情符号 + + bool is_punctuation; ///<是否是标点符号 + + bool begin_disable; ///<是否行首禁用符号 + bool end_disable; ///<是否行尾禁用符号 + bool vrotate; ///<竖排时是否需要旋转 + + FontAdvInfo adv_info; ///<字符绘制信息 + };//struct CharLayoutAttributes + + using CLA=CharLayoutAttributes; + + protected: + + RenderableCreater *rc; + TextLayoutAttributes tla; + + protected: + + TextDirection direction; + + bool endless; + float splite_line_max_limit; + + int max_chars; ///<总字符数量 + int draw_chars_count; ///<可绘制字符数量 + + List chars_attributes; + + protected: + + template int preprocess(const BaseString &origin_string); + template int plane_preprocess(const BaseString &origin_string); + + bool h_splite_to_lines(float view_limit); + bool v_splite_to_lines(float view_limit); + + + int pl_h_l2r(); + int pl_h_r2l(); + int pl_v_r2l(); + int pl_v_l2r(); + + protected: + + TEXT_COORD_TYPE x,y; + TEXT_COORD_TYPE char_height; + TEXT_COORD_TYPE space_size; + TEXT_COORD_TYPE full_space_size; + TEXT_COORD_TYPE tab_size; + TEXT_COORD_TYPE char_gap; + TEXT_COORD_TYPE line_gap; + TEXT_COORD_TYPE line_height; + TEXT_COORD_TYPE paragraph_gap; + + protected: + + AutoDelete vertex, + tex_coord; + + public: + + TextLayout() + { + rc=nullptr; + + direction.text_direction=0; + max_chars =0; + draw_chars_count =0; + + vertex =nullptr; + tex_coord =nullptr; + } + + virtual ~TextLayout()=default; + + bool Set(RenderableCreater *_rc) {if(_rc)rc=_rc;} + bool Set(const TextLayoutAttributes *_tla) {if(_tla)memcpy(&tla,_tla,sizeof(TextLayoutAttributes));} + bool Set(FontSource *fs) {if(fs)tla.font_source=fs;} + bool SetTextDirection(const uint8 &td) {tla.text_direction=td;} + bool Set(const TextAlign &ta) {tla.align=ta;} + bool SetMaxWidth(const float mw) {tla.max_width=mw;} + bool SetMaxHeight(const float mh) {tla.max_height=mh;} + + virtual bool Init (); ///<初始化排版 + +// virtual int Layout (const int max_chars,const BaseString &)=0; ///<排版 + + template + int PlaneLayout (const int max_chars,const BaseString &)=0; ///<简易排版 + };//class TextLayout }//namespace graph }//namespace hgl #endif//HGL_GRAPH_TEXT_LAYOUT_INCLUDE diff --git a/src/SceneGraph/font/TextLayout.cpp b/src/SceneGraph/font/TextLayout.cpp index e6fe0038..531e0597 100644 --- a/src/SceneGraph/font/TextLayout.cpp +++ b/src/SceneGraph/font/TextLayout.cpp @@ -18,29 +18,6 @@ namespace hgl constexpr int CurrencySymbolsCount=(sizeof(CurrencySymbols)/sizeof(u16char))-1; constexpr int VRotateSymbolsCount =(sizeof(VRotateSymbols) /sizeof(u16char))-1; - using TEXT_COORD_TYPE=int; //字符必须坐标对齐显示才能不模糊,所以这里坐标系全部使用整型坐标 - - template - struct CharLayoutAttributes - { - T ch; ///<字符 - - int size; ///<字符排版尺寸(一般为宽) - - bool visible; ///<是否可显示字符 - - bool is_cjk; ///<是否是中日韩文字 - bool is_emoji; ///<是否是表情符号 - - bool is_punctuation; ///<是否是标点符号 - - bool begin_disable; ///<是否行首禁用符号 - bool end_disable; ///<是否行尾禁用符号 - bool vrotate; ///<竖排时是否需要旋转 - - FontAdvInfo adv_info; ///<字符绘制信息 - };//struct CharLayoutAttributes - /** * 4舍5入处理 */ @@ -48,289 +25,269 @@ namespace hgl { return TEXT_COORD_TYPE(floor(value+0.5)); } - - template class TextLayoutEngine - { - protected: - - RenderableCreater *rc; - const TextLayoutAttributes *tla; - - TextDirection direction; - - bool endless; - float splite_line_max_limit; - - int max_chars; - - BaseString origin_string; - - using CLA=CharLayoutAttributes; - - List chars_attributes; - - protected: - - TEXT_COORD_TYPE x,y; - TEXT_COORD_TYPE char_height; - TEXT_COORD_TYPE space_size; - TEXT_COORD_TYPE full_space_size; - TEXT_COORD_TYPE tab_size; - TEXT_COORD_TYPE char_gap; - TEXT_COORD_TYPE line_gap; - TEXT_COORD_TYPE line_height; - TEXT_COORD_TYPE paragraph_gap; - - protected: - - AutoDelete vertex; - - public: - - TextLayoutEngine() - { - rc=nullptr; - tla=nullptr; - direction.text_direction=0; - max_chars=0; - vertex=nullptr; - } - - virtual ~TextLayoutEngine()=default; - - bool Init(RenderableCreater *_rc,const TextLayoutAttributes *_tla) - { - if(!_rc - ||!_tla - ||!tla->font_source - ||!tla->char_attributes) - return false; - - rc=_rc; - tla=_tla; - - direction.text_direction=tla->text_direction; - - if(direction.vertical) - { - endless =(tla->max_width<=0.0f); - splite_line_max_limit =tla->max_width; - } - else - { - endless =(tla->max_height<=0.0f); - splite_line_max_limit =tla->max_height; - } - - const float origin_char_height=tla->font_source->GetCharHeight(); - - x=y=0; - char_height =out4in5(origin_char_height); - space_size =out4in5(origin_char_height*tla->space_size); - full_space_size =out4in5(origin_char_height*tla->full_space_size); - tab_size =out4in5(origin_char_height*tla->tab_size); - char_gap =out4in5(origin_char_height*tla->char_gap); - line_gap =out4in5(origin_char_height*tla->line_gap); - line_height =out4in5(origin_char_height+line_gap); - paragraph_gap =out4in5(origin_char_height*tla->paragraph_gap); - - return(true); - } - - protected: - - /** - * 预处理所有的字符,获取所有字符的宽高,以及是否标点符号等信息 - */ - int preprocess() - { - const int count=hgl_min(max_chars,origin_string.Length()); - - if(count<=0) - return 0; - - chars_attributes.SetCount(count); - - CLA *cla=chars_attributes.GetData(); - const T *cp=origin_string.c_str(); - - for(int i=0;ich=*cp; - - if(hgl::isspace(*cp)) - { - cla->visible=false; - - if(*cp=='\t') cla->size=tab_size; else - if(*cp==HGL_FULL_SPACE) cla->size=full_space_size; else - cla->size=space_size; - } - else - { - cla->visible=true; cla->size=out4in5(tla->font_source->GetCharAdvWidth(*cp)); - - cla->begin_disable =hgl::strchr(BeginSymbols, *cp,BeginSymbolsCount ); - cla->end_disable =hgl::strchr(EndSymbols, *cp,EndSymbolsCount ); - - if(!cla->end_disable) //货币符号同样行尾禁用 - cla->end_disable =hgl::strchr(CurrencySymbols,*cp,CurrencySymbolsCount ); - - cla->vrotate =hgl::strchr(VRotateSymbols,*cp,VRotateSymbolsCount ); - - cla->is_cjk =isCJK(*cp); - cla->is_emoji =isEmoji(*cp); - - cla->is_punctuation =isPunctuation(*cp); - - if(!tla->font_source->GetCharAdvInfo(cla->adv_info,*cp)) - hgl_zero(cla->adv_info); - } - - ++cp; - ++cla; - } - - return count; - } - - /** - * 将字符串断成多行,处理标点禁用,以及英文单词禁拆分 - */ - bool h_splite_to_lines(float view_limit) - { - const int count=chars_attributes.GetCount(); - const CLA *cla=chars_attributes.GetData(); - - int cur_size=0; - - for(int i=0;i &str) - { - if(mc<=0 - ||!str - ||!(*str)) - return(-1); - - max_chars=mc; - origin_string=str; - - if(preprocess()<=0) - return(-3); - - if(direction.vertical) - { - if(!v_splite_to_lines(tla->max_height)) - return(-4); - } - else - { - if(!h_splite_to_lines(tla->max_width)) - return(-4); - } - - return 0; - } - - protected: - - int pl_h_l2r() - { - const int count=chars_attributes.GetCount(); - const CLA *cla=chars_attributes.GetData(); - - int cur_size=0; - - for(int i=0;iWrite(x,y - } - } - - int pl_h_r2l() - { - return 0; - } - - int pl_v_r2l() - { - return 0; - } - - int pl_v_l2r() - { - return 0; - } - - public: - - /** - * 平面文本排版
- * 不处理自动换行,仅支持\r\n换行。无任何特殊处理 - */ - int plane_layout(const int mc,const BaseString &str) - { - if(mc<=0 - ||!str - ||!(*str)) - return(-1); - - max_chars=hgl_min(mc,str.Length()); - origin_string=str; - - if(preprocess()<=0) - return(-3); - - if(!rc->Init(ch_count)) - return(-4); - - vertex=rc->CreateVADA(VAN::Vertex); - - if(!vertex) - return(-5); - - if(direction.vertical) - { - if(direction.right_to_left) - return pl_v_r2l(); - else - return pl_v_l2r(); - } - else - { - if(direction.right_to_left) - return pl_h_r2l(); - else - return pl_h_l2r(); - } - - return 0; - } - };//template class TextLayoutEngine }//namespace - int TextLayout(RenderableCreater *rc,const TextLayoutAttributes *tla,const int max_chars,const UTF16String &str) + bool TextLayout::Init() { - TextLayoutEngine engine; + if(!rc + ||!tla.font_source + ||!tla.char_attributes) + return(false); - if(!engine.Init(rc,tla)) + direction.text_direction=tla.text_direction; + + if(direction.vertical) + { + endless =(tla.max_width<=0.0f); + splite_line_max_limit = tla.max_width; + } + else + { + endless =(tla.max_height<=0.0f); + splite_line_max_limit = tla.max_height; + } + + const float origin_char_height=tla.font_source->GetCharHeight(); + + x=y=0; + char_height =out4in5(origin_char_height); + space_size =out4in5(origin_char_height*tla.space_size); + full_space_size =out4in5(origin_char_height*tla.full_space_size); + tab_size =out4in5(origin_char_height*tla.tab_size); + char_gap =out4in5(origin_char_height*tla.char_gap); + line_gap =out4in5(origin_char_height*tla.line_gap); + line_height =out4in5(origin_char_height+line_gap); + paragraph_gap =out4in5(origin_char_height*tla.paragraph_gap); + + return(true); + } + + /** + * 预处理所有的字符,获取所有字符的宽高,以及是否标点符号等信息 + */ + template + int TextLayout::preprocess(const BaseString &origin_string) + { + const int count=hgl_min(max_chars,origin_string.Length()); + + if(count<=0) + return 0; + + chars_attributes.SetCount(count); + draw_chars_count=0; + + CLA *cla=chars_attributes.GetData(); + const T *cp=origin_string.c_str(); + + for(int i=0;ich=*cp; + + if(hgl::isspace(*cp)) + { + cla->visible=false; + + if(*cp=='\t') cla->size=tab_size; else + if(*cp==HGL_FULL_SPACE) cla->size=full_space_size; else + cla->size=space_size; + } + else + { + cla->visible=true; cla->size=out4in5(tla.font_source->GetCharAdvWidth(*cp)); + + cla->begin_disable =hgl::strchr(BeginSymbols, *cp,BeginSymbolsCount ); + cla->end_disable =hgl::strchr(EndSymbols, *cp,EndSymbolsCount ); + + if(!cla->end_disable) //货币符号同样行尾禁用 + cla->end_disable =hgl::strchr(CurrencySymbols,*cp,CurrencySymbolsCount ); + + cla->vrotate =hgl::strchr(VRotateSymbols,*cp,VRotateSymbolsCount ); + + cla->is_cjk =isCJK(*cp); + cla->is_emoji =isEmoji(*cp); + + cla->is_punctuation =isPunctuation(*cp); + + if(!tla->font_source->GetCharAdvInfo(cla->adv_info,*cp)) + hgl_zero(cla->adv_info); + else + if(cla->adv_info.w>0&&cla->adv_info.h>0) + ++draw_chars_count; + } + + ++cp; + ++cla; + } + + return count; + } + + /** + * 简易预处理所有的字符,获取所有字符的宽高,以及是否标点符号等信息 + */ + template + int TextLayout::plane_preprocess(const BaseString &origin_string) + { + const int count=hgl_min(max_chars,origin_string.Length()); + + if(count<=0) + return 0; + + chars_attributes.SetCount(count); + draw_chars_count=0; + + CLA *cla=chars_attributes.GetData(); + const T *cp=origin_string.c_str(); + + for(int i=0;ich=*cp; + + if(hgl::isspace(*cp)) + { + cla->visible=false; + + if(*cp=='\t') cla->size=tab_size; else + if(*cp==HGL_FULL_SPACE) cla->size=full_space_size; else + cla->size=space_size; + } + else + { + cla->visible=true; cla->size=out4in5(tla.font_source->GetCharAdvWidth(*cp)); + + cla->vrotate =hgl::strchr(VRotateSymbols,*cp,VRotateSymbolsCount ); + + if(!tla->font_source->GetCharAdvInfo(cla->adv_info,*cp)) + hgl_zero(cla->adv_info); + else + if(cla->adv_info.w>0&&cla->adv_info.h>0) + ++draw_chars_count; + } + + ++cp; + ++cla; + } + + return count; + } + + /** + * 将字符串断成多行,处理标点禁用,以及英文单词禁拆分 + */ + bool TextLayout::h_splite_to_lines(float view_limit) + { + const int count=chars_attributes.GetCount(); + const CLA *cla=chars_attributes.GetData(); + + int cur_size=0; + + for(int i=0;i &str) + //{ + // if(mc<=0 + // ||!str + // ||!(*str)) + // return(-1); + + // max_chars=mc; + // origin_string=str; + + // if(preprocess()<=0) + // return(-3); + // + // if(!rc->Init(draw_chars_count)) + // return(-4); + + // vertex =rc->CreateVADA(VAN::Vertex); + // tex_coord =rc->CreateVADA(VAN::TexCoord); + + // if(!vertex||!tex_coord) + // return(-5); + + // if(direction.vertical) + // { + // if(!v_splite_to_lines(tla->max_height)) + // return(-4); + // } + // else + // { + // if(!h_splite_to_lines(tla->max_width)) + // return(-4); + // } + + // return 0; + //} + + int TextLayout::pl_h_l2r() + { + const int count=chars_attributes.GetCount(); + const CLA *cla=chars_attributes.GetData(); + + int cur_size=0; + int left=0,top=0; + + for(int i=0;iWrite( + } + } + + int TextLayout::pl_h_r2l(){return 0;} + int TextLayout::pl_v_r2l(){return 0;} + int TextLayout::pl_v_l2r(){return 0;} + + /** + * 平面文本排版
+ * 不处理自动换行,仅支持\r\n换行。无任何特殊处理 + */ + template + int TextLayout::PlaneLayout(const int mc,const BaseString &str) + { + if(mc<=0||str.IsEmpty() return(-1); - return engine.layout(max_chars,str); + max_chars=hgl_min(mc,str.Length()); + + if(plane_preprocess(str)<=0) + return(-3); + + if(!rc->Init(draw_chars_count)) + return(-4); + + vertex =rc->CreateVADA(VAN::Vertex); + tex_coord =rc->CreateVADA(VAN::TexCoord); + + if(!vertex||!tex_coord) + return(-5); + + if(direction.vertical) + { + if(direction.right_to_left) + return pl_v_r2l(); + else + return pl_v_l2r(); + } + else + { + if(direction.right_to_left) + return pl_h_r2l(); + else + return pl_h_l2r(); + } + + return 0; } }//namespace graph }//namespace hgl