Example #1
0
bool font_face::glyph_dimensions(glyph_info & glyph) const
{
    FT_Vector pen;
    pen.x = 0;
    pen.y = 0;
    FT_Set_Transform(face_, 0, &pen);

    if (FT_Load_Glyph(face_, glyph.glyph_index, FT_LOAD_NO_HINTING))
    {
        MAPNIK_LOG_ERROR(font_face) << "FT_Load_Glyph failed";
        return false;
    }
    FT_Glyph image;
    if (FT_Get_Glyph(face_->glyph, &image))
    {
        MAPNIK_LOG_ERROR(font_face) << "FT_Get_Glyph failed";
        return false;
    }
    FT_BBox glyph_bbox;
    FT_Glyph_Get_CBox(image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
    FT_Done_Glyph(image);
    glyph.unscaled_ymin = glyph_bbox.yMin;
    glyph.unscaled_ymax = glyph_bbox.yMax;
    glyph.unscaled_advance = face_->glyph->advance.x;
    glyph.unscaled_line_height = face_->size->metrics.height;
    glyph.unscaled_ascender = unscaled_ascender_;
    return true;
}
Example #2
0
text_placements_ptr text_placements_simple::from_xml(xml_node const& xml, fontset_map const& fontsets, bool is_shield)
{
    // TODO - handle X cleaner
    std::string placements_string = xml.get_attr<std::string>("placements", "X");
    // like set_property_from_xml in properties_util.hpp
    if (!placements_string.empty())
    {
        if (placements_string == "X")
        {
            text_placements_ptr ptr = std::make_shared<text_placements_simple>(placements_string);
            ptr->defaults.from_xml(xml, fontsets, is_shield);
            return ptr;
        }
        else
        {
            try
            {
                // we don't use parse_expression(placements_string) directly here to benefit from the cache in the xml_node
                boost::optional<expression_ptr> val = xml.get_opt_attr<expression_ptr>("placements");
                if (val)
                {
                    text_placements_ptr ptr = std::make_shared<text_placements_simple>(*val);
                    ptr->defaults.from_xml(xml, fontsets, is_shield);
                    return ptr;
                }
            }
            catch (std::exception const& ex)
            {
                // otherwise ensure it is valid
                std::vector<directions_e> direction;
                std::vector<int> text_sizes;
                if (!parse_positions(placements_string,direction,text_sizes))
                {
                    MAPNIK_LOG_ERROR(text_placements) << "Could not parse text_placement_simple placement string ('" << placements_string << "')";
                    if (direction.size() == 0)
                    {
                        MAPNIK_LOG_ERROR(text_placements) << "text_placements_simple with no valid placements! ('"<< placements_string <<"')";
                    }
                    return text_placements_ptr();
                }
                else
                {
                    text_placements_ptr ptr = std::make_shared<text_placements_simple>(placements_string,std::move(direction),std::move(text_sizes));
                    ptr->defaults.from_xml(xml, fontsets, is_shield);
                    return ptr;
                }
            }
            text_placements_ptr ptr = std::make_shared<text_placements_simple>(placements_string);
            ptr->defaults.from_xml(xml, fontsets, is_shield);
            return ptr;
        }
    }
    return text_placements_ptr();
}
Example #3
0
bool datasource_cache::register_datasource(std::string const& filename)
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    try
    {
        if (!mapnik::util::exists(filename))
        {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Cannot load '"
                    << filename << "' (plugin does not exist)";
            return false;
        }
        std::shared_ptr<PluginInfo> plugin = std::make_shared<PluginInfo>(filename,"datasource_name");
        if (plugin->valid())
        {
            if (plugin->name().empty())
            {
                MAPNIK_LOG_ERROR(datasource_cache)
                        << "Problem loading plugin library '"
                        << filename << "' (plugin is lacking compatible interface)";
            }
            else
            {
                if (plugins_.emplace(plugin->name(),plugin).second)
                {
                    MAPNIK_LOG_DEBUG(datasource_cache)
                            << "datasource_cache: Registered="
                            << plugin->name();
                    return true;
                }
            }
        }
        else
        {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Problem loading plugin library: "
                    << filename << " (dlopen failed - plugin likely has an unsatisfied dependency or incompatible ABI)";
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(datasource_cache)
                << "Exception caught while loading plugin library: "
                << filename << " (" << ex.what() << ")";
    }
    return false;
}
bool freetype_engine::register_font(std::string const& file_name)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    FT_Library library = 0;
    FT_Error error = FT_Init_FreeType(&library);
    if (error)
    {
        throw std::runtime_error("Failed to initialize FreeType2 library");
    }

    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
    for ( int i = 0; face == 0 || i < num_faces; i++ ) {
        // if face is null then this is the first face
        error = FT_New_Face (library,file_name.c_str(),i,&face);
        if (error)
        {
            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)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            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";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
    }
    if (face)
        FT_Done_Face(face);
    if (library)
        FT_Done_FreeType(library);
    return success;
}
Example #5
0
void xml_node::add_attribute(const char * name, const char * value)
{
    auto result = attributes_.emplace(name,xml_attribute(value));
    if (!result.second)
    {
        MAPNIK_LOG_ERROR(xml_tree) << "ignoring duplicate attribute '" << name << "'";
    }
}
Example #6
0
void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_points()
{
    label_placement_enum how_placed = placement_->properties.label_placement;
    if (how_placed == LINE_PLACEMENT)
    {
        point_placement_ = false;
        return;
    }
    else
    {
        point_placement_ = true;
    }

    double label_x=0.0;
    double label_y=0.0;
    double z=0.0;

    std::list<geometry_type*>::const_iterator itr = geometries_to_process_.begin();
    std::list<geometry_type*>::const_iterator end = geometries_to_process_.end();
    for (; itr != end; itr++)
    {
        geometry_type const& geom = **itr;
        if (how_placed == VERTEX_PLACEMENT)
        {
            geom.rewind(0);
            for(unsigned i = 0; i < geom.size(); i++)
            {
                geom.vertex(&label_x, &label_y);
                prj_trans_.backward(label_x, label_y, z);
                t_.forward(&label_x, &label_y);
                points_.push_back(std::make_pair(label_x, label_y));
            }
        }
        else
        {
            if (geom.type() == LineString)
            {
                label::middle_point(geom, label_x,label_y);
            }
            else if (how_placed == POINT_PLACEMENT)
            {
                label::centroid(geom, label_x, label_y);
            }
            else if (how_placed == INTERIOR_PLACEMENT)
            {
                label::interior_position(geom, label_x, label_y);
            }
            else
            {
                MAPNIK_LOG_ERROR(symbolizer_helpers) << "ERROR: Unknown placement type in initialize_points()";
            }
            prj_trans_.backward(label_x, label_y, z);
            t_.forward(&label_x, &label_y);
            points_.push_back(std::make_pair(label_x, label_y));
        }
    }
    point_itr_ = points_.begin();
}
Example #7
0
bool vertex_cache::backward(double length)
{
    if (length < 0)
    {
        MAPNIK_LOG_ERROR(vertex_cache) << "vertex_cache::backward() called with negative argument!\n";
        return false;
    }
    return move(-length);
}
Example #8
0
bool datasource_cache::register_datasources(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    plugin_directories_.insert(dir);
    if (!mapnik::util::is_directory(dir))
    {
        return register_datasource(dir);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
#ifdef _WINDOWS
        std::wstring wide_dir(mapnik::utf8_to_utf16(dir));
        for (boost::filesystem::directory_iterator itr(wide_dir); itr != end_itr; ++itr)
        {
            std::string file_name = mapnik::utf16_to_utf8(itr->path().wstring());
#else
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
            std::string file_name = itr->path().string();
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_datasources(file_name, true))
                {
                    success = true;
                }
            }
            else
            {
                std::string base_name = itr->path().filename().string();
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_input_plugin(file_name))
                {
                    if (register_datasource(file_name))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(datasource_cache) << "register_datasources: " << ex.what();
    }
    return success;
}
Example #9
0
text_placement_info_simple::text_placement_info_simple(text_placements_simple const* parent,
                           std::string const& evaluated_positions,
                           double scale_factor)
