From 27e3991a52de08b3297a347979453f4adb48d4ca Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Fri, 19 Feb 2021 17:47:03 +0100 Subject: [PATCH 1/6] Add face_index support to celiagg and kiva.agg backends. --- kiva/agg/src/font_type.i | 18 +++++----- kiva/agg/src/graphics_context.i | 5 +-- kiva/agg/src/kiva_font_type.cpp | 11 +++--- kiva/agg/src/kiva_font_type.h | 4 ++- kiva/agg/src/kiva_graphics_context_base.cpp | 4 +-- kiva/celiagg.py | 11 +++--- kiva/fonttools/font.py | 9 ++--- kiva/fonttools/font_manager.py | 38 +++++++++++++-------- kiva/fonttools/tests/test_font.py | 6 ++-- 9 files changed, 62 insertions(+), 44 deletions(-) diff --git a/kiva/agg/src/font_type.i b/kiva/agg/src/font_type.i index 507e66e47..503a6fe05 100644 --- a/kiva/agg/src/font_type.i +++ b/kiva/agg/src/font_type.i @@ -26,7 +26,8 @@ namespace kiva std::string name; int family; int style; - int encoding; + int encoding; + int face_index; std::string filename; // constructor @@ -35,6 +36,7 @@ namespace kiva int _family=0, int _style=0, int _encoding=0, + int _face_index=0, bool validate=true); int change_filename(std::string _filename); @@ -47,12 +49,11 @@ namespace kiva char *__repr__() { static char tmp[1024]; - // Write out elements of trans_affine in a,b,c,d,tx,ty order // !! We should work to make output formatting conform to // !! whatever it Numeric does (which needs to be cleaned up also). - sprintf(tmp,"Font(%s,%d,%d,%d,%d)", self->name.c_str(), self->family, - self->size, self->style, - self->encoding); + sprintf(tmp,"Font(%s,%d,%d,%d,%d,%d)", + self->name.c_str(), self->family, self->size, self->style, + self->encoding, self->face_index); return tmp; } int __eq__(kiva::font_type& other) @@ -61,14 +62,15 @@ namespace kiva self->family == other.family && self->size == other.size && self->style == other.style && - self->encoding == other.encoding); + self->encoding == other.encoding && + self->face_index == other.face_index); } } %pythoncode %{ def unicode_safe_init(self, _name="Arial", _size=12, _family=0, _style=0, - _encoding=0, validate=True): + _encoding=0, _face_index=0, validate=True): ### HACK: C++ stuff expects a string (not unicode) for the face_name, so fix ### if needed. ### Only for python < 3 @@ -79,7 +81,7 @@ def unicode_safe_init(self, _name="Arial", _size=12, _family=0, _style=0, if isinstance(_name, bytes): _name = _name.decode() obj = _agg.new_AggFontType(_name, _size, _family, _style, - _encoding, validate) + _encoding, _face_index, validate) _swig_setattr(self, AggFontType, "this", obj) _swig_setattr(self, AggFontType, "thisown", 1) diff --git a/kiva/agg/src/graphics_context.i b/kiva/agg/src/graphics_context.i index fcebdc1f6..930c0018d 100644 --- a/kiva/agg/src/graphics_context.i +++ b/kiva/agg/src/graphics_context.i @@ -560,11 +560,12 @@ namespace kiva { and (font.encoding == cur_font.encoding): return else: - newfilename = font.findfont() + newfilename, face_index = font.findfont() agg_font = AggFontType(font.face_name, font.size, font.family, font.style, - font.encoding, False) + font.encoding, face_index, False) agg_font.filename = newfilename else: + # XXX: What are we expecting here? agg_font = AggFontType(font.face_name, font.size, font.family, font.style, font.encoding) try: retval = _agg.GraphicsContextArray_set_font(self, agg_font) diff --git a/kiva/agg/src/kiva_font_type.cpp b/kiva/agg/src/kiva_font_type.cpp index 9b14cd78a..8fe29cd8a 100755 --- a/kiva/agg/src/kiva_font_type.cpp +++ b/kiva/agg/src/kiva_font_type.cpp @@ -39,9 +39,10 @@ const char* freetype_suffixes[] = { ".ttf", ".pfa", ".pfb" }; // Therefore this simple function is left in. kiva::font_type::font_type(std::string _name, int _size, int _family, - int _style, int _encoding, bool validate): + int _style, int _encoding, int _face_index, bool validate): name(_name), size(_size), family(_family), style(_style), - encoding(_encoding), _is_loaded(false) + encoding(_encoding), face_index(_face_index), + _is_loaded(false) { std::string full_file_name; if (validate) @@ -83,10 +84,9 @@ kiva::font_type::font_type(std::string _name, int _size, int _family, kiva::font_type::font_type(const kiva::font_type &font) : name(font.name), filename(font.filename), size(font.size), - _is_loaded(font.is_loaded()) + family(font.family), style(font.style), encoding(font.encoding), + face_index(font.face_index), _is_loaded(font.is_loaded()) { - this->family = font.family; - this->style = font.style; } kiva::font_type &kiva::font_type::operator=(const kiva::font_type& font) @@ -95,6 +95,7 @@ kiva::font_type &kiva::font_type::operator=(const kiva::font_type& font) this->family = font.family; this->style = font.style; this->encoding = font.encoding; + this->face_index = font.face_index; this->name = font.name; this->filename = font.filename; this->_is_loaded = font.is_loaded(); diff --git a/kiva/agg/src/kiva_font_type.h b/kiva/agg/src/kiva_font_type.h index 46910400f..7f3d2977d 100644 --- a/kiva/agg/src/kiva_font_type.h +++ b/kiva/agg/src/kiva_font_type.h @@ -28,6 +28,7 @@ namespace kiva int family; int style; int encoding; + int face_index; // Constructors @@ -39,6 +40,7 @@ namespace kiva int _family=0, int _style=0, int _encoding=0, + int _face_index=0, bool validate=true); font_type(const font_type &font); @@ -57,7 +59,7 @@ namespace kiva { return (a.size == b.size) && (a.name == b.name) && (a.style == b.style) && (a.encoding == b.encoding) && - (a.family == b.family); + (a.family == b.family) && (a.face_index == b.face_index); } diff --git a/kiva/agg/src/kiva_graphics_context_base.cpp b/kiva/agg/src/kiva_graphics_context_base.cpp index 20ff40eed..224000035 100755 --- a/kiva/agg/src/kiva_graphics_context_base.cpp +++ b/kiva/agg/src/kiva_graphics_context_base.cpp @@ -668,12 +668,12 @@ void graphics_context_base::_grab_font_manager() #ifdef KIVA_USE_FREETYPE if (font->filename != "") { - font_engine->load_font(font->filename.c_str(), 0, + font_engine->load_font(font->filename.c_str(), font->face_index, agg24::glyph_ren_agg_gray8); } else { - font_engine->load_font(font->name.c_str(), 0, + font_engine->load_font(font->name.c_str(), font->face_index, agg24::glyph_ren_agg_gray8); } #endif diff --git a/kiva/celiagg.py b/kiva/celiagg.py index bf1b2b76d..ba578db6d 100644 --- a/kiva/celiagg.py +++ b/kiva/celiagg.py @@ -15,9 +15,9 @@ import celiagg as agg import numpy as np -from .abstract_graphics_context import AbstractGraphicsContext -from .fonttools import Font +from kiva.abstract_graphics_context import AbstractGraphicsContext import kiva.constants as constants +from kiva.fonttools import Font # These are the symbols that a backend has to define. __all__ = ["CompiledPath", "Font", "font_metrics_provider", "GraphicsContext"] @@ -608,15 +608,16 @@ def normalize_image(img): # Drawing Text # ---------------------------------------------------------------- - def select_font(self, name, size, textEncoding): + def select_font(self, face_name, size=12, style='regular', encoding=None): """ Set the font for the current graphics context. """ - self.font = agg.Font(name, size) + self.set_font(Font(face_name, size=size, style=style)) def set_font(self, font): """ Set the font for the current graphics context. """ - self.select_font(font.findfont(), font.size, None) + filename, face_index = font.findfont() + self.font = agg.Font(filename, font.size, face_index) def set_font_size(self, size): """ Set the font size for the current graphics context. diff --git a/kiva/fonttools/font.py b/kiva/fonttools/font.py index ca46e0eab..cb40cfed7 100644 --- a/kiva/fonttools/font.py +++ b/kiva/fonttools/font.py @@ -112,11 +112,12 @@ def __init__(self, face_name="", size=12, family=SWISS, weight=NORMAL, self.encoding = encoding def findfont(self): - """ Returns the file name containing the font that most closely matches - our font properties. + """ Returns the file name and face index of the font that most closely + matches our font properties. """ fp = self._make_font_props() - return str(default_font_manager().findfont(fp)) + filename, face_index = default_font_manager().findfont(fp) + return str(filename), face_index def findfontname(self): """ Returns the name of the font that most closely matches our font @@ -181,7 +182,7 @@ def __ne__(self, other): def __repr__(self): fmt = ( "Font(size=%d,family=%d,weight=%d, style=%d, face_name='%s', " - + "encoding=%d)" + "encoding=%d)" ) return fmt % ( self.size, diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index e9e7248c9..0c67e396c 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -545,22 +545,25 @@ class FontEntry(object): """ def __init__(self, fname="", name="", style="normal", variant="normal", - weight="normal", stretch="normal", size="medium"): + weight="normal", stretch="normal", size="medium", + face_index=0): self.fname = fname self.name = name self.style = style self.variant = variant self.weight = weight self.stretch = stretch + self.face_index = face_index try: self.size = str(float(size)) except ValueError: self.size = size def __repr__(self): - return "" % ( + return "" % ( self.name, os.path.basename(self.fname), + self.face_index, self.style, self.variant, self.weight, @@ -568,7 +571,7 @@ def __repr__(self): ) -def ttfFontProperty(fpath, font): +def ttfFontProperty(fpath, font, index=0): """ A function for populating the :class:`FontKey` by extracting information from the TrueType font file. @@ -639,7 +642,7 @@ def ttfFontProperty(fpath, font): # !!!! Incomplete size = "scalable" - return FontEntry(fpath, name, style, variant, weight, stretch, size) + return FontEntry(fpath, name, style, variant, weight, stretch, size, index) def afmFontProperty(fontpath, font): @@ -758,8 +761,8 @@ def createFontList(fontfiles, fontext="ttf"): collection = TTCollection(f) try: props = [] - for font in collection.fonts: - props.append(ttfFontProperty(fpath, font)) + for idx, font in enumerate(collection.fonts): + props.append(ttfFontProperty(fpath, font, idx)) fontlist.extend(props) continue except Exception: @@ -878,12 +881,13 @@ def get_name(self): Return the name of the font that best matches the font properties. """ - filename = str(default_font_manager().findfont(self)) + filename, face_index = default_font_manager().findfont(self) + filename = str(filename) if filename.endswith(".afm"): return afm.AFM(open(filename)).get_familyname() - font = default_font_manager().findfont(self) - prop_dict = getPropDict(TTFont(str(font))) + font, face_index = default_font_manager().findfont(self) + prop_dict = getPropDict(TTFont(str(font), fontNumber=face_index)) return prop_dict["name"] def get_style(self): @@ -1091,7 +1095,7 @@ 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__ = 7 + __version__ = 8 def __init__(self, size=None, weight="normal"): self._version = self.__version__ @@ -1314,7 +1318,9 @@ def findfont(self, prop, fontext="ttf", directory=None, fname = prop.get_file() if fname is not None: logger.debug("findfont returning %s", fname) - return fname + # It's not at all clear where a `FontProperties` instance with + # `fname` already set would come from. Assume face_index == 0. + return (fname, 0) if fontext == "afm": font_cache = self.afm_lookup_cache @@ -1369,18 +1375,20 @@ def findfont(self, prop, fontext="ttf", directory=None, % (prop, self.defaultFont[fontext]), UserWarning, ) - result = self.defaultFont[fontext] + # Assume this is never a .ttc font, so 0 is ok for face index. + result = (self.defaultFont[fontext], 0) else: logger.debug( - "findfont: Matching %s to %s (%s) with score of %f", + "findfont: Matching %s to %s (%s[%d]) with score of %f", prop, best_font.name, best_font.fname, + best_font.face_index, best_score, ) - result = best_font.fname + result = (best_font.fname, best_font.face_index) - if not os.path.isfile(result): + if not os.path.isfile(result[0]): if rebuild_if_missing: logger.debug( "findfont: Found a missing font file. Rebuilding cache." diff --git a/kiva/fonttools/tests/test_font.py b/kiva/fonttools/tests/test_font.py index ae67bacac..6358ec0c3 100644 --- a/kiva/fonttools/tests/test_font.py +++ b/kiva/fonttools/tests/test_font.py @@ -30,8 +30,9 @@ def test_find_font_empty_name(self): # the path from which the font manager loads font files, then this test # can be less fragile. font = Font(face_name="") - font_file_path = font.findfont() + font_file_path, face_index = font.findfont() self.assertTrue(os.path.exists(font_file_path)) + self.assertEqual(face_index, 0) def test_find_font_some_face_name(self): font = Font(face_name="ProbablyNotFound") @@ -39,8 +40,9 @@ def test_find_font_some_face_name(self): # There will be warnings as there will be no match for the requested # face name. with self.assertWarns(UserWarning): - font_file_path = font.findfont() + font_file_path, face_index = font.findfont() self.assertTrue(os.path.exists(font_file_path)) + self.assertEqual(face_index, 0) def test_find_font_name(self): font = Font(face_name="ProbablyNotFound") From ab0756915499685867eb12707afbac00331a7e52 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Fri, 26 Feb 2021 14:57:19 +0100 Subject: [PATCH 2/6] Make findfont() return an object instead of a tuple --- kiva/agg/src/graphics_context.i | 6 +++--- kiva/celiagg.py | 4 ++-- kiva/fonttools/font.py | 3 +-- kiva/fonttools/font_manager.py | 33 +++++++++++++++++++++---------- kiva/fonttools/tests/test_font.py | 12 +++++------ 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/kiva/agg/src/graphics_context.i b/kiva/agg/src/graphics_context.i index 930c0018d..fe8d90534 100644 --- a/kiva/agg/src/graphics_context.i +++ b/kiva/agg/src/graphics_context.i @@ -560,10 +560,10 @@ namespace kiva { and (font.encoding == cur_font.encoding): return else: - newfilename, face_index = font.findfont() + spec = font.findfont() agg_font = AggFontType(font.face_name, font.size, font.family, font.style, - font.encoding, face_index, False) - agg_font.filename = newfilename + font.encoding, spec.face_index, False) + agg_font.filename = spec.filename else: # XXX: What are we expecting here? agg_font = AggFontType(font.face_name, font.size, font.family, font.style, font.encoding) diff --git a/kiva/celiagg.py b/kiva/celiagg.py index ba578db6d..3473f34f1 100644 --- a/kiva/celiagg.py +++ b/kiva/celiagg.py @@ -616,8 +616,8 @@ def select_font(self, face_name, size=12, style='regular', encoding=None): def set_font(self, font): """ Set the font for the current graphics context. """ - filename, face_index = font.findfont() - self.font = agg.Font(filename, font.size, face_index) + spec = font.findfont() + self.font = agg.Font(spec.filename, font.size, spec.face_index) def set_font_size(self, size): """ Set the font size for the current graphics context. diff --git a/kiva/fonttools/font.py b/kiva/fonttools/font.py index cb40cfed7..84ed98278 100644 --- a/kiva/fonttools/font.py +++ b/kiva/fonttools/font.py @@ -116,8 +116,7 @@ def findfont(self): matches our font properties. """ fp = self._make_font_props() - filename, face_index = default_font_manager().findfont(fp) - return str(filename), face_index + return default_font_manager().findfont(fp) def findfontname(self): """ Returns the name of the font that most closely matches our font diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 0c67e396c..9123f666f 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -881,13 +881,14 @@ def get_name(self): Return the name of the font that best matches the font properties. """ - filename, face_index = default_font_manager().findfont(self) - filename = str(filename) - if filename.endswith(".afm"): - return afm.AFM(open(filename)).get_familyname() + spec = default_font_manager().findfont(self) + if spec.filename.endswith(".afm"): + return afm.AFM(open(spec.filename)).get_familyname() - font, face_index = default_font_manager().findfont(self) - prop_dict = getPropDict(TTFont(str(font), fontNumber=face_index)) + spec = default_font_manager().findfont(self) + prop_dict = getPropDict( + TTFont(spec.filename), fontNumber=spec.face_index + ) return prop_dict["name"] def get_style(self): @@ -1313,6 +1314,18 @@ def findfont(self, prop, fontext="ttf", directory=None, `_ documentation for a description of the font finding algorithm. """ + class FontSpec(object): + """ An object to represent the return value of findfont(). + """ + def __init__(self, filename, face_index=0): + self.filename = str(filename) + self.face_index = face_index + + def __fspath__(self): + """ Implement the os.PathLike abstract interface. + """ + return self.filename + if not isinstance(prop, FontProperties): prop = FontProperties(prop) fname = prop.get_file() @@ -1320,7 +1333,7 @@ def findfont(self, prop, fontext="ttf", directory=None, logger.debug("findfont returning %s", fname) # It's not at all clear where a `FontProperties` instance with # `fname` already set would come from. Assume face_index == 0. - return (fname, 0) + return FontSpec(fname) if fontext == "afm": font_cache = self.afm_lookup_cache @@ -1376,7 +1389,7 @@ def findfont(self, prop, fontext="ttf", directory=None, UserWarning, ) # Assume this is never a .ttc font, so 0 is ok for face index. - result = (self.defaultFont[fontext], 0) + result = FontSpec(self.defaultFont[fontext]) else: logger.debug( "findfont: Matching %s to %s (%s[%d]) with score of %f", @@ -1386,9 +1399,9 @@ def findfont(self, prop, fontext="ttf", directory=None, best_font.face_index, best_score, ) - result = (best_font.fname, best_font.face_index) + result = FontSpec(best_font.fname, best_font.face_index) - if not os.path.isfile(result[0]): + if not os.path.isfile(result.filename): if rebuild_if_missing: logger.debug( "findfont: Found a missing font file. Rebuilding cache." diff --git a/kiva/fonttools/tests/test_font.py b/kiva/fonttools/tests/test_font.py index 6358ec0c3..c3ee9795d 100644 --- a/kiva/fonttools/tests/test_font.py +++ b/kiva/fonttools/tests/test_font.py @@ -30,9 +30,9 @@ def test_find_font_empty_name(self): # the path from which the font manager loads font files, then this test # can be less fragile. font = Font(face_name="") - font_file_path, face_index = font.findfont() - self.assertTrue(os.path.exists(font_file_path)) - self.assertEqual(face_index, 0) + spec = font.findfont() + self.assertTrue(os.path.exists(spec.filename)) + self.assertEqual(spec.face_index, 0) def test_find_font_some_face_name(self): font = Font(face_name="ProbablyNotFound") @@ -40,9 +40,9 @@ def test_find_font_some_face_name(self): # There will be warnings as there will be no match for the requested # face name. with self.assertWarns(UserWarning): - font_file_path, face_index = font.findfont() - self.assertTrue(os.path.exists(font_file_path)) - self.assertEqual(face_index, 0) + spec = font.findfont() + self.assertTrue(os.path.exists(spec.filename)) + self.assertEqual(spec.face_index, 0) def test_find_font_name(self): font = Font(face_name="ProbablyNotFound") From 3aee7edba5c49f94cdd1e38c7bcb0373d12859e6 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Fri, 26 Feb 2021 15:02:24 +0100 Subject: [PATCH 3/6] Fix a typo --- kiva/fonttools/font_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 9123f666f..23fe5d546 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -887,7 +887,7 @@ def get_name(self): spec = default_font_manager().findfont(self) prop_dict = getPropDict( - TTFont(spec.filename), fontNumber=spec.face_index + TTFont(spec.filename, fontNumber=spec.face_index) ) return prop_dict["name"] From 7d1a54243f6cae72de087b9c1871a742114c88d1 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Fri, 5 Mar 2021 15:34:41 +0100 Subject: [PATCH 4/6] Select fonts differently on Celiagg+Win32 --- kiva/celiagg.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kiva/celiagg.py b/kiva/celiagg.py index 9121b4fb3..d0cb0b3e7 100644 --- a/kiva/celiagg.py +++ b/kiva/celiagg.py @@ -10,6 +10,7 @@ from collections import namedtuple from math import fabs import os +import sys import warnings import celiagg as agg @@ -616,8 +617,13 @@ def select_font(self, face_name, size=12, style='regular', encoding=None): def set_font(self, font): """ Set the font for the current graphics context. """ - spec = font.findfont() - self.font = agg.Font(spec.filename, font.size, spec.face_index) + if sys.platform in ('win32', 'cygwin'): + # Win32 font selection is handled by the OS + self.font = agg.Font(font.findfontname(), font.size) + else: + # FreeType font selection is handled by kiva + spec = font.findfont() + self.font = agg.Font(spec.filename, font.size, spec.face_index) def set_font_size(self, size): """ Set the font size for the current graphics context. @@ -625,8 +631,8 @@ def set_font_size(self, size): if self.font is None: return - font = self.font - self.select_font(font.filepath, size) + # Just set a new height + self.font.height = size def set_character_spacing(self, spacing): msg = "set_character_spacing not implemented on celiagg yet." From 1edbaef0f8a075752bf0b199b5a911d7037f3671 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Fri, 5 Mar 2021 15:43:39 +0100 Subject: [PATCH 5/6] Add font face_index to the cache key --- .../font_freetype/agg_font_freetype.cpp | 22 ++++++++++++------- .../agg-24/font_freetype/agg_font_freetype.h | 4 ++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp b/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp index c2287997e..a284a5f44 100644 --- a/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp +++ b/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp @@ -490,6 +490,7 @@ namespace agg24 + static const unsigned _face_lookup_scratch_length = 1024; @@ -505,6 +506,7 @@ namespace agg24 delete [] m_face_names; delete [] m_faces; delete [] m_signature; + delete [] m_face_lookup_scratch_space; if(m_library_initialized) FT_Done_FreeType(m_library); } @@ -517,9 +519,9 @@ namespace agg24 m_last_error(0), m_name(0), m_name_len(256-16-1), - m_face_index(0), m_char_map(FT_ENCODING_NONE), m_signature(new char [256+256-16]), + m_face_lookup_scratch_space(new char [_face_lookup_scratch_length]), m_height(0), m_width(0), m_hinting(true), @@ -567,12 +569,17 @@ namespace agg24 //------------------------------------------------------------------------ - int font_engine_freetype_base::find_face(const char* face_name) const + int font_engine_freetype_base::find_face(const char* face_name, unsigned face_index) const { unsigned i; + + // Build the lookup string by combining the face_index and face_name + snprintf(m_face_lookup_scratch_space, _face_lookup_scratch_length, + "%04u%s", face_index, face_name); + for(i = 0; i < m_num_faces; ++i) { - if(strcmp(face_name, m_face_names[i]) == 0) return i; + if(strcmp(m_face_lookup_scratch_space, m_face_names[i]) == 0) return i; } return -1; } @@ -612,7 +619,7 @@ namespace agg24 { m_last_error = 0; - int idx = find_face(font_name); + int idx = find_face(font_name, face_index); if(idx >= 0) { m_cur_face = m_faces[idx]; @@ -651,8 +658,8 @@ namespace agg24 if(m_last_error == 0) { - m_face_names[m_num_faces] = new char [strlen(font_name) + 1]; - strcpy(m_face_names[m_num_faces], font_name); + m_face_names[m_num_faces] = new char [strlen(font_name) + 4 + 1]; + sprintf(m_face_names[m_num_faces], "%04u%s", face_index, font_name); m_cur_face = m_faces[m_num_faces]; m_name = m_face_names[m_num_faces]; ++m_num_faces; @@ -838,10 +845,9 @@ namespace agg24 } sprintf(m_signature, - "%s,%u,%d,%d,%d:%dx%d,%d,%d,%08X", + "%s,%u,%d,%d:%dx%d,%d,%d,%08X", m_name, m_char_map, - m_face_index, int(m_glyph_rendering), m_resolution, m_height, diff --git a/kiva/agg/agg-24/font_freetype/agg_font_freetype.h b/kiva/agg/agg-24/font_freetype/agg_font_freetype.h index 0f285f4a9..8ddff46ab 100644 --- a/kiva/agg/agg-24/font_freetype/agg_font_freetype.h +++ b/kiva/agg/agg-24/font_freetype/agg_font_freetype.h @@ -109,16 +109,16 @@ namespace agg24 void update_char_size(); void update_signature(); - int find_face(const char* face_name) const; + int find_face(const char* face_name, unsigned face_index) const; bool m_flag32; int m_change_stamp; int m_last_error; char* m_name; unsigned m_name_len; - unsigned m_face_index; FT_Encoding m_char_map; char* m_signature; + char* m_face_lookup_scratch_space; unsigned m_height; unsigned m_width; bool m_hinting; From 51a40a5efd7e75ea49835e15073649add4f141b0 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Mon, 8 Mar 2021 09:42:31 +0100 Subject: [PATCH 6/6] Don't use a fixed size for the font name lookup scratch space --- .../font_freetype/agg_font_freetype.cpp | 24 ++++++++++++------- .../agg-24/font_freetype/agg_font_freetype.h | 5 ++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp b/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp index a284a5f44..fa970d00d 100644 --- a/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp +++ b/kiva/agg/agg-24/font_freetype/agg_font_freetype.cpp @@ -490,7 +490,6 @@ namespace agg24 - static const unsigned _face_lookup_scratch_length = 1024; @@ -506,7 +505,7 @@ namespace agg24 delete [] m_face_names; delete [] m_faces; delete [] m_signature; - delete [] m_face_lookup_scratch_space; + delete [] m_face_lookup_scratch; if(m_library_initialized) FT_Done_FreeType(m_library); } @@ -521,7 +520,8 @@ namespace agg24 m_name_len(256-16-1), m_char_map(FT_ENCODING_NONE), m_signature(new char [256+256-16]), - m_face_lookup_scratch_space(new char [_face_lookup_scratch_length]), + m_face_lookup_scratch_len(512), + m_face_lookup_scratch(new char [m_face_lookup_scratch_len]), m_height(0), m_width(0), m_hinting(true), @@ -569,17 +569,24 @@ namespace agg24 //------------------------------------------------------------------------ - int font_engine_freetype_base::find_face(const char* face_name, unsigned face_index) const + int font_engine_freetype_base::find_face(const char* face_name, unsigned face_name_len, unsigned face_index) { unsigned i; + if ((face_name_len + 4 + 1) > m_face_lookup_scratch_len) + { + delete [] m_face_lookup_scratch; + m_face_lookup_scratch_len = face_name_len + 4 + 1; + m_face_lookup_scratch = new char [m_face_lookup_scratch_len]; + } + // Build the lookup string by combining the face_index and face_name - snprintf(m_face_lookup_scratch_space, _face_lookup_scratch_length, + snprintf(m_face_lookup_scratch, m_face_lookup_scratch_len, "%04u%s", face_index, face_name); for(i = 0; i < m_num_faces; ++i) { - if(strcmp(m_face_lookup_scratch_space, m_face_names[i]) == 0) return i; + if(strcmp(m_face_lookup_scratch, m_face_names[i]) == 0) return i; } return -1; } @@ -619,7 +626,8 @@ namespace agg24 { m_last_error = 0; - int idx = find_face(font_name, face_index); + unsigned font_name_len = strlen(font_name); + int idx = find_face(font_name, font_name_len, face_index); if(idx >= 0) { m_cur_face = m_faces[idx]; @@ -658,7 +666,7 @@ namespace agg24 if(m_last_error == 0) { - m_face_names[m_num_faces] = new char [strlen(font_name) + 4 + 1]; + m_face_names[m_num_faces] = new char [font_name_len + 4 + 1]; sprintf(m_face_names[m_num_faces], "%04u%s", face_index, font_name); m_cur_face = m_faces[m_num_faces]; m_name = m_face_names[m_num_faces]; diff --git a/kiva/agg/agg-24/font_freetype/agg_font_freetype.h b/kiva/agg/agg-24/font_freetype/agg_font_freetype.h index 8ddff46ab..863fc57c5 100644 --- a/kiva/agg/agg-24/font_freetype/agg_font_freetype.h +++ b/kiva/agg/agg-24/font_freetype/agg_font_freetype.h @@ -109,7 +109,7 @@ namespace agg24 void update_char_size(); void update_signature(); - int find_face(const char* face_name, unsigned face_index) const; + int find_face(const char* face_name, unsigned face_name_len, unsigned face_index); bool m_flag32; int m_change_stamp; @@ -118,7 +118,8 @@ namespace agg24 unsigned m_name_len; FT_Encoding m_char_map; char* m_signature; - char* m_face_lookup_scratch_space; + unsigned m_face_lookup_scratch_len; + char* m_face_lookup_scratch; unsigned m_height; unsigned m_width; bool m_hinting;