alternative exaustive face fallback implementation ref #3534 #3559

This commit is contained in:
artemp 2017-01-31 17:44:25 +01:00
parent df51f6087c
commit 755d178d20

View file

@ -80,17 +80,17 @@ static void shape_text(text_line & line,
line.reserve(length); line.reserve(length);
auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);}; auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);};
const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(),hb_buffer_deleter); const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(), hb_buffer_deleter);
hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length)); hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length));
mapnik::value_unicode_string const& text = itemizer.text(); mapnik::value_unicode_string const& text = itemizer.text();
for (auto const& text_item : list) for (auto const& text_item : list)
{ {
auto item_length = static_cast<int>(text_item.end - text_item.start);
face_set_ptr face_set = font_manager.get_face_set(text_item.format_->face_name, text_item.format_->fontset); 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; double size = text_item.format_->text_size * scale_factor;
face_set->set_unscaled_character_sizes(); face_set->set_unscaled_character_sizes();
std::size_t num_faces = face_set->size(); std::size_t num_faces = face_set->size();
std::size_t pos = 0;
font_feature_settings const& ff_settings = text_item.format_->ff_settings; font_feature_settings const& ff_settings = text_item.format_->ff_settings;
int ff_count = safe_cast<int>(ff_settings.count()); int ff_count = safe_cast<int>(ff_settings.count());
@ -104,38 +104,34 @@ static void shape_text(text_line & line,
// this table is filled with information for rendering each glyph, so that // this table is filled with information for rendering each glyph, so that
// several font faces can be used in a single text_item // several font faces can be used in a single text_item
std::vector<glyph_face_info> glyphinfos; std::vector<glyph_face_info> glyphinfos;
unsigned valid_glyphs = 0; int valid_glyphs = 0;
std::size_t pos = 0;
for (auto const& face : *face_set) for (auto const& face : *face_set)
{ {
++pos; ++pos;
hb_buffer_clear_contents(buffer.get()); hb_buffer_clear_contents(buffer.get());
hb_buffer_add_utf16(buffer.get(), uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, static_cast<int>(text_item.end - text_item.start)); hb_buffer_add_utf16(buffer.get(), uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, item_length);
hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL)?HB_DIRECTION_RTL:HB_DIRECTION_LTR); hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
hb_buffer_set_script(buffer.get(), _icu_script_to_script(text_item.script)); hb_buffer_set_script(buffer.get(), _icu_script_to_script(text_item.script));
hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr)); hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
// https://github.com/mapnik/test-data-visual/pull/25 // https://github.com/mapnik/test-data-visual/pull/25
#if HB_VERSION_MAJOR > 0 #if (HB_VERSION_MAJOR > 0 && HB_VERSION_ATLEAST(1, 0, 5))
#if HB_VERSION_ATLEAST(1, 0 , 5) hb_ft_font_set_load_flags(font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); #endif
#endif
#endif
hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count); hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count);
hb_font_destroy(font); hb_font_destroy(font);
unsigned num_glyphs = hb_buffer_get_length(buffer.get()); unsigned num_glyphs = hb_buffer_get_length(buffer.get());
hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), &num_glyphs);
hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), &num_glyphs);
// if the number of rendered glyphs has increased, we need to resize the table // if the number of rendered glyphs has increased, we need to resize the table
if (num_glyphs > glyphinfos.size()) if (num_glyphs > glyphinfos.size())
{ {
glyphinfos.resize(num_glyphs); glyphinfos.resize(num_glyphs);
} }
hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), nullptr);
hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), nullptr);
// Check if all glyphs are valid. // Check if all glyphs are valid.
for (unsigned i=0; i<num_glyphs; ++i) for (unsigned i = 0; i < num_glyphs; ++i)
{ {
// if we have a valid codepoint, save rendering info. // if we have a valid codepoint, save rendering info.
if (glyphs[i].codepoint) if (glyphs[i].codepoint)
@ -143,41 +139,38 @@ static void shape_text(text_line & line,
if (!glyphinfos[i].glyph.codepoint) if (!glyphinfos[i].glyph.codepoint)
{ {
++valid_glyphs; ++valid_glyphs;
glyphinfos[i] = { face, glyphs[i], positions[i] };
} }
glyphinfos[i] = { face, glyphs[i], positions[i] };
} }
} }
if (valid_glyphs < num_glyphs && (pos < num_faces)) if (valid_glyphs < item_length && (pos < num_faces))
{ {
//Try next font in fontset //Try next font in fontset
continue; continue;
} }
double max_glyph_height = 0; double max_glyph_height = 0;
for (unsigned i=0; i<num_glyphs; ++i) for (auto const& info : glyphinfos)
{ {
auto& gpos = positions[i]; if (info.glyph.codepoint)
auto& glyph = glyphs[i];
face_ptr theface = face;
if (glyphinfos[i].glyph.codepoint)
{ {
gpos = glyphinfos[i].position; auto const& gpos = info.position;
glyph = glyphinfos[i].glyph; auto const& glyph = info.glyph;
theface = glyphinfos[i].face; auto const& theface = info.face;
}
unsigned char_index = glyph.cluster; unsigned char_index = glyph.cluster;
glyph_info g(glyph.codepoint,char_index,text_item.format_); glyph_info g(glyph.codepoint, char_index, text_item.format_);
if (theface->glyph_dimensions(g)) if (theface->glyph_dimensions(g))
{ {
g.face = theface; g.face = theface;
g.scale_multiplier = size / theface->get_face()->units_per_EM; g.scale_multiplier = size / theface->get_face()->units_per_EM;
//Overwrite default advance with better value provided by HarfBuzz //Overwrite default advance with better value provided by HarfBuzz
g.unscaled_advance = gpos.x_advance; g.unscaled_advance = gpos.x_advance;
g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier); g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
double tmp_height = g.height(); double tmp_height = g.height();
if (tmp_height > max_glyph_height) max_glyph_height = tmp_height; if (tmp_height > max_glyph_height) max_glyph_height = tmp_height;
width_map[char_index] += g.advance(); width_map[char_index] += g.advance();
line.add_glyph(std::move(g), scale_factor); line.add_glyph(std::move(g), scale_factor);
}
} }
} }
line.update_max_char_height(max_glyph_height); line.update_max_char_height(max_glyph_height);