From e6e6bcf55cc92b0f2da8902ffe0e9ee262fcba62 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Mon, 4 Nov 2019 12:01:19 +0200 Subject: [PATCH] [core] Parse GeoJSONSource description in background Unblocks the UI thread on heavy GeoJSON tiles parsing operation --- src/mbgl/style/sources/geojson_source.cpp | 36 +++++++++++++++-------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index 3832977cd45..5523336f127 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -69,18 +70,29 @@ void GeoJSONSource::loadDescription(FileSource& fileSource) { observer->onSourceError( *this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON"))); } else { - conversion::Error error; - std::shared_ptr geoJSONData; - if (optional geoJSON = conversion::convertJSON(*res.data, error)) { - geoJSONData = GeoJSONData::create(*geoJSON, impl().getOptions()); - } else { - // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for tiles to load. - Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", - error.message.c_str()); - } - baseImpl = makeMutable(impl(), std::move(geoJSONData)); - loaded = true; - observer->onSourceLoaded(*this); + auto makeImplInBackground = [currentImpl = baseImpl, data = res.data]() -> Immutable { + assert(data); + auto& impl = static_cast(*currentImpl); + conversion::Error error; + std::shared_ptr geoJSONData; + if (optional geoJSON = conversion::convertJSON(*data, error)) { + geoJSONData = GeoJSONData::create(*geoJSON, impl.getOptions()); + } else { + // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for tiles to load. + Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", error.message.c_str()); + } + return makeMutable(impl, std::move(geoJSONData)); + }; + auto onImplReady = [this, self = makeWeakPtr(), capturedReq = req.get()](Immutable newImpl) { + assert(capturedReq); + if (!self) return; // This source has been deleted. + if (capturedReq != req.get()) return; // A new request is being processed, ignore this impl. + + baseImpl = std::move(newImpl); + loaded = true; + observer->onSourceLoaded(*this); + }; + Scheduler::GetBackground()->scheduleAndReplyValue(makeImplInBackground, onImplReady); } }); }