Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expose metadata in protobuf #97

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions proto/glyphs.proto
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Protocol Version 1

package llmr.glyphs;
package mbgl.glyphs;

option optimize_for = LITE_RUNTIME;

// Stores a glyph with metrics and optional SDF bitmap information.
message glyph {
message Glyph {
required uint32 id = 1;

// A signed distance field of the glyph with a border of 3 pixels.
// Signed distance field of a glyph with buffer documented in metadata.
optional bytes bitmap = 2;

// Glyph metrics.
Expand All @@ -19,15 +19,31 @@ message glyph {
required uint32 advance = 7;
}

// Stores fontstack information and a list of faces.
message fontstack {
required string name = 1;
required string range = 2;
repeated glyph glyphs = 3;
// Store a face with glyphs and optional metadata.
message Face {
repeated Glyph glyphs = 1;

// Store SDF metadata.
message Metadata {
optional uint32 size = 1;
optional uint32 buffer = 2;
optional float cutoff = 3;
optional float scale = 4;
optional uint32 granularity = 5;
optional float offset = 6;
optional uint32 radius = 7;
}

optional Metadata metadata = 2;

optional string family_name = 3;
optional string style_name = 4;
optional double ascender = 5;
optional double descender = 6;
optional double line_height = 7;
}

message glyphs {
repeated fontstack stacks = 1;

message Glyphs {
repeated Face faces = 1;
extensions 16 to 8191;
}
113 changes: 55 additions & 58 deletions src/glyphs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ typedef std::pair<Point, Point> SegmentPair;
typedef std::pair<Box, SegmentPair> SegmentValue;
typedef bgi::rtree<SegmentValue, bgi::rstar<16>> Tree;

namespace node_fontnik
{
namespace node_fontnik {

struct FaceMetadata {
std::string family_name;
Expand Down Expand Up @@ -170,15 +169,15 @@ NAN_METHOD(Range) {
start->IntegerValue(),
end->IntegerValue());
uv_queue_work(uv_default_loop(), &baton->request, RangeAsync, (uv_after_work_cb)AfterRange);

NanReturnUndefined();
}

struct ft_library_guard {
ft_library_guard(FT_Library * lib) :
library_(lib) {}

~ft_library_guard()
{
~ft_library_guard() {
if (library_) FT_Done_FreeType(*library_);
}

Expand All @@ -189,8 +188,7 @@ struct ft_glyph_guard {
ft_glyph_guard(FT_Glyph * glyph) :
glyph_(glyph) {}

~ft_glyph_guard()
{
~ft_glyph_guard() {
if (glyph_) FT_Done_Glyph(*glyph_);
}

Expand All @@ -211,8 +209,7 @@ void LoadAsync(uv_work_t* req) {
}
FT_Face ft_face = 0;
int num_faces = 0;
for ( int i = 0; ft_face == 0 || i < num_faces; ++i )
{
for (int i = 0; ft_face == 0 || i < num_faces; ++i) {
FT_Error face_error = FT_New_Memory_Face(library, reinterpret_cast<FT_Byte const*>(baton->font_data), static_cast<FT_Long>(baton->font_size), i, &ft_face);
if (face_error) {
baton->error_name = std::string("could not open font file");
Expand Down Expand Up @@ -286,25 +283,36 @@ void RangeAsync(uv_work_t* req) {

FT_Face ft_face = 0;

llmr::glyphs::glyphs glyphs;
mbgl::glyphs::Glyphs glyphs;

int num_faces = 0;
for ( int i = 0; ft_face == 0 || i < num_faces; ++i )
{
for (int i = 0; ft_face == 0 || i < num_faces; ++i) {
FT_Error face_error = FT_New_Memory_Face(library, reinterpret_cast<FT_Byte const*>(baton->font_data), static_cast<FT_Long>(baton->font_size), i, &ft_face);
if (face_error) {
baton->error_name = std::string("could not open font");
return;
}

llmr::glyphs::fontstack *mutable_fontstack = glyphs.add_stacks();
mutable_fontstack->set_name(std::string(ft_face->family_name) + " " + ft_face->style_name);
mutable_fontstack->set_range(std::to_string(baton->start) + "-" + std::to_string(baton->end));

const double scale_factor = 1.0;
mbgl::glyphs::Face *mutable_face = glyphs.add_faces();
// mutable_face->set_range(std::to_string(baton->start) + "-" + std::to_string(baton->end));
mutable_face->set_family_name(ft_face->family_name);
mutable_face->set_style_name(ft_face->style_name);
mutable_face->set_ascender(ft_face->ascender);
mutable_face->set_descender(ft_face->descender);
mutable_face->set_line_height(ft_face->height);

// Add metadata to face.
mbgl::glyphs::Face::Metadata mutable_metadata = mutable_face->metadata();
mutable_metadata.set_size(char_size);
mutable_metadata.set_buffer(buffer_size);
mutable_metadata.set_cutoff(cutoff_size);
mutable_metadata.set_scale(scale_factor);
mutable_metadata.set_granularity(granularity);
mutable_metadata.set_offset(offset_size);
mutable_metadata.set_radius(radius_size);

// Set character sizes.
double size = 24 * scale_factor;
double size = char_size * scale_factor;
FT_Set_Char_Size(ft_face,0,(FT_F26Dot6)(size * (1<<6)),0,0);

for (std::vector<uint32_t>::size_type x = 0; x != baton->chars.size(); x++) {
Expand All @@ -317,22 +325,23 @@ void RangeAsync(uv_work_t* req) {
if (!char_index) continue;

glyph.glyph_index = char_index;
RenderSDF(glyph, 24, 3, 0.25, ft_face);
RenderSDF(glyph, char_size, buffer_size, cutoff_size, ft_face);

// Add glyph to fontstack.
llmr::glyphs::glyph *mutable_glyph = mutable_fontstack->add_glyphs();
// Add glyph to face.
mbgl::glyphs::Glyph *mutable_glyph = mutable_face->add_glyphs();
mutable_glyph->set_id(char_code);
mutable_glyph->set_width(glyph.width);
mutable_glyph->set_height(glyph.height);
mutable_glyph->set_left(glyph.left);
mutable_glyph->set_top(glyph.top - glyph.ascender);
mutable_glyph->set_top(glyph.top);
mutable_glyph->set_advance(glyph.advance);

if (glyph.width > 0) {
mutable_glyph->set_bitmap(glyph.bitmap);
}

}

if (ft_face) {
FT_Done_Face(ft_face);
}
Expand Down Expand Up @@ -363,20 +372,17 @@ struct User {
Points ring;
};

void CloseRing(Points &ring)
{
void CloseRing(Points &ring) {
const Point &first = ring.front();
const Point &last = ring.back();

if (first.get<0>() != last.get<0>() ||
first.get<1>() != last.get<1>())
{
first.get<1>() != last.get<1>()) {
ring.push_back(first);
}
}

int MoveTo(const FT_Vector *to, void *ptr)
{
int MoveTo(const FT_Vector *to, void *ptr) {
User *user = (User*)ptr;
if (!user->ring.empty()) {
CloseRing(user->ring);
Expand All @@ -387,17 +393,15 @@ int MoveTo(const FT_Vector *to, void *ptr)
return 0;
}

int LineTo(const FT_Vector *to, void *ptr)
{
int LineTo(const FT_Vector *to, void *ptr) {
User *user = (User*)ptr;
user->ring.push_back(Point { float(to->x) / 64, float(to->y) / 64 });
return 0;
}

int ConicTo(const FT_Vector *control,
const FT_Vector *to,
void *ptr)
{
void *ptr) {
User *user = (User*)ptr;

Point prev = user->ring.back();
Expand All @@ -406,8 +410,8 @@ int ConicTo(const FT_Vector *control,
user->ring.pop_back();

agg_fontnik::curve3_div curve(prev.get<0>(), prev.get<1>(),
float(control->x) / 64, float(control->y) / 64,
float(to->x) / 64, float(to->y) / 64);
float(control->x) / 64, float(control->y) / 64,
float(to->x) / 64, float(to->y) / 64);

curve.rewind(0);
double x, y;
Expand All @@ -423,8 +427,7 @@ int ConicTo(const FT_Vector *control,
int CubicTo(const FT_Vector *c1,
const FT_Vector *c2,
const FT_Vector *to,
void *ptr)
{
void *ptr) {
User *user = (User*)ptr;

Point prev = user->ring.back();
Expand All @@ -433,9 +436,9 @@ int CubicTo(const FT_Vector *c1,
user->ring.pop_back();

agg_fontnik::curve4_div curve(prev.get<0>(), prev.get<1>(),
float(c1->x) / 64, float(c1->y) / 64,
float(c2->x) / 64, float(c2->y) / 64,
float(to->x) / 64, float(to->y) / 64);
float(c1->x) / 64, float(c1->y) / 64,
float(c2->x) / 64, float(c2->y) / 64,
float(to->x) / 64, float(to->y) / 64);

curve.rewind(0);
double x, y;
Expand All @@ -449,8 +452,7 @@ int CubicTo(const FT_Vector *c1,
}

// point in polygon ray casting algorithm
bool PolyContainsPoint(const Rings &rings, const Point &p)
{
bool PolyContainsPoint(const Rings &rings, const Point &p) {
bool c = false;

for (const Points &ring : rings) {
Expand All @@ -467,17 +469,15 @@ bool PolyContainsPoint(const Rings &rings, const Point &p)
return c;
}

double SquaredDistance(const Point &v, const Point &w)
{
double SquaredDistance(const Point &v, const Point &w) {
const double a = v.get<0>() - w.get<0>();
const double b = v.get<1>() - w.get<1>();
return a * a + b * b;
}

Point ProjectPointOnLineSegment(const Point &p,
const Point &v,
const Point &w)
{
const Point &w) {
const double l2 = SquaredDistance(v, w);
if (l2 == 0) return v;

Expand All @@ -493,16 +493,14 @@ Point ProjectPointOnLineSegment(const Point &p,

double SquaredDistanceToLineSegment(const Point &p,
const Point &v,
const Point &w)
{
const Point &w) {
const Point s = ProjectPointOnLineSegment(p, v, w);
return SquaredDistance(p, s);
}

double MinDistanceToLineSegment(const Tree &tree,
const Point &p,
int radius)
{
int radius) {
const int squared_radius = radius * radius;

std::vector<SegmentValue> results;
Expand All @@ -529,12 +527,10 @@ double MinDistanceToLineSegment(const Tree &tree,
}

void RenderSDF(glyph_info &glyph,
int size,
int buffer,
float cutoff,
FT_Face ft_face)
{

int size,
int buffer,
float cutoff,
FT_Face ft_face) {
if (FT_Load_Glyph (ft_face, glyph.glyph_index, FT_LOAD_NO_HINTING)) {
return;
}
Expand Down Expand Up @@ -611,8 +607,8 @@ void RenderSDF(glyph_info &glyph,
glyph.height = bbox_ymax - bbox_ymin;

Tree tree;
float offset = 0.5;
int radius = 8;
float offset = offset_size;
int radius = radius_size;

for (const Points &ring : user.rings) {
auto p1 = ring.begin();
Expand Down Expand Up @@ -651,7 +647,7 @@ void RenderSDF(glyph_info &glyph,
double d = MinDistanceToLineSegment(tree, Point {x + offset, y + offset}, radius) * (256 / radius);

// Invert if point is inside.
const bool inside = PolyContainsPoint(user.rings, Point { x + offset, y + offset });
const bool inside = PolyContainsPoint(user.rings, Point {x + offset, y + offset});
if (inside) {
d = -d;
}
Expand All @@ -663,8 +659,9 @@ void RenderSDF(glyph_info &glyph,
// Clamp to 0-255 to prevent overflows or underflows.
int n = d > 255 ? 255 : d;
n = n < 0 ? 0 : n;
n = ((255 - n) / granularity) * granularity;

glyph.bitmap[i] = static_cast<char>(255 - n);
glyph.bitmap[i] = static_cast<char>(n);
}
}
}
Expand Down
Loading