Skip to content

Commit

Permalink
Merge pull request #37 from mapbox/char-array
Browse files Browse the repository at this point in the history
Char array
  • Loading branch information
yhahn committed Jun 2, 2014
2 parents f2524ba + db8997f commit 859300b
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 69 deletions.
15 changes: 14 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ conf(env_options);

module.exports = fontserver;
module.exports.range = range;
module.exports.getRange = getRange;

// Retrieve a range of glyphs as a pbf.
function range(options, callback) {
Expand All @@ -21,7 +22,7 @@ function range(options, callback) {
options.fontstack = options.fontstack || 'Open Sans Regular';

var glyphs = new fontserver.Glyphs();
glyphs.range(options.fontstack, options.start, options.end, deflate);
glyphs.range(options.fontstack, options.start + '-' + options.end, getRange(options.start, options.end), deflate);

function deflate(err) {
if (err) return callback(err);
Expand All @@ -39,3 +40,15 @@ function conf(options) {
fontserver.register_fonts(d, {recurse: true});
});
}

function getRange(start, end) {
if (typeof start !== 'number') throw new Error('start must be a number from 0-65533');
if (start < 0) throw new Error('start must be a number from 0-65533');
if (typeof end !== 'number') throw new Error('end must be a number from 0-65533');
if (end > 65533) throw new Error('end must be a number from 0-65533');
if (start > end) throw new Error('start must be less than or equal to end');
var range = [];
for (var i = start; i <= end; i++) range.push(i);
return range;
}

54 changes: 18 additions & 36 deletions src/glyphs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ struct RangeBaton {
v8::Persistent<v8::Function> callback;
Glyphs *glyphs;
std::string fontstack;
std::string range;
bool error;
std::string error_name;
unsigned long start;
unsigned long end;
std::vector<std::uint32_t> chars;
};

v8::Persistent<v8::FunctionTemplate> Glyphs::constructor;
Expand Down Expand Up @@ -103,53 +103,40 @@ v8::Handle<v8::Value> Glyphs::Range(const v8::Arguments& args) {
v8::String::New("fontstack must be a string")));
}

if (args.Length() < 2 || !args[1]->IsNumber()) {
if (args.Length() < 2 || !args[1]->IsString()) {
return ThrowException(v8::Exception::TypeError(
v8::String::New("start must be a number")));
v8::String::New("range must be a string")));
}

if (args.Length() < 3 || !args[2]->IsNumber()) {
if (args.Length() < 3 || !args[2]->IsArray()) {
return ThrowException(v8::Exception::TypeError(
v8::String::New("end must be a number")));
v8::String::New("chars must be an array")));
}

if (args.Length() < 4 || !args[3]->IsFunction()) {
return ThrowException(v8::Exception::TypeError(
v8::String::New("callback must be a function")));
}

v8::String::Utf8Value fontstack(args[0]->ToString());
v8::String::Utf8Value range(args[1]->ToString());
v8::Local<v8::Array> charsArray = v8::Local<v8::Array>::Cast(args[2]);
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(args[3]);

if (args[1]->NumberValue() < 0 || args[1]->NumberValue() > 65533) {
v8::Local<v8::Value> argv[1] = { v8::Exception::Error(v8::String::New("start must be a number from 0-65533")) };
callback->Call(v8::Context::GetCurrent()->Global(), 1, argv);
return v8::Undefined();
}

if (args[2]->NumberValue() < 0 || args[2]->NumberValue() > 65533) {
v8::Local<v8::Value> argv[1] = { v8::Exception::Error(v8::String::New("end must be a number from 0-65533")) };
callback->Call(v8::Context::GetCurrent()->Global(), 1, argv);
return v8::Undefined();
}

