-
Notifications
You must be signed in to change notification settings - Fork 3k
/
font.py
136 lines (119 loc) · 5.13 KB
/
font.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import ctypes
import logging
import os
import platform
import plistlib
from shutil import copy2, rmtree
from subprocess import call, check_output
HERE = os.path.split(__file__)[0]
SYSTEM = platform.system().lower()
class FontInstaller(object):
def __init__(self, font_dir=None, **fonts):
self.font_dir = font_dir
self.installed_fonts = False
self.created_dir = False
self.fonts = fonts
def __call__(self, env_options=None, env_config=None):
return self
def __enter__(self):
for _, font_path in self.fonts.items():
font_name = font_path.split('/')[-1]
install = getattr(self, 'install_%s_font' % SYSTEM, None)
if not install:
logging.warning('Font installation not supported on %s',
SYSTEM)
return False
if install(font_name, font_path):
self.installed_fonts = True
logging.info('Installed font: %s', font_name)
else:
logging.warning('Unable to install font: %s', font_name)
def __exit__(self, exc_type, exc_val, exc_tb):
if not self.installed_fonts:
return False
for _, font_path in self.fonts.items():
font_name = font_path.split('/')[-1]
remove = getattr(self, 'remove_%s_font' % SYSTEM, None)
if not remove:
logging.warning('Font removal not supported on %s', SYSTEM)
return False
if remove(font_name, font_path):
logging.info('Removed font: %s', font_name)
else:
logging.warning('Unable to remove font: %s', font_name)
def install_linux_font(self, font_name, font_path):
if not self.font_dir:
self.font_dir = os.path.join(os.path.expanduser('~'), '.fonts')
if not os.path.exists(self.font_dir):
os.makedirs(self.font_dir)
self.created_dir = True
if not os.path.exists(os.path.join(self.font_dir, font_name)):
copy2(font_path, self.font_dir)
try:
fc_cache_returncode = call('fc-cache')
return not fc_cache_returncode
except OSError: # If fontconfig doesn't exist, return False
logging.error('fontconfig not available on this Linux system.')
return False
def install_darwin_font(self, font_name, font_path):
if not self.font_dir:
self.font_dir = os.path.join(os.path.expanduser('~'),
'Library/Fonts')
if not os.path.exists(self.font_dir):
os.makedirs(self.font_dir)
self.created_dir = True
installed_font_path = os.path.join(self.font_dir, font_name)
if not os.path.exists(installed_font_path):
copy2(font_path, self.font_dir)
# Per https://github.com/web-platform-tests/results-collection/issues/218
# installing Ahem on macOS is flaky, so check if it actually installed
fonts = check_output(['/usr/sbin/system_profiler', '-xml', 'SPFontsDataType'])
fonts = plistlib.readPlistFromString(fonts)
assert len(fonts) == 1
for font in fonts[0]['_items']:
if font['path'] == installed_font_path:
return True
return False
def install_windows_font(self, _, font_path):
hwnd_broadcast = 0xFFFF
wm_fontchange = 0x001D
gdi32 = ctypes.WinDLL('gdi32')
if gdi32.AddFontResourceW(font_path):
from ctypes import wintypes
wparam = 0
lparam = 0
SendMessageW = ctypes.windll.user32.SendMessageW
SendMessageW.argtypes = [wintypes.HANDLE, wintypes.UINT,
wintypes.WPARAM, wintypes.LPARAM]
return bool(SendMessageW(hwnd_broadcast, wm_fontchange,
wparam, lparam))
def remove_linux_font(self, font_name, _):
if self.created_dir:
rmtree(self.font_dir)
else:
os.remove('%s/%s' % (self.font_dir, font_name))
try:
fc_cache_returncode = call('fc-cache')
return not fc_cache_returncode
except OSError: # If fontconfig doesn't exist, return False
logging.error('fontconfig not available on this Linux system.')
return False
def remove_darwin_font(self, font_name, _):
if self.created_dir:
rmtree(self.font_dir)
else:
os.remove(os.path.join(self.font_dir, font_name))
return True
def remove_windows_font(self, _, font_path):
hwnd_broadcast = 0xFFFF
wm_fontchange = 0x001D
gdi32 = ctypes.WinDLL('gdi32')
if gdi32.RemoveFontResourceW(font_path):
from ctypes import wintypes
wparam = 0
lparam = 0
SendMessageW = ctypes.windll.user32.SendMessageW
SendMessageW.argtypes = [wintypes.HANDLE, wintypes.UINT,
wintypes.WPARAM, wintypes.LPARAM]
return bool(SendMessageW(hwnd_broadcast, wm_fontchange,
wparam, lparam))