Skip to content

Commit

Permalink
freetype/harfbuzz: APIs to query font metadata (#1215)
Browse files Browse the repository at this point in the history
This is necessary for proper language support in mupdf with arbitrary
fonts in html/pdf - mupdf expects a real font server for its callbacks,
we're told abstract typeface, script and language that must be
accounted for whenever offering close-kin substitutes of a typeface.

There are marginal uses for this elsewhere, eg. localized font
names in UI - koreader/koreader#6763
  • Loading branch information
ezdiy authored Oct 15, 2020
1 parent 32af1b8 commit e4a66e5
Show file tree
Hide file tree
Showing 7 changed files with 853 additions and 62 deletions.
98 changes: 94 additions & 4 deletions ffi-cdecl/freetype2_decl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@
#include <freetype/freetype.h>
#include <freetype/ftsynth.h>
#include <freetype/ftoutln.h>

#include <freetype/ftsnames.h>
#include <freetype/tttables.h>
#include <freetype/tttags.h>
#include <freetype/ttnameid.h>

cdecl_type(FT_String)
cdecl_type(FT_Byte)
cdecl_type(FT_UShort)
cdecl_type(FT_Short)
cdecl_type(FT_Int)
cdecl_type(FT_UInt)
cdecl_type(FT_Long)
cdecl_type(FT_ULong)
cdecl_type(FT_Error)
cdecl_type(FT_Pos)

Expand Down Expand Up @@ -105,11 +117,89 @@ cdecl_func(FT_Outline_Embolden)
cdecl_func(FT_Outline_Translate)
cdecl_func(FT_MulFix)

cdecl_const(FT_LOAD_RENDER)
cdecl_func(FT_Get_First_Char)
cdecl_func(FT_Get_Next_Char)

cdecl_const(FT_LOAD_DEFAULT)
cdecl_const(FT_LOAD_TARGET_LIGHT)
cdecl_const(FT_LOAD_NO_AUTOHINT)
cdecl_const(FT_LOAD_NO_SCALE)
cdecl_const(FT_LOAD_NO_HINTING)
cdecl_const(FT_LOAD_RENDER)
cdecl_const(FT_LOAD_NO_BITMAP)
cdecl_const(FT_LOAD_VERTICAL_LAYOUT)
cdecl_const(FT_LOAD_FORCE_AUTOHINT)
cdecl_const(FT_LOAD_CROP_BITMAP)
cdecl_const(FT_LOAD_PEDANTIC)
cdecl_const(FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH)
cdecl_const(FT_LOAD_NO_RECURSE)
cdecl_const(FT_LOAD_IGNORE_TRANSFORM)
cdecl_const(FT_LOAD_MONOCHROME)
cdecl_const(FT_LOAD_LINEAR_DESIGN)

cdecl_const(FT_LOAD_SBITS_ONLY)
cdecl_const(FT_LOAD_NO_AUTOHINT)

cdecl_const(FT_LOAD_TARGET_NORMAL)
cdecl_const(FT_LOAD_TARGET_LIGHT)
cdecl_const(FT_LOAD_TARGET_MONO)
cdecl_const(FT_LOAD_TARGET_LCD)
cdecl_const(FT_LOAD_TARGET_LCD_V)

cdecl_const(FT_FACE_FLAG_SCALABLE)
cdecl_const(FT_FACE_FLAG_FIXED_SIZES)
cdecl_const(FT_FACE_FLAG_FIXED_WIDTH)
cdecl_const(FT_FACE_FLAG_HORIZONTAL)
cdecl_const(FT_FACE_FLAG_VERTICAL)
cdecl_const(FT_FACE_FLAG_SFNT)
cdecl_const(FT_FACE_FLAG_KERNING)
cdecl_const(FT_FACE_FLAG_MULTIPLE_MASTERS)
cdecl_const(FT_FACE_FLAG_GLYPH_NAMES)
cdecl_const(FT_FACE_FLAG_EXTERNAL_STREAM)
cdecl_const(FT_FACE_FLAG_FAST_GLYPHS)
cdecl_const(FT_FACE_FLAG_HINTER)


cdecl_const(FT_STYLE_FLAG_BOLD)
cdecl_const(FT_STYLE_FLAG_ITALIC)


cdecl_const(FT_KERNING_DEFAULT)
cdecl_const(FT_KERNING_UNFITTED)
cdecl_const(FT_KERNING_UNSCALED)

cdecl_struct(TT_OS2_)
cdecl_type(TT_OS2)

cdecl_enum(FT_Sfnt_Tag_)
cdecl_type(FT_Sfnt_Tag)
cdecl_func(FT_Get_Sfnt_Table)

cdecl_struct(FT_SfntName_)
cdecl_type(FT_SfntName)



cdecl_const(TT_NAME_ID_COPYRIGHT)
cdecl_const(TT_NAME_ID_FONT_FAMILY)
cdecl_const(TT_NAME_ID_FONT_SUBFAMILY)
cdecl_const(TT_NAME_ID_UNIQUE_ID)
cdecl_const(TT_NAME_ID_FULL_NAME)
cdecl_const(TT_NAME_ID_VERSION_STRING)
cdecl_const(TT_NAME_ID_PS_NAME)
cdecl_const(TT_NAME_ID_TRADEMARK)
cdecl_const(TT_NAME_ID_MANUFACTURER)
cdecl_const(TT_NAME_ID_DESIGNER)
cdecl_const(TT_NAME_ID_DESCRIPTION)
cdecl_const(TT_NAME_ID_VENDOR_URL)
cdecl_const(TT_NAME_ID_DESIGNER_URL)
cdecl_const(TT_NAME_ID_LICENSE)
cdecl_const(TT_NAME_ID_LICENSE_URL)
cdecl_const(TT_NAME_ID_PREFERRED_FAMILY)
cdecl_const(TT_NAME_ID_PREFERRED_SUBFAMILY)
cdecl_const(TT_NAME_ID_MAC_FULL_NAME)
cdecl_const(TT_NAME_ID_SAMPLE_TEXT)
cdecl_const(TT_NAME_ID_CID_FINDFONT_NAME)
cdecl_const(TT_NAME_ID_WWS_FAMILY)
cdecl_const(TT_NAME_ID_WWS_SUBFAMILY)

cdecl_func(FT_Get_Sfnt_Name_Count)
cdecl_func(FT_Get_Sfnt_Name)
28 changes: 28 additions & 0 deletions ffi-cdecl/harfbuzz_cdecl.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ cdecl_func(hb_ft_font_set_funcs)

cdecl_type(hb_ot_math_glyph_part_flags_t)
cdecl_type(hb_ot_var_axis_flags_t)
cdecl_type(hb_ot_name_id_t)

cdecl_struct(hb_ot_name_entry_t)
cdecl_struct(hb_ot_color_layer_t)
Expand Down Expand Up @@ -508,3 +509,30 @@ cdecl_func(hb_ot_var_named_instance_get_design_coords)
cdecl_func(hb_ot_var_normalize_variations)
cdecl_func(hb_ot_var_normalize_coords)

// Annoyingly, this one isn't an enum for some reason...
cdecl_const(HB_OT_NAME_ID_COPYRIGHT)
cdecl_const(HB_OT_NAME_ID_FONT_FAMILY)
cdecl_const(HB_OT_NAME_ID_FONT_SUBFAMILY)
cdecl_const(HB_OT_NAME_ID_UNIQUE_ID)
cdecl_const(HB_OT_NAME_ID_FULL_NAME)
cdecl_const(HB_OT_NAME_ID_VERSION_STRING)
cdecl_const(HB_OT_NAME_ID_POSTSCRIPT_NAME)
cdecl_const(HB_OT_NAME_ID_TRADEMARK)
cdecl_const(HB_OT_NAME_ID_MANUFACTURER)
cdecl_const(HB_OT_NAME_ID_DESIGNER)
cdecl_const(HB_OT_NAME_ID_DESCRIPTION)
cdecl_const(HB_OT_NAME_ID_VENDOR_URL)
cdecl_const(HB_OT_NAME_ID_DESIGNER_URL)
cdecl_const(HB_OT_NAME_ID_LICENSE)
cdecl_const(HB_OT_NAME_ID_LICENSE_URL)
cdecl_const(HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY)
cdecl_const(HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY)
cdecl_const(HB_OT_NAME_ID_MAC_FULL_NAME)
cdecl_const(HB_OT_NAME_ID_SAMPLE_TEXT)
cdecl_const(HB_OT_NAME_ID_CID_FINDFONT_NAME)
cdecl_const(HB_OT_NAME_ID_WWS_FAMILY)
cdecl_const(HB_OT_NAME_ID_WWS_SUBFAMILY)
cdecl_const(HB_OT_NAME_ID_LIGHT_BACKGROUND)
cdecl_const(HB_OT_NAME_ID_DARK_BACKGROUND)
cdecl_const(HB_OT_NAME_ID_VARIATIONS_PS_PREFIX)

48 changes: 47 additions & 1 deletion ffi/freetype.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,46 @@ function FTFace_mt.__index:getHeightAndAscender()
end

function FTFace_mt.__index:done()
-- Note that past this point, accessing self is illegal, FT2 frees the pointer
assert(ft2.FT_Done_Face(self) == 0, "freetype error when freeing face")
end

FTFace_mt.__gc = FTFace_mt.__index.done;
function FTFace_mt.__index:getInfo()
local finfo = {
name = ffi.string(self.family_name),
-- Style
mono = bit.band(tonumber(self.face_flags), ft2.FT_FACE_FLAG_FIXED_WIDTH) ~= 0,
hint = bit.band(tonumber(self.face_flags), ft2.FT_FACE_FLAG_HINTER) ~= 0,
bold = bit.band(tonumber(self.style_flags), ft2.FT_STYLE_FLAG_BOLD) ~= 0,
italic = bit.band(tonumber(self.style_flags), ft2.FT_STYLE_FLAG_ITALIC) ~= 0,
serif = nil,
ui = false,
names = nil,
}

-- In practice, just going by latin name can tell us more than the depressingly absent tags
finfo.ui = finfo.name:match("UI$") ~= nil
local lname = finfo.name:lower()
if lname:match("serif") then
finfo.serif = true
elseif lname:match("sans") then
finfo.serif = false
elseif bit.band(tonumber(self.face_flags), ft2.FT_FACE_FLAG_SFNT) ~= 0 then
local os2 = ft2.FT_Get_Sfnt_Table(self, ft2.FT_SFNT_OS2)
if os2 ~= nil then
local kls = tonumber(ffi.cast("TT_OS2*", os2).sFamilyClass)
if kls ~= 0 then -- 0 is usually bogus
-- class 8 = sans, otherwise serif
finfo.serif = bit.band(kls, 0x0800) == 0
end
end
if finfo.serif == nil then
--TODO: Maybe it's worth to consult panose tables too?
finfo.serif = true
end
end
return finfo
end

local FTFaceType = ffi.metatype("struct FT_FaceRec_", FTFace_mt) -- luacheck: ignore 211

Expand Down Expand Up @@ -157,4 +193,14 @@ function FT.newFace(filename, pxsize, faceindex)
return face
end

function FT.getFaceCount(filename, info)
-- Probes number of faces available within the font file
local ftface = ffi.new("FT_Face[1]")
if ft2.FT_New_Face(freetypelib, filename, -1, ftface) ~= 0 then return nil end
local fp = ftface[0]
local nfaces = tonumber(ftface[0].num_faces)
fp:done()
return nfaces
end

return FT
Loading

0 comments on commit e4a66e5

Please sign in to comment.