int main (int argc, char** argv) { if (argc != 2) { std::cerr << "Usage: " << argv[0] << " <num-iter>" << std::endl; return EXIT_FAILURE; } const unsigned NUM_ITER = atoi(argv[1]); // open first face in the font FT_Library ft_library = 0; FT_Error error = FT_Init_FreeType(&ft_library); if (error) throw std::runtime_error("Failed to initialize FreeType2 library"); FT_Face ft_face[NUM_EXAMPLES]; FT_New_Face(ft_library, "fonts/DejaVuSerif.ttf", 0, &ft_face[ENGLISH]); FT_New_Face(ft_library, "fonts/amiri-0.104/amiri-regular.ttf", 0, &ft_face[ARABIC]); FT_New_Face(ft_library, "fonts/fireflysung-1.3.0/fireflysung.ttf", 0, &ft_face[CHINESE]); // Get our harfbuzz font structs hb_font_t *hb_ft_font[NUM_EXAMPLES]; hb_ft_font[ENGLISH] = hb_ft_font_create(ft_face[ENGLISH], NULL); hb_ft_font[ARABIC] = hb_ft_font_create(ft_face[ARABIC] , NULL); hb_ft_font[CHINESE] = hb_ft_font_create(ft_face[CHINESE], NULL); { std::cerr << "Starting ICU shaping:" << std::endl; progress_timer timer1(std::clog,"ICU shaping done"); UErrorCode err = U_ZERO_ERROR; for (unsigned i = 0; i < NUM_ITER; ++i) { for (unsigned j = 0; j < NUM_EXAMPLES; ++j) { UnicodeString text = UnicodeString::fromUTF8(texts[j]); int32_t length = text.length(); UnicodeString reordered; UnicodeString shaped; 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); 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); shaped.releaseBuffer(length); if (U_SUCCESS(err)) { U_NAMESPACE_QUALIFIER StringCharacterIterator iter(shaped); for (iter.setToStart(); iter.hasNext();) { UChar ch = iter.nextPostInc(); int32_t glyph_index = FT_Get_Char_Index(ft_face[j], ch); if (i == 0) { std::cerr << glyph_index << ":"; } } if (i == 0) std::cerr << std::endl; } } } } { const char **shaper_list = hb_shape_list_shapers(); for ( ;*shaper_list; shaper_list++) { std::cerr << *shaper_list << std::endl; } std::cerr << "Starting Harfbuzz shaping" << std::endl; progress_timer timer2(std::clog,"Harfbuzz shaping done"); const char* const shapers[] = { /*"ot",*/"fallback" }; hb_buffer_t *buffer(hb_buffer_create()); for (unsigned i = 0; i < NUM_ITER; ++i) { for (unsigned j = 0; j < NUM_EXAMPLES; ++j) { UnicodeString text = UnicodeString::fromUTF8(texts[j]); int32_t length = text.length(); hb_buffer_clear_contents(buffer); //hb_buffer_set_unicode_funcs(buffer.get(), hb_icu_get_unicode_funcs()); hb_buffer_pre_allocate(buffer, length); hb_buffer_add_utf16(buffer, text.getBuffer(), text.length(), 0, length); hb_buffer_set_direction(buffer, text_directions[j]); hb_buffer_set_script(buffer, scripts[j]); hb_buffer_set_language(buffer,hb_language_from_string(languages[j], std::strlen(languages[j]))); //hb_shape(hb_ft_font[j], buffer.get(), 0, 0); hb_shape_full(hb_ft_font[j], buffer, 0, 0, shapers); unsigned num_glyphs = hb_buffer_get_length(buffer); hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer, NULL); //hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), NULL); for (unsigned k=0; k<num_glyphs; ++k) { int32_t glyph_index = glyphs[k].codepoint; if (i == 0) { std::cerr << glyph_index << ":"; } } if (i == 0) std::cerr << std::endl; } } hb_buffer_destroy(buffer); } // cleanup for (int j=0; j < NUM_EXAMPLES; ++j) { hb_font_destroy(hb_ft_font[j]); } FT_Done_FreeType(ft_library); return EXIT_SUCCESS; }
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(); std::size_t length = end - start; if (!length) return; std::list<text_item> const& list = itemizer.itemize(start, end); line.reserve(length); 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); hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length)); mapnik::value_unicode_string const& text = itemizer.text(); 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(); std::size_t num_faces = face_set->size(); std::size_t pos = 0; font_feature_settings const& ff_settings = text_item.format_->ff_settings; int ff_count = safe_cast<int>(ff_settings.count()); for (auto const& face : *face_set) { ++pos; 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_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_font_t *font(hb_ft_font_create(face->get_face(), nullptr)); // https://github.com/mapnik/test-data-visual/pull/25 #if HB_VERSION_MAJOR > 0 #if HB_VERSION_ATLEAST(1, 0 , 5) hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); #endif #endif hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count); hb_font_destroy(font); unsigned num_glyphs = hb_buffer_get_length(buffer.get()); 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); bool font_has_all_glyphs = true; // Check if all glyphs are valid. for (unsigned i=0; i<num_glyphs; ++i) { if (!glyphs[i].codepoint) { font_has_all_glyphs = false; break; } } if (!font_has_all_glyphs && (pos < num_faces)) { //Try next font in fontset continue; } double max_glyph_height = 0; for (unsigned i=0; i<num_glyphs; ++i) { auto const& gpos = positions[i]; auto const& glyph = glyphs[i]; unsigned char_index = glyph.cluster; glyph_info g(glyph.codepoint,char_index,text_item.format_); if (face->glyph_dimensions(g)) { g.face = face; g.scale_multiplier = size / face->get_face()->units_per_EM; //Overwrite default advance with better value provided by HarfBuzz g.unscaled_advance = gpos.x_advance; g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier); double tmp_height = g.height(); if (tmp_height > max_glyph_height) max_glyph_height = tmp_height; width_map[char_index] += g.advance(); line.add_glyph(std::move(g), scale_factor); } } line.update_max_char_height(max_glyph_height); break; //When we reach this point the current font had all glyphs. } } }