: text_placement_info(parent, scale_factor),
  state(0),
  position_state(0),
  direction_(parent->direction_),
  text_sizes_(parent->text_sizes_),
  parent_(parent)
{
    if (direction_.empty() && !parse_positions(evaluated_positions,direction_,text_sizes_))
    {
        MAPNIK_LOG_ERROR(text_placements) << "Could not parse text_placement_simple placement string ('" << evaluated_positions << "')";
        if (direction_.size() == 0)
        {
            MAPNIK_LOG_ERROR(text_placements) << "text_placements_simple with no valid placements! ('"<< evaluated_positions <<"')";
        }
    }
}
Example #10
0
bool freetype_engine::register_fonts_impl(std::string const& dir,
                                          font_library & library,
                                          freetype_engine::font_file_mapping_type & font_file_mapping,
                                          bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return register_font_impl(dir, library, font_file_mapping);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
#ifdef _WINDOWS
        std::wstring wide_dir(mapnik::utf8_to_utf16(dir));
        for (boost::filesystem::directory_iterator itr(wide_dir); itr != end_itr; ++itr)
        {
            std::string file_name = mapnik::utf16_to_utf8(itr->path().wstring());
#else
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
            std::string file_name = itr->path().string();
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts_impl(file_name, library, font_file_mapping, true))
                {
                    success = true;
                }
            }
            else
            {
                std::string base_name = itr->path().filename().string();
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (register_font_impl(file_name, library, font_file_mapping))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}
Example #11
0
void text_itemizer::itemize_direction(unsigned start, unsigned end)
{
    direction_runs_.clear();
    UErrorCode error = U_ZERO_ERROR;
    int32_t length = end - start;
    UBiDi *bidi = ubidi_openSized(length, 0, &error);
    if (!bidi || U_FAILURE(error))
    {
        MAPNIK_LOG_ERROR(text_itemizer) << "Failed to create bidi object: " << u_errorName(error) << "\n";
        return;
    }
    ubidi_setPara(bidi, text_.getBuffer() + start, length, UBIDI_DEFAULT_LTR, 0, &error);
    if (U_SUCCESS(error))
    {
        UBiDiDirection direction = ubidi_getDirection(bidi);
        if (direction != UBIDI_MIXED)
        {
            direction_runs_.emplace_back(direction, start, end);
        }
        else
        {
            // mixed-directional
            int32_t count = ubidi_countRuns(bidi, &error);
            if(U_SUCCESS(error))
            {
                for(int i=0; i<count; ++i)
                {
                    int32_t vis_length;
                    int32_t run_start;
                    direction = ubidi_getVisualRun(bidi, i, &run_start, &vis_length);
                    run_start += start; //Add offset to compensate offset in setPara
                    direction_runs_.emplace_back(direction, run_start, run_start+vis_length);
                }
            }
        }
    }
    else
    {
        MAPNIK_LOG_ERROR(text_itemizer) << "ICU error: " << u_errorName(error) << "\n"; //TODO: Exception
    }
    ubidi_close(bidi);
}
Example #12
0
 ~prepared_index_statement()
 {
     if (stmt_)
     {
         int res = sqlite3_finalize(stmt_);
         if (res != SQLITE_OK)
         {
             if (*(*ds_))
             {
                 MAPNIK_LOG_ERROR(sqlite) << "~prepared_index_statement:"
                                          << sqlite3_errmsg(*(*ds_));
             }
             else
             {
                 MAPNIK_LOG_ERROR(sqlite) << "~prepared_index_statement:"
                                          << res;
             }
         }
     }
 }
