diff --git a/CMCore b/CMCore index 360a7434..0e9bb594 160000 --- a/CMCore +++ b/CMCore @@ -1 +1 @@ -Subproject commit 360a743491e3310c8eedfc594a5c49b97180f177 +Subproject commit 0e9bb594d737717493ab0c943d34d2851f616f59 diff --git a/inc/hgl/graph/font/TextLayout.h b/inc/hgl/graph/font/TextLayout.h index 6431e28a..5d365b03 100644 --- a/inc/hgl/graph/font/TextLayout.h +++ b/inc/hgl/graph/font/TextLayout.h @@ -20,82 +20,66 @@ namespace hgl Color4f CharColor; ///<字符颜色 Color4f BackgroundColor; ///<背影颜色 };//struct CharAttributes + + /** + * 文本排列方向 + */ + union TextDirection + { + uint8 text_direction; + + struct + { + uint vertical:1; ///<是否竖排 + uint right_to_left:1; ///<是否从右往左 + uint bottom_to_top:1; ///<是否从下到上 + }; + };//union TextDirection /** - * 段落对齐 + * 文本对齐 */ - enum class ParagraphAlign + enum class TextAlign { Left=0, ///<左对齐 Right, ///<右对齐 Center, ///<居中 + Fill, ///<排满整行/列 Top =Left, ///<上对齐 Bottom =Right ///<下对齐 - };//enum class ParagraphAlign + };//enum class TextAlign /** - * 段落属性 - */ - struct ParagraphAttributes - { - ParagraphAlign align =ParagraphAlign::Left; ///<段落对齐 - float char_gap =0.0f; ///<字间距 - float line_gap =0.1f; ///<行间距(相对于字符高度) - - uint32 char_attributes =0; ///<缺省字符属性 - - bool border_symbols_disable =true; ///<边界符号禁用(如行首禁用逗号) - bool auto_symbols_convert =true; ///<自动符号转换(如tm/(r)/(c)等) - - float space_size =0.5f; ///<空格符尺寸(对应字符高度的系数) - float tab_size =2.0f; ///; - using ParagraphAttributesList=Map; - - /** - * 文本排版处理配置 + * 文本排版属性 */ struct TextLayoutAttributes { - FontSource * source =nullptr; ///字符源 + FontSource * font_source =nullptr; ///<字符源 + CharAttributes *char_attributes =nullptr; ///<缺省字符属性 - CharAttributesList char_attributes; ///<文本属性 - ParagraphAttributesList paragraph_attributes; ///<段落属性 - - float max_width =0.0f; ///<最大宽度(<=0代表无限制) - float max_height =0.0f; ///<最大高度(<=0代表无限制) + uint8 text_direction =0; ///<文本排列方向 + TextAlign align =TextAlign::Left; ///<段落对齐 + float char_gap =0.0f; ///<字间距 + float line_gap =0.1f; ///<行间距(相对于字符高度) + float paragraph_gap =1.0f; ///<段间距(相对于字符高度) - TextAttributes attributes; ///<文本属性 + float max_width =0.0f; ///<最大宽度(<=0代表无限制) + float max_height =0.0f; ///<最大高度(<=0代表无限制) + + bool border_symbols_disable =true; ///<边界符号禁用(如行首禁用逗号) +// bool auto_symbols_convert =true; ///<自动符号转换(如tm/(r)/(c)等) + + float space_size =0.5f; ///<半角空格尺寸(对应字符高度的系数) + float full_space_size =1.0f; ///<全角空格尺寸(对应字符高度的系数) + float tab_size =4.0f; ///h=gm.gmBlackBoxY; bmp->x=gm.gmptGlyphOrigin.x; - bmp->y=fnt.height-gm.gmptGlyphOrigin.y-LineDistance; + bmp->y=gm.gmptGlyphOrigin.y; bmp->adv_x=gm.gmCellIncX; bmp->adv_y=gm.gmCellIncY; diff --git a/src/SceneGraph/font/TextLayout.cpp b/src/SceneGraph/font/TextLayout.cpp new file mode 100644 index 00000000..4fd91718 --- /dev/null +++ b/src/SceneGraph/font/TextLayout.cpp @@ -0,0 +1,243 @@ +#include +#include +#include + +namespace hgl +{ + namespace graph + { + namespace + { + constexpr u16char BeginSymbols []=U16_TEXT("!),❟.:;?]}¨·ˇˉ―‖’❜”„❞…∶、。〃々❯〉》」』】〕〗!"'),.:;?]`|}~»›"); //行首禁用符号 + constexpr u16char EndSymbols []=U16_TEXT("([{·❛‘“‟❝❮〈《「『【〔〖(.[{«‹"); //行尾禁用符号 + constexpr u16char CurrencySymbols []=U16_TEXT("₳฿₿¢₡¢₢₵₫€££₤₣ƒ₲₭Ł₥₦₽₱$$₮ℳ₶₩₩¥¥₴₸¤₰៛₪₯₠₧﷼㍐원৳₹₨৲௹"); //货币符号 + constexpr u16char VRotateSymbols []=U16_TEXT("()[]{}〈〉《》「」『』【】〔〕〖〗()[]{}―‖…∶|~"); //竖排必须旋转的符号 + + constexpr int BeginSymbolsCount =sizeof(BeginSymbols) /sizeof(u16char); + constexpr int EndSymbolsCount =sizeof(EndSymbols) /sizeof(u16char); + constexpr int CurrencySymbolsCount=sizeof(CurrencySymbols)/sizeof(u16char); + constexpr int VRotateSymbolsCount =sizeof(VRotateSymbols) /sizeof(u16char); + + 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; ///<竖排时是否需要旋转 + };//struct CharLayoutAttributes + + /** + * 4舍5入处理 + */ + inline TEXT_COORD_TYPE out4in5(const double value) + { + 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; + + public: + + 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); + } + + ++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; + } + };//template class TextLayoutEngine + }//namespace + + int TextLayout(RenderableCreater *rc,const TextLayoutAttributes *tla,const int max_chars,const UTF16String &str) + { + TextLayoutEngine engine; + + if(!engine.Init(rc,tla)) + return(-1); + + return engine.layout(max_chars,str); + } + }//namespace graph +}//namespace hgl diff --git a/src/SceneGraph/font/TextLayoutPlane.cpp b/src/SceneGraph/font/TextLayoutPlane.cpp new file mode 100644 index 00000000..25b9f335 --- /dev/null +++ b/src/SceneGraph/font/TextLayoutPlane.cpp @@ -0,0 +1,21 @@ +#include + +namespace hgl +{ + namespace graph + { + /** + * 平面文本排版 + */ + int PlaneTextLayout(RenderableCreater *rc,FontSource *font_source,const int max_chars,const UTF16String &str) + { + if(!rc + ||!font_source + ||max_chars<=0 + ||str.IsEmpty()) + return 0; + + + } + }//namespace graph +}//namespace hgl \ No newline at end of file