@@ -50,6 +50,34 @@ namespace iText.Layout.Font {
5050 public class FontSelector {
5151 protected internal IList < FontInfo > fonts ;
5252
53+ private const int EXPECTED_FONT_IS_BOLD_AWARD = 5 ;
54+
55+ private const int EXPECTED_FONT_IS_NOT_BOLD_AWARD = 3 ;
56+
57+ private const int EXPECTED_FONT_IS_ITALIC_AWARD = 5 ;
58+
59+ private const int EXPECTED_FONT_IS_NOT_ITALIC_AWARD = 3 ;
60+
61+ private const int EXPECTED_FONT_IS_MONOSPACED_AWARD = 5 ;
62+
63+ private const int EXPECTED_FONT_IS_NOT_MONOSPACED_AWARD = 1 ;
64+
65+ private const int FULL_NAME_EQUALS_AWARD = 11 ;
66+
67+ private const int FONT_NAME_EQUALS_AWARD = 11 ;
68+
69+ private const int ALIAS_EQUALS_AWARD = 11 ;
70+
71+ private const int FULL_NAME_CONTAINS_AWARD = 7 ;
72+
73+ private const int FONT_NAME_CONTAINS_AWARD = 7 ;
74+
75+ private const int ALIAS_CONTAINS_AWARD = 7 ;
76+
77+ private const int CONTAINS_ADDITIONAL_AWARD = 3 ;
78+
79+ private const int EQUALS_ADDITIONAL_AWARD = 3 ;
80+
5381 /// <summary>Create new FontSelector instance.</summary>
5482 /// <param name="allFonts">Unsorted set of all available fonts.</param>
5583 /// <param name="fontFamilies">Sorted list of preferred font families.</param>
@@ -132,77 +160,105 @@ private static FontCharacteristics ParseFontStyle(String fontFamily, FontCharact
132160 return fc ;
133161 }
134162
163+ /// <summary>
164+ /// This method is used to compare two fonts (the first is described by fontInfo,
165+ /// the second is described by fc and fontName) and measure their similarity.
166+ /// </summary>
167+ /// <remarks>
168+ /// This method is used to compare two fonts (the first is described by fontInfo,
169+ /// the second is described by fc and fontName) and measure their similarity.
170+ /// The more the fonts are similar the higher the score is.
171+ /// We check whether the fonts are both:
172+ /// a) bold
173+ /// b) italic
174+ /// c) monospaced
175+ /// We also check whether the font names are identical. There are two blocks of conditions:
176+ /// "equals" and "contains". They cannot be satisfied simultaneously.
177+ /// Some remarks about these checks:
178+ /// a) "contains" block checks are much easier to be satisfied so one can get award from this block
179+ /// higher than from "equals" block only if all "contains" conditions are satisfied.
180+ /// b) since ideally all conditions of a certain block are satisfied simultaneously, it may result
181+ /// in highly inflated score. So we decrease an award for other conditions of the block
182+ /// if one has been already satisfied.
183+ /// </remarks>
135184 private static int CharacteristicsSimilarity ( String fontName , FontCharacteristics fc , FontInfo fontInfo ) {
136185 bool isFontBold = fontInfo . GetDescriptor ( ) . IsBold ( ) || fontInfo . GetDescriptor ( ) . GetFontWeight ( ) > 500 ;
137186 bool isFontItalic = fontInfo . GetDescriptor ( ) . IsItalic ( ) || fontInfo . GetDescriptor ( ) . GetItalicAngle ( ) < 0 ;
138187 bool isFontMonospace = fontInfo . GetDescriptor ( ) . IsMonospace ( ) ;
139188 int score = 0 ;
140189 if ( fc . IsBold ( ) ) {
141190 if ( isFontBold ) {
142- score += 5 ;
191+ score += EXPECTED_FONT_IS_BOLD_AWARD ;
143192 }
144193 else {
145- score -= 5 ;
194+ score -= EXPECTED_FONT_IS_BOLD_AWARD ;
146195 }
147196 }
148197 else {
149198 if ( isFontBold ) {
150- score -= 3 ;
199+ score -= EXPECTED_FONT_IS_NOT_BOLD_AWARD ;
151200 }
152201 }
153202 if ( fc . IsItalic ( ) ) {
154203 if ( isFontItalic ) {
155- score += 5 ;
204+ score += EXPECTED_FONT_IS_ITALIC_AWARD ;
156205 }
157206 else {
158- score -= 5 ;
207+ score -= EXPECTED_FONT_IS_ITALIC_AWARD ;
159208 }
160209 }
161210 else {
162211 if ( isFontItalic ) {
163- score -= 3 ;
212+ score -= EXPECTED_FONT_IS_NOT_ITALIC_AWARD ;
164213 }
165214 }
166215 if ( fc . IsMonospace ( ) ) {
167216 if ( isFontMonospace ) {
168- score += 5 ;
217+ score += EXPECTED_FONT_IS_MONOSPACED_AWARD ;
169218 }
170219 else {
171- score -= 5 ;
220+ score -= EXPECTED_FONT_IS_MONOSPACED_AWARD ;
172221 }
173222 }
174223 else {
175224 if ( isFontMonospace ) {
176- score -= 1 ;
225+ score -= EXPECTED_FONT_IS_NOT_MONOSPACED_AWARD ;
177226 }
178227 }
179228 FontProgramDescriptor descriptor = fontInfo . GetDescriptor ( ) ;
180229 // Note, aliases are custom behaviour, so in FontSelector will find only exact name,
181230 // it should not be any 'contains' with aliases.
182231 bool checkContains = true ;
183232 if ( fontName . Equals ( descriptor . GetFullNameLowerCase ( ) ) ) {
184- score += 4 ;
233+ // the next condition can be simplified. it's been written that way to prevent mistakes if the condition is moved.
234+ score += checkContains ? FULL_NAME_EQUALS_AWARD : EQUALS_ADDITIONAL_AWARD ;
185235 checkContains = false ;
186236 }
187237 if ( fontName . Equals ( descriptor . GetFontNameLowerCase ( ) ) ) {
188- score += 4 ;
238+ score += checkContains ? FONT_NAME_EQUALS_AWARD : EQUALS_ADDITIONAL_AWARD ;
189239 checkContains = false ;
190240 }
191241 if ( fontName . Equals ( fontInfo . GetAlias ( ) ) ) {
192- score += 4 ;
242+ score += checkContains ? ALIAS_EQUALS_AWARD : EQUALS_ADDITIONAL_AWARD ;
193243 checkContains = false ;
194244 }
195245 if ( checkContains ) {
246+ bool conditionHasBeenSatisfied = false ;
196247 if ( descriptor . GetFullNameLowerCase ( ) . Contains ( fontName ) ) {
197- score += 3 ;
248+ // the next condition can be simplified. it's been written that way to prevent mistakes if the condition is moved.
249+ score += conditionHasBeenSatisfied ? FULL_NAME_CONTAINS_AWARD : CONTAINS_ADDITIONAL_AWARD ;
250+ conditionHasBeenSatisfied = true ;
198251 }
199252 if ( descriptor . GetFontNameLowerCase ( ) . Contains ( fontName ) ) {
200- score += 3 ;
253+ score += conditionHasBeenSatisfied ? FONT_NAME_CONTAINS_AWARD : CONTAINS_ADDITIONAL_AWARD ;
254+ conditionHasBeenSatisfied = true ;
201255 }
202256 if ( null != fontInfo . GetAlias ( ) && fontInfo . GetAlias ( ) . Contains ( fontName ) ) {
203- score += 3 ;
257+ score += conditionHasBeenSatisfied ? ALIAS_CONTAINS_AWARD : CONTAINS_ADDITIONAL_AWARD ;
258+ conditionHasBeenSatisfied = true ;
204259 }
205260 }
261+ // this line is redundant. it's added to prevent mistakes if other condition is added.
206262 return score ;
207263 }
208264 }
0 commit comments