sublimehq / sublime_text

Issue tracker for Sublime Text
https://www.sublimetext.com
807 stars 39 forks source link

When the font size is odd and ≤15, two halfwidth characters are wider than a fullwidth character #3026

Open Thom1729 opened 4 years ago

Thom1729 commented 4 years ago

Description

On Mac OS 10.14.6, when the font_size is odd and less than or equal to 15, fullwidth characters are less than twice as wide as halfwidth characters.

Possibly related: #1933.

Steps to reproduce

  1. Install Noto Sans CJK SC Regular.
  2. view.settings().set('font_face', 'Noto Sans Mono CJK SC')
  3. view.settings().set('font_size', 15)
  4. Paste the following example text:
ABCDEFGH|
aabbccddeeffgghh|
A|
aa|

The wide, uppercase letters are fullwidth forms. I have verified that the font is installed correctly, that Sublime is using that font, and that all of the characters in the example are rendered using that font. I have also tried examples with a variety of halfwidth characters including spaces, and a variety of fullwidth characters including ideographs.

I checked this both on a MacBook Pro retina display and on a garden-variety 1080p monitor with regular pixel density.

Expected behavior

The pipes on each line should line up exactly.

Actual behavior

The halfwidth lines are longer, so the pipes do not line up. Eyeballing it, I'm guessing that each pair of halfwidth characters is 1px wider than a fullwidth character.

The problem vanishes if font_size is even. It seems that when font_size is odd, the halfwidth characters “round up” in some way — the halfwidth character lines are the same length when the font_size is 13 or 14, or (seemingly) any odd number and the next-higher even number. However, the fullwidth characters increase in size in a smooth and linear manner according to font_size.

The problem also vanishes when font_size > 15. For instance, when font_size is 17, everything lines up.

The problem seems to correspond to rounding behavior of view.em_width(). With this font and setup, view.em_width() seems to be exactly half of font_size — except that when font_size ≤ 15, view.em_width() is rounded upward. I don't know much about text layout in general or Sublime's in particular, but I would guess that whatever internal calculation drives view.em_width() is also driving the character width mismatch. If so, then two possible solutions would be:

  1. Stop rounding view.em_width() at small sizes. (I assume it's doing this for a reason, though, probably legibility.)
  2. Ensure that double-width characters always take up twice view.em_width(), e.g. by rounding up to the nearest even number at small sizes.

Environment

wbond commented 4 years ago

For consistency with other Mac programs (e.g. Terminal), we ceil() glyph width to whole pixels on Mac when the font size is small.

Have you tried the no_round font_options?

Thom1729 commented 4 years ago

That works.

It sounds like the underlying problem is this: When the font size is small, and the natural width of a halfwidth character is w, then the rounded width of a halfwidth character is ceil(w) and a fullwidth ceil(2*w), but the fullwidth should actually be 2*ceil(w).

wbond commented 4 years ago

I'd be curious is Terminal treats it this way

Thom1729 commented 4 years ago

It seems to — at least, I couldn't reproduce the bug in Terminal; everything lined up correctly.

wbond commented 4 years ago

Ok - thanks for confirming that. I won't be looking into this immediately, but I will put it on my list of things to check out.

Thom1729 commented 4 years ago

It's a critical bug affecting my Minesweeper package — which is to say, probably not all that urgent.

aerobounce commented 4 years ago

@wbond , FYI, I've been making my own font and noticed that, Xcode reacts font's glyph's width precisely. So that half-width/full-width mis-alignment does never happen. Referring to Xcode renderings might be better since it's also a text editor (IDE though, but sort of). While I was adjusting my font's glyphs, Xcode was the most reliable.

macOS Terminal has weird behavior here and there. It's doing its own private renderings which isn't documented anywhere. It's not quite macOS-ish rendering. Its line-spacing is also kinda weird.