how does a font tell the OS that "I AM a MONSPACED / FIXED-WIDTH FONT"?
Asked Answered
D

2

7

at the very first, i only want to know, why in IDE PYCHARM on Windows 10, while "show only monospaced fonts" checked, many fonts will not be listed in the editor's font selecting dialog-box[settings/editor/colors and fonts/font], also in mintty.

I don't know how does the pycharm do, but the mintty uses the win32 API "LOGFONT".

then, how did the windows OS know whether the font is monospaced(fixed-width)?

i.e.: "source code pro" is listed, "source code pro black / extralight / light ... are not;

"fira code" is listed, but fira code light/medium/retina are not;

and, some other monospaced fonts are not listed there if "show only monospaced".

it seems that pycharm only recognize the font family name when checked "show only monospced fonts"

in OSX(Mavericks) it's a little complicated : if the 'show only monospaced fonts' was checked, pycharm could still get the family name, but it could not know which font-weight is default if the rugular weighted font version was installed.


then, i tried to modify some fonts, and by the way having a glance to the original font's 'file-info' in font forge, but i don't know which part really effects the WINDOWS or PYCHARM(IDEA/INTELIJ/by JDK in fact?) to know which font is monospaced.

in "OS/2" part, any parameters mentioned fixed-width/monospace/monospaced are checked, but not helped any, and in windows pycharm still can't detect them.

so, at last, i really wonder, which parameter do TTF files or any other font file types use to tell the [windows/osx/mac os/linux] OS that 'i am monospaced'?

Daughterinlaw answered 3/4, 2017 at 6:54 Comment(0)
T
5

PyCharm and for that matter all of the JetBrains IDEA suite do not use font flags to identify monospace fonts. Instead, they determine if a font is monospaced using the following algorithm:

  • Are the 'l', 'W' and ' ' characters of the regular variant the same width at size 12?
  • Are the 'l', 'W' and ' ' characters of the bold variant the same width as the regular variant at size 12?
  • Are the 'l', 'W' and ' ' characters of the italics variant the same width as the regular variant at size 12?
  • Are the 'l', 'W' and ' ' characters of the bold-italics variant the same width as the regular variant at size 12?

The font will be listed as non-monospace if any of the width calculations above return an inconsistent answer.

To solve this problem, you should install a bold variant of the font you are trying to use. If a bold version of the font is not available, IntelliJ's font renderer will auto-generate one which affects the width of the characters, and therefore, causes the monospace check to fail.


Source: The IntelliJ Community Edition Source Code (Excerpts shortened for brevity, and are licensed under the Apache 2.0 license rather than StackOverflow's CC-BY-SA licence.)

private static int getFontWidth(Font font, int mask) {
    int width = getCharWidth(font, ' ');
    return width == getCharWidth(font, 'l')
        && width == getCharWidth(font, 'W') ? width : 0;
}

In the FontInfo constructor.

int width = getFontWidth(font, Font.PLAIN);
if (!plainOnly) {
    if (width != 0 && width != getFontWidth(font, Font.BOLD)) width = 0;
    if (width != 0 && width != getFontWidth(font, Font.ITALIC)) width = 0;
    if (width != 0 && width != getFontWidth(font, Font.BOLD | Font.ITALIC)) width = 0;
}
boolean isMonospaced = width > 0;
Third answered 15/3, 2018 at 12:16 Comment(0)
M
5

A TrueType font can contain a post table. The post table contains a 32-bit field named isFixedPitch. If this contains a 0, it indicates a proportional font. A monospaced font should have this set to 1 (but its normally recommended that a font engine should accept any non-zero value as indicating a monospaced font, since that's what early versions of the TT spec required).

A monospaced font should also have the numberOfHMetrics in the hhea and hmtx tables set to 3.

There's also data in the panose font matching data (in the OS/2 table) to specify whether a font is monospaced or not.

If I had to guess, I'd say Apple is more likely to use the post table, while Microsoft is more likely to use the Panose data (but I could easily be wrong about either or both of those).


References:

  1. Apple documentation of 'post' table
  2. Microsoft OpenType Recommendations
  3. Panose Classification Metrics Guide
Munger answered 3/4, 2017 at 7:15 Comment(1)
thank you so much, amazing world to get valuable answers. it seemed that the font i modified with a panose bit '9' for monospace was successful and it's recognized by OSX successfully, and according to your reflink#2, the microsoft recommends to use panose data, but the pycharm could not recognize it, maybe it's the pycharm's or jdk's problem then.Daughterinlaw
T
5

PyCharm and for that matter all of the JetBrains IDEA suite do not use font flags to identify monospace fonts. Instead, they determine if a font is monospaced using the following algorithm:

  • Are the 'l', 'W' and ' ' characters of the regular variant the same width at size 12?
  • Are the 'l', 'W' and ' ' characters of the bold variant the same width as the regular variant at size 12?
  • Are the 'l', 'W' and ' ' characters of the italics variant the same width as the regular variant at size 12?
  • Are the 'l', 'W' and ' ' characters of the bold-italics variant the same width as the regular variant at size 12?

The font will be listed as non-monospace if any of the width calculations above return an inconsistent answer.

To solve this problem, you should install a bold variant of the font you are trying to use. If a bold version of the font is not available, IntelliJ's font renderer will auto-generate one which affects the width of the characters, and therefore, causes the monospace check to fail.


Source: The IntelliJ Community Edition Source Code (Excerpts shortened for brevity, and are licensed under the Apache 2.0 license rather than StackOverflow's CC-BY-SA licence.)

private static int getFontWidth(Font font, int mask) {
    int width = getCharWidth(font, ' ');
    return width == getCharWidth(font, 'l')
        && width == getCharWidth(font, 'W') ? width : 0;
}

In the FontInfo constructor.

int width = getFontWidth(font, Font.PLAIN);
if (!plainOnly) {
    if (width != 0 && width != getFontWidth(font, Font.BOLD)) width = 0;
    if (width != 0 && width != getFontWidth(font, Font.ITALIC)) width = 0;
    if (width != 0 && width != getFontWidth(font, Font.BOLD | Font.ITALIC)) width = 0;
}
boolean isMonospaced = width > 0;
Third answered 15/3, 2018 at 12:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.