1+ using System ;
2+ using System . Text ;
3+ using System . Text . RegularExpressions ;
4+
5+ namespace jp . netsis . RubyText
6+ {
7+ public static class RubyTextConstants
8+ {
9+ public enum RubyShowType
10+ {
11+ RUBY_ALIGNMENT ,
12+ BASE_ALIGNMENT ,
13+ BASE_NO_OVERRAP_RUBY_ALIGNMENT ,
14+ }
15+
16+ public static readonly Regex RUBY_REGEX = new ( @"<r(uby)?=""?(?<ruby>[\s\S]*?)""?>(?<val>[\s\S]*?)<\/r(uby)?>" ) ;
17+ private static Lazy < StringBuilder > stringBuilder = new ( ) ;
18+
19+ public static string ReplaceRubyTags ( this IRubyText targetRubyText , string str , int dir , float fontSizeScale , float hiddenSpaceW )
20+ {
21+ // Replace <ruby> tags text layout.
22+ MatchCollection matches = RUBY_REGEX . Matches ( str ) ;
23+ int lastMatchIndex = 0 ;
24+ float currentTextW = 0f ;
25+ float rubyCurrentTextW = 0f ;
26+ StringBuilder stringBuilder = new ( ) ;
27+
28+ if ( matches . Count == 0 )
29+ {
30+ stringBuilder . Append ( str ) ;
31+ }
32+ else
33+ {
34+ foreach ( Match match in matches )
35+ {
36+ if ( match . Groups . Count != 5 )
37+ {
38+ continue ;
39+ }
40+
41+ if ( match . Index > lastMatchIndex )
42+ {
43+ string unmatchPart = str . Substring ( lastMatchIndex , match . Index - lastMatchIndex ) ;
44+ float unmatchTextW = targetRubyText . GetPreferredValues ( unmatchPart ) . x ;
45+ currentTextW += unmatchTextW ;
46+ stringBuilder . Append ( unmatchPart ) ;
47+ }
48+
49+ string rubyText = match . Groups [ "ruby" ] . ToString ( ) ;
50+ string baseText = match . Groups [ "val" ] . ToString ( ) ;
51+
52+ float rubyTextW = targetRubyText . GetPreferredValues ( rubyText ) . x * ( targetRubyText . isOrthographic ? 1 : 10f ) *
53+ targetRubyText . rubyScale ;
54+ float baseTextW = targetRubyText . GetPreferredValues ( baseText ) . x * ( targetRubyText . isOrthographic ? 1 : 10f ) ;
55+
56+ if ( targetRubyText . enableAutoSizing )
57+ {
58+ rubyTextW *= fontSizeScale ;
59+ baseTextW *= fontSizeScale ;
60+ }
61+
62+ string replace = targetRubyText . CreateReplaceValue (
63+ dir ,
64+ baseText , baseTextW ,
65+ rubyText , rubyTextW ,
66+ ref currentTextW , ref rubyCurrentTextW ) ;
67+
68+ lastMatchIndex = match . Index + match . Length ;
69+
70+ stringBuilder . Append ( replace ) ;
71+ }
72+
73+ Match lastMatch = matches [ matches . Count - 1 ] ;
74+ stringBuilder . Append ( str . Substring ( lastMatch . Index + lastMatch . Length ) ) ;
75+ }
76+
77+ if ( ! string . IsNullOrWhiteSpace ( targetRubyText . rubyLineHeight ) )
78+ // warning! bad Know-how
79+ // line-height tag is down the next line start.
80+ // now line can't change, corresponding by putting a hidden ruby
81+ {
82+ stringBuilder . Insert ( 0 , $ "<line-height={ targetRubyText . rubyLineHeight } ><voffset={ targetRubyText . rubyVerticalOffset } ><size={ targetRubyText . rubyScale * 100f } %>\u00A0 </size></voffset><space={ hiddenSpaceW } >") ;
83+ }
84+
85+ return stringBuilder . ToString ( ) ;
86+ }
87+
88+ private static string CreateReplaceValue (
89+ this IRubyText targetRubyText ,
90+ int dir ,
91+ string baseText , float baseTextW ,
92+ string rubyText , float rubyTextW ,
93+ ref float currentTextW , ref float rubyCurrentTextW )
94+ {
95+ float baseTextDirW = dir * baseTextW ;
96+ float rubyTextDirW = dir * rubyTextW ;
97+ float rubyTextOffset = - dir * ( baseTextW * 0.5f + rubyTextW * 0.5f ) ;
98+ float compensationOffset = dir * ( ( baseTextW - rubyTextW ) * 0.5f ) ;
99+
100+ string replace = string . Empty ;
101+
102+ switch ( targetRubyText . rubyShowType )
103+ {
104+ case RubyShowType . BASE_ALIGNMENT :
105+ replace = targetRubyText . CreateBaseAfterRubyText ( baseText , rubyText , rubyTextOffset , compensationOffset ) ;
106+ currentTextW += baseTextDirW ;
107+ break ;
108+
109+ case RubyShowType . RUBY_ALIGNMENT :
110+ if ( targetRubyText . isRightToLeftText )
111+ {
112+ if ( compensationOffset < 0 )
113+ {
114+ replace = targetRubyText . CreateBaseAfterRubyText ( baseText , rubyText , rubyTextOffset , compensationOffset ) ;
115+ currentTextW += baseTextDirW ;
116+ }
117+ else
118+ {
119+ replace = targetRubyText . CreateRubyAfterBaseText ( baseText , rubyText , rubyTextOffset , compensationOffset ) ;
120+ currentTextW += rubyTextDirW ;
121+ }
122+ }
123+ else
124+ {
125+ if ( compensationOffset < 0 )
126+ {
127+ replace = targetRubyText . CreateRubyAfterBaseText ( baseText , rubyText , rubyTextOffset , compensationOffset ) ;
128+ currentTextW += rubyTextDirW ;
129+ }
130+ else
131+ {
132+ replace = targetRubyText . CreateBaseAfterRubyText ( baseText , rubyText , rubyTextOffset , compensationOffset ) ;
133+ currentTextW += baseTextDirW ;
134+ }
135+ }
136+ break ;
137+ case RubyShowType . BASE_NO_OVERRAP_RUBY_ALIGNMENT :
138+ stringBuilder . Value . Clear ( ) ;
139+ float rubyCurrentTextOffsetW = currentTextW + ( baseTextDirW + rubyTextOffset ) - rubyCurrentTextW ;
140+
141+ if ( 0f > rubyCurrentTextOffsetW ) {
142+ stringBuilder . Value . Append ( $ "<space={ - rubyCurrentTextOffsetW } >") ;
143+ rubyCurrentTextW = rubyCurrentTextW + rubyTextDirW + targetRubyText . rubyMargin ;
144+ currentTextW += - rubyCurrentTextOffsetW ;
145+ }
146+ else
147+ {
148+ rubyCurrentTextW = currentTextW + ( baseTextDirW + rubyTextOffset ) + rubyTextDirW ;
149+ }
150+
151+ currentTextW += baseTextDirW ;
152+
153+ string append = targetRubyText . CreateBaseAfterRubyText ( baseText , rubyText , rubyTextOffset , compensationOffset ) ;
154+ stringBuilder . Value . Append ( append ) ;
155+
156+ replace = stringBuilder . Value . ToString ( ) ;
157+ break ;
158+ default :
159+ throw new ArgumentOutOfRangeException ( ) ;
160+ }
161+
162+ return replace ;
163+ }
164+
165+ public static string CreateBaseAfterRubyText (
166+ this IRubyText targetRubyText , string baseText , string rubyText , float rubyTextOffset , float compensationOffset )
167+ {
168+ return
169+ $ "<nobr>{ baseText } <space={ rubyTextOffset } ><voffset={ targetRubyText . rubyVerticalOffset } ><size={ targetRubyText . rubyScale * 100f } %>{ rubyText } </size></voffset><space={ compensationOffset } ></nobr>";
170+ }
171+
172+ public static string CreateRubyAfterBaseText (
173+ this IRubyText targetRubyText , string baseText , string rubyText , float rubyTextOffset , float compensationOffset )
174+ {
175+ return
176+ $ "<nobr><space={ - compensationOffset } >{ baseText } <space={ rubyTextOffset } ><voffset={ targetRubyText . rubyVerticalOffset } ><size={ targetRubyText . rubyScale * 100f } %>{ rubyText } </size></voffset><space={ compensationOffset } ></nobr>";
177+ }
178+ }
179+ }
0 commit comments