if (args[1]->NumberValue() > args[2]->NumberValue()) {
v8::Local<v8::Value> argv[1] = { v8::Exception::Error(v8::String::New("start must be less than or equal to end")) };
callback->Call(v8::Context::GetCurrent()->Global(), 1, argv);
return v8::Undefined();
unsigned array_size = charsArray->Length();
std::vector<std::uint32_t> chars;
for (unsigned i=0; i < array_size; i++) {
chars.push_back(charsArray->Get(i)->IntegerValue());
}

v8::String::Utf8Value fontstack(args[0]->ToString());
unsigned long start = args[1]->NumberValue();
unsigned long end = args[2]->NumberValue();

Glyphs *glyphs = node::ObjectWrap::Unwrap<Glyphs>(args.This());

RangeBaton* baton = new RangeBaton();
baton->callback = v8::Persistent<v8::Function>::New(callback);
baton->glyphs = glyphs;
baton->fontstack = *fontstack;
baton->start = start;
baton->end = end;
baton->range = *range;
baton->chars = chars;

uv_work_t *req = new uv_work_t();
req->data = baton;
Expand Down Expand Up @@ -179,17 +166,11 @@ void Glyphs::AsyncRange(uv_work_t* req) {
return;
}

FT_ULong char_code = baton->start;
FT_ULong char_end = baton->end + 1;

llmr::glyphs::glyphs& glyphs = baton->glyphs->glyphs;

llmr::glyphs::fontstack *mutable_fontstack = glyphs.add_stacks();
mutable_fontstack->set_name(baton->fontstack);

std::stringstream range;
range << baton->start << "-" << baton->end;
mutable_fontstack->set_range(range.str());
mutable_fontstack->set_range(baton->range);

fontserver::text_format format(baton->fontstack, 24);
const double scale_factor = 1.0;
Expand All @@ -198,7 +179,8 @@ void Glyphs::AsyncRange(uv_work_t* req) {
double size = format.text_size * scale_factor;
face_set->set_character_sizes(size);

for (; char_code < char_end; char_code++) {
for (std::vector<uint32_t>::size_type i = 0; i != baton->chars.size(); i++) {
FT_ULong char_code = baton->chars[i];
fontserver::glyph_info glyph;

for (auto const& face : *face_set) {
Expand Down
26 changes: 26 additions & 0 deletions test/expected/chars.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"stacks": {
"Open Sans Regular, Siyam Rupali Regular": {
"glyphs": {
"97": {
"id": 97,
"width": 11,
"height": 15,
"left": 1,
"top": -12,
"advance": 13
},
"122": {
"id": 122,
"width": 11,
"height": 13,
"left": 0,
"top": -13,
"advance": 11
}
},
"name": "Open Sans Regular, Siyam Rupali Regular",
"range": "a-and-z"
}
}
}
76 changes: 44 additions & 32 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('glyphs', function() {

it('range', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('Open Sans Regular, Siyam Rupali Regular', 0, 256, function(err) {
glyphs.range('Open Sans Regular, Siyam Rupali Regular', '0-256', fontserver.getRange(0, 256), function(err) {
assert.ifError(err);
var vt = new Glyphs(new Protobuf(new Uint8Array(glyphs.serialize())));
var json = JSON.parse(JSON.stringify(vt, nobuffer));
Expand All @@ -57,41 +57,62 @@ describe('glyphs', function() {
});
});

// Render a long range of characters which can cause segfaults
// with V8 arrays ... not sure yet why.
it('longrange', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('Open Sans Regular, Siyam Rupali Regular', '0-1024', fontserver.getRange(0, 1024), function(err) {
assert.ifError(err);
done();
});
});

it('range (chars input)', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('Open Sans Regular, Siyam Rupali Regular', 'a-and-z', [('a').charCodeAt(0), ('z').charCodeAt(0)], function(err) {
assert.ifError(err);
var vt = new Glyphs(new Protobuf(new Uint8Array(glyphs.serialize())));
var json = JSON.parse(JSON.stringify(vt, nobuffer));
jsonEqual('chars', json);
done();
});
});

it('range typeerror fontstack', function(done) {
var glyphs = new fontserver.Glyphs();
assert.throws(function() {
glyphs.range(0, 0, 256, function() {});
glyphs.range(0, '0-256', fontserver.getRange(0, 256), function() {});
}, /fontstack must be a string/);
done();
});

it('range typeerror start', function(done) {
it('range typeerror range', function(done) {
var glyphs = new fontserver.Glyphs();
assert.throws(function() {
glyphs.range('Open Sans Regular', 'foo', 256, function() {});
}, /start must be a number/);
glyphs.range('Open Sans Regular', 0, fontserver.getRange(0, 256), function() {});
}, /range must be a string/);
done();
});

it('range typeerror end', function(done) {
it('range typeerror chars', function(done) {
var glyphs = new fontserver.Glyphs();
assert.throws(function() {
glyphs.range('Open Sans Regular', 0, 'foo', function() {});
}, /end must be a number/);
glyphs.range('Open Sans Regular', '0-256', 'foo', function() {});
}, /chars must be an array/);
done();
});

it('range typeerror callback', function(done) {
var glyphs = new fontserver.Glyphs();
assert.throws(function() {
glyphs.range('Open Sans Regular', 0, 256, '');
glyphs.range('Open Sans Regular', '0-256', fontserver.getRange(0, 256), '');
}, /callback must be a function/);
done();
});

it('range for fontstack with 0 matching fonts', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('doesnotexist', 0, 256, function(err) {
glyphs.range('doesnotexist', '0-256', fontserver.getRange(0, 256), function(err) {
assert.ok(err);
assert.equal('Error: Failed to find face doesnotexist', err.toString());
done();
Expand All @@ -100,41 +121,32 @@ describe('glyphs', function() {

it('range for fontstack with 1 bad font', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('Open Sans Regular, doesnotexist', 0, 256, function(err) {
glyphs.range('Open Sans Regular, doesnotexist', '0-256', fontserver.getRange(0, 256), function(err) {
assert.ok(err);
assert.equal('Error: Failed to find face doesnotexist', err.toString());
done();
});
});

// Should error because start is < 0
it('range error start < 0', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('Open Sans Regular', -128, 256, function(err) {
assert.ok(err);
assert.equal('Error: start must be a number from 0-65533', err.toString());
done();
});
it('getRange error start < 0', function() {
assert.throws(function() {
fontserver.getRange(-128, 256);
}, 'Error: start must be a number from 0-65533');
});

// Should error because end < start
it('range error end < start', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('Open Sans Regular', 256, 0, function(err) {
assert.ok(err);
assert.equal('Error: start must be less than or equal to end', err.toString());
done();
});
it('getRange error end < start', function() {
assert.throws(function() {
fontserver.getRange(256, 0);
}, 'Error: start must be less than or equal to end');
});

// Should error because end > 65533
it('range error end > 65533', function(done) {
var glyphs = new fontserver.Glyphs();
glyphs.range('Open Sans Regular', 0, 65534, function(err) {
assert.ok(err);
assert.equal('Error: end must be a number from 0-65533', err.toString());
done();
});
it('getRange error end > 65533', function() {
assert.throws(function() {
fontserver.getRange(0, 65534);
}, 'Error: end must be a number from 0-65533');
});
});

0 comments on commit 859300b

Please sign in to comment.