From 2b843ec6a9b28030d592b4d2721af7a9325ea6a8 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 11 Jun 2014 19:56:55 -0400 Subject: [PATCH] first attempt at unscaled glyph dimensions --- include/mapnik/text/dummy_shaper.hpp | 8 +++--- include/mapnik/text/face.hpp | 2 ++ include/mapnik/text/glyph_info.hpp | 36 ++++++++++++++++++------- include/mapnik/text/harfbuzz_shaper.hpp | 9 ++++--- include/mapnik/text/icu_shaper.hpp | 5 ++-- src/text/face.cpp | 31 ++++++++++++++++----- src/text/placement_finder.cpp | 18 ++++++------- src/text/text_line.cpp | 9 ++++--- 8 files changed, 80 insertions(+), 38 deletions(-) diff --git a/include/mapnik/text/dummy_shaper.hpp b/include/mapnik/text/dummy_shaper.hpp index 8f80a2514..a7f276bd7 100644 --- a/include/mapnik/text/dummy_shaper.hpp +++ b/include/mapnik/text/dummy_shaper.hpp @@ -61,7 +61,7 @@ static void shape_text(text_line & line, { 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_character_sizes(size); + face_set->set_unscaled_character_sizes(); if (face_set->begin() == face_set->end()) return; // Invalid face set face_ptr face = *(face_set->begin()); FT_Face freetype_face = face->get_face(); @@ -73,12 +73,14 @@ static void shape_text(text_line & line, tmp.glyph_index = FT_Get_Char_Index(freetype_face, c); if (tmp.glyph_index == 0) continue; // Skip unknown characters tmp.char_index = i; - tmp.width = 0; // Filled in by glyph_dimensions + tmp.unscaled_width = 0; // Filled in by glyph_dimensions tmp.offset.clear(); tmp.face = face; tmp.format = text_item.format; face->glyph_dimensions(tmp); - width_map[i] += tmp.width; + tmp.scale_multiplier = (size / face->get_face()->units_per_EM); + std::cout << tmp.unscaled_advance; + width_map[i] += tmp.advance(); line.add_glyph(tmp, scale_factor); } line.update_max_char_height(face->get_char_height()); diff --git a/include/mapnik/text/face.hpp b/include/mapnik/text/face.hpp index 0528cf6a6..bc4ecff36 100644 --- a/include/mapnik/text/face.hpp +++ b/include/mapnik/text/face.hpp @@ -67,6 +67,7 @@ public: double get_char_height() const; bool set_character_sizes(double size); + bool set_unscaled_character_sizes(); void glyph_dimensions(glyph_info &glyph) const; @@ -88,6 +89,7 @@ public: void add(face_ptr face); void set_character_sizes(double size); + void set_unscaled_character_sizes(); unsigned size() const { return faces_.size(); } iterator begin() { return faces_.begin(); } diff --git a/include/mapnik/text/glyph_info.hpp b/include/mapnik/text/glyph_info.hpp index a387045e0..b88599337 100644 --- a/include/mapnik/text/glyph_info.hpp +++ b/include/mapnik/text/glyph_info.hpp @@ -42,25 +42,43 @@ struct glyph_info : glyph_index(0), face(nullptr), char_index(0), - width(0.0), - ymin(0.0), - ymax(0.0), - line_height(0.0), + unscaled_ymin(0.0), + unscaled_ymax(0.0), + unscaled_width(0.0), + unscaled_height(0.0), + unscaled_advance(0.0), + unscaled_ascender(0.0), + unscaled_descender(0.0), + unscaled_line_height(0.0), + scale_multiplier(0.0), offset(), format() {} glyph_index_t glyph_index; face_ptr face; // Position in the string of all characters i.e. before itemizing unsigned char_index; - double width; - double ymin; - double ymax; + double unscaled_ymin; + double unscaled_ymax; + double unscaled_width; + double unscaled_height; + double unscaled_advance; + double unscaled_ascender; + double unscaled_descender; // Line height returned by freetype, includes normal font // line spacing, but not additional user defined spacing - double line_height; + double unscaled_line_height; + double scale_multiplier; pixel_position offset; char_properties_ptr format; - double height() const { return ymax-ymin; } + + double ymin() const { return unscaled_ymin * scale_multiplier; } + double ymax() const { return unscaled_ymax * scale_multiplier; } + double width() const { return unscaled_width * scale_multiplier; }; + double height() const { return unscaled_height * scale_multiplier; }; + double advance() const { return unscaled_advance * scale_multiplier; }; + double ascender() const { return unscaled_ascender * scale_multiplier; }; + double descender() const { return unscaled_descender * scale_multiplier; }; + double line_height() const { return unscaled_line_height * scale_multiplier; }; }; } //ns mapnik diff --git a/include/mapnik/text/harfbuzz_shaper.hpp b/include/mapnik/text/harfbuzz_shaper.hpp index 2b0c5f96e..5af40a258 100644 --- a/include/mapnik/text/harfbuzz_shaper.hpp +++ b/include/mapnik/text/harfbuzz_shaper.hpp @@ -63,7 +63,7 @@ static void shape_text(text_line & line, { 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_character_sizes(size); + face_set->set_unscaled_character_sizes(); font_face_set::iterator face_itr = face_set->begin(), face_end = face_set->end(); for (; face_itr != face_end; ++face_itr) { @@ -105,10 +105,11 @@ static void shape_text(text_line & line, tmp.face = face; tmp.format = text_item.format; face->glyph_dimensions(tmp); - //tmp.width = positions[i].x_advance / 64.0; //Overwrite default width with better value provided by HarfBuzz - tmp.width = positions[i].x_advance >> 6; + tmp.scale_multiplier = (size / face->get_face()->units_per_EM); + //Overwrite default advance with better value provided by HarfBuzz + tmp.unscaled_advance = positions[i].x_advance; tmp.offset.set(positions[i].x_offset / 64.0, positions[i].y_offset / 64.0); - width_map[glyphs[i].cluster] += tmp.width; + width_map[glyphs[i].cluster] += tmp.advance(); line.add_glyph(tmp, scale_factor); } line.update_max_char_height(face->get_char_height()); diff --git a/include/mapnik/text/icu_shaper.hpp b/include/mapnik/text/icu_shaper.hpp index db5246a05..05970565b 100644 --- a/include/mapnik/text/icu_shaper.hpp +++ b/include/mapnik/text/icu_shaper.hpp @@ -65,7 +65,7 @@ static void shape_text(text_line & line, { 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_character_sizes(size); + face_set->set_unscaled_character_sizes(); for (auto const& face : *face_set) { UBiDi *bidi = ubidi_openSized(length, 0, &err); @@ -105,7 +105,8 @@ static void shape_text(text_line & line, tmp.face = face; tmp.format = text_item.format; face->glyph_dimensions(tmp); - width_map[i] += tmp.width; + tmp.scale_multiplier = (size / face->get_face()->units_per_EM) / 64.0; + width_map[i] += tmp.advance(); line.add_glyph(tmp, scale_factor); ++i; } diff --git a/src/text/face.cpp b/src/text/face.cpp index d3344dd1a..4b2a42dab 100644 --- a/src/text/face.cpp +++ b/src/text/face.cpp @@ -52,6 +52,12 @@ bool font_face::set_character_sizes(double size) return !FT_Set_Char_Size(face_,0,(FT_F26Dot6)(size * (1<<6)),0,0); } +bool font_face::set_unscaled_character_sizes() +{ + char_height_ = 0.0; + return !FT_Set_Char_Size(face_,0,face_->units_per_EM,0,0); +} + void font_face::glyph_dimensions(glyph_info & glyph) const { //TODO @@ -85,13 +91,16 @@ void font_face::glyph_dimensions(glyph_info & glyph) const FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox); FT_Done_Glyph(image); - glyph.ymin = glyph_bbox.yMin; //pixels! - glyph.ymax = glyph_bbox.yMax; - glyph.line_height = face_->size->metrics.height/64.0; - // TODO: we round to integers for now to maintain - // back compatibility with Mapnik 2.x - //glyph.width = face_->glyph->advance.x/64.0; - glyph.width = face_->glyph->advance.x >> 6; + glyph.unscaled_ymin = glyph_bbox.yMin; + glyph.unscaled_ymax = glyph_bbox.yMax; + + glyph.unscaled_width = glyph_bbox.xMax - glyph_bbox.xMin; + glyph.unscaled_height = glyph_bbox.yMax - glyph_bbox.yMin; + glyph.unscaled_advance = face_->glyph->advance.x; + + glyph.unscaled_ascender = face_->size->metrics.ascender; + glyph.unscaled_descender = face_->size->metrics.descender; + glyph.unscaled_line_height = face_->size->metrics.height; //TODO: dimension_cache_.insert(std::pair(c, dim)); } @@ -120,6 +129,14 @@ void font_face_set::set_character_sizes(double size) } } +void font_face_set::set_unscaled_character_sizes() +{ + for (face_ptr const& face : faces_) + { + face->set_unscaled_character_sizes(); + } +} + /******************************************************************************/ void stroker::init(double radius) diff --git a/src/text/placement_finder.cpp b/src/text/placement_finder.cpp index 31744619e..9bc689f99 100644 --- a/src/text/placement_finder.cpp +++ b/src/text/placement_finder.cpp @@ -157,10 +157,10 @@ bool placement_finder::find_point_placement(pixel_position const& pos) { // place the character relative to the center of the string envelope glyphs->push_back(glyph, (pixel_position(x, y).rotate(orientation)) + layout_offset, orientation); - if (glyph.width) + if (glyph.advance()) { //Only advance if glyph is not part of a multiple glyph sequence - x += glyph.width + glyph.format->character_spacing * scale_factor_; + x += glyph.advance() + glyph.format->character_spacing * scale_factor_; } } } @@ -313,8 +313,8 @@ bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e or pos.y = -pos.y - char_height/2.0*rot.cos; pos.x = pos.x + char_height/2.0*rot.sin; - cluster_offset.x += rot.cos * glyph.width; - cluster_offset.y -= rot.sin * glyph.width; + cluster_offset.x += rot.cos * glyph.advance(); + cluster_offset.y -= rot.sin * glyph.advance(); box2d bbox = get_bbox(layout, glyph, pos, rot); if (collision(bbox)) return false; @@ -446,18 +446,18 @@ box2d placement_finder::get_bbox(text_layout const& layout, glyph_info c Add glyph offset in y direction, but not in x direction (as we use the full cluster width anyways)! */ double width = layout.cluster_width(glyph.char_index); - if (glyph.width <= 0) width = -width; + if (glyph.advance() <= 0) width = -width; pixel_position tmp, tmp2; - tmp.set(0, glyph.ymax); + tmp.set(0, glyph.ymax()); tmp = tmp.rotate(rot); - tmp2.set(width, glyph.ymax); + tmp2.set(width, glyph.ymax()); tmp2 = tmp2.rotate(rot); box2d bbox(tmp.x, -tmp.y, tmp2.x, -tmp2.y); - tmp.set(width, glyph.ymin); + tmp.set(width, glyph.ymin()); tmp = tmp.rotate(rot); bbox.expand_to_include(tmp.x, -tmp.y); - tmp.set(0, glyph.ymin); + tmp.set(0, glyph.ymin()); tmp = tmp.rotate(rot); bbox.expand_to_include(tmp.x, -tmp.y); pixel_position pos2 = pos + pixel_position(0, glyph.offset.y).rotate(rot); diff --git a/src/text/text_line.cpp b/src/text/text_line.cpp index 86c6d412c..9365a5cc4 100644 --- a/src/text/text_line.cpp +++ b/src/text/text_line.cpp @@ -36,15 +36,16 @@ text_line::text_line(unsigned first_char, unsigned last_char) void text_line::add_glyph(glyph_info const& glyph, double scale_factor_) { - line_height_ = std::max(line_height_, glyph.line_height + glyph.format->line_spacing); + line_height_ = std::max(line_height_, glyph.line_height() + glyph.format->line_spacing); + double advance = glyph.advance(); if (glyphs_.empty()) { - width_ = glyph.width; + width_ = advance; } - else if (glyph.width) + else if (advance) { // Only add character spacing if the character is not a zero-width part of a cluster. - width_ += glyph.width + glyphs_.back().format->character_spacing * scale_factor_; + width_ += advance + glyphs_.back().format->character_spacing * scale_factor_; } glyphs_.push_back(glyph); }