IDEA-97665 Provide an option to specify fall back fonts

New fallback fonts-aware fonts infrastructure correctly handles Dialog fonts now
This commit is contained in:
Denis.Zhdanov
2013-01-31 17:14:48 +04:00
parent 0fb0213c94
commit 09c0a67d8b
5 changed files with 85 additions and 35 deletions
@@ -264,7 +264,7 @@ public class FontOptions extends JPanel implements OptionsPanel{
myLineSpacingField.setText(Float.toString(getLineSpacing()));
mySelectedFontsModel.clear();
FontPreferences fontPreferences = getFontPreferences();
List<String> fontFamilies = fontPreferences.getFontFamilies();
List<String> fontFamilies = fontPreferences.getEffectiveFontFamilies();
Set<String> selectedFonts = ContainerUtilRt.newHashSet();
Object selectedValue = mySelectedFontsList.getSelectedValue();
mySelectedFontsModel.clear();
@@ -21,6 +21,7 @@ import com.intellij.util.containers.ContainerUtilRt;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.List;
@@ -41,7 +42,8 @@ public class FontPreferences {
public static final int DEFAULT_FONT_SIZE = FontSize.SMALL.getSize();
@NotNull private final TObjectIntHashMap<String> myFontSizes = new TObjectIntHashMap<String>();
@NotNull private final List<String> myFontFamilies = ContainerUtilRt.newArrayList();
@NotNull private final List<String> myEffectiveFontFamilies = ContainerUtilRt.newArrayList();
@NotNull private final List<String> myRealFontFamilies = ContainerUtilRt.newArrayList();
/**
* Font size to use by default. Default value is {@link #DEFAULT_FONT_SIZE}.
@@ -49,12 +51,14 @@ public class FontPreferences {
private int myTemplateFontSize = DEFAULT_FONT_SIZE;
public void clear() {
myFontFamilies.clear();
myEffectiveFontFamilies.clear();
myRealFontFamilies.clear();
myFontSizes.clear();
}
public void clearFonts() {
myFontFamilies.clear();
myEffectiveFontFamilies.clear();
myRealFontFamilies.clear();
}
public boolean hasSize(@NotNull String fontName) {
@@ -74,38 +78,69 @@ public class FontPreferences {
myTemplateFontSize = size;
}
/**
* This method might return results different from {@link #getRealFontFamilies()} when
* {@link #getFallbackName(String, int, EditorColorsScheme) a font family unavailable at current environment}
* has been {@link #register(String, int) registered} at the current font preferences object.
* <p/>
* Effective fonts will hold fallback values for such font families then (exposed by the current method), 'real fonts' will
* be available via {@link #getRealFontFamilies()}.
*
* @return effective font families to use
*/
@NotNull
public List<String> getFontFamilies() {
return myFontFamilies;
public List<String> getEffectiveFontFamilies() {
return myEffectiveFontFamilies;
}
/**
* @return 'real' font families
* @see #getEffectiveFontFamilies()
*/
@NotNull
public List<String> getRealFontFamilies() {
return myRealFontFamilies;
}
public void register(@NotNull String fontFamily, int size) {
if (!myFontFamilies.contains(fontFamily)) {
myFontFamilies.add(fontFamily);
String fallbackFontFamily = getFallbackName(fontFamily, size, null);
if (!myRealFontFamilies.contains(fontFamily)) {
myRealFontFamilies.add(fontFamily);
}
String effectiveFontFamily = fallbackFontFamily == null ? fontFamily : fallbackFontFamily;
if (!myEffectiveFontFamilies.contains(effectiveFontFamily)) {
myEffectiveFontFamilies.add(effectiveFontFamily);
}
setSize(fontFamily, size);
}
/**
* @return first element of the {@link #getFontFamilies() registered font families} (if any);
* @return first element of the {@link #getEffectiveFontFamilies() registered font families} (if any);
* {@link #DEFAULT_FONT_NAME} otherwise
*/
@NotNull
public String getFontFamily() {
return myFontFamilies.isEmpty() ? DEFAULT_FONT_NAME : myFontFamilies.get(0);
return myEffectiveFontFamilies.isEmpty() ? DEFAULT_FONT_NAME : myEffectiveFontFamilies.get(0);
}
public void addFontFamily(@NotNull String fontFamily) {
if (!myFontFamilies.contains(fontFamily)) {
myFontFamilies.add(fontFamily);
String fallbackFontFamily = getFallbackName(fontFamily, DEFAULT_FONT_SIZE, null);
if (!myRealFontFamilies.contains(fontFamily)) {
myRealFontFamilies.add(fontFamily);
}
String effectiveFontFamily = fallbackFontFamily == null ? fontFamily : fallbackFontFamily;
if (!myEffectiveFontFamilies.contains(effectiveFontFamily)) {
myEffectiveFontFamilies.add(effectiveFontFamily);
}
}
public void copyTo(@NotNull final FontPreferences preferences) {
preferences.myFontFamilies.clear();
preferences.myFontFamilies.addAll(myFontFamilies);
preferences.myEffectiveFontFamilies.clear();
preferences.myEffectiveFontFamilies.addAll(myEffectiveFontFamilies);
preferences.myRealFontFamilies.clear();
preferences.myRealFontFamilies.addAll(myRealFontFamilies);
preferences.myFontSizes.clear();
for (String fontFamily : myFontFamilies) {
for (String fontFamily : myRealFontFamilies) {
if (myFontSizes.containsKey(fontFamily)) {
preferences.myFontSizes.put(fontFamily, myFontSizes.get(fontFamily));
}
@@ -114,7 +149,7 @@ public class FontPreferences {
@Override
public int hashCode() {
return myFontFamilies.hashCode();
return myRealFontFamilies.hashCode();
}
@Override
@@ -124,8 +159,8 @@ public class FontPreferences {
FontPreferences that = (FontPreferences)o;
if (!myFontFamilies.equals(that.myFontFamilies)) return false;
for (String fontFamily : myFontFamilies) {
if (!myRealFontFamilies.equals(that.myRealFontFamilies)) return false;
for (String fontFamily : myRealFontFamilies) {
if (myFontSizes.get(fontFamily) != that.myFontSizes.get(fontFamily)) {
return false;
}
@@ -147,4 +182,25 @@ public class FontPreferences {
return "Monospaced";
}
/**
* There is a possible case that particular font family is not available at particular environment (e.g. Monaco under *nix).
* However, java environment tries to mask that via 'Dialog' fonts, i.e. when we try to create font like
* {@code new Font("Monaco", style, size)}, it creates a font object which has font family "Monaco" but is a "Dialog" font.
* <p/>
* That's why we have a special check for such a situation.
*
* @param fontName font family name to check
* @param fontSize target font size
* @param fallbackScheme colors scheme to use for fallback fonts retrieval (if necessary);
* @return fallback font family to use if font family with the given name is not registered at current environment;
* <code>null</code> if font family with the given name is registered at the current environment
*/
@Nullable
public static String getFallbackName(@NotNull String fontName, int fontSize, @Nullable EditorColorsScheme fallbackScheme) {
Font plainFont = new Font(fontName, Font.PLAIN, fontSize);
if (plainFont.getFamily().equals("Dialog") && !"Dialog".equals(fontName)) {
return fallbackScheme == null ? DEFAULT_FONT_NAME : fallbackScheme.getEditorFontName();
}
return fontName;
}
}
@@ -208,17 +208,12 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
protected void initFonts() {
String editorFontName = getEditorFontName();
int editorFontSize = getEditorFontSize();
myFallbackFontName = FontPreferences.getFallbackName(editorFontName, editorFontSize, myParentScheme);
if (myFallbackFontName != null) {
editorFontName = myFallbackFontName;
}
Font plainFont = new Font(editorFontName, Font.PLAIN, editorFontSize);
if (plainFont.getFamily().equals("Dialog") && !editorFontName.equals("Dialog")) {
editorFontName = myParentScheme != null ? myParentScheme.getEditorFontName() : FontPreferences.DEFAULT_FONT_NAME;
myFallbackFontName = editorFontName;
plainFont = new Font(editorFontName, Font.PLAIN, editorFontSize);
}
else {
myFallbackFontName = null;
}
Font boldFont = new Font(editorFontName, Font.BOLD, editorFontSize);
Font italicFont = new Font(editorFontName, Font.ITALIC, editorFontSize);
Font boldItalicFont = new Font(editorFontName, Font.BOLD | Font.ITALIC, editorFontSize);
@@ -305,7 +300,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
}
}
if (myConsoleFontPreferences.getFontFamilies().isEmpty()) {
if (myConsoleFontPreferences.getEffectiveFontFamilies().isEmpty()) {
myFontPreferences.copyTo(myConsoleFontPreferences);
}
@@ -442,7 +437,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
// IJ has used a 'single customizable font' mode for ages. That's why we want to support that format now, when it's possible
// to specify fonts sequence (see getFontPreferences()), there are big chances that many clients still will use a single font.
// That's why we want to use old format when zero or one font is selected and 'extended' format otherwise.
boolean useOldFontFormat = myFontPreferences.getFontFamilies().size() <= 1;
boolean useOldFontFormat = myFontPreferences.getEffectiveFontFamilies().size() <= 1;
if (useOldFontFormat) {
element = new Element(OPTION_ELEMENT);
element.setAttribute(NAME_ATTR, EDITOR_FONT_SIZE);
@@ -454,7 +449,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
}
if (!myFontPreferences.equals(myConsoleFontPreferences)) {
if (myConsoleFontPreferences.getFontFamilies().size() <= 1) {
if (myConsoleFontPreferences.getEffectiveFontFamilies().size() <= 1) {
element = new Element(OPTION_ELEMENT);
element.setAttribute(NAME_ATTR, CONSOLE_FONT_NAME);
element.setAttribute(VALUE_ELEMENT, getConsoleFontName());
@@ -504,7 +499,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
}
private static void writeFontPreferences(@NotNull String key, @NotNull Element parent, @NotNull FontPreferences preferences) {
for (String fontFamily : preferences.getFontFamilies()) {
for (String fontFamily : preferences.getRealFontFamilies()) {
Element element = new Element(key);
Element e = new Element(OPTION_ELEMENT);
e.setAttribute(NAME_ATTR, EDITOR_FONT_NAME);
@@ -146,7 +146,7 @@ public class ComplementaryFontsRegistry {
@NotNull
public static FontInfo getFontAbleToDisplay(char c, @JdkConstants.FontStyle int style, @NotNull FontPreferences preferences) {
boolean tryDefaultFont = true;
List<String> fontFamilies = preferences.getFontFamilies();
List<String> fontFamilies = preferences.getEffectiveFontFamilies();
FontInfo result;
for (String fontFamily : fontFamilies) {
result = doGetFontAbleToDisplay(c, preferences.getSize(fontFamily), style, fontFamily);
@@ -83,7 +83,6 @@ import com.intellij.util.Producer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.HashMap;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.util.ui.ButtonlessScrollBarUI;
@@ -5805,7 +5804,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
@NotNull
@Override
public FontPreferences getFontPreferences() {
return myFontPreferences.getFontFamilies().isEmpty() ? getGlobal().getFontPreferences() : myFontPreferences;
return myFontPreferences.getEffectiveFontFamilies().isEmpty() ? getGlobal().getFontPreferences() : myFontPreferences;
}
@Override