fast, non-caching check if a font can be opened and read

This commit is contained in:
Dane Springmeyer 2014-10-01 20:32:03 -07:00
commit 687a33575c
3 changed files with 60 additions and 8 deletions

View file

@ -71,7 +71,11 @@ public:
static std::vector<std::string> face_names();
static font_file_mapping_type const& get_mapping();
static font_memory_cache_type & get_cache();
static face_ptr create_face(std::string const& family_name,
static bool can_open(std::string const& face_name,
font_library & library,
font_file_mapping_type const& font_file_mapping,
font_file_mapping_type const& global_font_file_mapping);
static face_ptr create_face(std::string const& face_name,
font_library & library,
font_file_mapping_type const& font_file_mapping,
freetype_engine::font_memory_cache_type const& font_cache,

View file

@ -259,6 +259,48 @@ freetype_engine::font_memory_cache_type & freetype_engine::get_cache()
return global_memory_fonts_;
}
bool freetype_engine::can_open(std::string const& face_name,
font_library & library,
font_file_mapping_type const& font_file_mapping,
font_file_mapping_type const& global_font_file_mapping)
{
bool found_font_file = false;
font_file_mapping_type::const_iterator itr = font_file_mapping.find(face_name);
if (itr != font_file_mapping.end())
{
found_font_file = true;
}
else
{
itr = global_font_file_mapping.find(face_name);
if (itr != global_font_file_mapping.end())
{
found_font_file = true;
}
}
if (!found_font_file) return false;
mapnik::util::file file(itr->second.second);
if (!file.open()) return false;
FT_Face face = 0;
FT_Open_Args args;
FT_StreamRec streamRec;
memset(&args, 0, sizeof(args));
memset(&streamRec, 0, sizeof(streamRec));
streamRec.base = 0;
streamRec.pos = 0;
streamRec.size = file.size();
streamRec.descriptor.pointer = file.get();
streamRec.read = ft_read_cb;
streamRec.close = NULL;
args.flags = FT_OPEN_STREAM;
args.stream = &streamRec;
// -1 is used to quickly check if the font file appears valid without iterating each face
FT_Error error = FT_Open_Face(library.get(), &args, -1, &face);
if (face) FT_Done_Face(face);
if (error) return false;
return true;
}
face_ptr freetype_engine::create_face(std::string const& family_name,
font_library & library,
freetype_engine::font_file_mapping_type const& font_file_mapping,

View file

@ -88,9 +88,8 @@ public:
strict_(strict),
filename_(filename),
font_library_(),
font_manager_(font_library_,map.get_font_file_mapping(),map.get_font_memory_cache()),
xml_base_path_()
{}
font_file_mapping_(map.get_font_file_mapping()),
xml_base_path_() {}
void parse_map(Map & map, xml_node const& node, std::string const& base_path);
private:
@ -131,7 +130,7 @@ private:
std::string filename_;
std::map<std::string,parameters> datasource_templates_;
font_library font_library_;
face_manager_freetype font_manager_;
freetype_engine::font_file_mapping_type & font_file_mapping_;
std::map<std::string,std::string> file_sources_;
std::map<std::string,font_set> fontsets_;
std::string xml_base_path_;
@ -518,8 +517,11 @@ bool map_parser::parse_font(font_set &fset, xml_node const& f)
optional<std::string> face_name = f.get_opt_attr<std::string>("face-name");
if (face_name)
{
face_ptr face = font_manager_.get_face(*face_name);
if (face)
// TODO - cache results to avoid repeated opens
if (freetype_engine::can_open(*face_name,
font_library_,
font_file_mapping_,
freetype_engine::get_mapping()))
{
fset.add_face_name(*face_name);
return true;
@ -1521,7 +1523,11 @@ void map_parser::parse_pair_layout(group_symbolizer_properties & prop, xml_node
void map_parser::ensure_font_face(std::string const& face_name)
{
if (! font_manager_.get_face(face_name))
// TODO - cache results to avoid repeated opens
if (!freetype_engine::can_open(face_name,
font_library_,
font_file_mapping_,
freetype_engine::get_mapping()))
{
throw config_error("Failed to find font face '" +
face_name + "'");