Skip to content

Commit

Permalink
Remove default_size and __default_weight from FontManager (#723)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwiggins authored Mar 16, 2021
1 parent 48d9772 commit b0b8454
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 229 deletions.
13 changes: 0 additions & 13 deletions kiva/fonttools/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,6 @@
"modern",
}

font_scalings = {
"xx-small": 0.579,
"x-small": 0.694,
"small": 0.833,
"medium": 1.0,
"large": 1.200,
"x-large": 1.440,
"xx-large": 1.728,
"larger": 1.2,
"smaller": 0.833,
None: 1.0,
}

preferred_fonts = {
"fantasy": [
"Comic Sans MS",
Expand Down
39 changes: 10 additions & 29 deletions kiva/fonttools/_font_properties.py → kiva/fonttools/_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
from fontTools.afmLib import AFM
from fontTools.ttLib import TTFont

from kiva.fonttools._constants import font_scalings, stretch_dict, weight_dict
from kiva.fonttools._constants import stretch_dict, weight_dict
from kiva.fonttools._util import get_ttf_prop_dict
from kiva.fonttools.font_manager import default_font_manager


class FontProperties(object):
""" A class for storing and manipulating font properties.
class FontQuery(object):
""" A class for storing properties needed to query the font manager.
The font properties are those described in the `W3C Cascading
Style Sheet, Level 1
<http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_ font
specification. The six properties are:
The properties are those described in the `W3C Cascading
Style Sheet, Level 1 <http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_ font
specification. The six properties are:
- family: A list of font names in decreasing order of priority.
The items may include a generic font family name, either
Expand All @@ -41,17 +40,10 @@ class FontProperties(object):
'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy',
'extra bold', 'black'
- size: Either an relative value of 'xx-small', 'x-small',
'small', 'medium', 'large', 'x-large', 'xx-large' or an
absolute font size, e.g. 12
- size: An absolute font size, e.g. 12
Alternatively, a font may be specified using an absolute path to a
.ttf file, by using the *fname* kwarg.
The preferred usage of font sizes is to use the relative values,
e.g. 'large', instead of absolute font sizes, e.g. 12. This
approach allows all text sizes to be made larger or smaller based
on the font manager's default font size.
"""
def __init__(self, family=None, style=None, variant=None, weight=None,
stretch=None, size=None, fname=None, _init=None):
Expand Down Expand Up @@ -146,15 +138,6 @@ def get_size(self):
"""
return self._size

def get_size_in_points(self):
if self._size is not None:
try:
return float(self._size)
except ValueError:
pass
default_size = default_font_manager().get_default_size()
return default_size * font_scalings.get(self._size)

def get_file(self):
""" Return the filename of the associated font.
"""
Expand Down Expand Up @@ -238,15 +221,13 @@ def set_stretch(self, stretch):
def set_size(self, size):
""" Set the font size.
Either an relative value of 'xx-small', 'x-small', 'small', 'medium',
'large', 'x-large', 'xx-large' or an absolute font size, e.g. 12.
An absolute font size, e.g. 12.
"""
if size is not None:
try:
size = float(size)
except ValueError:
if size is not None and size not in font_scalings:
raise ValueError("size is invalid")
raise ValueError("size is invalid")
self._size = size

def set_file(self, file):
Expand All @@ -259,4 +240,4 @@ def set_file(self, file):
def copy(self):
""" Return a deep copy of self
"""
return FontProperties(_init=self)
return FontQuery(_init=self)
7 changes: 3 additions & 4 deletions kiva/fonttools/_score.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
####################
"""
from kiva.fonttools._constants import (
font_family_aliases, font_scalings, preferred_fonts, stretch_dict,
weight_dict
font_family_aliases, preferred_fonts, stretch_dict, weight_dict
)

# Each of the scoring functions below should return a value between
Expand Down Expand Up @@ -49,7 +48,7 @@ def score_family(families, family2):
return 1.0


def score_size(size1, size2, default):
def score_size(size1, size2):
""" Returns a match score between *size1* and *size2*.
If *size2* (the size specified in the font file) is 'scalable', this
Expand All @@ -65,7 +64,7 @@ def score_size(size1, size2, default):
try:
sizeval1 = float(size1)
except ValueError:
sizeval1 = default * font_scalings.get(size1, 1.0)
return 1.0
try:
sizeval2 = float(size2)
except ValueError:
Expand Down
21 changes: 10 additions & 11 deletions kiva/fonttools/font.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
BOLD_ITALIC, BOLD, DECORATIVE, DEFAULT, ITALIC, MODERN, NORMAL, ROMAN,
SCRIPT, SWISS, TELETYPE,
)
from kiva.fonttools._font_properties import FontProperties
from kiva.fonttools._query import FontQuery
from kiva.fonttools.font_manager import default_font_manager

# Various maps used by str_to_font
Expand Down Expand Up @@ -116,19 +116,18 @@ def findfont(self):
""" Returns the file name and face index of the font that most closely
matches our font properties.
"""
fp = self._make_font_props()
return default_font_manager().findfont(fp)
query = self._make_font_query()
return default_font_manager().findfont(query)

def findfontname(self):
""" Returns the name of the font that most closely matches our font
properties
"""
fp = self._make_font_props()
return fp.get_name()
query = self._make_font_query()
return query.get_name()

def _make_font_props(self):
""" Returns a font_manager.FontProperties object that encapsulates our
font properties
def _make_font_query(self):
""" Returns a FontQuery object that encapsulates our font properties.
"""
# XXX: change the weight to a numerical value
if self.style == BOLD or self.style == BOLD_ITALIC:
Expand All @@ -139,15 +138,15 @@ def _make_font_props(self):
style = "italic"
else:
style = "normal"
fp = FontProperties(
query = FontQuery(
family=self.familymap[self.family],
style=style,
weight=weight,
size=self.size,
)
if self.face_name != "":
fp.set_name(self.face_name)
return fp
query.set_name(self.face_name)
return query

def _get_name(self):
return self.face_name
Expand Down
68 changes: 25 additions & 43 deletions kiva/fonttools/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,11 @@ class FontManager:
# Increment this version number whenever the font cache data
# format or behavior has changed and requires a existing font
# cache files to be rebuilt.
__version__ = 10
__version__ = 11

def __init__(self, size=None, weight="normal"):
def __init__(self):
self._version = self.__version__

self.__default_weight = weight
self.default_size = size if size is not None else 12.0
self.default_family = "sans-serif"
self.default_font = {}

Expand Down Expand Up @@ -123,21 +121,6 @@ def __init__(self, size=None, weight="normal"):
self.ttf_lookup_cache = {}
self.afm_lookup_cache = {}

def get_default_weight(self):
""" Return the default font weight.
"""
return self.__default_weight

def get_default_size(self):
""" Return the default font size.
"""
return self.default_size

def set_default_weight(self, weight):
""" Set the default font weight. The initial value is 'normal'.
"""
self.__default_weight = weight

def update_fonts(self, paths):
""" Update the font lists with new font files.
Expand All @@ -156,10 +139,10 @@ def update_fonts(self, paths):
update_font_database(self.afm_db, afm_paths, fontext="afm")
update_font_database(self.ttf_db, ttf_paths, fontext="ttf")

def findfont(self, prop, fontext="ttf", directory=None,
def findfont(self, query, fontext="ttf", directory=None,
fallback_to_default=True, rebuild_if_missing=True):
""" Search the font list for the font that most closely matches
the :class:`FontProperties` *prop*.
the :class:`FontQuery` *query*.
:meth:`findfont` performs a nearest neighbor search. Each
font is given a similarity score to the target font
Expand All @@ -181,7 +164,7 @@ def findfont(self, prop, fontext="ttf", directory=None,
<http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_ documentation
for a description of the font finding algorithm.
"""
from kiva.fonttools._font_properties import FontProperties
from kiva.fonttools._query import FontQuery

class FontSpec(object):
""" An object to represent the return value of findfont().
Expand All @@ -199,13 +182,13 @@ def __repr__(self):
args = f"{self.filename}, face_index={self.face_index}"
return f"FontSpec({args})"

if not isinstance(prop, FontProperties):
prop = FontProperties(prop)
if not isinstance(query, FontQuery):
query = FontQuery(query)

fname = prop.get_file()
fname = query.get_file()
if fname is not None:
logger.debug("findfont returning %s", fname)
# It's not at all clear where a `FontProperties` instance with
# It's not at all clear where a `FontQuery` instance with
# `fname` already set would come from. Assume face_index == 0.
return FontSpec(fname)

Expand All @@ -217,7 +200,7 @@ def __repr__(self):
font_db = self.ttf_db

if directory is None:
cached = font_cache.get(hash(prop))
cached = font_cache.get(hash(query))
if cached:
return cached

Expand All @@ -232,20 +215,20 @@ def __repr__(self):
# both `fonts_for_family` and `score_family` will expand generic
# families ("serif", "monospace") into lists of candidate families,
# which ensures that all possible matching fonts will be scored.
fontlist = font_db.fonts_for_family(prop.get_family())
fontlist = font_db.fonts_for_family(query.get_family())

best_score = 20.0
best_font = None
for font in fontlist:
# Matching family should have highest priority, so it is multiplied
# by 10.0
score = (
score_family(prop.get_family(), font.family) * 10.0
+ score_style(prop.get_style(), font.style)
+ score_variant(prop.get_variant(), font.variant)
+ score_weight(prop.get_weight(), font.weight)
+ score_stretch(prop.get_stretch(), font.stretch)
+ score_size(prop.get_size(), font.size, self.default_size)
score_family(query.get_family(), font.family) * 10.0
+ score_style(query.get_style(), font.style)
+ score_variant(query.get_variant(), font.variant)
+ score_weight(query.get_weight(), font.weight)
+ score_stretch(query.get_stretch(), font.stretch)
+ score_size(query.get_size(), font.size)
)
# Lowest score wins
if score < best_score:
Expand All @@ -259,28 +242,28 @@ def __repr__(self):
if fallback_to_default:
warnings.warn(
"findfont: Font family %s not found. Falling back to %s"
% (prop.get_family(), self.default_family)
% (query.get_family(), self.default_family)
)
default_prop = prop.copy()
default_prop.set_family(self.default_family)
default_query = query.copy()
default_query.set_family(self.default_family)
return self.findfont(
default_prop, fontext, directory,
default_query, fontext, directory,
fallback_to_default=False,
)
else:
# This is a hard fail -- we can't find anything reasonable,
# so just return the vera.ttf
warnings.warn(
"findfont: Could not match %s. Returning %s"
% (prop, self.default_font[fontext]),
% (query, self.default_font[fontext]),
UserWarning,
)
# Assume this is never a .ttc font, so 0 is ok for face index.
result = FontSpec(self.default_font[fontext])
else:
logger.debug(
"findfont: Matching %s to %s (%s[%d]) with score of %f",
prop,
query,
best_font.family,
best_font.fname,
best_font.face_index,
Expand All @@ -295,15 +278,15 @@ def __repr__(self):
)
_rebuild()
return default_font_manager().findfont(
prop, fontext, directory,
query, fontext, directory,
fallback_to_default=True,
rebuild_if_missing=False,
)
else:
raise ValueError("No valid font could be found")

if directory is None:
font_cache[hash(prop)] = result
font_cache[hash(query)] = result
return result


Expand Down Expand Up @@ -373,7 +356,6 @@ def _load_from_cache_or_rebuild(cache_file):
or fontManager._version != FontManager.__version__):
fontManager = _new_font_manager(cache_file)
else:
fontManager.default_size = None
logger.debug("Using fontManager instance from %s", cache_file)
except Exception:
fontManager = _new_font_manager(cache_file)
Expand Down
Loading

0 comments on commit b0b8454

Please sign in to comment.