File: _win32.py

package info (click to toggle)
python-vispy 0.15.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,868 kB
  • sloc: python: 59,799; javascript: 6,800; makefile: 69; sh: 6
file content (105 lines) | stat: -rw-r--r-- 4,514 bytes parent folder | download | duplicates (4)
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
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
# -----------------------------------------------------------------------------

import os
from os import path as op
import warnings


from ctypes import (cast, byref, sizeof, create_unicode_buffer,
                    c_void_p, c_wchar_p)
from ...ext.gdi32plus import (gdiplus, gdi32, user32, winreg, LOGFONT,
                              OUTLINETEXTMETRIC, GM_ADVANCED, FW_NORMAL,
                              FW_BOLD, LF_FACESIZE, DEFAULT_CHARSET,
                              TRUETYPE_FONTTYPE, FONTENUMPROC, BOOL)


# Inspired by:
# http://forums.codeguru.com/showthread.php?90792-How-to-get-a-system-
# font-file-name-given-a-LOGFONT-face-name

# XXX This isn't perfect, but it should work for now...

def find_font(face, bold, italic, orig_face=None):
    style_dict = {'Regular': 0, 'Bold': 1, 'Italic': 2, 'Bold Italic': 3}

    # Figure out which font to actually use by trying to instantiate by name
    dc = user32.GetDC(0)  # noqa, analysis:ignore
    gdi32.SetGraphicsMode(dc, GM_ADVANCED)  # only TT and OT fonts
    logfont = LOGFONT()
    logfont.lfHeight = -12  # conv point to pixels
    logfont.lfWeight = FW_BOLD if bold else FW_NORMAL
    logfont.lfItalic = italic
    logfont.lfFaceName = face  # logfont needs Unicode
    hfont = gdi32.CreateFontIndirectW(byref(logfont))
    original = gdi32.SelectObject(dc, hfont)
    n_byte = gdi32.GetOutlineTextMetricsW(dc, 0, None)
    assert n_byte > 0
    metrics = OUTLINETEXTMETRIC()
    assert sizeof(metrics) >= n_byte
    assert gdi32.GetOutlineTextMetricsW(dc, n_byte, byref(metrics))
    gdi32.SelectObject(dc, original)
    user32.ReleaseDC(None, dc)
    use_face = cast(byref(metrics, metrics.otmpFamilyName), c_wchar_p).value
    if use_face != face:
        warnings.warn('Could not find face match "%s", falling back to "%s"'
                      % (orig_face or face, use_face))
    use_style = cast(byref(metrics, metrics.otmpStyleName), c_wchar_p).value
    use_style = style_dict.get(use_style, 'Regular')
    # AK: I get "Standaard" for use_style, which is Dutch for standard/regular

    # Now we match by creating private font collections until we find
    # the one that was used
    font_dir = op.join(os.environ['WINDIR'], 'Fonts')
    reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
    key = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts'
    reg_vals = winreg.OpenKey(reg, key)
    n_values = winreg.QueryInfoKey(reg_vals)[1]
    fname = None
    for vi in range(n_values):
        name, ff = winreg.EnumValue(reg_vals, vi)[:2]
        if name.endswith('(TrueType)'):
            ff = op.join(font_dir, ff) if op.basename(ff) == ff else ff
            assert op.isfile(ff)
            pc = c_void_p()
            assert gdiplus.GdipNewPrivateFontCollection(byref(pc)) == 0
            gdiplus.GdipPrivateAddFontFile(pc, ff)
            family = c_void_p()
            if gdiplus.GdipCreateFontFamilyFromName(use_face, pc,
                                                    byref(family)) == 0:
                val = BOOL()
                assert gdiplus.GdipIsStyleAvailable(family, use_style,
                                                    byref(val)) == 0
                if val.value:
                    buf = create_unicode_buffer(LF_FACESIZE)
                    assert gdiplus.GdipGetFamilyName(family, buf, 0) == 0
                    assert buf.value == use_face
                    fname = ff
                    break
    fname = fname or find_font('', bold, italic, face)  # fall back to default
    return fname


def _list_fonts():
    dc = user32.GetDC(0)
    gdi32.SetGraphicsMode(dc, GM_ADVANCED)  # only TT and OT fonts
    logfont = LOGFONT()
    logfont.lfCharSet = DEFAULT_CHARSET
    logfont.lfFaceName = ''
    logfont.lfPitchandFamily = 0
    fonts = list()

    def enum_fun(lp_logfont, lp_text_metric, font_type, l_param):
        # Only support TTF for now (silly Windows shortcomings)
        if font_type == TRUETYPE_FONTTYPE:
            font = lp_logfont.contents.lfFaceName
            if not font.startswith('@') and font not in fonts:
                fonts.append(font)
        return 1

    gdi32.EnumFontFamiliesExW(dc, byref(logfont), FONTENUMPROC(enum_fun), 0, 0)
    user32.ReleaseDC(None, dc)
    return fonts