move glyphrange into AsyncRange function

This commit is contained in:
Mike Morris 2014-05-08 17:02:01 -04:00
parent 4e4ecc41c5
commit 22b8310279
2 changed files with 176 additions and 3 deletions

View File

@ -6,7 +6,7 @@
// node
#include <node_buffer.h>
// stl
#include <set>
#include <algorithm>
#include <memory>
#include <iostream>
@ -124,6 +124,180 @@ v8::Handle<v8::Value> Tile::Shape(const v8::Arguments& args) {
void Tile::AsyncShape(uv_work_t* req) {
ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);
// Maps char index (UTF-16) to width. If multiple glyphs map to the
// same char the sum of all widths is used.
// Note: this probably isn't the best solution. it would be better
// to have an object for each cluster, but it needs to be
// implemented with no overhead.
std::map<unsigned, double> width_map_;
fontserver::freetype_engine font_engine_;
fontserver::face_manager_freetype font_manager(font_engine_);
fontserver::text_itemizer itemizer;
fontserver::font_set fset(baton->fontstack);
fset.add_fontstack(baton->fontstack, ',');
fontserver::face_set_ptr face_set = font_manager.get_face_set(fset);
if (!face_set->size()) return;
std::map<fontserver::face_ptr, fontserver::tile_face *> face_map;
std::vector<fontserver::tile_face *> tile_faces;
llmr::vector::tile& tile = baton->tile->tile;
// for every label
for (int i = 0; i < tile.layers_size(); i++) {
const llmr::vector::layer& layer = tile.layers(i);
typedef std::set<int> Strings;
Strings strings;
// Compile a set of all strings we need to shape.
for (int j = 0; j < layer.features_size(); j++) {
const llmr::vector::feature& feature = layer.features(j);
for (int k = 1; k < feature.tags_size(); k += 2) {
const std::string& key = layer.keys(feature.tags(k - 1));
if (key == "name") {
// TODO: handle multiple fonts stacks
strings.insert(feature.tags(k));
}
// TODO: extract all keys we need to shape
}
}
llmr::vector::layer* mutable_layer = tile.mutable_layers(i);
fontserver::text_format format(baton->fontstack, 24);
fontserver::text_format_ptr format_ptr =
std::make_shared<fontserver::text_format>(format);
// Process strings per layer.
for (auto const& key : strings) {
const llmr::vector::value& value = layer.values(key);
std::string text;
if (value.has_string_value()) {
text = value.string_value();
}
if (!text.empty()) {
// Clear cluster widths.
width_map_.clear();
UnicodeString const& str = text.data();
fontserver::text_line line(0, str.length() - 1);
itemizer.add_text(str, format_ptr);
const double scale_factor = 1.0;
// Shape the text.
fontserver::harfbuzz_shaper shaper;
shaper.shape_text(line,
itemizer,
width_map_,
face_set,
// font_manager,
scale_factor);
llmr::vector::label *label = mutable_layer->add_labels();
label->set_text(key);
// TODO: support multiple font stacks
label->set_stack(0);
// Add all glyphs for this labels and add new font
// faces as they appear.
for (auto const& glyph : line) {
if (!glyph.face) {
std::cout << text << ' ' <<
line.size() << " glyphs\n" <<
" codepoint: " << glyph.glyph_index <<
" char_index: " << glyph.char_index <<
" face_ptr: " << glyph.face <<
'\n';
continue;
}
// Try to find whether this font has already been
// used in this tile.
std::map<fontserver::face_ptr, fontserver::tile_face *>::iterator face_map_itr = face_map.find(glyph.face);
if (face_map_itr == face_map.end()) {
fontserver::tile_face *face =
new fontserver::tile_face(glyph.face);
std::pair<fontserver::face_ptr, fontserver::tile_face *> keyed(glyph.face, face);
face_map_itr = face_map.insert(keyed).first;
// Add to shared face cache if not found.
fontserver::font_face_set::iterator face_itr = std::find(face_set->begin(), face_set->end(), glyph.face);
if (face_itr == face_set->end()) {
face_set->add(glyph.face);
}
}
fontserver::tile_face *face = face_map_itr->second;
// Find out whether this font has been used in
// this tile before and get its position.
std::vector<fontserver::tile_face *>::iterator tile_itr = std::find(tile_faces.begin(), tile_faces.end(), face);
if (tile_itr == tile_faces.end()) {
tile_faces.push_back(face);
tile_itr = tile_faces.end() - 1;
}
int tile_face_id = tile_itr - tile_faces.begin();
// Add glyph to tile_face.
face->add_glyph(glyph);
label->add_faces(tile_face_id);
label->add_glyphs(glyph.glyph_index);
label->add_x(width_map_[glyph.char_index]);
label->add_y(glyph.offset.y);
}
itemizer.clear();
}
}
// Add a textual representation of the font so that we can figure out
// later what font we need to use.
for (auto const& face : tile_faces) {
std::string name = face->family + " " + face->style;
mutable_layer->add_faces(name);
// We don't delete the TileFace objects here because
// they are 'owned' by the global faces map and deleted
// later on.
}
// Insert FAKE stacks
mutable_layer->add_stacks(baton->fontstack);
}
// Insert SDF glyphs + bitmaps
for (auto const& face : tile_faces) {
llmr::vector::face *mutable_face = tile.add_faces();
mutable_face->set_family(face->family);
mutable_face->set_style(face->style);
for (auto const& glyph : face->glyphs) {
llmr::vector::glyph *mutable_glyph = mutable_face->add_glyphs();
mutable_glyph->set_id(glyph.glyph_index);
mutable_glyph->set_width(glyph.width);
mutable_glyph->set_height(glyph.height);
mutable_glyph->set_left(glyph.left);
mutable_glyph->set_top(glyph.top);
mutable_glyph->set_advance(glyph.advance);
if (glyph.width > 0) {
mutable_glyph->set_bitmap(glyph.bitmap);
}
}
}
}
void Tile::AsyncRange(uv_work_t* req) {
ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);
fontserver::freetype_engine font_engine_;
fontserver::face_manager_freetype font_manager(font_engine_);
@ -192,8 +366,6 @@ void Tile::AsyncShape(uv_work_t* req) {
mutable_glyph->set_bitmap(glyph.bitmap);
}
}
delete face;
}
}

View File

@ -19,6 +19,7 @@ protected:
static v8::Handle<v8::Value> Shape(const v8::Arguments& args);
static void AsyncShape(uv_work_t* req);
static void AsyncRange(uv_work_t* req);
static void ShapeAfter(uv_work_t* req);
public:
llmr::vector::tile tile;