summaryrefslogtreecommitdiff
path: root/platform/node/src/node_map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/node/src/node_map.cpp')
-rw-r--r--platform/node/src/node_map.cpp208
1 files changed, 93 insertions, 115 deletions
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 1c8bf6d1d2..9a7ebce445 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -4,14 +4,15 @@
#include "node_conversion.hpp"
#include "node_geojson.hpp"
-#include <mbgl/gl/headless_display.hpp>
#include <mbgl/util/exception.hpp>
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/map/query.hpp>
+#include <mbgl/map/map_observer.hpp>
#include <mbgl/util/premultiply.hpp>
#include <unistd.h>
@@ -24,27 +25,18 @@ struct NodeMap::RenderOptions {
double pitch = 0;
double latitude = 0;
double longitude = 0;
- unsigned int width = 512;
- unsigned int height = 512;
+ mbgl::Size size = { 512, 512 };
std::vector<std::string> classes;
mbgl::MapDebugOptions debugOptions = mbgl::MapDebugOptions::NoDebug;
};
Nan::Persistent<v8::Function> NodeMap::constructor;
-static std::shared_ptr<mbgl::HeadlessDisplay> sharedDisplay() {
- static auto display = std::make_shared<mbgl::HeadlessDisplay>();
- return display;
-}
-
static const char* releasedMessage() {
return "Map resources have already been released";
}
-NodeBackend::NodeBackend()
- : HeadlessBackend(sharedDisplay()) {}
-
-void NodeBackend::onDidFailLoadingMap(std::exception_ptr error) {
+void NodeMapObserver::onDidFailLoadingMap(std::exception_ptr error) {
std::rethrow_exception(error);
}
@@ -60,8 +52,8 @@ void NodeMap::Init(v8::Local<v8::Object> target) {
Nan::SetPrototypeMethod(tpl, "release", Release);
Nan::SetPrototypeMethod(tpl, "cancel", Cancel);
- Nan::SetPrototypeMethod(tpl, "addClass", AddClass);
Nan::SetPrototypeMethod(tpl, "addSource", AddSource);
+ Nan::SetPrototypeMethod(tpl, "removeSource", RemoveSource);
Nan::SetPrototypeMethod(tpl, "addLayer", AddLayer);
Nan::SetPrototypeMethod(tpl, "removeLayer", RemoveLayer);
Nan::SetPrototypeMethod(tpl, "addImage", AddImage);
@@ -79,9 +71,6 @@ void NodeMap::Init(v8::Local<v8::Object> target) {
constructor.Reset(tpl->GetFunction());
Nan::Set(target, Nan::New("Map").ToLocalChecked(), tpl->GetFunction());
-
- // Initialize display connection on module load.
- sharedDisplay();
}
/**
@@ -163,25 +152,15 @@ void NodeMap::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(info.This());
}
-std::string StringifyStyle(v8::Local<v8::Value> styleHandle) {
- Nan::HandleScope scope;
-
- v8::Local<v8::Object> JSON = Nan::To<v8::Object>(
- Nan::Get(
- Nan::GetCurrentContext()->Global(),
- Nan::New("JSON").ToLocalChecked()
- ).ToLocalChecked()
- ).ToLocalChecked();
-
- return *Nan::Utf8String(Nan::MakeCallback(JSON, "stringify", 1, &styleHandle));
-}
-
/**
* Load a stylesheet
*
* @function
* @name load
* @param {string|Object} stylesheet either an object or a JSON representation
+ * @param {Object} options
+ * @param {boolean} options.defaultStyleCamera if true, sets the default style
+ * camera
* @returns {undefined} loads stylesheet into map
* @throws {Error} if stylesheet is missing or invalid
* @example
@@ -206,7 +185,8 @@ void NodeMap::Load(const Nan::FunctionCallbackInfo<v8::Value>& info) {
std::string style;
if (info[0]->IsObject()) {
- style = StringifyStyle(info[0]);
+ Nan::JSON JSON;
+ style = *Nan::Utf8String(JSON.Stringify(info[0]->ToObject()).ToLocalChecked());
} else if (info[0]->IsString()) {
style = *Nan::Utf8String(info[0]);
} else {
@@ -214,11 +194,26 @@ void NodeMap::Load(const Nan::FunctionCallbackInfo<v8::Value>& info) {
}
try {
- nodeMap->map->setStyleJSON(style);
+ nodeMap->map->getStyle().loadJSON(style);
} catch (const std::exception &ex) {
return Nan::ThrowError(ex.what());
}
+ if (info.Length() == 2) {
+ if (!info[1]->IsObject()) {
+ return Nan::ThrowTypeError("Second argument must be an options object");
+ }
+ auto options = Nan::To<v8::Object>(info[1]).ToLocalChecked();
+ if (Nan::Has(options, Nan::New("defaultStyleCamera").ToLocalChecked()).FromJust()) {
+ if (!Nan::Get(options, Nan::New("defaultStyleCamera").ToLocalChecked()).ToLocalChecked()->IsBoolean()) {
+ return Nan::ThrowError("Options object 'defaultStyleCamera' property must be a boolean");
+ }
+ if (Nan::Get(options, Nan::New("cameraMutated").ToLocalChecked()).ToLocalChecked()->BooleanValue()) {
+ nodeMap->map->jumpTo(nodeMap->map->getStyle().getDefaultCamera());
+ }
+ }
+ }
+
nodeMap->loaded = true;
info.GetReturnValue().SetUndefined();
@@ -266,11 +261,11 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
}
if (Nan::Has(obj, Nan::New("width").ToLocalChecked()).FromJust()) {
- options.width = Nan::Get(obj, Nan::New("width").ToLocalChecked()).ToLocalChecked()->IntegerValue();
+ options.size.width = Nan::Get(obj, Nan::New("width").ToLocalChecked()).ToLocalChecked()->IntegerValue();
}
if (Nan::Has(obj, Nan::New("height").ToLocalChecked()).FromJust()) {
- options.height = Nan::Get(obj, Nan::New("height").ToLocalChecked()).ToLocalChecked()->IntegerValue();
+ options.size.height = Nan::Get(obj, Nan::New("height").ToLocalChecked()).ToLocalChecked()->IntegerValue();
}
if (Nan::Has(obj, Nan::New("classes").ToLocalChecked()).FromJust()) {
@@ -278,7 +273,7 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
const int length = classes->Length();
options.classes.reserve(length);
for (int i = 0; i < length; i++) {
- options.classes.push_back(std::string { *Nan::Utf8String(Nan::To<v8::String>(Nan::Get(classes, i).ToLocalChecked()).ToLocalChecked()) });
+ options.classes.emplace_back(std::string { *Nan::Utf8String(Nan::To<v8::String>(Nan::Get(classes, i).ToLocalChecked()).ToLocalChecked()) });
}
}
@@ -366,48 +361,22 @@ void NodeMap::Render(const Nan::FunctionCallbackInfo<v8::Value>& info) {
}
void NodeMap::startRender(NodeMap::RenderOptions options) {
- map->setSize({ options.width, options.height });
+ frontend->setSize(options.size);
+ map->setSize(options.size);
- const mbgl::Size fbSize{ static_cast<uint32_t>(options.width * pixelRatio),
- static_cast<uint32_t>(options.height * pixelRatio) };
- if (!view || view->getSize() != fbSize) {
- view.reset();
- mbgl::BackendScope scope { backend };
- view = std::make_unique<mbgl::OffscreenView>(backend.getContext(), fbSize);
- }
-
- if (map->getClasses() != options.classes) {
- map->setClasses(options.classes);
- }
-
- if (map->getZoom() != options.zoom) {
- map->setZoom(options.zoom);
- }
-
- mbgl::LatLng latLng(options.latitude, options.longitude);
- if (map->getLatLng() != latLng) {
- map->setLatLng(latLng);
- }
-
- if (map->getBearing() != options.bearing) {
- map->setBearing(options.bearing);
- }
+ mbgl::CameraOptions camera;
+ camera.center = mbgl::LatLng { options.latitude, options.longitude };
+ camera.zoom = options.zoom;
+ camera.angle = -options.bearing * mbgl::util::DEG2RAD;
+ camera.pitch = options.pitch * mbgl::util::DEG2RAD;
- if (map->getPitch() != options.pitch) {
- map->setPitch(options.pitch);
- }
-
- if (map->getDebug() != options.debugOptions) {
- map->setDebug(options.debugOptions);
- }
-
- map->renderStill(*view, [this](const std::exception_ptr eptr) {
+ map->renderStill(camera, options.debugOptions, [this](const std::exception_ptr eptr) {
if (eptr) {
error = std::move(eptr);
uv_async_send(async);
} else {
assert(!image.data);
- image = view->readStillImage();
+ image = frontend->readStillImage();
uv_async_send(async);
}
});
@@ -506,7 +475,7 @@ void NodeMap::release() {
uv_close(reinterpret_cast<uv_handle_t *>(async), [] (uv_handle_t *h) {
delete reinterpret_cast<uv_async_t *>(h);
});
-
+
map.reset();
}
@@ -532,37 +501,24 @@ void NodeMap::Cancel(const Nan::FunctionCallbackInfo<v8::Value>& info) {
}
void NodeMap::cancel() {
- auto style = map->getStyleJSON();
+ auto style = map->getStyle().getJSON();
+
+ // Reset map explicitly as it resets the renderer frontend
+ map.reset();
- map = std::make_unique<mbgl::Map>(backend, mbgl::Size{ 256, 256 },
- pixelRatio, *this, threadpool, mbgl::MapMode::Still);
+ frontend = std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size{ 256, 256 }, pixelRatio, *this, threadpool);
+ map = std::make_unique<mbgl::Map>(*frontend, mapObserver, frontend->getSize(), pixelRatio,
+ *this, threadpool, mbgl::MapMode::Still);
// FIXME: Reload the style after recreating the map. We need to find
// a better way of canceling an ongoing rendering on the core level
// without resetting the map, which is way too expensive.
- map->setStyleJSON(style);
+ map->getStyle().loadJSON(style);
error = std::make_exception_ptr(std::runtime_error("Canceled"));
renderFinished();
}
-void NodeMap::AddClass(const Nan::FunctionCallbackInfo<v8::Value>& info) {
- auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
- if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
-
- if (info.Length() <= 0 || !info[0]->IsString()) {
- return Nan::ThrowTypeError("First argument must be a string");
- }
-
- try {
- nodeMap->map->addClass(*Nan::Utf8String(info[0]));
- } catch (const std::exception &ex) {
- return Nan::ThrowError(ex.what());
- }
-
- info.GetReturnValue().SetUndefined();
-}
-
void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
@@ -578,6 +534,10 @@ void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
+ if (!info[1]->IsObject()) {
+ return Nan::ThrowTypeError("Second argument must be an object");
+ }
+
Error error;
mbgl::optional<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], error, *Nan::Utf8String(info[0]));
if (!source) {
@@ -585,7 +545,25 @@ void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return;
}
- nodeMap->map->addSource(std::move(*source));
+ nodeMap->map->getStyle().addSource(std::move(*source));
+}
+
+void NodeMap::RemoveSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() != 1) {
+ return Nan::ThrowTypeError("One argument required");
+ }
+
+ if (!info[0]->IsString()) {
+ return Nan::ThrowTypeError("First argument must be a string");
+ }
+
+ nodeMap->map->getStyle().removeSource(*Nan::Utf8String(info[0]));
}
void NodeMap::AddLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -606,7 +584,7 @@ void NodeMap::AddLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return;
}
- nodeMap->map->addLayer(std::move(*layer));
+ nodeMap->map->getStyle().addLayer(std::move(*layer));
}
void NodeMap::RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -624,7 +602,7 @@ void NodeMap::RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- nodeMap->map->removeLayer(*Nan::Utf8String(info[0]));
+ nodeMap->map->getStyle().removeLayer(*Nan::Utf8String(info[0]));
}
void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -660,7 +638,7 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("width parameter required");
}
- if (!Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->IsUint32()) {
+ if (!Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->IsNumber()) {
return Nan::ThrowTypeError("pixelRatio parameter required");
}
@@ -671,7 +649,7 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("Max height and width is 1024");
}
- uint32_t pixelRatio = Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->Uint32Value();
+ float pixelRatio = Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->NumberValue();
auto imageBuffer = Nan::To<v8::Object>(info[1]).ToLocalChecked()->ToObject();
char * imageDataBuffer = node::Buffer::Data(imageBuffer);
@@ -686,7 +664,7 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
mbgl::UnassociatedImage cImage({ imageWidth, imageHeight}, std::move(data));
mbgl::PremultipliedImage cPremultipliedImage = mbgl::util::premultiply(std::move(cImage));
- nodeMap->map->addImage(*Nan::Utf8String(info[0]), std::make_unique<mbgl::style::Image>(std::move(cPremultipliedImage), pixelRatio));
+ nodeMap->map->getStyle().addImage(std::make_unique<mbgl::style::Image>(*Nan::Utf8String(info[0]), std::move(cPremultipliedImage), pixelRatio));
}
void NodeMap::RemoveImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -704,7 +682,7 @@ void NodeMap::RemoveImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- nodeMap->map->removeImage(*Nan::Utf8String(info[0]));
+ nodeMap->map->getStyle().removeImage(*Nan::Utf8String(info[0]));
}
void NodeMap::SetLayoutProperty(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -722,7 +700,7 @@ void NodeMap::SetLayoutProperty(const Nan::FunctionCallbackInfo<v8::Value>& info
return Nan::ThrowTypeError("First argument must be a string");
}
- mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ mbgl::style::Layer* layer = nodeMap->map->getStyle().getLayer(*Nan::Utf8String(info[0]));
if (!layer) {
return Nan::ThrowTypeError("layer not found");
}
@@ -754,7 +732,7 @@ void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>& info)
return Nan::ThrowTypeError("First argument must be a string");
}
- mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ mbgl::style::Layer* layer = nodeMap->map->getStyle().getLayer(*Nan::Utf8String(info[0]));
if (!layer) {
return Nan::ThrowTypeError("layer not found");
}
@@ -763,12 +741,7 @@ void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>& info)
return Nan::ThrowTypeError("Second argument must be a string");
}
- mbgl::optional<std::string> klass;
- if (info.Length() == 4 && info[3]->IsString()) {
- klass = std::string(*Nan::Utf8String(info[3]));
- }
-
- mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2], klass);
+ mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2]);
if (error) {
return Nan::ThrowTypeError(error->message.c_str());
}
@@ -812,7 +785,7 @@ void NodeMap::SetFilter(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ mbgl::style::Layer* layer = nodeMap->map->getStyle().getLayer(*Nan::Utf8String(info[0]));
if (!layer) {
return Nan::ThrowTypeError("layer not found");
}
@@ -911,6 +884,8 @@ void NodeMap::DumpDebugLogs(const Nan::FunctionCallbackInfo<v8::Value>& info) {
if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
nodeMap->map->dumpDebugLogs();
+ nodeMap->frontend->getRenderer()->dumpDebugLogs();
+
info.GetReturnValue().SetUndefined();
}
@@ -947,7 +922,7 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
auto layers = layersOption.As<v8::Array>();
std::vector<std::string> layersVec;
for (uint32_t i=0; i < layers->Length(); i++) {
- layersVec.push_back(*Nan::Utf8String(Nan::Get(layers,i).ToLocalChecked()));
+ layersVec.emplace_back(*Nan::Utf8String(Nan::Get(layers,i).ToLocalChecked()));
}
queryOptions.layerIDs = layersVec;
}
@@ -972,7 +947,7 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
auto pos0 = Nan::Get(posOrBox, 0).ToLocalChecked().As<v8::Array>();
auto pos1 = Nan::Get(posOrBox, 1).ToLocalChecked().As<v8::Array>();
- optional = nodeMap->map->queryRenderedFeatures(mbgl::ScreenBox {
+ optional = nodeMap->frontend->getRenderer()->queryRenderedFeatures(mbgl::ScreenBox {
{
Nan::Get(pos0, 0).ToLocalChecked()->NumberValue(),
Nan::Get(pos0, 1).ToLocalChecked()->NumberValue()
@@ -983,7 +958,7 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
}, queryOptions);
} else {
- optional = nodeMap->map->queryRenderedFeatures(mbgl::ScreenCoordinate {
+ optional = nodeMap->frontend->getRenderer()->queryRenderedFeatures(mbgl::ScreenCoordinate {
Nan::Get(posOrBox, 0).ToLocalChecked()->NumberValue(),
Nan::Get(posOrBox, 1).ToLocalChecked()->NumberValue()
}, queryOptions);
@@ -1007,9 +982,12 @@ NodeMap::NodeMap(v8::Local<v8::Object> options)
.ToLocalChecked()
->NumberValue()
: 1.0;
- }()),
- map(std::make_unique<mbgl::Map>(backend,
- mbgl::Size{ 256, 256 },
+ }())
+ , mapObserver(NodeMapObserver())
+ , frontend(std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size { 256, 256 }, pixelRatio, *this, threadpool))
+ , map(std::make_unique<mbgl::Map>(*frontend,
+ mapObserver,
+ frontend->getSize(),
pixelRatio,
*this,
threadpool,