summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Morris <mikemorris@users.noreply.github.com>2016-04-13 18:42:49 -0700
committerMike Morris <mikemorris@users.noreply.github.com>2016-04-13 18:42:49 -0700
commite39482d5570719654e7206d74a2c7bee1aa96dae (patch)
tree0882fca33ce21b0f5db11a751c788618ed72d912
parentfea3aa573ad49003068f94374d766300fc35247f (diff)
downloadqtlocation-mapboxgl-upstream/harfbuzz.tar.gz
wire in some freetype nonsenseupstream/harfbuzz
-rw-r--r--src/mbgl/geometry/glyph_atlas.cpp2
-rw-r--r--src/mbgl/text/font.cpp266
-rw-r--r--src/mbgl/text/font.hpp5
-rw-r--r--src/mbgl/text/font_stack.cpp26
4 files changed, 135 insertions, 164 deletions
diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp
index 24c1b8c8db..39b286a6b7 100644
--- a/src/mbgl/geometry/glyph_atlas.cpp
+++ b/src/mbgl/geometry/glyph_atlas.cpp
@@ -53,7 +53,7 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
const std::string& stackName,
const SDFGlyph& glyph)
{
- // Use constant value for now.
+ // TODO: Use constant value for now.
const uint8_t buffer = 3;
std::map<uint32_t, GlyphValue>& face = index[stackName];
diff --git a/src/mbgl/text/font.cpp b/src/mbgl/text/font.cpp
index 34cfda4501..2943d59b5b 100644
--- a/src/mbgl/text/font.cpp
+++ b/src/mbgl/text/font.cpp
@@ -1,14 +1,41 @@
#include <mbgl/text/font.hpp>
-#include <harfbuzz/hb-ft.h>
-
#include <fstream>
#include <iostream>
-
#include <codecvt>
+// freetype2
+extern "C" {
+#include FT_GLYPH_H
+// #include FT_OUTLINE_H
+}
+
namespace mbgl {
+struct ft_library_guard {
+ ft_library_guard(FT_Library* lib) :
+ library_(lib) {}
+
+ ~ft_library_guard()
+ {
+ if (library_) FT_Done_FreeType(*library_);
+ }
+
+ FT_Library* library_;
+};
+
+struct ft_glyph_guard {
+ ft_glyph_guard(FT_Glyph* glyph) :
+ glyph_(glyph) {}
+
+ ~ft_glyph_guard()
+ {
+ if (glyph_) FT_Done_Glyph(*glyph_);
+ }
+
+ FT_Glyph* glyph_;
+};
+
Font::Font(const std::string &filename)
: filename_(filename),
font_(0),
@@ -17,6 +44,12 @@ Font::Font(const std::string &filename)
}
Font::~Font() {
+ /*
+ for (FT_Face ft_face : ft_faces) {
+ FT_Done_Face(ft_face);
+ }
+ */
+
hb_buffer_destroy(buffer_);
hb_font_destroy(font_);
}
@@ -25,59 +58,88 @@ void Font::load() {
if (font_) return;
char *font_data;
- unsigned int size;
+ size_t font_size;
std::ifstream file(filename_.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
if (file.is_open())
{
- size = file.tellg();
- font_data = new char[size];
+ font_size = file.tellg();
+ font_data = new char[font_size];
file.seekg(0, std::ios::beg);
- file.read(font_data, size);
+ file.read(font_data, font_size);
file.close();
} else {
std::cerr << "Could not open font!\n";
return;
}
- hb_blob_t *blob = hb_blob_create(font_data, size, HB_MEMORY_MODE_WRITABLE, font_data, [](void* data) {
+/* ------------------------------------------------------------------ */
+
+ FT_Library library = nullptr;
+ ft_library_guard library_guard(&library);
+ FT_Error error = FT_Init_FreeType(&library);
+ if (error) {
+ throw std::runtime_error("Could not open FreeType library");
+ }
+
+ FT_Face ft_face = 0;
+ size_t num_faces = 0;
+ for (size_t i = 0; ft_face == 0 || i < num_faces; ++i) {
+ FT_Error face_error = FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(font_data), static_cast<FT_Long>(font_size), i, &ft_face);
+ if (face_error) {
+ throw std::runtime_error("Could not open font file");
+ }
+
+ if (num_faces == 0) {
+ num_faces = ft_face->num_faces;
+ ft_faces.reserve(num_faces);
+ }
+
+ ft_faces.push_back(ft_face);
+ }
+
+/* ------------------------------------------------------------------ */
+
+ hb_blob_t *blob = hb_blob_create(font_data, font_size, HB_MEMORY_MODE_WRITABLE, font_data, [](void* data) {
delete[] static_cast<char*>(data);
});
hb_face_t *face = hb_face_create(blob, 0 /*face_index*/);
hb_blob_destroy(blob);
font_ = hb_font_create(face);
- // TODO: Font size
+ // TODO: Font size?
upem_ = hb_face_get_upem(face);
- hb_font_set_scale(font_, upem_, upem_);
+
+ // TOOD: currently hardcoded in node-fontnik
+ size = (FT_F26Dot6)(24 * (1<<6)) / (double)upem_;
+ hb_font_set_scale(font_, size, size);
hb_face_destroy(face);
hb_ft_font_set_funcs(font_);
}
-Shaping Font::shape(const std::u32string &text, const float spacing, const vec2<float> &translate) {
+Shaping Font::shape(const std::u32string &text, const float spacing, const vec2<float> &translate, const std::map<uint32_t, SDFGlyph> &sdfs) {
Shaping shaping(translate.x * 24, translate.y * 24, text);
// TODO: the y offset *should* be part of the font metadata
- // const int32_t yOffset = -17;
+ const int32_t yOffset = -17;
- if (!font_) return shaping;
+ float x = 0;
+ const float y = yOffset;
- /*
- std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> cv;
- std::cout << cv.to_bytes(text) << std::endl;
- */
+ if (!font_) return shaping;
+ // TODO: itemize string here
hb_buffer_reset(buffer_);
hb_buffer_add_utf32(buffer_, reinterpret_cast<const uint32_t*>(text.c_str()), text.length(), 0, text.length());
- hb_buffer_set_direction(buffer_, HB_DIRECTION_RTL);
+ hb_buffer_set_direction(buffer_, HB_DIRECTION_LTR);
// hb_buffer_set_direction(buffer, hb_direction_from_string (direction, -1));
- hb_buffer_set_script(buffer_, HB_SCRIPT_ARABIC);
+ hb_buffer_set_script(buffer_, HB_SCRIPT_LATIN);
// hb_buffer_set_script(buffer, hb_script_from_string (script, -1));
- hb_buffer_set_language(buffer_, hb_language_from_string("ar", -1));
+ hb_buffer_set_language(buffer_, hb_language_from_string("en", -1));
// hb_buffer_set_language(buffer, hb_language_from_string (language, -1));
hb_shape(font_, buffer_, 0 /*features*/, 0 /*num_features*/);
@@ -86,135 +148,63 @@ Shaping Font::shape(const std::u32string &text, const float spacing, const vec2<
hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos(buffer_, NULL);
hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions(buffer_, NULL);
+ std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> cv;
+ std::cout << cv.to_bytes(text) <<
+ " num_glyphs: " << num_glyphs <<
+ " upem: " << upem_ <<
+ " size: " << size <<
+ " spacing: " << spacing << std::endl;
+
// Loop through all characters of this label and shape.
+ for (uint32_t chr : text) {
+ auto it = sdfs.find(chr);
+ if (it != sdfs.end()) {
+ std::cout << "chr: " << chr <<
+ " x_advance: "<< it->second.metrics.advance + spacing << std::endl;
+
+ shaping.positionedGlyphs.emplace_back(chr, x, y);
+ x += it->second.metrics.advance + spacing;
+ }
+ }
+
for (int i = 0; i < num_glyphs; i++) {
- uint32_t codepoint = hb_glyph[i].codepoint;
- shaping.positionedGlyphs.emplace_back(codepoint,
- hb_position[i].x_advance + spacing,
- hb_position[i].y_advance);
+ uint32_t glyph = 0;
+ hb_font_get_glyph(font_, hb_glyph[i].codepoint, 0, &glyph);
- /*
- std::cout << "glyph codepoint:" << hb_glyph[i].codepoint <<
+ char* name = new char[128];
+ hb_font_glyph_to_string(font_, hb_glyph[i].codepoint, name, 128);
+
+ std::cout << "glyph_index: " << hb_glyph[i].codepoint <<
+ " name: " << name <<
+ " x_advance: "<< hb_position[i].x_advance <<
" cluster: " << hb_glyph[i].cluster <<
" mask: " << hb_glyph[i].mask <<
- " x_advance: "<< hb_position[i].x_advance << "\n";
- // " y_advance: "<< hb_position[i].y_advance <<
- // " x_offset: "<< hb_position[i].x_offset <<
- // " y_offset: "<< hb_position[i].y_offset << "\n";
- // std::cout << "glyph:" << hb_glyph->codepoint << "\n";
- */
- }
+ " x_advance: "<< hb_position[i].x_advance <<
+ " y_advance: "<< hb_position[i].y_advance <<
+ " x_offset: "<< hb_position[i].x_offset <<
+ " y_offset: "<< hb_position[i].y_offset << std::endl;
- return shaping;
+ FT_ULong char_code;
+ FT_UInt glyph_index;
+ char_code = FT_Get_First_Char(ft_faces[0], &glyph_index);
+ std::cout << "char_code: " << char_code << std::endl;
- /*
- 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(), string.length());
+ /*
+ FT_UInt glyph_index = reinterpret_cast<FT_UInt>(hb_glyph[i].codepoint);
- mapnik::value_unicode_string const& text = itemizer.text();
+ if (FT_Load_Glyph(ft_faces[0], glyph_index, FT_LOAD_NO_HINTING)) {
+ throw std::runtime_error("Failed to load glyph");
+ }
- 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());
-
- // rendering information for a single glyph
- struct glyph_face_info
- {
- face_ptr face;
- hb_glyph_info_t glyph;
- hb_glyph_position_t position;
- };
- // this table is filled with information for rendering each glyph, so that
- // several font faces can be used in a single text_item
- std::vector<glyph_face_info> glyphinfos;
- unsigned valid_glyphs = 0;
-
- 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());
-
- // if the number of rendered glyphs has increased, we need to resize the table
- if (num_glyphs > glyphinfos.size())
- {
- 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.
- for (unsigned i=0; i<num_glyphs; ++i)
- {
- // if we have a valid codepoint, save rendering info.
- if (glyphs[i].codepoint)
- {
- if (!glyphinfos[i].glyph.codepoint)
- {
- ++valid_glyphs;
- }
- glyphinfos[i] = { face, glyphs[i], positions[i] };
- }
- }
- if (valid_glyphs < num_glyphs && (pos < num_faces))
- {
- //Try next font in fontset
- continue;
- }
-
- double max_glyph_height = 0;
- for (unsigned i=0; i<num_glyphs; ++i)
- {
- auto& gpos = positions[i];
- auto& glyph = glyphs[i];
- face_ptr theface = face;
- if (glyphinfos[i].glyph.codepoint)
- {
- gpos = glyphinfos[i].position;
- glyph = glyphinfos[i].glyph;
- theface = glyphinfos[i].face;
- }
- unsigned char_index = glyph.cluster;
- glyph_info g(glyph.codepoint,char_index,text_item.format_);
- if (theface->glyph_dimensions(g))
- {
- g.face = theface;
- g.scale_multiplier = size / theface->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.
+ FT_Glyph ft_glyph = nullptr;
+ ft_glyph_guard glyph_guard(&ft_glyph);
+ if (FT_Get_Glyph(ft_faces[0]->glyph, &ft_glyph)) {
+ throw std::runtime_error("Failed to get glyph");
}
+ */
}
- */
+
+ return shaping;
}
} // end namespace mbgl
diff --git a/src/mbgl/text/font.hpp b/src/mbgl/text/font.hpp
index 9d34b18df1..65e471ed18 100644
--- a/src/mbgl/text/font.hpp
+++ b/src/mbgl/text/font.hpp
@@ -7,6 +7,7 @@
#include <string>
#include <harfbuzz/hb.h>
+#include <harfbuzz/hb-ft.h>
namespace mbgl {
@@ -15,15 +16,17 @@ public:
Font(const std::string &filename);
~Font();
- Shaping shape(const std::u32string &text, const float spacing, const vec2<float> &translate);
+ Shaping shape(const std::u32string &text, const float spacing, const vec2<float> &translate, const std::map<uint32_t, SDFGlyph> &sdfs);
private:
void load();
std::string filename_;
+ std::vector<FT_Face> ft_faces;
hb_font_t *font_;
hb_buffer_t *buffer_;
unsigned int upem_;
+ double size = 0.0;
};
} // end namespace mbgl
diff --git a/src/mbgl/text/font_stack.cpp b/src/mbgl/text/font_stack.cpp
index 4c27a3dc5f..05274be315 100644
--- a/src/mbgl/text/font_stack.cpp
+++ b/src/mbgl/text/font_stack.cpp
@@ -35,31 +35,9 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float ma
const float lineHeight, const float horizontalAlign,
const float verticalAlign, const float justify,
const float spacing, const vec2<float> &translate) const {
- /*
- Shaping shaping(translate.x * 24, translate.y * 24, string);
-
- // TODO: the y offset *should* be part of the font metadata
- const int32_t yOffset = -17;
-
- float x = 0;
- const float y = yOffset;
- */
-
// Create new Harfbuzz font object
- Font font("/Library/Fonts/Arial Unicode.ttf");
- Shaping shaping = font.shape(string, spacing, translate);
-
- /*
- // Loop through all characters of this label and shape.
- for (uint32_t chr : string) {
- auto it = sdfs.find(chr);
- if (it != sdfs.end()) {
- // TODO: change this instead of assuming they stay in order
- shaping.positionedGlyphs.emplace_back(chr, x, y);
- x += it->second.metrics.advance + spacing;
- }
- }
- */
+ Font font("/Users/mikemorris/Desktop/Open_Sans/OpenSans-Regular.ttf");
+ Shaping shaping = font.shape(string, spacing, translate, sdfs);
if (shaping.positionedGlyphs.empty())
return shaping;