From a4770ac10b75ac716bef8dad7a15cede157237e0 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 2 Apr 2013 13:27:05 +0100 Subject: [PATCH 1/5] + cache fonts in memory --- include/mapnik/font_engine_freetype.hpp | 1 + src/font_engine_freetype.cpp | 43 +++++++++++++++++++------ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index 5667dce83..5d4736125 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -146,6 +146,7 @@ private: static boost::mutex mutex_; #endif static std::map > name2file_; + static std::map memory_fonts_; }; template diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 6a3080669..a1f92b782 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -114,11 +114,11 @@ bool freetype_engine::register_font(std::string const& file_name) if (face->family_name && face->style_name) { std::string name = std::string(face->family_name) + " " + std::string(face->style_name); - // skip fonts with leading . in name + // skip fonts with leading . in the name if (!boost::algorithm::starts_with(name,".")) { - success = true; name2file_.insert(std::make_pair(name, std::make_pair(i,file_name))); + success = true; } } else @@ -210,18 +210,41 @@ std::map > const& freetype_engine::get_ma face_ptr freetype_engine::create_face(std::string const& family_name) { - std::map >::iterator itr; + std::map >::const_iterator itr; itr = name2file_.find(family_name); if (itr != name2file_.end()) { FT_Face face; - FT_Error error = FT_New_Face (library_, - itr->second.second.c_str(), - itr->second.first, - &face); - if (!error) + + std::map::const_iterator mem_font_itr = memory_fonts_.find(itr->second.second); + + if (mem_font_itr != memory_fonts_.end()) // memory font { - return boost::make_shared(face); + FT_Error error = FT_New_Memory_Face(library_, + (FT_Byte const*) mem_font_itr->second.c_str(), //buffer + mem_font_itr->second.size(), // size + itr->second.first, // face index + &face); + + if (!error) return boost::make_shared(face); + } + else + { + // load font into memory + std::ifstream is(itr->second.second.c_str() , std::ios::binary); + std::string buffer((std::istreambuf_iterator(is)), + std::istreambuf_iterator()); + + FT_Error error = FT_New_Memory_Face (library_, + (FT_Byte const*) buffer.c_str(), + buffer.size(), + itr->second.first, + &face); + if (!error) + { + memory_fonts_.insert(std::make_pair(itr->second.second, buffer)); + return boost::make_shared(face); + } } } return face_ptr(); @@ -659,6 +682,8 @@ void text_renderer::render_id(mapnik::value_integer feature_id, boost::mutex freetype_engine::mutex_; #endif std::map > freetype_engine::name2file_; +std::map freetype_engine::memory_fonts_; + template text_renderer::text_renderer(image_32&, face_manager&, halo_rasterizer_e, From 5703821b00f8a948a5f04f40d63fcc91da51d606 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 3 Apr 2013 13:52:54 +0100 Subject: [PATCH 2/5] + add benchmark for loading font faces. --- benchmark/run.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/benchmark/run.cpp b/benchmark/run.cpp index 8964ccdc5..e6069f650 100644 --- a/benchmark/run.cpp +++ b/benchmark/run.cpp @@ -708,6 +708,41 @@ struct test12 } }; +#include + +struct test13 +{ + unsigned iter_; + unsigned threads_; + + test13(unsigned iterations, + unsigned threads) + : iter_(iterations), + threads_(threads) + { + mapnik::freetype_engine::register_fonts("./fonts", true); + } + + bool validate() + { + return true; + } + + void operator()() + { + mapnik::freetype_engine engine; + unsigned long count = 0; + for (unsigned i=0;i 0) { @@ -864,6 +899,10 @@ int main( int argc, char** argv) benchmark(runner,"clipping polygon with mapnik::polygon_clipper"); } + { + test13 runner(1000,10); + benchmark(runner,"create font faces"); + } std::cout << "...benchmark done\n"; return 0; } From b65c19aa51615839a0da75ce2238d4d2b0fc3e87 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 3 Apr 2013 14:17:18 +0100 Subject: [PATCH 3/5] + better message --- benchmark/run.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/benchmark/run.cpp b/benchmark/run.cpp index e6069f650..c20c153d3 100644 --- a/benchmark/run.cpp +++ b/benchmark/run.cpp @@ -709,7 +709,7 @@ struct test12 }; #include - +#include struct test13 { unsigned iter_; @@ -719,9 +719,7 @@ struct test13 unsigned threads) : iter_(iterations), threads_(threads) - { - mapnik::freetype_engine::register_fonts("./fonts", true); - } + {} bool validate() { @@ -900,8 +898,10 @@ int main( int argc, char** argv) } { + mapnik::freetype_engine::register_fonts("./fonts", true); + unsigned face_count = mapnik::freetype_engine::face_names().size(); test13 runner(1000,10); - benchmark(runner,"create font faces"); + benchmark(runner, (boost::format("font_engihe: created %ld faces in ") % (face_count * 1000 * 10)).str()); } std::cout << "...benchmark done\n"; return 0; From 3959f8d2bc00d7b90c9b257f280e76ce7d75b4ed Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 5 Apr 2013 22:51:53 -0700 Subject: [PATCH 4/5] python tests: print exception if nose is unavailable --- tests/run_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run_tests.py b/tests/run_tests.py index 128ded2fa..5d89dd9f3 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -4,8 +4,8 @@ import sys try: import nose -except ImportError: - sys.stderr.write("Unable to run python tests: the third party 'nose' module is required\nTo install 'nose' do:\n\tsudo pip install nose (or on debian systems: apt-get install python-nose\n") +except ImportError, e: + sys.stderr.write("Unable to run python tests: the third party 'nose' module is required\nTo install 'nose' do:\n\tsudo pip install nose (or on debian systems: apt-get install python-nose): %s\n" % e) sys.exit(1) from python_tests.utilities import TodoPlugin From 8814994dc444832258ddecf7c86cbcc00b24c2ab Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Sun, 7 Apr 2013 23:43:34 -0700 Subject: [PATCH 5/5] add test using invalid png which leaks fd when it throws - refs #1783 --- tests/cpp_tests/image_io_test.cpp | 41 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp index f42718d85..ea51b1d70 100644 --- a/tests/cpp_tests/image_io_test.cpp +++ b/tests/cpp_tests/image_io_test.cpp @@ -12,17 +12,17 @@ namespace sys = boost::system; int main( int, char*[] ) { - std::string blank; + std::string should_throw; boost::optional type; try { - blank = "./tests/cpp_tests/data/blank.jpg"; - BOOST_TEST( fs::exists( blank ) ); - type = mapnik::type_from_filename(blank); + should_throw = "./tests/cpp_tests/data/blank.jpg"; + BOOST_TEST( fs::exists( should_throw ) ); + type = mapnik::type_from_filename(should_throw); BOOST_TEST( type ); try { - std::auto_ptr reader(mapnik::get_image_reader(blank,*type)); + std::auto_ptr reader(mapnik::get_image_reader(should_throw,*type)); BOOST_TEST( false ); } catch (std::exception const&) @@ -30,13 +30,13 @@ int main( int, char*[] ) BOOST_TEST( true ); } - blank = "./tests/cpp_tests/data/blank.png"; - BOOST_TEST( fs::exists( blank ) ); - type = mapnik::type_from_filename(blank); + should_throw = "./tests/cpp_tests/data/blank.png"; + BOOST_TEST( fs::exists( should_throw ) ); + type = mapnik::type_from_filename(should_throw); BOOST_TEST( type ); try { - std::auto_ptr reader(mapnik::get_image_reader(blank,*type)); + std::auto_ptr reader(mapnik::get_image_reader(should_throw,*type)); BOOST_TEST( false ); } catch (std::exception const&) @@ -44,19 +44,34 @@ int main( int, char*[] ) BOOST_TEST( true ); } - blank = "./tests/cpp_tests/data/blank.tiff"; - BOOST_TEST( fs::exists( blank ) ); - type = mapnik::type_from_filename(blank); + should_throw = "./tests/cpp_tests/data/blank.tiff"; + BOOST_TEST( fs::exists( should_throw ) ); + type = mapnik::type_from_filename(should_throw); BOOST_TEST( type ); try { - std::auto_ptr reader(mapnik::get_image_reader(blank,*type)); + std::auto_ptr reader(mapnik::get_image_reader(should_throw,*type)); BOOST_TEST( false ); } catch (std::exception const&) { BOOST_TEST( true ); } + + should_throw = "./tests/data/images/xcode-CgBI.png"; + BOOST_TEST( fs::exists( should_throw ) ); + type = mapnik::type_from_filename(should_throw); + BOOST_TEST( type ); + try + { + std::auto_ptr reader(mapnik::get_image_reader(should_throw,*type)); + BOOST_TEST( false ); + } + catch (std::exception const&) + { + BOOST_TEST( true ); + } + } catch (std::exception const & ex) {