04-03-2017, 11:33 AM
I'd like to delineate a possible performance issue with Illustrator – and ways to greatly improve the speed with hdi_core – so other developers can benefit from this as well. We had some issues with our own plugins recently, which were resolved as explained below.
When using hdi::core::Illustrator::fontWithName() or hdi::core::FontPref, especially in the context of a long loop, performance can take a serious hit. Our plugins have some instances in which we must loop over thousands of art objects and inspect some stored font data, which ultimately comes down to many calls to hdi::core::Illustrator::fontWithName(). Illustrator itself provides no direct way to acquire a font by name, so we must loop over all the fonts in order to find it. Some users have thousands of fonts, which makes the problem even worse.
To remedy this situation, hdi_core has always had hdi::core::Illustrator::cacheFonts() and hdi::core::Illustrator::clearFontCache(). This allows one to create a cached font "context", where we build a map in memory of all fonts keyed by their names. This reduces the order of complexity from O(n) to O(log n). Before e.g. starting a long loop which will acquire fonts by name, first cache all the fonts. After the loop is over, clear the font cache.
It is not worthwhile to cache fonts before every call to hdi::core::Illustrator::fontWithName() because of the overhead of creating the font cache in the first place (we must loop over all fonts exactly once to build the map). However, one cannot simply cache all the fonts when their plugin loads and clear the cache when the plugin is unloaded, because technologies like Adobe TypeKit allow fonts to be added to/removed from Illustrator at runtime.
To hammer the point home, we utilized some code profiling on customers machines to determine that certain common operations were taking several seconds to complete (for customers where lots of art and lots of fonts were involved). After adding font caching to the proper spots, we reduced the timing to mere hundredths of a second.
When using hdi::core::Illustrator::fontWithName() or hdi::core::FontPref, especially in the context of a long loop, performance can take a serious hit. Our plugins have some instances in which we must loop over thousands of art objects and inspect some stored font data, which ultimately comes down to many calls to hdi::core::Illustrator::fontWithName(). Illustrator itself provides no direct way to acquire a font by name, so we must loop over all the fonts in order to find it. Some users have thousands of fonts, which makes the problem even worse.
To remedy this situation, hdi_core has always had hdi::core::Illustrator::cacheFonts() and hdi::core::Illustrator::clearFontCache(). This allows one to create a cached font "context", where we build a map in memory of all fonts keyed by their names. This reduces the order of complexity from O(n) to O(log n). Before e.g. starting a long loop which will acquire fonts by name, first cache all the fonts. After the loop is over, clear the font cache.
It is not worthwhile to cache fonts before every call to hdi::core::Illustrator::fontWithName() because of the overhead of creating the font cache in the first place (we must loop over all fonts exactly once to build the map). However, one cannot simply cache all the fonts when their plugin loads and clear the cache when the plugin is unloaded, because technologies like Adobe TypeKit allow fonts to be added to/removed from Illustrator at runtime.
To hammer the point home, we utilized some code profiling on customers machines to determine that certain common operations were taking several seconds to complete (for customers where lots of art and lots of fonts were involved). After adding font caching to the proper spots, we reduced the timing to mere hundredths of a second.