I have a method which decides what font size to use for drawing a string. I'm using java.awt.Font.
Font size depends on string length and height, and I use do-while loop to decrease font size until the string fits targetHeight. So in general it looks something like this:
private void decideOnFontSize(String text) {
int fontSize = 72;
do {
font = new Font("Arial", Font.PLAIN, fontSize);
// Calculating things...
fontSize -= 2;
} while (textHeight >= targetHeight);
}
With this approach I need to instantiate a new Font object every time when I need a smaller font size. Method decideOnFontSize is a part of a service in a public API, so it could be called pretty often. At first sight, instantiating new Font looks pretty wasteful in this case.
Another approach is to create a pre-defined collection of Fonts and get them as required. So I could create a utility class like this:
public class FontsUtil {
private static Map<Integer, Font> fonts = new HashMap<>();
public static final Integer MAX_FONT_SIZE = 72;
public static final Integer MIN_FONT_SIZE = 10;
static {
String fontName = "Arial";
for(int fontSize = MAX_FONT_SIZE; fontSize >= MIN_FONT_SIZE; fontSize -= 2) {
fonts.put(fontSize, new Font(fontName, Font.PLAIN, fontSize));
}
}
public static Font getFontBySize(Integer fontSize) {
return fonts.get(fontSize);
}
}
...and then I could get these pre-defined Fonts in do-while loop, so my method will look like this:
private void decideOnFontSize(String text) {
int fontSize = FontsUtil.MAX_FONT_SIZE;
do {
font = FontsUtil.getFontBySize(fontSize);
// Calculating things...
fontSize -= 2;
} while (textHeight >= targetHeight);
}
To my mind, the second approach looks better, because (in theory) it consumes less resources. Am I right, or it doesn't really matter?
UPD: More specifically, I create one or more TextLayout objects using LineBreakMeasurer, because I have two initial params to fit: targetWidth and targetHeight. So my do-while looks like this:
List<TextLayout> lines;
int fontSize = font.getSize();
int textHeight;
do {
font = FontsUtil.getFontBySize(fontSize);
g2d.setFont(font);
lines = splitStringIntoPiecesToFitTargetWidth(text, targetWidth, g2d);
textHeight = getTextHeight(lines);
fontSize -= 2;
} while (textHeight >= targetHeight);
*where font is an instance variable
And method splitStringIntoPiecesToFitTargetWidth looks like this:
private List<TextLayout> splitStringIntoPiecesToFitTargetWidth(String string,
int width, Graphics2D g2d) {
List<TextLayout> lines = new ArrayList<>();
AttributedString attributedString = new AttributedString(string);
attributedString.addAttribute(TextAttribute.FONT, font);
LineBreakMeasurer lineBreakMeasurer =
new LineBreakMeasurer(attributedString.getIterator(), g2d.getFontRenderContext());
while (lineBreakMeasurer.getPosition() < string.length()) {
lines.add(lineBreakMeasurer.nextLayout(width));
}
return lines;
}