Example #13
0
 Detector & detector(std::string const & key)
 {
     auto it = cache_.find(key);
     if (it == cache_.end())
     {
         MAPNIK_LOG_ERROR(detector) << "Collision cache '" <<
             key << "' does not exist. Default cache is used instead.";
         return default_;
     }
     return it->second;
 }
bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return mapnik::freetype_engine::register_font(dir);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
    #if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = itr->path().string();
    #else // v2
            std::string file_name = itr->string();
    #endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts(file_name, true))
                {
                    success = true;
                }
            }
            else
            {
    #if (BOOST_FILESYSTEM_VERSION == 3)
                std::string base_name = itr->path().filename().string();
    #else // v2
                std::string base_name = itr->filename();
    #endif
                if (!boost::algorithm::starts_with(base_name,".") &&
                    boost::filesystem::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (mapnik::freetype_engine::register_font(file_name))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}
bool datasource_cache::register_datasource(std::string const& str)
{
    bool success = false;
    try
    {
        lt_dlhandle module = lt_dlopen(str.c_str());
        if (module)
        {
            // http://www.mr-edd.co.uk/blog/supressing_gcc_warnings
#ifdef __GNUC__
            __extension__
#endif
                datasource_name* ds_name =
                reinterpret_cast<datasource_name*>(lt_dlsym(module, "datasource_name"));
            if (ds_name && insert(ds_name(),module))
            {
                MAPNIK_LOG_DEBUG(datasource_cache) << "datasource_cache: Registered=" << ds_name();

                success = true;
            }
            else if (!ds_name)
            {
                MAPNIK_LOG_ERROR(datasource_cache)
                        << "Problem loading plugin library '"
                        << str << "' (plugin is lacking compatible interface)";
            }
        }
        else
        {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Problem loading plugin library: " << str
                    << " (dlopen failed - plugin likely has an unsatisfied dependency or incompatible ABI)";
        }
    }
    catch (...) {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Exception caught while loading plugin library: " << str;
    }
    return success;
}
Example #16
0
 static inline boost::optional<mapnik::enumeration<T,MAX> > xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source)
 {
     using result_type = typename boost::optional<mapnik::enumeration<T,MAX> >;
     try
     {
         mapnik::enumeration<T,MAX> e;
         e.from_string(source);
         return result_type(e);
     }
     catch (illegal_enum_value const& ex)
     {
         MAPNIK_LOG_ERROR(do_xml_attribute_cast) << ex.what();
         return result_type();
     }
 }
