|
Packit Service |
76cb02 |
#
|
|
Packit Service |
76cb02 |
# Slow interface to fontconfig for Dblatex, that only parses some commmand line
|
|
Packit Service |
76cb02 |
# output to store the fonts available on the system and their characteristics.
|
|
Packit Service |
76cb02 |
#
|
|
Packit Service |
76cb02 |
# An efficient solution should use some python bindings to directly call the
|
|
Packit Service |
76cb02 |
# C fontconfig library.
|
|
Packit Service |
76cb02 |
#
|
|
Packit Service |
cd7d79 |
import sys
|
|
Packit Service |
76cb02 |
import logging
|
|
Packit Service |
76cb02 |
from subprocess import Popen, PIPE
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def execute(cmd):
|
|
Packit Service |
76cb02 |
p = Popen(cmd, stdout=PIPE)
|
|
Packit Service |
76cb02 |
data = p.communicate()[0]
|
|
Packit Service |
cd7d79 |
if isinstance(data, bytes):
|
|
Packit Service |
cd7d79 |
data = data.decode(sys.getdefaultencoding())
|
|
Packit Service |
76cb02 |
rc = p.wait()
|
|
Packit Service |
76cb02 |
if rc != 0:
|
|
Packit Service |
76cb02 |
raise OSError("'%s' failed (%d)" % (" ".join(cmd), rc))
|
|
Packit Service |
76cb02 |
return data
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
class FcFont:
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Font Object with properties filled with the fc-match command output.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
def __init__(self, fontnames, partial=False):
|
|
Packit Service |
76cb02 |
self.log = logging.getLogger("dblatex")
|
|
Packit Service |
76cb02 |
self.name = fontnames[0]
|
|
Packit Service |
76cb02 |
self.aliases = fontnames[1:]
|
|
Packit Service |
76cb02 |
self._completed = False
|
|
Packit Service |
76cb02 |
if not(partial):
|
|
Packit Service |
76cb02 |
self.complete()
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def complete(self):
|
|
Packit Service |
76cb02 |
if not(self._completed):
|
|
Packit Service |
76cb02 |
d = execute(["fc-match", "--verbose", self.name])
|
|
Packit Service |
76cb02 |
d = d.strip()
|
|
Packit Service |
76cb02 |
self._build_attr_from(d)
|
|
Packit Service |
76cb02 |
self._completed = True
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def _build_attr_from(self, data):
|
|
Packit Service |
76cb02 |
ninfos = self._splitinfos(data)
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
# Remove the first line
|
|
Packit Service |
76cb02 |
ninfos[0] = ninfos[0].split("\n")[1]
|
|
Packit Service |
76cb02 |
for i in ninfos:
|
|
Packit Service |
76cb02 |
if i: self._buildattr(i)
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
# Check the consistency
|
|
Packit Service |
76cb02 |
if self.family != self.name.replace("\-", "-"):
|
|
Packit Service |
76cb02 |
raise ValueError("Unknown font '%s' vs '%s'" % (self.name,
|
|
Packit Service |
76cb02 |
self.family))
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def _splitinfos(self, data):
|
|
Packit Service |
76cb02 |
ninfos = [data]
|
|
Packit Service |
76cb02 |
for sep in ("(s)", "(w)", "(=)"):
|
|
Packit Service |
76cb02 |
infos = ninfos
|
|
Packit Service |
76cb02 |
ninfos = []
|
|
Packit Service |
76cb02 |
for i in infos:
|
|
Packit Service |
76cb02 |
ni = i.split(sep)
|
|
Packit Service |
76cb02 |
ninfos += ni
|
|
Packit Service |
76cb02 |
return ninfos
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def _buildattr(self, infos):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Parse things like:
|
|
Packit Service |
76cb02 |
'fullname: "Mukti"(s)
|
|
Packit Service |
76cb02 |
fullnamelang: "en"(s)
|
|
Packit Service |
76cb02 |
slant: 0(i)(s)
|
|
Packit Service |
76cb02 |
weight: 80(i)(s)
|
|
Packit Service |
76cb02 |
width: 100(i)(s)
|
|
Packit Service |
76cb02 |
size: 12(f)(s)'
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
try:
|
|
Packit Service |
76cb02 |
attrname, attrdata = infos.split(":", 1)
|
|
Packit Service |
76cb02 |
except:
|
|
Packit Service |
76cb02 |
# Skip this row
|
|
Packit Service |
76cb02 |
self.log.warning("Wrong data? '%s'" % infos)
|
|
Packit Service |
76cb02 |
return
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
#print infos
|
|
Packit Service |
76cb02 |
attrname = attrname.strip() # Remove \t
|
|
Packit Service |
76cb02 |
attrdata = attrdata.strip() # Remove space
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
# Specific case
|
|
Packit Service |
76cb02 |
if attrname == "charset":
|
|
Packit Service |
76cb02 |
self._build_charset(attrdata)
|
|
Packit Service |
76cb02 |
return
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
# Get the data type
|
|
Packit Service |
76cb02 |
if (not(attrdata) or (attrdata[0] == '"' and attrdata[-1] == '"')):
|
|
Packit Service |
76cb02 |
setattr(self, attrname, attrdata.strip('"'))
|
|
Packit Service |
76cb02 |
return
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
if (attrdata.endswith("(i)")):
|
|
Packit Service |
76cb02 |
setattr(self, attrname, int(attrdata.strip("(i)")))
|
|
Packit Service |
76cb02 |
return
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
if (attrdata.endswith("(f)")):
|
|
Packit Service |
76cb02 |
setattr(self, attrname, float(attrdata.strip("(f)")))
|
|
Packit Service |
76cb02 |
return
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
if (attrdata == "FcTrue"):
|
|
Packit Service |
76cb02 |
setattr(self, attrname, True)
|
|
Packit Service |
76cb02 |
return
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
if (attrdata == "FcFalse"):
|
|
Packit Service |
76cb02 |
setattr(self, attrname, False)
|
|
Packit Service |
76cb02 |
return
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def _build_charset(self, charset):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Parse something like:
|
|
Packit Service |
76cb02 |
'0000: 00000000 ffffffff ffffffff 7fffffff 00000000 00002001 00800000 00800000
|
|
Packit Service |
76cb02 |
0009: 00000000 00000000 00000000 00000030 fff99fee f3c5fdff b080399f 07ffffcf
|
|
Packit Service |
76cb02 |
0020: 30003000 00000000 00000010 00000000 00000000 00001000 00000000 00000000
|
|
Packit Service |
76cb02 |
0025: 00000000 00000000 00000000 00000000 00000000 00000000 00001000 00000000'
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
self.charsetstr = charset
|
|
Packit Service |
76cb02 |
self.charset = []
|
|
Packit Service |
76cb02 |
lines = charset.split("\n")
|
|
Packit Service |
76cb02 |
for l in lines:
|
|
Packit Service |
76cb02 |
umajor, row = l.strip().split(":", 1)
|
|
Packit Service |
76cb02 |
int32s = row.split()
|
|
Packit Service |
76cb02 |
p = 0
|
|
Packit Service |
76cb02 |
for w in int32s:
|
|
Packit Service |
76cb02 |
#print "=> %s" % w
|
|
Packit Service |
76cb02 |
v = int(w, 16)
|
|
Packit Service |
76cb02 |
for i in range(0, 32):
|
|
Packit Service |
76cb02 |
m = 1 << i
|
|
Packit Service |
76cb02 |
#m = 0x80000000 >> i
|
|
Packit Service |
76cb02 |
if (m & v):
|
|
Packit Service |
76cb02 |
uchar = umajor + "%02X" % (p + i)
|
|
Packit Service |
76cb02 |
#print uchar
|
|
Packit Service |
76cb02 |
self.charset.append(int(uchar, 16))
|
|
Packit Service |
76cb02 |
p += 32
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def remove_char(self, char):
|
|
Packit Service |
76cb02 |
try:
|
|
Packit Service |
76cb02 |
self.charset.remove(char)
|
|
Packit Service |
76cb02 |
except:
|
|
Packit Service |
76cb02 |
pass
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def has_char(self, char):
|
|
Packit Service |
76cb02 |
#print self.family, char, self.charset
|
|
Packit Service |
76cb02 |
return (ord(char) in self.charset)
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
class FcManager:
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Collect all the fonts available in the system. The building can be partial,
|
|
Packit Service |
76cb02 |
i.e. the font objects can be partially created, and updated later (when
|
|
Packit Service |
76cb02 |
used).
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
The class tries to build three ordered list of fonts, one per standard
|
|
Packit Service |
76cb02 |
generic font family:
|
|
Packit Service |
76cb02 |
- Serif : main / body font
|
|
Packit Service |
76cb02 |
- Sans-serif : used to render sans-serif forms
|
|
Packit Service |
76cb02 |
- Monospace : used to render verbatim / monospace characters
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
def __init__(self):
|
|
Packit Service |
76cb02 |
self.log = logging.getLogger("dblatex")
|
|
Packit Service |
76cb02 |
self.fonts = {}
|
|
Packit Service |
76cb02 |
self.fonts_family = {}
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def get_font(self, fontname):
|
|
Packit Service |
76cb02 |
font = self.fonts.get(fontname)
|
|
Packit Service |
76cb02 |
if font:
|
|
Packit Service |
76cb02 |
font.complete()
|
|
Packit Service |
76cb02 |
return font
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def get_font_handling(self, char, all=False, family_type=""):
|
|
Packit Service |
76cb02 |
if not(family_type):
|
|
Packit Service |
76cb02 |
font_family = self.fonts.values()
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
font_family = self.fonts_family.get(family_type, None)
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
if not(font_family):
|
|
Packit Service |
76cb02 |
return []
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
fonts = self.get_font_handling_from(font_family, char, all=all)
|
|
Packit Service |
76cb02 |
return fonts
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def get_font_handling_from(self, fontlist, char, all=False):
|
|
Packit Service |
76cb02 |
fonts = []
|
|
Packit Service |
76cb02 |
# Brutal method to get something...
|
|
Packit Service |
76cb02 |
for f in fontlist:
|
|
Packit Service |
76cb02 |
f.complete()
|
|
Packit Service |
76cb02 |
if f.has_char(char):
|
|
Packit Service |
76cb02 |
if all:
|
|
Packit Service |
76cb02 |
fonts.append(f)
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
return f
|
|
Packit Service |
76cb02 |
return fonts
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def build_fonts(self, partial=False):
|
|
Packit Service |
76cb02 |
self.build_fonts_all(partial=partial)
|
|
Packit Service |
76cb02 |
self.build_fonts_family("serif")
|
|
Packit Service |
76cb02 |
self.build_fonts_family("sans-serif")
|
|
Packit Service |
76cb02 |
self.build_fonts_family("monospace")
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def build_fonts_all(self, partial=False):
|
|
Packit Service |
76cb02 |
# Grab all the fonts installed on the system
|
|
Packit Service |
76cb02 |
d = execute(["fc-list"])
|
|
Packit Service |
76cb02 |
fonts = d.strip().split("\n")
|
|
Packit Service |
76cb02 |
for f in fonts:
|
|
Packit Service |
76cb02 |
fontnames = f.split(":")[0].split(",")
|
|
Packit Service |
76cb02 |
mainname = fontnames[0]
|
|
Packit Service |
76cb02 |
if not(mainname):
|
|
Packit Service |
76cb02 |
continue
|
|
Packit Service |
76cb02 |
if self.fonts.get(mainname):
|
|
Packit Service |
76cb02 |
self.log.debug("'%s': duplicated" % mainname)
|
|
Packit Service |
76cb02 |
continue
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
#print fontnames
|
|
Packit Service |
76cb02 |
font = FcFont(fontnames, partial=partial)
|
|
Packit Service |
76cb02 |
self.fonts[mainname] = font
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def build_fonts_family(self, family_type):
|
|
Packit Service |
76cb02 |
# Create a sorted list matching a generic family
|
|
Packit Service |
76cb02 |
# Use --sort to have only fonts completing unicode range
|
|
Packit Service |
76cb02 |
font_family = []
|
|
Packit Service |
76cb02 |
self.fonts_family[family_type] = font_family
|
|
Packit Service |
76cb02 |
d = execute(["fc-match", "--sort", family_type, "family"])
|
|
Packit Service |
76cb02 |
fonts = d.strip().split("\n")
|
|
Packit Service |
76cb02 |
for f in fonts:
|
|
Packit Service |
76cb02 |
font = self.fonts.get(f)
|
|
Packit Service |
76cb02 |
if not(font in font_family):
|
|
Packit Service |
76cb02 |
font_family.append(font)
|
|
Packit Service |
76cb02 |
#print family_type
|
|
Packit Service |
76cb02 |
#print font_family
|
|
Packit Service |
76cb02 |
|