diff --git a/benchmark/test_face_ptr_creation.cpp b/benchmark/test_face_ptr_creation.cpp index b546c32c8..ff1b6f2ad 100644 --- a/benchmark/test_face_ptr_creation.cpp +++ b/benchmark/test_face_ptr_creation.cpp @@ -12,23 +12,27 @@ public: std::size_t count = 0; std::size_t expected_count = mapnik::freetype_engine::face_names().size(); mapnik::freetype_engine engine; + mapnik::freetype_engine::font_file_mapping_type font_file_mapping; + mapnik::freetype_engine::font_memory_cache_type font_cache; for (std::string const& name : mapnik::freetype_engine::face_names()) { - mapnik::face_ptr f = engine.create_face(name); + mapnik::face_ptr f = engine.create_face(name,font_file_mapping,font_cache); if (f) ++count; } return count == expected_count; } void operator()() const { - mapnik::freetype_engine engine; std::size_t expected_count = mapnik::freetype_engine::face_names().size(); for (unsigned i=0;i & font_manager, + face_manager_freetype & font_manager, composite_mode_e comp_op = src_over, composite_mode_e halo_comp_op = src_over, double scale_factor = 1.0); diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index 1bae33087..095ad7cad 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -27,6 +27,7 @@ #include #include #include +#include // stl #include @@ -38,8 +39,6 @@ #include #endif -struct FT_LibraryRec_; -struct FT_MemoryRec_; namespace boost { template class optional; } namespace mapnik @@ -52,10 +51,11 @@ using face_set_ptr = std::shared_ptr; class font_face; using face_ptr = std::shared_ptr; - class MAPNIK_DECL freetype_engine { public: + using font_file_mapping_type = std::map>; + using font_memory_cache_type = std::map, std::size_t>>; static bool is_font_file(std::string const& file_name); /*! \brief register a font file * @param file_name path to a font file. @@ -69,50 +69,64 @@ public: */ static bool register_fonts(std::string const& dir, bool recurse = false); static std::vector face_names(); - static std::map > const& get_mapping(); - face_ptr create_face(std::string const& family_name); + static font_file_mapping_type const& get_mapping(); + static face_ptr create_face(std::string const& family_name, + util::font_library & library, + font_file_mapping_type const& font_file_mapping, + freetype_engine::font_memory_cache_type const& font_cache); stroker_ptr create_stroker(); virtual ~freetype_engine(); freetype_engine(); + static bool register_font_impl(std::string const& file_name, + util::font_library & libary, + font_file_mapping_type & font_file_mapping); + static bool register_fonts_impl(std::string const& dir, + util::font_library & libary, + font_file_mapping_type & font_file_mapping, + bool recurse = false); + util::font_library & get_library() + { + return library_; + } private: - static bool register_font_impl(std::string const& file_name, FT_LibraryRec_ * library); - static bool register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse = false); - FT_LibraryRec_ * library_; - std::unique_ptr memory_; + util::font_library library_; #ifdef MAPNIK_THREADSAFE static std::mutex mutex_; #endif - static std::map > name2file_; - static std::map, std::size_t> > memory_fonts_; + static font_file_mapping_type global_font_file_mapping_; + static font_memory_cache_type global_memory_fonts_; }; -template class MAPNIK_DECL face_manager : private mapnik::noncopyable { - using font_engine_type = T; using face_ptr_cache_type = std::map; public: - face_manager(T & engine) + face_manager(freetype_engine & engine, + freetype_engine::font_file_mapping_type const& font_file_mapping, + freetype_engine::font_memory_cache_type const& font_cache) : engine_(engine), - stroker_(engine_.create_stroker()), - face_ptr_cache_() {} + stroker_(engine_.create_stroker()), + face_ptr_cache_(), + library_(engine_.get_library()), + font_file_mapping_(font_file_mapping), + font_memory_cache_(font_cache) {} face_ptr get_face(std::string const& name); face_set_ptr get_face_set(std::string const& name); face_set_ptr get_face_set(font_set const& fset); face_set_ptr get_face_set(std::string const& name, boost::optional fset); - - inline stroker_ptr get_stroker() { return stroker_; } - private: - font_engine_type & engine_; + freetype_engine & engine_; stroker_ptr stroker_; face_ptr_cache_type face_ptr_cache_; + util::font_library & library_; + freetype_engine::font_file_mapping_type const& font_file_mapping_; + freetype_engine::font_memory_cache_type const& font_memory_cache_; }; -using face_manager_freetype = face_manager; +using face_manager_freetype = face_manager; } diff --git a/include/mapnik/map.hpp b/include/mapnik/map.hpp index da2ac10ce..2ada24f7d 100644 --- a/include/mapnik/map.hpp +++ b/include/mapnik/map.hpp @@ -32,6 +32,7 @@ #include #include #include +#include // boost #include @@ -97,6 +98,9 @@ private: boost::optional > maximum_extent_; std::string base_path_; parameters extra_params_; + boost::optional font_directory_; + freetype_engine::font_file_mapping_type font_file_mapping_; + freetype_engine::font_memory_cache_type font_memory_cache_; public: @@ -209,6 +213,14 @@ public: */ std::map & fontsets(); + /*! \brief register fonts. + */ + bool register_fonts(std::string const& dir, bool recurse); + + /*! \brief cache registered fonts. + */ + bool load_fonts(); + /*! \brief Get number of all layers. */ size_t layer_count() const; @@ -437,6 +449,36 @@ public: */ void set_extra_parameters(parameters& params); + boost::optional const& font_directory() const + { + return font_directory_; + } + + void set_font_directory(std::string const& dir) + { + font_directory_ = dir; + } + + freetype_engine::font_file_mapping_type const& get_font_file_mapping() const + { + return font_file_mapping_; + } + + freetype_engine::font_file_mapping_type & get_font_file_mapping() + { + return font_file_mapping_; + } + + freetype_engine::font_memory_cache_type const& get_font_memory_cache() const + { + return font_memory_cache_; + } + + freetype_engine::font_memory_cache_type & get_font_memory_cache() + { + return font_memory_cache_; + } + private: friend void swap(Map & rhs, Map & lhs); void fixAspectRatio(); diff --git a/include/mapnik/renderer_common.hpp b/include/mapnik/renderer_common.hpp index fc10cdcfc..c080b768c 100644 --- a/include/mapnik/renderer_common.hpp +++ b/include/mapnik/renderer_common.hpp @@ -56,8 +56,8 @@ struct renderer_common : private mapnik::noncopyable attributes vars_; // TODO: dirty hack for cairo renderer, figure out how to remove this std::shared_ptr shared_font_engine_; - freetype_engine &font_engine_; - face_manager font_manager_; + freetype_engine & font_engine_; + face_manager_freetype font_manager_; box2d query_extent_; view_transform t_; std::shared_ptr detector_; diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index 4dee1b33d..8dd044b4c 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -71,7 +71,7 @@ struct virtual_renderer_common : private mapnik::noncopyable // TODO: dirty hack for cairo renderer, figure out how to remove this std::shared_ptr & shared_font_engine_; freetype_engine & font_engine_; - face_manager & font_manager_; + face_manager_freetype & font_manager_; box2d & query_extent_; view_transform & t_; std::shared_ptr detector_; diff --git a/include/mapnik/text/text_layout.hpp b/include/mapnik/text/text_layout.hpp index eb59838ff..511d62c5e 100644 --- a/include/mapnik/text/text_layout.hpp +++ b/include/mapnik/text/text_layout.hpp @@ -97,7 +97,7 @@ public: void add_child(text_layout_ptr const& child_layout); inline text_layout_vector const& get_child_layouts() const { return child_layout_list_; } - inline face_manager & get_font_manager() const { return font_manager_; } + inline face_manager_freetype & get_font_manager() const { return font_manager_; } inline double get_scale_factor() const { return scale_factor_; } inline text_layout_properties const& get_layout_properties() const { return properties_; } diff --git a/include/mapnik/util/file_io.hpp b/include/mapnik/util/file_io.hpp new file mode 100644 index 000000000..940112863 --- /dev/null +++ b/include/mapnik/util/file_io.hpp @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_FILE_IO_HPP +#define MAPNIK_FILE_IO_HPP + +// mapnik +#include +#include +#include +//#include + +// stl +#include +#include +#include + +namespace mapnik { namespace util { + +class file : public noncopyable +{ +public: + using file_ptr = std::unique_ptr; + + explicit file(std::string const& filename) +#ifdef _WINDOWS + : file_(_wfopen(mapnik::utf8_to_utf16(filename).c_str(), L"rb"), std::fclose), +#else + : file_(std::fopen(filename.c_str(),"rb"), std::fclose), +#endif + size_(0) + + { + if (file_) + { + std::fseek(file_.get(), 0, SEEK_END); + size_ = std::ftell(file_.get()); + } + } + + inline bool open() const + { + return file_ ? true : false; + } + + inline std::FILE * get() const + { + return file_.get();; + } + + inline std::size_t size() const + { + return size_; + } + + inline std::unique_ptr data() const + { + if (!size_) return nullptr; + std::fseek(file_.get(), 0, SEEK_SET); + std::unique_ptr buffer(new char[size_]); + std::fread(buffer.get(), size_, 1, file_.get()); + return std::move(buffer); + } +private: + file_ptr file_; + std::size_t size_; +}; + +}} + + +#endif // FILE_IO diff --git a/include/mapnik/util/font_library.hpp b/include/mapnik/util/font_library.hpp new file mode 100644 index 000000000..d0921c5cd --- /dev/null +++ b/include/mapnik/util/font_library.hpp @@ -0,0 +1,59 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_FONT_LIBRARY_HPP +#define MAPNIK_FONT_LIBRARY_HPP + +// mapnik +#include +#include + +// stl +#include + +struct FT_LibraryRec_; +struct FT_MemoryRec_; + +namespace mapnik { + +class font_face; +using face_ptr = std::shared_ptr; + +namespace util { + +class MAPNIK_DECL font_library : public noncopyable +{ +public: + explicit font_library(); + ~font_library(); + FT_LibraryRec_ * get(); + face_ptr face_from_memory(const char * buffer, + std::size_t size, + int index); +private: + FT_LibraryRec_ * library_; + std::unique_ptr memory_; +}; + +}} + +#endif // MAPNIK_FONT_LIBRARY_HPP diff --git a/src/build.py b/src/build.py index 7854f6022..e1cfe37da 100644 --- a/src/build.py +++ b/src/build.py @@ -142,6 +142,7 @@ else: # unix, non-macos source = Split( """ + font_library.cpp expression_grammar.cpp fs.cpp request.cpp diff --git a/src/cairo/cairo_context.cpp b/src/cairo/cairo_context.cpp index 1c59a8303..681e74358 100644 --- a/src/cairo/cairo_context.cpp +++ b/src/cairo/cairo_context.cpp @@ -432,7 +432,7 @@ void cairo_context::glyph_path(unsigned long index, pixel_position const &pos) void cairo_context::add_text(glyph_positions_ptr path, cairo_face_manager & manager, - face_manager & font_manager, + face_manager_freetype & font_manager, composite_mode_e comp_op, composite_mode_e halo_comp_op, double scale_factor) diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 4fc64c6b4..11f0d90f1 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include // boost @@ -36,7 +37,6 @@ // stl #include #include -#include // freetype2 extern "C" @@ -47,45 +47,14 @@ extern "C" #include FT_MODULE_H } -void* _Alloc_Func(FT_Memory memory, long size) -{ - return std::malloc(size); -} - -void _Free_Func(FT_Memory memory, void *block) -{ - std::free(block); -} - -void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block) -{ - return std::realloc(block, new_size); -} namespace mapnik { -void init_freetype(FT_Memory memory, FT_Library & library) -{ - memory->alloc = _Alloc_Func; - memory->free = _Free_Func; - memory->realloc = _Realloc_Func; - FT_Error error = FT_New_Library(memory, &library ); - if (error) throw std::runtime_error("can not initalise FreeType2 library"); - FT_Add_Default_Modules(library); -} - freetype_engine::freetype_engine() - : library_(nullptr), - memory_(new FT_MemoryRec_) -{ - init_freetype(&*memory_, library_); -} + : library_() {} -freetype_engine::~freetype_engine() -{ - FT_Done_Library(library_); -} +freetype_engine::~freetype_engine() {} bool freetype_engine::is_font_file(std::string const& file_name) { @@ -116,37 +85,27 @@ bool freetype_engine::register_font(std::string const& file_name) #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - - FT_Library library = 0; - std::unique_ptr memory(new FT_MemoryRec_); - init_freetype(&*memory, library); - bool result = register_font_impl(file_name, library); - FT_Done_Library(library); - return result; + util::font_library library; + return register_font_impl(file_name, library, global_font_file_mapping_); } -bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library) +bool freetype_engine::register_font_impl(std::string const& file_name, + util::font_library & library, + freetype_engine::font_file_mapping_type & font_file_mapping) { MAPNIK_LOG_DEBUG(font_engine_freetype) << "registering: " << file_name; -#ifdef _WINDOWS - FILE * file = _wfopen(mapnik::utf8_to_utf16(file_name).c_str(), L"rb"); -#else - FILE * file = std::fopen(file_name.c_str(),"rb"); -#endif - if (file == nullptr) return false; + mapnik::util::file file(file_name); + 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)); - fseek(file, 0, SEEK_END); - std::size_t file_size = std::ftell(file); - fseek(file, 0, SEEK_SET); streamRec.base = 0; streamRec.pos = 0; - streamRec.size = file_size; - streamRec.descriptor.pointer = file; + streamRec.size = file.size(); + streamRec.descriptor.pointer = file.get(); streamRec.read = ft_read_cb; streamRec.close = NULL; args.flags = FT_OPEN_STREAM; @@ -159,7 +118,7 @@ bool freetype_engine::register_font_impl(std::string const& file_name, FT_Librar for ( int i = 0; face == 0 || i < num_faces; ++i ) { // if face is null then this is the first face - FT_Error error = FT_Open_Face(library, &args, i, &face); + FT_Error error = FT_Open_Face(library.get(), &args, i, &face); if (error) break; // store num_faces locally, after FT_Done_Face it can not be accessed any more if (num_faces == 0) @@ -173,10 +132,10 @@ bool freetype_engine::register_font_impl(std::string const& file_name, FT_Librar if (!boost::algorithm::starts_with(name,".")) { // http://stackoverflow.com/a/24795559/2333354 - auto range = name2file_.equal_range(name); + auto range = font_file_mapping.equal_range(name); if (range.first == range.second) // the key was previously absent; insert a pair { - name2file_.emplace_hint(range.first,name,std::move(std::make_pair(i,file_name))); + font_file_mapping.emplace_hint(range.first,name,std::move(std::make_pair(i,file_name))); } else // the key was present, replace the associated value { /* some action with value range.first->second about to be overwritten here */ @@ -200,7 +159,6 @@ bool freetype_engine::register_font_impl(std::string const& file_name, FT_Librar } if (face) FT_Done_Face(face); } - std::fclose(file); return success; } @@ -209,15 +167,14 @@ bool freetype_engine::register_fonts(std::string const& dir, bool recurse) #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - std::unique_ptr memory(new FT_MemoryRec_); - FT_Library library = 0; - init_freetype(&*memory, library); - bool result = register_fonts_impl(dir, library, recurse); - FT_Done_Library(library); - return result; + util::font_library library; + return register_fonts_impl(dir, library, global_font_file_mapping_, recurse); } -bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse) +bool freetype_engine::register_fonts_impl(std::string const& dir, + util::font_library & library, + freetype_engine::font_file_mapping_type & font_file_mapping, + bool recurse) { if (!mapnik::util::exists(dir)) { @@ -225,7 +182,7 @@ bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ } if (!mapnik::util::is_directory(dir)) { - return mapnik::freetype_engine::register_font_impl(dir, library); + return register_font_impl(dir, library, font_file_mapping); } bool success = false; try @@ -251,7 +208,7 @@ bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ #endif if (boost::filesystem::is_directory(*itr) && recurse) { - if (register_fonts_impl(file_name, library, true)) + if (register_fonts_impl(file_name, library, font_file_mapping, true)) { success = true; } @@ -267,7 +224,7 @@ bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ mapnik::util::is_regular_file(file_name) && is_font_file(file_name)) { - if (mapnik::freetype_engine::register_font_impl(file_name, library)) + if (register_font_impl(file_name, library, font_file_mapping)) { success = true; } @@ -286,37 +243,58 @@ bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ std::vector freetype_engine::face_names () { std::vector names; - for (auto const& kv : name2file_) + for (auto const& kv : global_font_file_mapping_) { names.push_back(kv.first); } return names; } -std::map > const& freetype_engine::get_mapping() +freetype_engine::font_file_mapping_type const& freetype_engine::get_mapping() { - return name2file_; + return global_font_file_mapping_; } -face_ptr freetype_engine::create_face(std::string const& family_name) +face_ptr freetype_engine::create_face(std::string const& family_name, + util::font_library & library, + freetype_engine::font_file_mapping_type const& font_file_mapping, + freetype_engine::font_memory_cache_type const& font_cache) { - auto itr = name2file_.find(family_name); - if (itr != name2file_.end()) + bool found_font_file = false; + font_file_mapping_type::const_iterator itr = font_file_mapping.find(family_name); + if (itr != font_file_mapping.end()) { - FT_Face face; - - auto mem_font_itr = memory_fonts_.find(itr->second.second); - - if (mem_font_itr != memory_fonts_.end()) // memory font + found_font_file = true; + auto mem_font_itr = font_cache.find(itr->second.second); + if (mem_font_itr != font_cache.end()) // memory font { - FT_Error error = FT_New_Memory_Face(library_, - reinterpret_cast(mem_font_itr->second.first.get()), // data - static_cast(mem_font_itr->second.second), // size - itr->second.first, // face index - &face); - - if (!error) return std::make_shared(face); + face_ptr face = library.face_from_memory(mem_font_itr->second.first.get(), + mem_font_itr->second.second, + itr->second.first); + if (face) + { + return face; + } + } + } + else + { + itr = global_font_file_mapping_.find(family_name); + if (itr != global_font_file_mapping_.end()) + { + found_font_file = true; + } + } + if (found_font_file) + { + auto mem_font_itr = global_memory_fonts_.find(itr->second.second); + if (mem_font_itr != global_memory_fonts_.end()) // memory font + { + face_ptr face = library.face_from_memory(mem_font_itr->second.first.get(), + mem_font_itr->second.second, + itr->second.first); + if (face) return face; } else { @@ -325,41 +303,29 @@ face_ptr freetype_engine::create_face(std::string const& family_name) mapnik::scoped_lock lock(mutex_); #endif -#ifdef _WINDOWS - std::unique_ptr file(_wfopen(mapnik::utf8_to_utf16(itr->second.second).c_str(), L"rb"), fclose); -#else - std::unique_ptr file(std::fopen(itr->second.second.c_str(),"rb"), std::fclose); -#endif - if (file != nullptr) + mapnik::util::file file(itr->second.second); + if (file.open()) { - std::fseek(file.get(), 0, SEEK_END); - std::size_t file_size = std::ftell(file.get()); - std::fseek(file.get(), 0, SEEK_SET); - std::unique_ptr buffer(new char[file_size]); - std::fread(buffer.get(), file_size, 1, file.get()); - auto result = memory_fonts_.emplace(itr->second.second, std::make_pair(std::move(buffer),file_size)); - FT_Error error = FT_New_Memory_Face (library_, - reinterpret_cast(result.first->second.first.get()), - static_cast(result.first->second.second), - itr->second.first, - &face); - if (!error) return std::make_shared(face); - else + auto result = global_memory_fonts_.emplace(itr->second.second, std::make_pair(std::move(file.data()),file.size())); + face_ptr face = library.face_from_memory(result.first->second.first.get(), + result.first->second.second, + itr->second.first); + if (!face) { // we can't load font, erase it. - memory_fonts_.erase(result.first); + global_memory_fonts_.erase(result.first); } + return face; } } } return face_ptr(); } - stroker_ptr freetype_engine::create_stroker() { FT_Stroker s; - FT_Error error = FT_Stroker_New(library_, &s); + FT_Error error = FT_Stroker_New(library_.get(), &s); if (!error) { return std::make_shared(s); @@ -367,10 +333,7 @@ stroker_ptr freetype_engine::create_stroker() return stroker_ptr(); } - - -template -face_ptr face_manager::get_face(std::string const& name) +face_ptr face_manager::get_face(std::string const& name) { auto itr = face_ptr_cache_.find(name); if (itr != face_ptr_cache_.end()) @@ -379,7 +342,7 @@ face_ptr face_manager::get_face(std::string const& name) } else { - face_ptr face = engine_.create_face(name); + face_ptr face = engine_.create_face(name,library_,font_file_mapping_,font_memory_cache_); if (face) { face_ptr_cache_.emplace(name,face); @@ -388,8 +351,7 @@ face_ptr face_manager::get_face(std::string const& name) } } -template -face_set_ptr face_manager::get_face_set(std::string const& name) +face_set_ptr face_manager::get_face_set(std::string const& name) { face_set_ptr face_set = std::make_shared(); if (face_ptr face = get_face(name)) @@ -399,8 +361,7 @@ face_set_ptr face_manager::get_face_set(std::string const& name) return face_set; } -template -face_set_ptr face_manager::get_face_set(font_set const& fset) +face_set_ptr face_manager::get_face_set(font_set const& fset) { std::vector const& names = fset.get_face_names(); face_set_ptr face_set = std::make_shared(); @@ -423,8 +384,7 @@ face_set_ptr face_manager::get_face_set(font_set const& fset) return face_set; } -template -face_set_ptr face_manager::get_face_set(const std::string &name, boost::optional fset) +face_set_ptr face_manager::get_face_set(const std::string &name, boost::optional fset) { if (fset && fset->size() > 0) { @@ -439,8 +399,7 @@ face_set_ptr face_manager::get_face_set(const std::string &name, boost::optio #ifdef MAPNIK_THREADSAFE std::mutex freetype_engine::mutex_; #endif -std::map > freetype_engine::name2file_; -std::map,std::size_t> > freetype_engine::memory_fonts_; -template class face_manager; +freetype_engine::font_file_mapping_type freetype_engine::global_font_file_mapping_; +std::map,std::size_t> > freetype_engine::global_memory_fonts_; } diff --git a/src/font_library.cpp b/src/font_library.cpp new file mode 100644 index 000000000..4c5c5a5d8 --- /dev/null +++ b/src/font_library.cpp @@ -0,0 +1,99 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +// mapnik +#include +#include + +// stl +#include + +// freetype2 +extern "C" +{ +#include +#include FT_FREETYPE_H +#include FT_MODULE_H +} + +namespace { + +void* _Alloc_Func(FT_Memory memory, long size) +{ + return std::malloc(size); +} + +void _Free_Func(FT_Memory memory, void *block) +{ + std::free(block); +} + +void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block) +{ + return std::realloc(block, new_size); +} + +} + +namespace mapnik { + +namespace util { + + font_library::font_library() + : library_(nullptr), + memory_(new FT_MemoryRec_) + { + memory_->alloc = _Alloc_Func; + memory_->free = _Free_Func; + memory_->realloc = _Realloc_Func; + FT_Error error = FT_New_Library(&*memory_, &library_); + if (error) throw std::runtime_error("can not initalize FreeType2 library"); + FT_Add_Default_Modules(library_); + } + + FT_Library font_library::get() { + return library_; + } + + face_ptr font_library::face_from_memory(const char * buffer, + std::size_t size, + int index) + { + FT_Face face; + FT_Error error = FT_New_Memory_Face(library_, + reinterpret_cast(buffer), // data + static_cast(size), // size + index, // face index + &face); + if (!error) return std::make_shared(face); + return face_ptr(); + } + + + + font_library::~font_library() { + FT_Done_Library(library_); + } + +} // end namespace util + +} // end namespace mapnik diff --git a/src/load_map.cpp b/src/load_map.cpp index 0c43eb5bb..4acecc72c 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -84,10 +84,10 @@ constexpr unsigned name2int(const char *str, int off = 0) class map_parser : mapnik::noncopyable { public: - map_parser(bool strict, std::string const& filename = "") : + map_parser(Map & map, bool strict, std::string const& filename = "") : strict_(strict), filename_(filename), - font_manager_(font_engine_), + font_manager_(font_engine_,map.get_font_file_mapping(),map.get_font_memory_cache()), xml_base_path_() {} @@ -130,7 +130,7 @@ private: std::string filename_; std::map datasource_templates_; freetype_engine font_engine_; - face_manager font_manager_; + face_manager_freetype font_manager_; std::map file_sources_; std::map fontsets_; std::string xml_base_path_; @@ -143,7 +143,7 @@ void load_map(Map & map, std::string const& filename, bool strict, std::string b xml_tree tree("utf8"); tree.set_filename(filename); read_xml(filename, tree.root()); - map_parser parser(strict, filename); + map_parser parser(map, strict, filename); parser.parse_map(map, tree.root(), base_path); //dump_xml(tree.root()); } @@ -160,7 +160,7 @@ void load_map_string(Map & map, std::string const& str, bool strict, std::string { read_xml_string(str, tree.root(), map.base_path()); // FIXME - this value is not fully known yet } - map_parser parser(strict, base_path); + map_parser parser(map, strict, base_path); parser.parse_map(map, tree.root(), base_path); } @@ -262,7 +262,9 @@ void map_parser::parse_map(Map & map, xml_node const& node, std::string const& b optional font_directory = map_node.get_opt_attr("font-directory"); if (font_directory) { - if (!freetype_engine::register_fonts(ensure_relative_to_xml(font_directory), false)) + map.set_font_directory(*font_directory); + if (!map.register_fonts(ensure_relative_to_xml(font_directory), false)) + //if (!freetype_engine::register_fonts(ensure_relative_to_xml(font_directory), false)) { if (strict_) { diff --git a/src/map.cpp b/src/map.cpp index a58bb51f6..e729c1b87 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -38,8 +38,9 @@ #include #include #include // for PROJ_ENVELOPE_POINTS - -// boost +#include +#include +#include // stl #include @@ -70,7 +71,11 @@ Map::Map() background_image_comp_op_(src_over), background_image_opacity_(1.0), aspectFixMode_(GROW_BBOX), - base_path_("") {} + base_path_(""), + extra_params_(), + font_directory_(), + font_file_mapping_(), + font_memory_cache_() {} Map::Map(int width,int height, std::string const& srs) : width_(width), @@ -80,7 +85,11 @@ Map::Map(int width,int height, std::string const& srs) background_image_comp_op_(src_over), background_image_opacity_(1.0), aspectFixMode_(GROW_BBOX), - base_path_("") {} + base_path_(""), + extra_params_(), + font_directory_(), + font_file_mapping_(), + font_memory_cache_() {} Map::Map(Map const& rhs) : width_(rhs.width_), @@ -98,7 +107,11 @@ Map::Map(Map const& rhs) current_extent_(rhs.current_extent_), maximum_extent_(rhs.maximum_extent_), base_path_(rhs.base_path_), - extra_params_(rhs.extra_params_) {} + extra_params_(rhs.extra_params_), + font_directory_(rhs.font_directory_), + font_file_mapping_(rhs.font_file_mapping_), + // on copy discard memory cache + font_memory_cache_() {} Map::Map(Map && rhs) @@ -117,11 +130,13 @@ Map::Map(Map && rhs) current_extent_(std::move(rhs.current_extent_)), maximum_extent_(std::move(rhs.maximum_extent_)), base_path_(std::move(rhs.base_path_)), - extra_params_(std::move(rhs.extra_params_)) {} + extra_params_(std::move(rhs.extra_params_)), + font_directory_(std::move(rhs.font_directory_)), + font_file_mapping_(std::move(rhs.font_file_mapping_)), + font_memory_cache_(std::move(rhs.font_memory_cache_)) {} Map::~Map() {} - Map& Map::operator=(Map rhs) { swap(*this, rhs); @@ -147,9 +162,11 @@ void swap (Map & lhs, Map & rhs) std::swap(lhs.maximum_extent_, rhs.maximum_extent_); std::swap(lhs.base_path_, rhs.base_path_); std::swap(lhs.extra_params_, rhs.extra_params_); + std::swap(lhs.font_directory_,rhs.font_directory_); + std::swap(lhs.font_file_mapping_,rhs.font_file_mapping_); + std::swap(lhs.font_memory_cache_,rhs.font_memory_cache_); } - bool Map::operator==(Map const& rhs) const { return (width_ == rhs.width_) && @@ -167,7 +184,10 @@ bool Map::operator==(Map const& rhs) const (current_extent_ == rhs.current_extent_) && (maximum_extent_ == rhs.maximum_extent_) && (base_path_ == rhs.base_path_) && - (extra_params_ == rhs.extra_params_); + (extra_params_ == rhs.extra_params_) && + (font_directory_ == rhs.font_directory_) && + (font_file_mapping_ == rhs.font_file_mapping_) && + (font_memory_cache_ == rhs.font_memory_cache_); } std::map const& Map::styles() const @@ -247,6 +267,27 @@ std::map & Map::fontsets() return fontsets_; } +bool Map::register_fonts(std::string const& dir, bool recurse) +{ + util::font_library library; + return freetype_engine::register_fonts_impl(dir, library, font_file_mapping_, recurse); +} + +bool Map::load_fonts() +{ + bool result = false; + for (auto const& kv : font_file_mapping_) + { + mapnik::util::file file(kv.second.second); + if (file.open()) + { + auto item = font_memory_cache_.emplace(kv.second.second, std::make_pair(std::move(file.data()),file.size())); + if (item.second) result = true; + } + } + return result; +} + size_t Map::layer_count() const { return layers_.size(); diff --git a/src/renderer_common.cpp b/src/renderer_common.cpp index 15ba84e89..9811ad1b0 100644 --- a/src/renderer_common.cpp +++ b/src/renderer_common.cpp @@ -38,7 +38,7 @@ renderer_common::renderer_common(Map const& map, unsigned width, unsigned height vars_(vars), shared_font_engine_(std::make_shared()), font_engine_(*shared_font_engine_), - font_manager_(font_engine_), + font_manager_(font_engine_,map.get_font_file_mapping(),map.get_font_memory_cache()), query_extent_(), t_(t), detector_(detector) diff --git a/src/save_map.cpp b/src/save_map.cpp index 076f05e82..78c3a7888 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -625,6 +625,12 @@ void serialize_map(ptree & pt, Map const& map, bool explicit_defaults) set_attr( map_node, "background-color", * c ); } + optional const& font_directory = map.font_directory(); + if ( font_directory ) + { + set_attr( map_node, "font-directory", *font_directory ); + } + optional const& image_filename = map.background_image(); if ( image_filename ) { diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index 7482468e4..6c6e8154d 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -341,7 +341,7 @@ template text_symbolizer_helper::text_symbolizer_helper( unsigned height, double scale_factor, view_transform const& t, - face_manager &font_manager, + face_manager_freetype & font_manager, label_collision_detector4 &detector, box2d const& query_extent, agg::trans_affine const&); @@ -355,7 +355,7 @@ template text_symbolizer_helper::text_symbolizer_helper( unsigned height, double scale_factor, view_transform const& t, - face_manager &font_manager, + face_manager_freetype & font_manager, label_collision_detector4 &detector, box2d const& query_extent, agg::trans_affine const&);