Example #17
0
void raster_symbolizer::set_mode(std::string const& mode)
{
    MAPNIK_LOG_ERROR(raster_symbolizer) << "setting 'mode' is deprecated and will be removed in Mapnik 3.x, use 'comp-op' with Mapnik >= 2.1.x";
    mode_ = mode;
    if (mode == "normal")
    {
        MAPNIK_LOG_ERROR(raster_symbolizer) << "converting 'mode=normal' to 'comp-op:src_over'";
        this->set_comp_op(src_over);
    }
    else
    {
        std::string mode2 = boost::algorithm::replace_last_copy(mode,"2","");
        boost::optional<composite_mode_e> comp_op = comp_op_from_string(mode2);
        if (comp_op)
        {
            MAPNIK_LOG_ERROR(raster_symbolizer) << "converting 'mode:" << mode << "' to 'comp-op:" + *comp_op_to_string(*comp_op) + "'";
            this->set_comp_op(*comp_op);
        }
        else
        {
            MAPNIK_LOG_ERROR(raster_symbolizer) << "could not convert mode '" << mode << "' into comp-op, defaulting to 'comp-op:src-over'";
        }
    }
}
Example #18
0
bool datasource_cache::register_datasources(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    plugin_directories_.insert(dir);
    if (!mapnik::util::is_directory(dir))
    {
        return register_datasource(dir);
    }
    bool success = false;
    try
    {
        for (std::string const& file_name : mapnik::util::list_directory(dir))
        {
            if (mapnik::util::is_directory(file_name) && recurse)
            {
                if (register_datasources(file_name, true))
                {
                    success = true;
                }
            }
            else
            {
                std::string base_name = mapnik::util::basename(file_name);
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_input_plugin(file_name))
                {
                    if (register_datasource(file_name))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(datasource_cache) << "register_datasources: " << ex.what();
    }
    return success;
}
Example #19
0
bool freetype_engine::register_fonts_impl(std::string const& dir,
                                          font_library & library,
                                          freetype_engine::font_file_mapping_type & font_file_mapping,
                                          bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return register_font_impl(dir, library, font_file_mapping);
    }
    bool success = false;
    try
    {
        for (std::string const& file_name : mapnik::util::list_directory(dir))
        {
            if (mapnik::util::is_directory(file_name) && recurse)
            {
                if (register_fonts_impl(file_name, library, font_file_mapping, true))
                {
                    success = true;
                }
            }
            else
            {
                std::string base_name = mapnik::util::basename(file_name);
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (register_font_impl(file_name, library, font_file_mapping))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}
Example #20
0
    result_type operator() (
        Iterator,
        Iterator end,
        Iterator err_pos,
        boost::spirit::info const& what) const
    {
#ifdef MAPNIK_LOG
        std::stringstream s;
        using difference_type = typename std::iterator_traits<Iterator>::difference_type;
        auto start_err = err_pos;
        std::advance(err_pos, std::min(std::distance(err_pos, end), difference_type(16)));
        auto end_err = err_pos;
        assert(end_err <= end);
        s << "Mapnik GeoJSON parsing error:" << what << " expected but got: " << std::string(start_err, end_err);
        MAPNIK_LOG_ERROR(error_handler) << s.str();
#endif
        return boost::spirit::qi::fail;
    }
boost::optional<mapped_region_ptr> mapped_memory_cache::find(std::string const& uri, bool update_cache)
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::mutex> lock(mutex_);
#endif

    using iterator_type = std::unordered_map<std::string, mapped_region_ptr>::const_iterator;
    boost::optional<mapped_region_ptr> result;
    iterator_type itr = cache_.find(uri);
    if (itr != cache_.end())
    {
        result.reset(itr->second);
        return result;
    }

    if (mapnik::util::exists(uri))
    {
        try
        {
            boost::interprocess::file_mapping mapping(uri.c_str(),boost::interprocess::read_only);
            mapped_region_ptr region(std::make_shared<boost::interprocess::mapped_region>(mapping,boost::interprocess::read_only));
            result.reset(region);
            if (update_cache)
            {
                cache_.emplace(uri, *result);
            }
            return result;
        }
        catch (std::exception const& ex)
        {
            MAPNIK_LOG_ERROR(mapped_memory_cache)
                << "Error loading mapped memory file: '"
                << uri << "' (" << ex.what() << ")";
        }
    }
    /*
    else
    {
        MAPNIK_LOG_WARN(mapped_memory_cache) << "Memory region does not exist file: " << uri;
    }
    */
    return result;
}
Example #22
0
    image_gray8 create_bitmap(box2d<T> box)
    {
        if (!box.valid())
        {
            return image_gray8(0, 0);
        }

        try
        {
            return image_gray8(box.width(), box.height());
        }
        catch (std::runtime_error const & e)
        {
            // TODO: Scale down in this case.
            MAPNIK_LOG_ERROR(grid_vertex_adapter) << "grid vertex adapter: Cannot allocate underlaying bitmap. Bbox: "
                << box.to_string() << "; " << e.what();
            return image_gray8(0, 0);
        }
    }
Example #23
0
void text_placement_info_combined::apply_placement(text_placement_info_ptr placement_info) const
{
    text_placement_info_simple* simple = dynamic_cast<text_placement_info_simple*>(placement_info.get());
    if (simple)
    {
        apply_simple_placement();
    }
    else
    {
        text_placement_info_list* list = dynamic_cast<text_placement_info_list*>(placement_info.get());
        if (list)
        {
            apply_list_placement();
        }
        else
        {
              MAPNIK_LOG_ERROR(text_placement_info_combined) << "Could not apply unknown placement info ptr";
        }
    }
}
Example #24
0
    /** Converts @p str to an enum.
     * @throw illegal_enum_value @p str is not a legal identifier.
     * */
    void from_string(std::string const& str)
    {
        // TODO: Enum value strings with underscore are deprecated in Mapnik 3.x
        // and support will be removed in Mapnik 4.x.
        bool deprecated = false;
        std::string str_copy(str);
        if (str_copy.find('_') != std::string::npos)
        {
            std::replace(str_copy.begin(), str_copy.end(), '_', '-');
            deprecated = true;
        }
        for (unsigned i = 0; i < THE_MAX; ++i)
        {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc
#pragma GCC diagnostic ignored "-Wpragmas" // gcc
#pragma GCC diagnostic ignored "-Wundefined-var-template"
            if (str_copy == our_strings_[i])
#pragma GCC diagnostic pop
            {
                value_ = static_cast<ENUM>(i);
                if (deprecated)
                {
                    MAPNIK_LOG_ERROR(enumerations) << "enumeration value (" << str << ") using \"_\" is deprecated and will be removed in Mapnik 4.x, use '" << str_copy << "' instead";
                }
                return;
            }
        }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc
#pragma GCC diagnostic ignored "-Wpragmas" // gcc
#pragma GCC diagnostic ignored "-Wundefined-var-template"
        throw illegal_enum_value(std::string("Illegal enumeration value '") +
                                 str + "' for enum " + our_name_);
#pragma GCC diagnostic pop
    }
bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library)
{
#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;

    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.read  = ft_read_cb;
    streamRec.close = ft_close_cb;
    args.flags = FT_OPEN_STREAM;
    args.stream = &streamRec;
    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
    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);
        if (error) break;
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (num_faces == 0)
            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)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            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";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
        if (face) FT_Done_Face(face);
    }
    return success;
}
Example #26
0
// In the Unicode string characters are always stored in logical order.
// This makes line breaking easy. One word is added to the current line at a time. Once the line is too long
// we either go back one step or insert the line break at the current position (depending on "wrap_before" setting).
// At the end everything that is left over is added as the final line.
void text_layout::break_line_icu(std::pair<unsigned, unsigned> && line_limits)
{
    text_line line(line_limits.first, line_limits.second);
    shape_text(line);

    double scaled_wrap_width = wrap_width_ * scale_factor_;
    if (scaled_wrap_width <= 0 || line.width() < scaled_wrap_width)
    {
        add_line(std::move(line));
        return;
    }
    if (text_ratio_ > 0)
    {
        double wrap_at;
        double string_width = line.width();
        double string_height = line.line_height();
        for (double i = 1.0;
             ((wrap_at = string_width/i)/(string_height*i)) > text_ratio_ && (string_width/i) > scaled_wrap_width;
             i += 1.0) ;
        scaled_wrap_width = wrap_at;
    }

    mapnik::value_unicode_string const& text = itemizer_.text();
    Locale locale; // TODO: Is the default constructor correct?
    UErrorCode status = U_ZERO_ERROR;
    std::unique_ptr<BreakIterator> breakitr(BreakIterator::createLineInstance(locale, status));

    // Not breaking the text if an error occurs is probably the best thing we can do.
    // https://github.com/mapnik/mapnik/issues/2072
    if (!U_SUCCESS(status))
    {
        add_line(std::move(line));
        MAPNIK_LOG_ERROR(text_layout) << " could not create BreakIterator: " << u_errorName(status);
        return;
    }

    breakitr->setText(text);
    double current_line_length = 0;
    int last_break_position = static_cast<int>(line.first_char());
    for (unsigned i = line.first_char(); i < line.last_char(); ++i)
    {
        // TODO: character_spacing
        std::map<unsigned, double>::const_iterator width_itr = width_map_.find(i);
        if (width_itr != width_map_.end())
        {
            current_line_length += width_itr->second;
        }
        if (current_line_length <= scaled_wrap_width) continue;

        int break_position = wrap_before_ ? breakitr->preceding(i + 1) : breakitr->following(i);
        // following() returns a break position after the last word. So DONE should only be returned
        // when calling preceding.
        if (break_position <= last_break_position || break_position == static_cast<int>(BreakIterator::DONE))
        {
            // A single word is longer than the maximum line width.
            // Violate line width requirement and choose next break position
            break_position = breakitr->following(i);
            if (break_position == static_cast<int>(BreakIterator::DONE))
            {
                break_position = line.last_char();
                MAPNIK_LOG_ERROR(text_layout) << "Unexpected result in break_line. Trying to recover...\n";
            }
        }
        // Break iterator operates on the whole string, while we only look at one line. So we need to
        // clamp break values.
        if (break_position < static_cast<int>(line.first_char()))
        {
            break_position = line.first_char();
        }
        if (break_position > static_cast<int>(line.last_char()))
        {
            break_position = line.last_char();
        }
        bool adjust_for_space_character = break_position > 0 && text[break_position - 1] == 0x0020;

        text_line new_line(last_break_position, adjust_for_space_character ? break_position - 1 : break_position);
        clear_cluster_widths(last_break_position, adjust_for_space_character ? break_position - 1 : break_position);
        shape_text(new_line);
        add_line(std::move(new_line));

        last_break_position = break_position;
        i = break_position - 1;
        current_line_length = 0;
    }

    if (last_break_position == static_cast<int>(line.first_char()))
    {
        // No line breaks => no reshaping required
        add_line(std::move(line));
    }
    else if (last_break_position != static_cast<int>(line.last_char()))
    {
        text_line new_line(last_break_position, line.last_char());
        clear_cluster_widths(last_break_position, line.last_char());
        shape_text(new_line);
        add_line(std::move(new_line));
    }
}
Example #27
0
static void shape_text(text_line & line,
                       text_itemizer & itemizer,
                       std::map<unsigned,double> & width_map,
                       face_manager_freetype & font_manager,
                       double scale_factor )
{
    unsigned start = line.first_char();
    unsigned end = line.last_char();
    mapnik::value_unicode_string const& text = itemizer.text();
    size_t length = end - start;
    if (!length) return;
    line.reserve(length);
    std::list<text_item> const& list = itemizer.itemize(start, end);

    UErrorCode err = U_ZERO_ERROR;
    mapnik::value_unicode_string shaped;
    mapnik::value_unicode_string reordered;

    for (auto const& text_item : list)
    {
        face_set_ptr face_set = font_manager.get_face_set(text_item.format->face_name, text_item.format->fontset);
        double size = text_item.format->text_size * scale_factor;
        face_set->set_unscaled_character_sizes();
        for (auto const& face : *face_set)
        {
            UBiDi *bidi = ubidi_openSized(length, 0, &err);
            ubidi_setPara(bidi, text.getBuffer(), length, UBIDI_DEFAULT_LTR, 0, &err);
            ubidi_writeReordered(bidi, reordered.getBuffer(length),
                                 length, UBIDI_DO_MIRRORING, &err);
            ubidi_close(bidi);
            reordered.releaseBuffer(length);

            int32_t num_char = u_shapeArabic(reordered.getBuffer(), length,
                                             shaped.getBuffer(length), length,
                                             U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
                                             U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &err);
            if (num_char < 0)
            {
                MAPNIK_LOG_ERROR(icu_shaper) << " u_shapeArabic returned negative num_char " << num_char;
            }
            std::size_t num_chars = static_cast<std::size_t>(num_char);
            shaped.releaseBuffer(length);
            bool shaped_status = true;
            if (U_SUCCESS(err) && (num_chars == length))
            {
                U_NAMESPACE_QUALIFIER StringCharacterIterator iter(shaped);
                unsigned i = 0;
                for (iter.setToStart(); iter.hasNext();)
                {
                    UChar ch = iter.nextPostInc();
                    glyph_info tmp;
                    tmp.offset.clear();
                    tmp.char_index = i;
                    tmp.glyph_index = FT_Get_Char_Index(face->get_face(), ch);
                    if (tmp.glyph_index == 0)
                    {
                        shaped_status = false;
                        break;
                    }
                    tmp.face = face;
                    tmp.format = text_item.format;
                    face->glyph_dimensions(tmp);
                    tmp.scale_multiplier = size / face->get_face()->units_per_EM;
                    width_map[i] += tmp.advance();
                    line.add_glyph(std::move(tmp), scale_factor);
                    ++i;
                }
            }
            if (!shaped_status) continue;
            line.update_max_char_height(face->get_char_height(size));
            return;
        }
    }
}
Example #28
0
void base_symbolizer_helper::initialize_points()
{
    label_placement_enum how_placed = placement_->properties.label_placement;
    if (how_placed == LINE_PLACEMENT)
    {
        point_placement_ = false;
        return;
    }
    else
    {
        point_placement_ = true;
    }

    double label_x=0.0;
    double label_y=0.0;
    double z=0.0;

    for (auto * geom_ptr : geometries_to_process_)
    {
        geometry_type const& geom = *geom_ptr;
        if (how_placed == VERTEX_PLACEMENT)
        {
            geom.rewind(0);
            for(unsigned i = 0; i < geom.size(); ++i)
            {
                geom.vertex(&label_x, &label_y);
                prj_trans_.backward(label_x, label_y, z);
                t_.forward(&label_x, &label_y);
                points_.push_back(pixel_position(label_x, label_y));
            }
        }
        else
        {
            // https://github.com/mapnik/mapnik/issues/1423
            bool success = false;
            // https://github.com/mapnik/mapnik/issues/1350
            if (geom.type() == geometry_type::types::LineString)
            {
                success = label::middle_point(geom, label_x,label_y);
            }
            else if (how_placed == POINT_PLACEMENT)
            {
                success = label::centroid(geom, label_x, label_y);
            }
            else if (how_placed == INTERIOR_PLACEMENT)
            {
                success = label::interior_position(geom, label_x, label_y);
            }
            else
            {
                MAPNIK_LOG_ERROR(symbolizer_helpers) << "ERROR: Unknown placement type in initialize_points()";
            }
            if (success)
            {
                prj_trans_.backward(label_x, label_y, z);
                t_.forward(&label_x, &label_y);
                points_.push_back(pixel_position(label_x, label_y));
            }
        }
    }
    point_itr_ = points_.begin();
}
Example #29
0
void Map::zoom_all()
{
    try
    {
        if (layers_.empty())
        {
            return;
        }
        projection proj0(srs_);
        box2d<double> ext;
        bool success = false;
        bool first = true;
        std::vector<layer>::const_iterator itr = layers_.begin();
        std::vector<layer>::const_iterator end = layers_.end();
        while (itr != end)
        {
            if (itr->active())
            {
                std::string const& layer_srs = itr->srs();
                projection proj1(layer_srs);
                proj_transform prj_trans(proj0,proj1);
                box2d<double> layer_ext = itr->envelope();
                if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS))
                {
                    success = true;
                    MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " original ext=" << itr->envelope();
                    MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " transformed to map srs=" << layer_ext;
                    if (first)
                    {
                        ext = layer_ext;
                        first = false;
                    }
                    else
                    {
                        ext.expand_to_include(layer_ext);
                    }
                }
            }
            ++itr;
        }
        if (success)
        {
            if (maximum_extent_) {
                ext.clip(*maximum_extent_);
            }
            zoom_to_box(ext);
        }
        else
        {
            if (maximum_extent_)
            {
                MAPNIK_LOG_ERROR(map) << "could not zoom to combined layer extents"
                    << " so falling back to maximum-extent for zoom_all result";
                zoom_to_box(*maximum_extent_);
            }
            else
            {
                std::ostringstream s;
                s << "could not zoom to combined layer extents "
                  << "using zoom_all because proj4 could not "
                  << "back project any layer extents into the map srs "
                  << "(set map 'maximum-extent' to override layer extents)";
                throw std::runtime_error(s.str());
            }
        }
    }
    catch (proj_init_error const& ex)
    {
        throw mapnik::config_error(std::string("Projection error during map.zoom_all: ") + ex.what());
    }
}
Example #30
0
bool freetype_engine::register_font_impl(std::string const& file_name,
                                         font_library & library,
                                         freetype_engine::font_file_mapping_type & font_file_mapping)
{
    MAPNIK_LOG_DEBUG(font_engine_freetype) << "registering: " << file_name;
    mapnik::util::file file(file_name);
    if (!file) 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 = nullptr;
    args.flags = FT_OPEN_STREAM;
    args.stream = &streamRec;
    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
    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.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)
            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)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                // http://stackoverflow.com/a/24795559/2333354
                auto range = font_file_mapping.equal_range(name);
                if (range.first == range.second) // the key was previously absent; insert a pair
                {
                    font_file_mapping.emplace_hint(range.first, name, 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 */
                    MAPNIK_LOG_WARN(font_engine_freetype) << "registering new " << name << " at '" << file_name << "'";
                    range.first->second = std::make_pair(i,file_name); // replace value
                }
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            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";
            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
        if (face) FT_Done_Face(face);
    }
    return success;
}