diff --git a/fonts/osaka/Osaka.ttf b/fonts/osaka/Osaka.ttf new file mode 100644 index 000000000..88dea185c Binary files /dev/null and b/fonts/osaka/Osaka.ttf differ diff --git a/src/glyphs.cpp b/src/glyphs.cpp index 0525ff041..27b1bc821 100644 --- a/src/glyphs.cpp +++ b/src/glyphs.cpp @@ -180,18 +180,6 @@ struct ft_library_guard { 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_; -}; - void LoadAsync(uv_work_t* req) { LoadBaton* baton = static_cast(req->data); @@ -548,10 +536,6 @@ void RenderSDF(glyph_info &glyph, return; } - FT_Glyph ft_glyph = nullptr; - ft_glyph_guard glyph_guard(&ft_glyph); - if (FT_Get_Glyph(ft_face->glyph, &ft_glyph)) return; - int advance = ft_face->glyph->metrics.horiAdvance / 64; int ascender = ft_face->size->metrics.ascender / 64; int descender = ft_face->size->metrics.descender / 64; @@ -572,16 +556,22 @@ void RenderSDF(glyph_info &glyph, User user; - // Decompose outline into bezier curves and line segments - FT_Outline outline = ((FT_OutlineGlyph)ft_glyph)->outline; - if (FT_Outline_Decompose(&outline, &func_interface, &user)) return; + if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + // Decompose outline into bezier curves and line segments + FT_Outline outline = ft_face->glyph->outline; + if (FT_Outline_Decompose(&outline, &func_interface, &user)) return; - if (!user.ring.empty()) { - CloseRing(user.ring); - user.rings.push_back(user.ring); - } + if (!user.ring.empty()) { + CloseRing(user.ring); + user.rings.push_back(user.ring); + } - if (user.rings.empty()) return; + if (user.rings.empty()) { + return; + } + } else { + return; + } // Calculate the real glyph bbox. double bbox_xmin = std::numeric_limits::infinity(), diff --git a/test/fontnik.test.js b/test/fontnik.test.js index b5661a7ee..4685a9ee9 100644 --- a/test/fontnik.test.js +++ b/test/fontnik.test.js @@ -25,6 +25,7 @@ var expected = JSON.parse(fs.readFileSync(__dirname + '/expected/load.json').toS var firasans = fs.readFileSync(path.resolve(__dirname + '/../fonts/firasans-medium/FiraSans-Medium.ttf')); var opensans = fs.readFileSync(path.resolve(__dirname + '/../fonts/open-sans/OpenSans-Regular.ttf')); var guardianbold = fs.readFileSync(path.resolve(__dirname + '/../fonts/GuardianTextSansWeb/GuardianTextSansWeb-Bold.ttf')); +var osaka = fs.readFileSync(path.resolve(__dirname + '/../fonts/osaka/Osaka.ttf')); test('load', function(t) { t.test('loads: Fira Sans', function(t) { @@ -59,10 +60,24 @@ test('load', function(t) { }); }); - t.test('invalid font loading', function(t) { + t.test('loads: Osaka', function(t) { + fontnik.load(osaka, function(err, faces) { + t.error(err); + t.equal(faces[0].family_name, 'Osaka'); + t.equal(faces[0].style_name, 'Regular'); + t.end(); + }); + }); + + t.test('invalid arguments', function(t) { t.throws(function() { - fontnik.load(undefined, function(err, faces) {}); + fontnik.load(); }, /First argument must be a font buffer/); + + t.throws(function() { + fontnik.load({}); + }, /First argument must be a font buffer/); + t.end(); }); @@ -93,12 +108,32 @@ test('range', function(t) { t.test('ranges', function(t) { fontnik.range({font: opensans, start: 0, end: 256}, function(err, res) { t.error(err); - t.ok(res); - t.deepEqual(res, data); - var vt = new Glyphs(new Protobuf(new Uint8Array(res))); - var json = JSON.parse(JSON.stringify(vt, nobuffer)); - jsonEqual(t, 'range', json); - t.end(); + t.ok(data); + + var zpath = __dirname + '/fixtures/range.0.256.pbf'; + + function compare() { + zlib.inflate(fs.readFileSync(zpath), function(err, inflated) { + t.error(err); + t.deepEqual(data, inflated); + + var vt = new Glyphs(new Protobuf(new Uint8Array(data))); + var json = JSON.parse(JSON.stringify(vt, nobuffer)); + jsonEqual(t, 'range', json); + + t.end(); + }); + } + + if (UPDATE) { + zlib.deflate(data, function(err, zdata) { + t.error(err); + fs.writeFileSync(zpath, zdata); + compare(); + }); + } else { + compare(); + } }); }); @@ -121,17 +156,27 @@ test('range', function(t) { }); }); - t.test('range typeerror options', function(t) { + t.test('invalid arguments', function(t) { t.throws(function() { - fontnik.range(opensans, function(err, data) {}); + fontnik.range(); + }, /First argument must be an object of options/); + + t.throws(function() { + fontnik.range({font:'not an object'}, function(err, data) {}); }, /Font buffer is not an object/); + + t.throws(function() { + fontnik.range({font:{}}, function(err, data) {}); + }, /First argument must be a font buffer/); + t.end(); }); t.test('range filepath does not exist', function(t) { var doesnotexistsans = new Buffer('baloney'); fontnik.range({font: doesnotexistsans, start: 0, end: 256}, function(err, faces) { - t.ok(err.message.indexOf('Font buffer is not an object')); + t.ok(err); + t.equal(err.message, 'could not open font'); t.end(); }); }); @@ -183,4 +228,23 @@ test('range', function(t) { t.end(); }); }); + + t.test('range with osaka', function(t) { + fontnik.range({font: osaka, start:0, end: 256}, function(err, data) { + t.error(err); + var vt = new Glyphs(new Protobuf(new Uint8Array(data))); + var glyphs = vt.stacks['Osaka Regular'].glyphs; + var keys = Object.keys(glyphs); + + var glyph; + for (var i = 0; i < keys.length; i++) { + glyph = glyphs[keys[i]]; + t.deepEqual(Object.keys(glyph), ['id', 'width', 'height', 'left', 'top', 'advance']); + t.equal(glyph.width, 0); + t.equal(glyph.height, 0); + } + + t.end(); + }); + }); });