Skip to content

Commit 115f777

Browse files
committed
Changes in FontSelector's logic.
Introduce award constants. Minor changes suggested by reviewers. Decrease award for a block of conditions after it was added. Increase contains and check scores against style characteristics. DEVSIX-1685
1 parent 8c986f1 commit 115f777

File tree

3 files changed

+67
-16
lines changed

3 files changed

+67
-16
lines changed

layout/src/main/java/com/itextpdf/layout/font/FontSelector.java

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,25 @@ public class FontSelector {
5353

5454
protected List<FontInfo> fonts;
5555

56+
private static final int EXPECTED_FONT_IS_BOLD_AWARD = 5;
57+
private static final int EXPECTED_FONT_IS_NOT_BOLD_AWARD = 3;
58+
private static final int EXPECTED_FONT_IS_ITALIC_AWARD = 5;
59+
private static final int EXPECTED_FONT_IS_NOT_ITALIC_AWARD = 3;
60+
private static final int EXPECTED_FONT_IS_MONOSPACED_AWARD = 5;
61+
private static final int EXPECTED_FONT_IS_NOT_MONOSPACED_AWARD = 1;
62+
63+
private static final int FULL_NAME_EQUALS_AWARD = 11;
64+
private static final int FONT_NAME_EQUALS_AWARD = 11;
65+
private static final int ALIAS_EQUALS_AWARD = 11;
66+
67+
private static final int FULL_NAME_CONTAINS_AWARD = 7;
68+
private static final int FONT_NAME_CONTAINS_AWARD = 7;
69+
private static final int ALIAS_CONTAINS_AWARD = 7;
70+
71+
private static final int CONTAINS_ADDITIONAL_AWARD = 3;
72+
private static final int EQUALS_ADDITIONAL_AWARD = 3;
73+
74+
5675
/**
5776
* Create new FontSelector instance.
5877
* @param allFonts Unsorted set of all available fonts.
@@ -136,68 +155,100 @@ private static FontCharacteristics parseFontStyle(String fontFamily, FontCharact
136155
return fc;
137156
}
138157

158+
/**
159+
* This method is used to compare two fonts (the first is described by fontInfo,
160+
* the second is described by fc and fontName) and measure their similarity.
161+
* The more the fonts are similar the higher the score is.
162+
*
163+
* We check whether the fonts are both:
164+
* a) bold
165+
* b) italic
166+
* c) monospaced
167+
*
168+
* We also check whether the font names are identical. There are two blocks of conditions:
169+
* "equals" and "contains". They cannot be satisfied simultaneously.
170+
* Some remarks about these checks:
171+
* a) "contains" block checks are much easier to be satisfied so one can get award from this block
172+
* higher than from "equals" block only if all "contains" conditions are satisfied.
173+
* b) since ideally all conditions of a certain block are satisfied simultaneously, it may result
174+
* in highly inflated score. So we decrease an award for other conditions of the block
175+
* if one has been already satisfied.
176+
*/
139177
private static int characteristicsSimilarity(String fontName, FontCharacteristics fc, FontInfo fontInfo) {
140178
boolean isFontBold = fontInfo.getDescriptor().isBold() || fontInfo.getDescriptor().getFontWeight() > 500;
141179
boolean isFontItalic = fontInfo.getDescriptor().isItalic() || fontInfo.getDescriptor().getItalicAngle() < 0;
142180
boolean isFontMonospace = fontInfo.getDescriptor().isMonospace();
143181
int score = 0;
144182
if (fc.isBold()) {
145183
if (isFontBold) {
146-
score += 5;
184+
score += EXPECTED_FONT_IS_BOLD_AWARD;
147185
} else {
148-
score -= 5;
186+
score -= EXPECTED_FONT_IS_BOLD_AWARD;
149187
}
150188
} else {
151189
if (isFontBold) {
152-
score -= 3;
190+
score -= EXPECTED_FONT_IS_NOT_BOLD_AWARD;
153191
}
154192
}
155193

156194
if (fc.isItalic()) {
157195
if (isFontItalic) {
158-
score += 5;
196+
score += EXPECTED_FONT_IS_ITALIC_AWARD;
159197
} else {
160-
score -= 5;
198+
score -= EXPECTED_FONT_IS_ITALIC_AWARD;
161199
}
162200
} else {
163201
if (isFontItalic) {
164-
score -= 3;
202+
score -= EXPECTED_FONT_IS_NOT_ITALIC_AWARD;
165203
}
166204
}
167205

168206
if (fc.isMonospace()) {
169207
if (isFontMonospace) {
170-
score += 5;
208+
score += EXPECTED_FONT_IS_MONOSPACED_AWARD;
171209
} else {
172-
score -= 5;
210+
score -= EXPECTED_FONT_IS_MONOSPACED_AWARD;
173211
}
174212
} else {
175213
if (isFontMonospace) {
176-
score -= 1;
214+
score -= EXPECTED_FONT_IS_NOT_MONOSPACED_AWARD;
177215
}
178216
}
179217

180218
FontProgramDescriptor descriptor = fontInfo.getDescriptor();
181219
// Note, aliases are custom behaviour, so in FontSelector will find only exact name,
182220
// it should not be any 'contains' with aliases.
183221
boolean checkContains = true;
222+
184223
if (fontName.equals(descriptor.getFullNameLowerCase())) {
185-
score += 4;
224+
// the next condition can be simplified. it's been written that way to prevent mistakes if the condition is moved.
225+
score += checkContains ? FULL_NAME_EQUALS_AWARD : EQUALS_ADDITIONAL_AWARD;
186226
checkContains = false;
187227
}
188228
if (fontName.equals(descriptor.getFontNameLowerCase())) {
189-
score += 4;
229+
score += checkContains ? FONT_NAME_EQUALS_AWARD : EQUALS_ADDITIONAL_AWARD;
190230
checkContains = false;
191231
}
192232
if (fontName.equals(fontInfo.getAlias())) {
193-
score += 4;
233+
score += checkContains ? ALIAS_EQUALS_AWARD : EQUALS_ADDITIONAL_AWARD;
194234
checkContains = false;
195235
}
196236

197237
if (checkContains) {
198-
if (descriptor.getFullNameLowerCase().contains(fontName)) score += 3;
199-
if (descriptor.getFontNameLowerCase().contains(fontName)) score += 3;
200-
if (null != fontInfo.getAlias() && fontInfo.getAlias().contains(fontName)) score += 3;
238+
boolean conditionHasBeenSatisfied = false;
239+
if (descriptor.getFullNameLowerCase().contains(fontName)) {
240+
// the next condition can be simplified. it's been written that way to prevent mistakes if the condition is moved.
241+
score += conditionHasBeenSatisfied ? FULL_NAME_CONTAINS_AWARD : CONTAINS_ADDITIONAL_AWARD;
242+
conditionHasBeenSatisfied = true;
243+
}
244+
if (descriptor.getFontNameLowerCase().contains(fontName)) {
245+
score += conditionHasBeenSatisfied ? FONT_NAME_CONTAINS_AWARD : CONTAINS_ADDITIONAL_AWARD;
246+
conditionHasBeenSatisfied = true;
247+
}
248+
if (null != fontInfo.getAlias() && fontInfo.getAlias().contains(fontName)) {
249+
score += conditionHasBeenSatisfied ? ALIAS_CONTAINS_AWARD : CONTAINS_ADDITIONAL_AWARD;
250+
conditionHasBeenSatisfied = true; // this line is redundant. it's added to prevent mistakes if other condition is added.
251+
}
201252
}
202253

203254
return score;

layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public void customFontWeight2() throws Exception {
183183
sel.getFontSet().addFont(StandardFonts.HELVETICA);
184184
sel.getFontSet().addFont(StandardFonts.HELVETICA_BOLD);
185185
sel.getFontSet().addFont(StandardFonts.TIMES_ROMAN);
186-
//sel.getFontSet().addFont(FontConstants.TIMES_BOLD);
186+
//sel.getFontSet().addFont(StandardFonts.TIMES_BOLD);
187187

188188
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new FileOutputStream(outFileName)));
189189
Document doc = new Document(pdfDoc);

0 commit comments

Comments
 (0)