diff --git a/src/render/Font.lua b/src/render/Font.lua index 760c91b2..3b59cffb 100644 --- a/src/render/Font.lua +++ b/src/render/Font.lua @@ -137,8 +137,10 @@ function Font.load(data) -- typo'd path degrades exactly like a missing page image does above. if type(def.ttf) == "table" then local file = def.ttf.file or Font.PLAINPIXEL - local ok, obj = pcall(love.graphics.newFont, file, - def.ttf.size or Font.PLAINPIXEL_SIZE, "mono") + local size = def.ttf.size or Font.PLAINPIXEL_SIZE + -- The game renders into a pixel-exact canvas, so keep the TTF rasterizer + -- on that same 1x grid instead of inheriting the window DPI on mobile. + local ok, obj = pcall(love.graphics.newFont, file, size, "mono", 1) if ok and obj then -- nearest keeps the pixel font crisp under the integer UI scale if obj.setFilter then pcall(obj.setFilter, obj, "nearest", "nearest") end diff --git a/tests/engine/ttf_font_mode.lua b/tests/engine/ttf_font_mode.lua index 283f47a6..351f9a89 100644 --- a/tests/engine/ttf_font_mode.lua +++ b/tests/engine/ttf_font_mode.lua @@ -40,6 +40,27 @@ T.eq(Font.advanceOf(0x80), 8, "and the pen stays 8px monospace") -- ------------------------------------------------- the ttf takes over +-- Font rasterizers must use the same 1x pixel grid as PixelCanvas, rather +-- than inheriting Android's window density. Keep this local fake so the +-- contract is testable without requiring a real LÖVE window. +do + local g, oldNewFont = love.graphics, love.graphics.newFont + local args + g.newFont = function(...) + args = { ... } + return oldNewFont(Font.PLAINPIXEL, Font.PLAINPIXEL_SIZE) + end + local loaded, err = pcall(Font.load, { + font = { charmap = CHARMAP, ttf = { file = "custom.ttf", size = 13 } }, + }) + g.newFont = oldNewFont + if not loaded then error(err, 0) end + T.eq(args[1], "custom.ttf", "rasterizer uses the configured file") + T.eq(args[2], 13, "rasterizer uses the configured size") + T.eq(args[3], "mono", "rasterizer keeps the pixel hinting mode") + T.eq(args[4], 1, "rasterizer stays on the pixel canvas scale") +end + Font.load({ font = { charmap = CHARMAP, ttf = {} } }) T.check(Font.ttfActive(), "an empty ttf table loads the bundled font")