expose map.release() method
This commit is contained in:
@@ -100,6 +100,7 @@ install:
|
||||
|
||||
before_script:
|
||||
- ulimit -c unlimited -S
|
||||
- ulimit -a
|
||||
|
||||
script:
|
||||
- "./scripts/travis_test.sh"
|
||||
|
||||
@@ -30,6 +30,10 @@ static std::shared_ptr<mbgl::HeadlessDisplay> sharedDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
const static char* releasedMessage() {
|
||||
return "Map resources have already been released";
|
||||
}
|
||||
|
||||
void NodeMap::Init(v8::Handle<v8::Object> target) {
|
||||
NanScope();
|
||||
|
||||
@@ -40,6 +44,7 @@ void NodeMap::Init(v8::Handle<v8::Object> target) {
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "load", Load);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "render", Render);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "release", Release);
|
||||
|
||||
NanAssignPersistent(constructorTemplate, t);
|
||||
|
||||
@@ -72,8 +77,8 @@ NAN_METHOD(NodeMap::New) {
|
||||
|
||||
|
||||
try {
|
||||
auto map = new NodeMap(source);
|
||||
map->Wrap(args.This());
|
||||
auto nodeMap = new NodeMap(source);
|
||||
nodeMap->Wrap(args.This());
|
||||
} catch(std::exception &ex) {
|
||||
return NanThrowError(ex.what());
|
||||
}
|
||||
@@ -81,7 +86,6 @@ NAN_METHOD(NodeMap::New) {
|
||||
NanReturnValue(args.This());
|
||||
}
|
||||
|
||||
|
||||
const std::string StringifyStyle(v8::Handle<v8::Value> styleHandle) {
|
||||
NanScope();
|
||||
|
||||
@@ -94,6 +98,10 @@ const std::string StringifyStyle(v8::Handle<v8::Value> styleHandle) {
|
||||
NAN_METHOD(NodeMap::Load) {
|
||||
NanScope();
|
||||
|
||||
auto nodeMap = node::ObjectWrap::Unwrap<NodeMap>(args.Holder());
|
||||
|
||||
if (!nodeMap->isValid()) return NanThrowError(releasedMessage());
|
||||
|
||||
if (args.Length() < 1) {
|
||||
return NanThrowError("Requires a map style as first argument");
|
||||
}
|
||||
@@ -108,10 +116,8 @@ NAN_METHOD(NodeMap::Load) {
|
||||
return NanThrowTypeError("First argument must be a string or object");
|
||||
}
|
||||
|
||||
auto nodeMap = node::ObjectWrap::Unwrap<NodeMap>(args.Holder());
|
||||
|
||||
try {
|
||||
nodeMap->map.setStyleJSON(style, ".");
|
||||
nodeMap->map->setStyleJSON(style, ".");
|
||||
} catch (const std::exception &ex) {
|
||||
return NanThrowError(ex.what());
|
||||
}
|
||||
@@ -150,6 +156,10 @@ std::unique_ptr<NodeMap::RenderOptions> NodeMap::ParseOptions(v8::Local<v8::Obje
|
||||
NAN_METHOD(NodeMap::Render) {
|
||||
NanScope();
|
||||
|
||||
auto nodeMap = node::ObjectWrap::Unwrap<NodeMap>(args.Holder());
|
||||
|
||||
if (!nodeMap->isValid()) return NanThrowError(releasedMessage());
|
||||
|
||||
if (args.Length() <= 0 || !args[0]->IsObject()) {
|
||||
return NanThrowTypeError("First argument must be an options object");
|
||||
}
|
||||
@@ -160,8 +170,6 @@ NAN_METHOD(NodeMap::Render) {
|
||||
|
||||
auto options = ParseOptions(args[0]->ToObject());
|
||||
|
||||
auto nodeMap = node::ObjectWrap::Unwrap<NodeMap>(args.Holder());
|
||||
|
||||
assert(!nodeMap->callback);
|
||||
assert(!nodeMap->image);
|
||||
nodeMap->callback = std::unique_ptr<NanCallback>(new NanCallback(args[1].As<v8::Function>()));
|
||||
@@ -176,12 +184,12 @@ NAN_METHOD(NodeMap::Render) {
|
||||
}
|
||||
|
||||
void NodeMap::startRender(std::unique_ptr<NodeMap::RenderOptions> options) {
|
||||
map.resize(options->width, options->height, options->ratio);
|
||||
map.setClasses(options->classes);
|
||||
map.setLatLngZoom(mbgl::LatLng(options->latitude, options->longitude), options->zoom);
|
||||
map.setBearing(options->bearing);
|
||||
map->resize(options->width, options->height, options->ratio);
|
||||
map->setClasses(options->classes);
|
||||
map->setLatLngZoom(mbgl::LatLng(options->latitude, options->longitude), options->zoom);
|
||||
map->setBearing(options->bearing);
|
||||
|
||||
map.renderStill([this](const std::exception_ptr eptr, std::unique_ptr<const mbgl::StillImage> result) {
|
||||
map->renderStill([this](const std::exception_ptr eptr, std::unique_ptr<const mbgl::StillImage> result) {
|
||||
if (eptr) {
|
||||
error = std::move(eptr);
|
||||
uv_async_send(async);
|
||||
@@ -261,6 +269,36 @@ void NodeMap::renderFinished() {
|
||||
}
|
||||
}
|
||||
|
||||
NAN_METHOD(NodeMap::Release) {
|
||||
NanScope();
|
||||
|
||||
auto nodeMap = node::ObjectWrap::Unwrap<NodeMap>(args.Holder());
|
||||
|
||||
if (!nodeMap->isValid()) return NanThrowError(releasedMessage());
|
||||
|
||||
try {
|
||||
nodeMap->release();
|
||||
} catch (const std::exception &ex) {
|
||||
return NanThrowError(ex.what());
|
||||
}
|
||||
|
||||
NanReturnUndefined();
|
||||
}
|
||||
|
||||
void NodeMap::release() {
|
||||
if (!isValid()) throw mbgl::util::Exception(releasedMessage());
|
||||
|
||||
valid = false;
|
||||
|
||||
NanDisposePersistent(source);
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t *>(async), [] (uv_handle_t *handle) {
|
||||
delete reinterpret_cast<uv_async_t *>(handle);
|
||||
});
|
||||
|
||||
map.reset(nullptr);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Instance
|
||||
@@ -268,7 +306,7 @@ void NodeMap::renderFinished() {
|
||||
NodeMap::NodeMap(v8::Handle<v8::Object> source_) :
|
||||
view(sharedDisplay()),
|
||||
fs(*ObjectWrap::Unwrap<NodeFileSource>(source_)),
|
||||
map(view, fs, mbgl::MapMode::Still),
|
||||
map(std::make_unique<mbgl::Map>(view, fs, mbgl::MapMode::Still)),
|
||||
async(new uv_async_t) {
|
||||
|
||||
NanAssignPersistent(source, source_);
|
||||
@@ -287,11 +325,7 @@ NodeMap::NodeMap(v8::Handle<v8::Object> source_) :
|
||||
}
|
||||
|
||||
NodeMap::~NodeMap() {
|
||||
NanDisposePersistent(source);
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t *>(async), [] (uv_handle_t *handle) {
|
||||
delete reinterpret_cast<uv_async_t *>(handle);
|
||||
});
|
||||
if (valid) release();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,10 +27,14 @@ public:
|
||||
static NAN_METHOD(New);
|
||||
static NAN_METHOD(Load);
|
||||
static NAN_METHOD(Render);
|
||||
static NAN_METHOD(Release);
|
||||
|
||||
void startRender(std::unique_ptr<NodeMap::RenderOptions> options);
|
||||
void renderFinished();
|
||||
|
||||
void release();
|
||||
inline bool isValid() { return valid; }
|
||||
|
||||
static std::unique_ptr<NodeMap::RenderOptions> ParseOptions(v8::Local<v8::Object> obj);
|
||||
|
||||
static v8::Persistent<v8::FunctionTemplate> constructorTemplate;
|
||||
@@ -47,7 +51,7 @@ private:
|
||||
|
||||
mbgl::HeadlessView view;
|
||||
NodeFileSource &fs;
|
||||
mbgl::Map map;
|
||||
std::unique_ptr<mbgl::Map> map;
|
||||
|
||||
std::exception_ptr error;
|
||||
std::unique_ptr<const mbgl::StillImage> image;
|
||||
@@ -55,6 +59,8 @@ private:
|
||||
|
||||
// Async for delivering the notifications of render completion.
|
||||
uv_async_t *async;
|
||||
|
||||
bool valid = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ function renderTest(style, info, dir, key) {
|
||||
function render() {
|
||||
map.render(info[key], function(err, image) {
|
||||
t.error(err);
|
||||
|
||||
t.ok(true, 'render @ ' + ((+new Date) - start) + 'ms');
|
||||
if (++completed === remaining) {
|
||||
map.release();
|
||||
t.end();
|
||||
} else {
|
||||
render();
|
||||
|
||||
@@ -69,6 +69,8 @@ test('gzip', function(t) {
|
||||
map.render({}, function(err, data) {
|
||||
t.error(err);
|
||||
|
||||
map.release();
|
||||
|
||||
mbgl.removeAllListeners('message');
|
||||
|
||||
var filename = filePath('success.png');
|
||||
@@ -119,6 +121,8 @@ test('gzip', function(t) {
|
||||
map.render({}, function(err, data) {
|
||||
if (!errorEmitted) t.fail('no error emitted');
|
||||
|
||||
map.release();
|
||||
|
||||
mbgl.removeAllListeners('message');
|
||||
|
||||
var filename = filePath('unhandled.png');
|
||||
|
||||
@@ -94,19 +94,25 @@ test('Map', function(t) {
|
||||
t.throws(function() {
|
||||
map.load();
|
||||
}, /Requires a map style as first argument/);
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
t.test('expect either an object or array at root', { timeout: 1000 }, function(t) {
|
||||
mbgl.once('message', function(msg) {
|
||||
t.equal(msg.severity, 'ERROR');
|
||||
t.equal(msg.class, 'ParseStyle');
|
||||
t.ok(msg.text.match(/Expect either an object or array at root/));
|
||||
t.end();
|
||||
});
|
||||
|
||||
setup(fileSource, function(map) {
|
||||
mbgl.once('message', function(msg) {
|
||||
t.equal(msg.severity, 'ERROR');
|
||||
t.equal(msg.class, 'ParseStyle');
|
||||
t.ok(msg.text.match(/Expect either an object or array at root/));
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
map.load('invalid');
|
||||
});
|
||||
});
|
||||
@@ -119,6 +125,9 @@ test('Map', function(t) {
|
||||
t.doesNotThrow(function() {
|
||||
map.load('{}');
|
||||
});
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
@@ -132,6 +141,9 @@ test('Map', function(t) {
|
||||
t.doesNotThrow(function() {
|
||||
map.load(style);
|
||||
});
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
@@ -145,6 +157,9 @@ test('Map', function(t) {
|
||||
t.doesNotThrow(function() {
|
||||
map.load(JSON.stringify(style));
|
||||
});
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
@@ -171,6 +186,8 @@ test('Map', function(t) {
|
||||
map.render('invalid');
|
||||
}, /First argument must be an options object/);
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
@@ -185,6 +202,8 @@ test('Map', function(t) {
|
||||
map.render({}, 'invalid');
|
||||
}, /Second argument must be a callback function/);
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
@@ -194,14 +213,22 @@ test('Map', function(t) {
|
||||
t.throws(function() {
|
||||
map.render({}, function() {});
|
||||
}, /Style is not set/);
|
||||
|
||||
map.release();
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
t.test('returns an error', function(t) {
|
||||
mbgl.once('message', function(msg) {
|
||||
console.log(msg);
|
||||
});
|
||||
|
||||
setup(fileSource, function(map) {
|
||||
map.load(style);
|
||||
map.render({ zoom: 1 }, function(err, data) {
|
||||
map.release();
|
||||
t.ok(err);
|
||||
t.equal(err.message, 'Error rendering image');
|
||||
t.end();
|
||||
@@ -209,12 +236,26 @@ test('Map', function(t) {
|
||||
});
|
||||
});
|
||||
|
||||
t.test('double release', function(t) {
|
||||
setup(fileSource, function(map) {
|
||||
map.release();
|
||||
|
||||
t.throws(function() {
|
||||
map.release();
|
||||
}, /Map resources have already been released/);
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
t.test('returns an image', function(t) {
|
||||
setup(fileSource, function(map) {
|
||||
map.load(style);
|
||||
map.render({}, function(err, data) {
|
||||
t.error(err);
|
||||
|
||||
map.release();
|
||||
|
||||
var filename = filePath('image.png');
|
||||
|
||||
var png = new PNG({
|
||||
|
||||
@@ -54,6 +54,8 @@ function renderTest(style, info, base, key) {
|
||||
map.render(info[key], function(err, data) {
|
||||
t.error(err);
|
||||
|
||||
map.release();
|
||||
|
||||
var expected = path.join(dir, 'expected.png');
|
||||
var actual = path.join(dir, 'actual.png');
|
||||
var diff = path.join(dir, 'diff.png');
|
||||
|
||||
Reference in New Issue
Block a user