Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
enable / fonttools / _util.py
Size: Mime:
# (C) Copyright 2005-2022 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
from kiva.fonttools._constants import weight_dict

# Unicode & Apple
_plat_ids = (0, 1)
_english_id = 0
# MS
# https://docs.microsoft.com/en-us/typography/opentype/spec/name#windows-language-ids  # noqa: E501
_ms_plat_id = 3
_ms_english_ids = {
    0x0C09: "Australia",
    0x2809: "Belize",
    0x1009: "Canada",
    0x2409: "Caribbean",
    0x4009: "India",
    0x1809: "Ireland",
    0x2009: "Jamaica",
    0x4409: "Malaysia",
    0x1409: "New Zealand",
    0x3409: "Republic of the Philippines",
    0x4809: "Singapore",
    0x1C09: "South Africa",
    0x2C09: "Trinidad and Tobago",
    0x0809: "United Kingdom",
    0x0409: "United States",
    0x3009: "Zimbabwe",
}
# TrueType 'name' table IDs
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html  # noqa: E501
_name_ids = {
    0: "copyright",
    1: "family",
    2: "style",
    3: "unique_subfamily_id",
    4: "full_name",
    5: "version",
    6: "postscript_name",
}
# OpenType 'OS/2' table data
# https://docs.microsoft.com/en-us/typography/opentype/spec/os2
# `ulCodePageRange` bit meanings
_ot_code_page_masks = {
    "Latin": 0x93,
    "Cyrillic": 0x4,
    "Greek": 0x8,
    "Hebrew": 0x20,
    "Arabic": 0x40,
    "Vietnamese": 0x100,
    "Thai": 0x10000,
    "Japanese": 0x20000,
    "Simplified Chinese": 0x40000,
    "Traditional Chinese": 0x100000,
    "Korean": 0x280000,
    "Symbol": 0x80000000,
}
# `ulUnicodeRange` bit meanings
_ot_unicode_range_bits = {
    0: "Latin",
    1: "Latin",
    2: "Latin",
    3: "Latin",
    7: "Greek",
    8: "Coptic",
    9: "Cyrillic",
    10: "Armenian",
    11: "Hebrew",
    12: "Vai",
    13: "Arabic",
    14: "Nko",
    15: "Devanagari",
    16: "Bengali",
    17: "Gurmukhi",
    18: "Gujarati",
    19: "Oriya",
    20: "Tamil",
    21: "Telugu",
    22: "Kannada",
    23: "Malayalam",
    24: "Thai",
    25: "Lao",
    26: "Georgia",
    27: "Balinese",
    28: "Korean",
    29: "Latin",
    30: "Greek",
    38: "Math",
    52: "Korean",
    56: "Korean",
    58: "Phoenician",
    70: "Tibetan",
    71: "Syriac",
    72: "Thaana",
    73: "Sinhala",
    74: "Myanmar",
    75: "Ethiopic",
    76: "Cherokee",
    77: "Canadian_Aboriginal",
    78: "Ogham",
    79: "Runic",
    80: "Khmer",
    81: "Mongolian",
    86: "Gothic",
    87: "Deseret",
    93: "Limbu",
    94: "Tai_Le",
    95: "New_Tai_Lue",
    96: "Buginese",
    97: "Glagolitic",
    98: "Tifinagh",
}
_ot_width = {
    1: 'ultra-condensed',
    2: 'extra-condensed',
    3: 'condensed',
    4: 'semi-condensed',
    5: 'normal',
    6: 'semi-expanded',
    7: 'expanded',
    8: 'extra-expanded',
    9: 'ultra-expanded',
}


def get_ttf_prop_dict(font):
    """ Parse the 'name' and 'OS/2' tables of a :class:`TTFont` instance.
    """
    propdict = {}
    table = font["name"]
    for rec in table.names:
        # We only care about records in English
        plat, lang = rec.platformID, rec.langID
        if not ((plat in _plat_ids and lang == _english_id)
                or (plat == _ms_plat_id and lang in _ms_english_ids)):
            continue
        # And of those, just the ones we have names for
        if rec.nameID not in _name_ids:
            continue

        # Convert the nameID to a nice string
        key = _name_ids[rec.nameID]
        # Skip duplicate records
        if key in propdict:
            continue

        # Use the NameRecord's toStr() method instead of ad-hoc decoding
        propdict[key] = rec.toStr()

    # NOTE: Not all fonts have the "OS/2" table, but it's the easiest to
    # extract language support information from.  There is also information
    # about styles and weights that can be used.
    propdict["languages"] = set()
    try:
        table = font["OS/2"]
        languages = set()
        # Check the unicode range bits
        unicode_bits = table.getUnicodeRanges()
        if unicode_bits:
            for bit in unicode_bits:
                if bit in _ot_unicode_range_bits:
                    languages.add(_ot_unicode_range_bits[bit])
        # Check the codepage range bits
        try:
            cp_bits = table.ulCodePageRange1
            for lang, mask in _ot_code_page_masks.items():
                if cp_bits & mask:
                    languages.add(lang)
        except AttributeError:
            # some fonts don't have ulCodePageRange1
            pass
        # Lock the set so that it's hashable
        propdict["languages"] = frozenset(languages)

        # This is the numeric weight value from 100 to 1000
        if 100 <= table.usWeightClass <= 1000:
            propdict["weight"] = table.usWeightClass

        # This is the numeric stretch value from 1-9
        if 1 <= table.usWidthClass <= 9:
            propdict["stretch"] = _ot_width[table.usWidthClass]

        # Do we match the italic or oblique bits
        if table.fsSelection % 0x0001:
            propdict["slope"] = "italic"
        elif table.fsSelection % 0x0010:
            propdict["slope"] = "oblique"
    except KeyError:
        # don't have an OS/2 table
        pass

    # Make sure "languages" is never empty
    if not propdict["languages"]:
        propdict["languages"] = frozenset(["Unknown"])

    return propdict


def weight_as_number(weight):
    """ Return the weight property as a numeric value.

    String values are converted to their corresponding numeric value.
    """
    if isinstance(weight, str):
        try:
            weight = weight_dict[weight.lower()]
        except KeyError:
            weight = weight_dict["regular"]
    elif 100 <= weight <= 1000:
        pass
    else:
        raise ValueError("weight not a valid integer")
    return weight