diff options
Diffstat (limited to 'platform/node/src/node_map.cpp')
-rw-r--r-- | platform/node/src/node_map.cpp | 208 |
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, |