Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

console.lua: fix the max width calculation #14419

Merged
merged 3 commits into from
Jun 24, 2024

Conversation

guidocella
Copy link
Contributor

No description provided.

Copy link

github-actions bot commented Jun 22, 2024

Download the artifacts for this pull request:

Windows
macOS

@guidocella guidocella changed the title console.lua: calculate the max width more accurately console.lua: fix the max width calculation Jun 22, 2024
@@ -546,7 +547,8 @@ local function update()

local lines_max = calculate_max_log_lines()
-- Estimate how many characters fit in one line
local width_max = math.ceil(screenx / opts.font_size * get_font_hw_ratio())
local width_max = math.floor((screenx - margin - mp.get_property_native('osd-margin-x')) /
Copy link
Contributor

@christoph-heinrich christoph-heinrich Jun 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't osd-margin-x get subtracted from screenx before it gets divided by dpi_scale?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done that for the margin too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it doesn't seem right to substract the margins from the clip coordinates, so I divided them by the scale afterwards.

@MoSal
Copy link
Contributor

MoSal commented Jun 23, 2024

Before

select_pre

After

select_post


Wrapped character count went from 9️⃣ to 8️⃣.

@guidocella
Copy link
Contributor Author

Wrapped character count went from 9️⃣ to 8️⃣.

Does --osd-margin-x=0 fix it for you too?

@guidocella
Copy link
Contributor Author

Scaling --osd-margin-x relatively to 720 seems to fix this.

@guidocella guidocella force-pushed the console-width branch 2 times, most recently from f986171 to cba7e52 Compare June 23, 2024 08:57
@MoSal
Copy link
Contributor

MoSal commented Jun 23, 2024

Scaling --osd-margin-x relatively to 720 seems to fix this.

That's not the issue.

Did some logging.

max_width=98 screenx=960 bottom_left_margin=6 dpi_scale=4
osd-margin-x=0 aspect=1.7777777777778 font_size=28 hw_ratio=2.8863296703297

That hw_ratio is big. If hw_ratio was 2.65. We get max_width=90.147321428571 flooring to 90.

Figuring out what font is being used, it's Noto Sans Mono. So I set that in cosole config. And grep for fontselect in debug output (Note: Exo 2 Black is my osd font).

[osd/libass] fontselect: (Exo 2 Black, 700, 0) -> /usr/share/fonts/OTF/Exo2-Black.otf, 0, Exo2-Black
[osd/libass] fontselect: (sans-serif, 400, 0) -> /usr/share/fonts/noto/NotoSans-Condensed.ttf, 0, NotoSans-Condensed
[osd/libass] fontselect: (Noto Sans Mono, 400, 0) -> /usr/share/fonts/noto/NotoSansMono-Condensed.ttf, 0, NotoSansMono-Condensed
[osd/libass] fontselect: (Exo 2 Black, 700, 0) -> /usr/share/fonts/OTF/Exo2-Black.otf, 0, Exo2-Black
[osd/libass] fontselect: (Noto Sans Mono, 700, 0) -> /usr/share/fonts/noto/NotoSansMono-Bold.ttf, 0, NotoSansMono-Bold
[osd/libass] fontselect: (sans-serif, 400, 0) -> /usr/share/fonts/noto/NotoSans-Condensed.ttf, 0, NotoSans-Condensed
[osd/libass] fontselect: (Noto Sans Mono, 700, 0) -> /usr/share/fonts/TTF/custom-FiraMonoWithFallback-Bold.ttf, 0, FiraMonoWithFallback-Bold

So I change console font to 'Fira Mono Medium' which has hw_ratio=1.8945181765724 which is withing expected range, and the problem is gone:

[osd/libass] fontselect: (Exo 2 Black, 700, 0) -> /usr/share/fonts/OTF/Exo2-Black.otf, 0, Exo2-Black
[osd/libass] fontselect: (sans-serif, 400, 0) -> /usr/share/fonts/noto/NotoSans-Condensed.ttf, 0, NotoSans-Condensed
[osd/libass] fontselect: (Fira Mono Medium, 400, 0) -> /usr/share/fonts/OTF/FiraMono-Medium.otf, 0, FiraMono-Medium
[osd/libass] fontselect: (Exo 2 Black, 700, 0) -> /usr/share/fonts/OTF/Exo2-Black.otf, 0, Exo2-Black
[osd/libass] fontselect: (Fira Mono Medium, 700, 0) -> /usr/share/fonts/OTF/FiraMono-Medium.otf, 0, FiraMono-Medium
[osd/libass] fontselect: (sans-serif, 400, 0) -> /usr/share/fonts/noto/NotoSans-Condensed.ttf, 0, NotoSans-Condensed
[osd/libass] fontselect: (Fira Mono Medium, 700, 0) -> /usr/share/fonts/TTF/custom-FiraMonoWithFallback-Bold.ttf, 0, FiraMonoWithFallback-Bold

So the console using NotoSans-Condensed.ttf triggers the issue!
hw_ratio values for condensed fonts is maybe an issue!

@guidocella
Copy link
Contributor Author

Is this #14249 again? Does libass master fix it? Anyway --osd-margin-x=0 fixes the wrapping for me even without this patch so that definitely is an issue to be fixed too.

@MoSal
Copy link
Contributor

MoSal commented Jun 23, 2024

Is this #14249 again? Does libass master fix it? Anyway --osd-margin-x=0 fixes the wrapping for me even without this patch so that definitely is an issue to be fixed too.

Bingo.
Using libass master does fix it.

So the hw_ratio calculations used the condensed font, but the regular font was actually used for rendering!
Why wasn't the wrong font used for rendering anyway?
Shouldn't the font selected by libass be used to avoid any potential mismatches?

@guidocella guidocella force-pushed the console-width branch 2 times, most recently from 5b2dc12 to 43e154e Compare June 23, 2024 15:29
@christoph-heinrich
Copy link
Contributor

Here is why it osd-margin-x needs to be scaled for 720p

double scale = res_y / 720.0;
style->MarginL = opts->margin_x * scale;

@kasper93
Copy link
Contributor

Good that we have those magic numbers hardcoded around the codebase and no one knows why they are needed, until digging into it. /s

@guidocella
Copy link
Contributor Author

Something is still off in the calculation as the lines can still wrap. Also I don't understand why it doesn't seem to be affected by --osd-scale-by-window.

@MoSal
Copy link
Contributor

MoSal commented Jun 23, 2024

@guidocella
Are you sure no glyphs are using a different font?

@christoph-heinrich
Copy link
Contributor

Also I don't understand why it doesn't seem to be affected by --osd-scale-by-window.

I'm pretty sure that's because the resolution to use for the supplied ass is set in mp.set_osd_ass(screenx, screeny, ass.text)

@guidocella
Copy link
Contributor Author

@guidocella Are you sure no glyphs are using a different font?

Yeah you should be able to reproduce it by making the window smaller.

I'm pretty sure that's because the resolution to use for the supplied ass is set in mp.set_osd_ass(screenx, screeny, ass.text)

It's because prepare_osd_ass which checks opts->osd_scale_by_window isn't called from osd-overlay, I checked with gdb. But it still affected by the 720 scaling.

@christoph-heinrich
Copy link
Contributor

It's because prepare_osd_ass which checks opts->osd_scale_by_window isn't called from osd-overlay, I checked with gdb. But it still affected by the 720 scaling.

Oh you meant why osd-margin-x isn't affected by osd-scale-by-window, I thought you meant the output text in general.

Copy link
Contributor

@christoph-heinrich christoph-heinrich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an improvement over the status quo, even if it's not perfect for everyone.

Even if ass:pos() hardcodes the position at 6px from the left, we still
need to subtract the left --osd-margin-x from the available text width.
See how libass/ass_render.c:ass_render_event() subtracts it from
max_text_width without checking if the event is positioned.

The calculation is still not perfect as the width could be made a bit
larger before the text wraps.
In select mode and when printing the OSD, use \q2 to let libass clip
lines longer than the OSD. This works around having to leave a large
horizontal space unused due to libass subtracting the left margin from
the max text width even though the ASS event is anchored to the bottom
left. It also fixes truncating wide Unicode characters.
Copy link
Contributor

@christoph-heinrich christoph-heinrich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well

Copy link
Contributor

@christoph-heinrich christoph-heinrich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No wrap suggestions in the terminal also work.

@avih
Copy link
Member

avih commented Jun 24, 2024

disable_wrap = '\027[?7l'
enable_wrap = '\027[?7h'

These are DEC private mode reset/set auto-wrap mode (DECAWM).

mpv doesn't use terminal escape sequences "correctly" - it doesn't use terminfo or ncurses etc (which only use features supported by the terminal), which is why mpv should use only the most common escape sequences which are likely to work on most terminals out there.

I don't think It's guaranteed that this sequence is supported by all terminals, and I don't think this is generally a commonly-used escape sequence elsewhere. At least I don't recall encountering it in the past.

Off topic here, but same goes about using ALT-screen (iirc in sixel and/or tct), because it's not guaranteed to be supported or enabled on all terminals, for instance xterm on fedora by default doesn't have alt-screen AFAIK.

So mpv should try to limit itself as much as possible only to very common terminal features and sequences.

@guidocella
Copy link
Contributor Author

It did work in all terminals I tried including xterm. If it wasn't supported log lines would just be printed as they are. I don't think there is another sane way to predict terminal unicode width from Lua.

@na-na-hi
Copy link
Contributor

na-na-hi commented Jun 24, 2024

I don't think It's guaranteed that this sequence is supported by all terminals, and I don't think this is generally a commonly-used escape sequence elsewhere.

According to https://invisible-island.net/xterm/ctlseqs/ctlseqs.html:

Ps = 7 ⇒ Auto-Wrap Mode (DECAWM), VT100.

I think VT100 should be OK as a baseline, and is the default terminal assumed by most *nix TUI programs. It won't work on VT52 terminals but I doubt it's used in any meaningful capacity.

However, this won't work with Windows console if VT processing is disabled. And even if VT processing is enabled, this auto-wrap mode code isn't listed on the MS documentation. It's only supported for recent terminal versions: microsoft/terminal#3943 (other codes like show/hide cursor are listed in the documentation)

@guidocella
Copy link
Contributor Author

Is it worth keeping truncate_utf8 as a fallback for Windows then?

This prevents line wraps in select mode with terminal output which hide
the top items (OSD output no longer uses truncate_utf8 since the
previous commit). This is not ideal as even accented letters are assumed
to be 2 cells wide. The alternative is using \e[?7l and \e[?7h to
disable and enable text wrapping, but it won't work in Windows console
with VT processing disabled.
@guidocella
Copy link
Contributor Author

Changed to assume all non-ASCII characters span 2 cells instead.

@kasper93 kasper93 merged commit 01330db into mpv-player:master Jun 24, 2024
20 checks passed
@guidocella guidocella deleted the console-width branch June 24, 2024 19:31
@MoSal
Copy link
Contributor

MoSal commented Jun 24, 2024

Changed to assume all non-ASCII characters span 2 cells instead.

Quite the assumption:

select_new_with_info

On the other hand (not a real-world example, just to be clear):

select_new2

Clipping works.

@guidocella
Copy link
Contributor Author

It still clips graphical output. I liked clipping in the terminal too but we will probably integrate wcwidth in term_disp_width() and expose it to Lua due to this Windows console issue and needing to fix width calculation for msg.c anyway.

@kasper93
Copy link
Contributor

kasper93 commented Jun 24, 2024

due to this Windows console issue

And even if VT processing is enabled, this auto-wrap mode code isn't listed on the MS documentation. It's only supported for recent terminal versions: microsoft/terminal#3943 (other codes like show/hide cursor are listed in the documentation)

Ok, let's not worry too much about it. This has been merged into conhost in build 19603, which was 4 years ago. Sure we might left this one guy who uses 1507 and in the same time uses terminal... on Windows. I would argue that we can afford having this slightly broken. To trigger this you need to use non-ascii chars, use terminal and use old Windows build. Maybe there is one guy affected, but really... Non-VT mode is indeed a problem, but in this case we could fallback to wrapping.

Either way, I don't think preventing terminal wrapping, really solves the issue, because msg.c code expect that and will clear wrong lines because of line count mismatch. So the proper fix is to have common code term_disp_width() that calculates this width.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants