mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
Decrease fonts memory use (#10618)
Instead of opening the same font multiple times for each different size (multiple face instances), share one face instance and create multiple size instances.
This commit is contained in:
2
base
2
base
Submodule base updated: b4cfe83c1f...9b5cf240bf
@@ -109,15 +109,15 @@ local function collectFaceInfo(path)
|
||||
return
|
||||
end
|
||||
for i=0, n-1 do
|
||||
local ok, face = pcall(FT.newFace, path, nil, i)
|
||||
local ok, ftsize = pcall(FT.newFaceSize, path, nil, i)
|
||||
if not ok then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- If family_name is missing, it's probably too broken to be useful
|
||||
if face.family_name ~= nil then
|
||||
local fres = face:getInfo()
|
||||
local hbface = HB.hb_ft_face_create_referenced(face)
|
||||
if ftsize.face.family_name ~= nil then
|
||||
local fres = ftsize:getInfo()
|
||||
local hbface = HB.hb_ft_face_create_referenced(ftsize.face)
|
||||
fres.names = hbface:getNames()
|
||||
fres.scripts, fres.langs = hbface:getCoverage()
|
||||
fres.path = path
|
||||
@@ -125,7 +125,7 @@ local function collectFaceInfo(path)
|
||||
table.insert(res, fres)
|
||||
hbface:destroy()
|
||||
end
|
||||
face:done()
|
||||
ftsize:done()
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
@@ -195,7 +195,7 @@ local bold_strength_factor = 3/8 -- as crengine, lighter
|
||||
local _completeFaceProperties = function(face_obj)
|
||||
if not face_obj.embolden_half_strength then
|
||||
-- Cache this value in case we use bold, to avoid recomputation
|
||||
face_obj.embolden_half_strength = face_obj.ftface:getEmboldenHalfStrength(bold_strength_factor)
|
||||
face_obj.embolden_half_strength = face_obj.ftsize:getEmboldenHalfStrength(bold_strength_factor)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -302,9 +302,9 @@ function Font:getFace(font, size, faceindex)
|
||||
face_obj.orig_size = orig_size
|
||||
end
|
||||
else
|
||||
-- Build face if not found
|
||||
-- Build face size if not found
|
||||
local builtin_font_location = FontList.fontdir.."/"..realname
|
||||
local ok, face = pcall(Freetype.newFace, builtin_font_location, size, faceindex)
|
||||
local ok, ftsize = pcall(Freetype.newFaceSize, builtin_font_location, size, faceindex)
|
||||
|
||||
-- Not all fonts are bundled on all platforms because they come with the system.
|
||||
-- In that case, search through all font folders for the requested font.
|
||||
@@ -315,14 +315,14 @@ function Font:getFace(font, size, faceindex)
|
||||
for _k, _v in ipairs(fonts) do
|
||||
if _v:find(escaped_realname) then
|
||||
logger.dbg("Found font:", realname, "in", _v)
|
||||
ok, face = pcall(Freetype.newFace, _v, size, faceindex)
|
||||
ok, ftsize = pcall(Freetype.newFaceSize, _v, size, faceindex)
|
||||
|
||||
if ok then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not ok then
|
||||
logger.err("#! Font ", font, " (", realname, ") not supported: ", face)
|
||||
logger.err("#! Font ", font, " (", realname, ") not supported: ", ftsize)
|
||||
return nil
|
||||
end
|
||||
--- Freetype font face wrapper object
|
||||
@@ -330,14 +330,14 @@ function Font:getFace(font, size, faceindex)
|
||||
-- @field orig_font font name requested
|
||||
-- @field size size of the font face (after scaled by screen size)
|
||||
-- @field orig_size raw size of the font face (before scale)
|
||||
-- @field ftface font face object from freetype
|
||||
-- @field ftsize font size object from freetype
|
||||
-- @field hash hash key for this font face
|
||||
face_obj = {
|
||||
orig_font = font,
|
||||
realname = realname,
|
||||
size = size,
|
||||
orig_size = orig_size,
|
||||
ftface = face,
|
||||
ftsize = ftsize,
|
||||
hash = hash,
|
||||
is_real_bold = is_real_bold,
|
||||
}
|
||||
@@ -433,7 +433,7 @@ function Font:getAdjustedFace(face, bold)
|
||||
-- We can keep the same FT object and the same hash in this face_obj
|
||||
-- (which is only used to identify cached glyphs, that we don't need
|
||||
-- to distinguish as "bold" is appended when synthetized as bold)
|
||||
ftface = face.ftface,
|
||||
ftsize = face.ftsize,
|
||||
hash = face.hash,
|
||||
hb_features = face.hb_features,
|
||||
is_real_bold = nil,
|
||||
|
||||
@@ -87,15 +87,15 @@ function RenderText:getGlyph(face, charcode, bold)
|
||||
-- cache hit
|
||||
return glyph
|
||||
end
|
||||
local rendered_glyph = face.ftface:renderGlyph(charcode, bold)
|
||||
if face.ftface:checkGlyph(charcode) == 0 then
|
||||
local rendered_glyph = face.ftsize:renderGlyph(charcode, bold)
|
||||
if not face.ftsize:hasGlyph(charcode) then
|
||||
for index, font in pairs(Font.fallbacks) do
|
||||
-- use original size before scaling by screen DPI
|
||||
local fb_face = Font:getFace(font, face.orig_size)
|
||||
if fb_face ~= nil then
|
||||
-- for some characters it cannot find in Fallbacks, it will crash here
|
||||
if fb_face.ftface:checkGlyph(charcode) ~= 0 then
|
||||
rendered_glyph = fb_face.ftface:renderGlyph(charcode, orig_bold)
|
||||
if fb_face.ftsize:hasGlyph(charcode) then
|
||||
rendered_glyph = fb_face.ftsize:renderGlyph(charcode, orig_bold)
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -127,7 +127,7 @@ function RenderText:getSubTextByWidth(text, face, width, kerning, bold)
|
||||
if pen_x < width then
|
||||
local glyph = self:getGlyph(face, charcode, bold)
|
||||
if kerning and prevcharcode then
|
||||
local kern = face.ftface:getKerning(prevcharcode, charcode)
|
||||
local kern = face.ftsize:getKerning(prevcharcode, charcode)
|
||||
pen_x = pen_x + kern
|
||||
end
|
||||
pen_x = pen_x + glyph.ax
|
||||
@@ -170,7 +170,7 @@ function RenderText:sizeUtf8Text(x, width, face, text, kerning, bold)
|
||||
if not width or pen_x < (width - x) then
|
||||
local glyph = self:getGlyph(face, charcode, bold)
|
||||
if kerning and (prevcharcode ~= 0) then
|
||||
pen_x = pen_x + (face.ftface):getKerning(prevcharcode, charcode)
|
||||
pen_x = pen_x + (face.ftsize):getKerning(prevcharcode, charcode)
|
||||
end
|
||||
pen_x = pen_x + glyph.ax
|
||||
pen_y_top = math.max(pen_y_top, glyph.t)
|
||||
@@ -225,7 +225,7 @@ function RenderText:renderUtf8Text(dest_bb, x, baseline, face, text, kerning, bo
|
||||
if pen_x < text_width then
|
||||
local glyph = self:getGlyph(face, charcode, bold)
|
||||
if kerning and (prevcharcode ~= 0) then
|
||||
pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode)
|
||||
pen_x = pen_x + face.ftsize:getKerning(prevcharcode, charcode)
|
||||
end
|
||||
dest_bb:colorblitFrom(
|
||||
glyph.bb,
|
||||
@@ -299,7 +299,7 @@ function RenderText:getGlyphByIndex(face, glyphindex, bold)
|
||||
-- cache hit
|
||||
return glyph
|
||||
end
|
||||
local rendered_glyph = face.ftface:renderGlyphByIndex(glyphindex, bold and face.embolden_half_strength)
|
||||
local rendered_glyph = face.ftsize:renderGlyphByIndex(glyphindex, bold and face.embolden_half_strength)
|
||||
if not rendered_glyph then
|
||||
logger.warn("error rendering glyph (glyphindex=", glyphindex, ") for face", face)
|
||||
return
|
||||
|
||||
@@ -125,7 +125,7 @@ function TextBoxWidget:init()
|
||||
self.line_height_px = Math.round( (1 + self.line_height) * self.face.size )
|
||||
-- Get accurate initial baseline and possible height overflow (so our bb
|
||||
-- is tall enough to draw glyphs with descender larger than line height)
|
||||
local face_height, face_ascender = self.face.ftface:getHeightAndAscender()
|
||||
local face_height, face_ascender = self.face.ftsize:getHeightAndAscender()
|
||||
local line_heights_diff = math.floor(self.line_height_px - face_height)
|
||||
if line_heights_diff >= 0 then
|
||||
-- Glyphs will fit in our line_height_px: adjust baseline.
|
||||
@@ -1113,7 +1113,7 @@ function TextBoxWidget:getFontSizeToFitHeight(height_px, nb_lines, line_height_e
|
||||
local line_height_px = Math.round( (1 + line_height_em) * Screen:scaleBySize(font_size) )
|
||||
local face = Font:getFace(font_face, font_size)
|
||||
face = Font:getAdjustedFace(face, font_bold)
|
||||
local face_height = face.ftface:getHeightAndAscender()
|
||||
local face_height = face.ftsize:getHeightAndAscender()
|
||||
local line_heights_diff = math.floor(line_height_px - face_height)
|
||||
if line_heights_diff >= 0 then
|
||||
break
|
||||
|
||||
@@ -81,7 +81,7 @@ function TextWidget:getFontSizeToFitHeight(font_name, height_px, padding)
|
||||
break
|
||||
end
|
||||
local face = Font:getFace(font_name, font_size)
|
||||
local face_height = face.ftface:getHeightAndAscender()
|
||||
local face_height = face.ftsize:getHeightAndAscender()
|
||||
face_height = math.ceil(face_height) + 2*padding
|
||||
until face_height <= height_px
|
||||
return font_size
|
||||
@@ -109,7 +109,7 @@ function TextWidget:updateSize()
|
||||
-- But better compute baseline alignment from freetype font metrics
|
||||
-- to get better vertical centering of text in box
|
||||
-- (Freetype doc on this at https://www.freetype.org/freetype2/docs/tutorial/step2.html)
|
||||
local face_height, face_ascender = self.face.ftface:getHeightAndAscender()
|
||||
local face_height, face_ascender = self.face.ftsize:getHeightAndAscender()
|
||||
self._height = math.ceil(face_height) + 2*self.padding
|
||||
self._baseline_h = Math.round(face_ascender) + self.padding
|
||||
-- With our UI fonts, this usually gives 0.72 to 0.74, so text is aligned
|
||||
|
||||
@@ -7,10 +7,10 @@ describe("Font module", function()
|
||||
it("should get face", function()
|
||||
local f
|
||||
f = Font:getFace('cfont', 18)
|
||||
assert.are_not.equals(f.ftface, nil)
|
||||
assert.are_not.equals(f.ftsize, nil)
|
||||
f = Font:getFace('tfont', 16)
|
||||
assert.are_not.equals(f.ftface, nil)
|
||||
assert.are_not.equals(f.ftsize, nil)
|
||||
f = Font:getFace('hfont', 12)
|
||||
assert.are_not.equals(f.ftface, nil)
|
||||
assert.are_not.equals(f.ftsize, nil)
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user