summaryrefslogtreecommitdiffstats
path: root/player/lua
diff options
context:
space:
mode:
authorChristoph Heinrich <christoph.heinrich@student.tugraz.at>2023-11-08 00:03:48 +0100
committerDudemanguy <random342@airmail.cc>2023-12-06 19:06:41 +0000
commitc16f868dd7f0d6862a6e2cdfb12492467f288fee (patch)
treed74019112cd10285258b18994584b94d3c9194f2 /player/lua
parent21bd301372304c3b0c194999442d3c8b690d41c1 (diff)
downloadmpv-c16f868dd7f0d6862a6e2cdfb12492467f288fee.tar.bz2
mpv-c16f868dd7f0d6862a6e2cdfb12492467f288fee.tar.xz
console: automatically determine the font_hw_ratio
A simplified version of the text width estimation code from uosc. An osd_overlay is created with compute_bounds=true for measuring the width of the lower case alphabet at what's estimated to be the largest font size possible without clipping. The lower case alphabet was chosen to get decent results for proportional fonts, even if they aren't officially supported.
Diffstat (limited to 'player/lua')
-rw-r--r--player/lua/console.lua79
1 files changed, 77 insertions, 2 deletions
diff --git a/player/lua/console.lua b/player/lua/console.lua
index 45e576b9bb..a005db56ed 100644
--- a/player/lua/console.lua
+++ b/player/lua/console.lua
@@ -31,7 +31,8 @@ local opts = {
history_dedup = true,
-- The ratio of font height to font width.
-- Adjusts table width of completion suggestions.
- font_hw_ratio = 2.0,
+ -- Values in the range 1.8..2.5 make sense for common monospace fonts.
+ font_hw_ratio = 'auto',
}
function detect_platform()
@@ -107,6 +108,80 @@ mp.observe_property("user-data/osc/margins", "native", function(_, val)
update()
end)
+do
+ local width_length_ratio = 0.5
+ local osd_width, osd_height = 100, 100
+
+ ---Update osd resolution if valid
+ local function update_osd_resolution()
+ local dim = mp.get_property_native('osd-dimensions')
+ if not dim or dim.w == 0 or dim.h == 0 then
+ return
+ end
+ osd_width = dim.w
+ osd_height = dim.h
+ end
+
+ local text_osd = mp.create_osd_overlay('ass-events')
+ text_osd.compute_bounds, text_osd.hidden = true, true
+
+ local function measure_bounds(ass_text)
+ update_osd_resolution()
+ text_osd.res_x, text_osd.res_y = osd_width, osd_height
+ text_osd.data = ass_text
+ local res = text_osd:update()
+ return res.x0, res.y0, res.x1, res.y1
+ end
+
+ ---Measure text width and normalize to a font size of 1
+ ---text has to be ass safe
+ local function normalized_text_width(text, size, horizontal)
+ local align, rotation = horizontal and 7 or 1, horizontal and 0 or -90
+ local template = '{\\pos(0,0)\\rDefault\\blur0\\bord0\\shad0\\q2\\an%s\\fs%s\\fn%s\\frz%s}%s'
+ local x1, y1 = nil, nil
+ size = size / 0.8
+ -- prevent endless loop
+ local repetitions_left = 5
+ repeat
+ size = size * 0.8
+ local ass = assdraw.ass_new()
+ ass.text = template:format(align, size, opts.font, rotation, text)
+ _, _, x1, y1 = measure_bounds(ass.text)
+ repetitions_left = repetitions_left - 1
+ -- make sure nothing got clipped
+ until (x1 and x1 < osd_width and y1 < osd_height) or repetitions_left == 0
+ local width = (repetitions_left == 0 and not x1) and 0 or (horizontal and x1 or y1)
+ return width / size, horizontal and osd_width or osd_height
+ end
+
+ local function fit_on_osd(text)
+ local estimated_width = #text * width_length_ratio
+ if osd_width >= osd_height then
+ -- Fill the osd as much as possible, bigger is more accurate.
+ return math.min(osd_width / estimated_width, osd_height), true
+ else
+ return math.min(osd_height / estimated_width, osd_width), false
+ end
+ end
+
+ local measured_font_hw_ratio = nil
+ function get_font_hw_ratio()
+ local font_hw_ratio = tonumber(opts.font_hw_ratio)
+ if font_hw_ratio then
+ return font_hw_ratio
+ end
+ if not measured_font_hw_ratio then
+ local alphabet = 'abcdefghijklmnopqrstuvwxyz'
+ local text = alphabet:rep(3)
+ update_osd_resolution()
+ local size, horizontal = fit_on_osd(text)
+ local normalized_width = normalized_text_width(text, size * 0.9, horizontal)
+ measured_font_hw_ratio = #text / normalized_width * 0.95
+ end
+ return measured_font_hw_ratio
+ end
+end
+
-- Add a line to the log buffer (which is limited to 100 lines)
function log_add(style, text)
log_buffer[#log_buffer + 1] = { style = style, text = text }
@@ -312,7 +387,7 @@ function update()
local screeny_factor = (1 - global_margins.t - global_margins.b)
local lines_max = math.ceil(screeny * screeny_factor / opts.font_size - 1.5)
-- Estimate how many characters fit in one line
- local width_max = math.ceil(screenx / opts.font_size * opts.font_hw_ratio)
+ local width_max = math.ceil(screenx / opts.font_size * get_font_hw_ratio())
local suggestions, rows = format_table(suggestion_buffer, width_max, lines_max)
local suggestion_ass = style .. styles.suggestion .. ass_escape(suggestions)