From 3b498efbd99b68bc46995c97dd34bcc3d0896a5f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 23 Mar 2012 15:07:28 -0700 Subject: [PATCH] fixup font registration code ensuring invalid fonts will warn but not throw and register_fonts will only return success if > one font is registered and none have failed --- Makefile | 3 ++ SConstruct | 2 +- src/font_engine_freetype.cpp | 60 +++++++++++---------- src/load_map.cpp | 8 ++- tests/cpp_tests/build.py | 2 + tests/cpp_tests/font_registration_test.cpp | 27 ++++++---- tests/data/fonts/fake.ttf | 0 tests/data/fonts/intentionally-broken.ttf | Bin 0 -> 49420 bytes tests/data/good_maps/rtl_text_map.xml | 4 +- 9 files changed, 65 insertions(+), 41 deletions(-) create mode 100644 tests/data/fonts/fake.ttf create mode 100644 tests/data/fonts/intentionally-broken.ttf diff --git a/Makefile b/Makefile index e8957a80d..33de62e87 100755 --- a/Makefile +++ b/Makefile @@ -27,4 +27,7 @@ pep8: @pep8 -r --select=W293 -q --filename=*.py `pwd`/tests/ | xargs gsed -i 's/^[ \r\t]*$//' @pep8 -r --select=W391 -q --filename=*.py `pwd`/tests/ | xargs gsed -i -e :a -e '/^\n*$/{$d;N;ba' -e '}' +grind: + @valgrind --leak-check=full tests/cpp_tests/font_registration_test + .PHONY: clean reset uninstall test install diff --git a/SConstruct b/SConstruct index 60352732c..c014b9bb5 100644 --- a/SConstruct +++ b/SConstruct @@ -1716,7 +1716,7 @@ if not HELP_REQUESTED: # build C++ tests # not ready for release - #SConscript('tests/cpp_tests/build.py') + SConscript('tests/cpp_tests/build.py') # not ready for release #if env['SVG_RENDERER']: diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 8e0746f29..cef4551d8 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -71,11 +71,10 @@ bool freetype_engine::is_font_file(std::string const& file_name) bool freetype_engine::register_font(std::string const& file_name) { - if (!boost::filesystem::is_regular_file(file_name) || !is_font_file(file_name)) return false; #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif - FT_Library library; + FT_Library library = 0; FT_Error error = FT_Init_FreeType(&library); if (error) { @@ -84,6 +83,7 @@ bool freetype_engine::register_font(std::string const& file_name) FT_Face face = 0; int num_faces = 0; + bool success = false; // some font files have multiple fonts in a file // the count is in the 'root' face library[0] // see the FT_FaceRec in freetype.h @@ -92,31 +92,37 @@ bool freetype_engine::register_font(std::string const& file_name) error = FT_New_Face (library,file_name.c_str(),i,&face); if (error) { - FT_Done_FreeType(library); - return false; + break; } // store num_faces locally, after FT_Done_Face it can not be accessed any more if (!num_faces) num_faces = face->num_faces; // some fonts can lack names, skip them // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec - if (face->family_name && face->style_name) { + if (face->family_name && face->style_name) + { + success = true; std::string name = std::string(face->family_name) + " " + std::string(face->style_name); name2file_.insert(std::make_pair(name, std::make_pair(i,file_name))); - FT_Done_Face(face); - //FT_Done_FreeType(library); - //return true; - } else { - FT_Done_Face(face); - FT_Done_FreeType(library); + } + else + { std::ostringstream s; - s << "Error: unable to load invalid font file which lacks identifiable family and style name: '" - << file_name << "'"; - throw std::runtime_error(s.str()); + s << "Warning: unable to load font file '" << file_name << "' "; + if (!face->family_name && !face->style_name) + s << "which lacks both a family name and style name"; + else if (face->family_name) + s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name"; + else if (face->style_name) + s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name"; + std::clog << s.str() << std::endl; } } - FT_Done_FreeType(library); - return true; + if (face) + FT_Done_Face(face); + if (library) + FT_Done_FreeType(library); + return success; } bool freetype_engine::register_fonts(std::string const& dir, bool recurse) @@ -130,26 +136,24 @@ bool freetype_engine::register_fonts(std::string const& dir, bool recurse) return mapnik::freetype_engine::register_font(dir); boost::filesystem::directory_iterator end_itr; + bool success = false; for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr) { +#if (BOOST_FILESYSTEM_VERSION == 3) + std::string const& file_name = itr->path().string(); +#else // v2 + std::string const& file_name = itr->string(); +#endif if (boost::filesystem::is_directory(*itr) && recurse) { -#if (BOOST_FILESYSTEM_VERSION == 3) - if (!register_fonts(itr->path().string(), true)) return false; -#else // v2 - if (!register_fonts(itr->string(), true)) return false; -#endif + success = register_fonts(file_name, true); } - else + else if (boost::filesystem::is_regular_file(file_name) && is_font_file(file_name)) { -#if (BOOST_FILESYSTEM_VERSION == 3) - mapnik::freetype_engine::register_font(itr->path().string()); -#else // v2 - mapnik::freetype_engine::register_font(itr->string()); -#endif + success = mapnik::freetype_engine::register_font(file_name); } } - return true; + return success; } diff --git a/src/load_map.cpp b/src/load_map.cpp index ee4313d91..2682015fd 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -242,7 +242,13 @@ void map_parser::parse_map(Map & map, xml_node const& pt, std::string const& bas if (font_directory) { extra_attr["font-directory"] = *font_directory; - freetype_engine::register_fonts(ensure_relative_to_xml(font_directory), false); + if (!freetype_engine::register_fonts(ensure_relative_to_xml(font_directory), false)) + { + if (strict_) + { + throw config_error(std::string("Failed to load fonts from: ") << *font_directory); + } + } } optional min_version_string = map_node.get_opt_attr("minimum-version"); diff --git a/tests/cpp_tests/build.py b/tests/cpp_tests/build.py index 11cd33f45..bcc31bc94 100644 --- a/tests/cpp_tests/build.py +++ b/tests/cpp_tests/build.py @@ -11,6 +11,8 @@ headers = env['CPPPATH'] libraries = copy(env['LIBMAPNIK_LIBS']) libraries.append('mapnik') +test_env.Append(CXXFLAGS='-g') + for cpp_test in glob.glob('*_test.cpp'): test_program = test_env.Program(cpp_test.replace('.cpp',''), [cpp_test], CPPPATH=headers, LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS']) Depends(test_program, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME'])) diff --git a/tests/cpp_tests/font_registration_test.cpp b/tests/cpp_tests/font_registration_test.cpp index 1906d896b..55715b9b1 100644 --- a/tests/cpp_tests/font_registration_test.cpp +++ b/tests/cpp_tests/font_registration_test.cpp @@ -6,8 +6,6 @@ using fs::path; namespace sys = boost::system; #include -//#include -//#include #include #include @@ -39,14 +37,23 @@ int main( int, char*[] ) // directories without fonts std::string src("src"); - // a legitimate directory will return true even it is does not - // successfully register a font... - BOOST_TEST( mapnik::freetype_engine::register_fonts(src , true ) ); - face_names = mapnik::freetype_engine::face_names(); - BOOST_TEST( face_names.size() == 0 ); - std::clog << "number of registered fonts: " << face_names.size() << std::endl; + // an empty directory will not return true + // we need to register at least one font and not fail on any + // to return true + BOOST_TEST( mapnik::freetype_engine::register_font(src) == false ); + BOOST_TEST( mapnik::freetype_engine::register_fonts(src, true) == false ); + BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); - // register unifont + // bogus, emtpy file that looks like font + BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/fake.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/fake.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); + + BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/intentionally-broken.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/intentionally-broken.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); + + // register unifont, since we know it sits in the root fonts/ dir BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir) ); face_names = mapnik::freetype_engine::face_names(); std::clog << "number of registered fonts: " << face_names.size() << std::endl; @@ -71,7 +78,7 @@ int main( int, char*[] ) BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, true) ); face_names = mapnik::freetype_engine::face_names(); std::clog << "number of registered fonts: " << face_names.size() << std::endl; - BOOST_TEST( face_names.size() == 21 ); + BOOST_TEST( face_names.size() == 22 ); return ::boost::report_errors(); } diff --git a/tests/data/fonts/fake.ttf b/tests/data/fonts/fake.ttf new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/fonts/intentionally-broken.ttf b/tests/data/fonts/intentionally-broken.ttf new file mode 100644 index 0000000000000000000000000000000000000000..887230d766e322b73024f482f859abecf6818fb2 GIT binary patch literal 49420 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 literal 0 HcmV?d00001 diff --git a/tests/data/good_maps/rtl_text_map.xml b/tests/data/good_maps/rtl_text_map.xml index 3892c69af..38f46aca1 100644 --- a/tests/data/good_maps/rtl_text_map.xml +++ b/tests/data/good_maps/rtl_text_map.xml @@ -1,5 +1,7 @@ - + + +