diff options
author | Nicholas Hallahan <nick@theoutpost.io> | 2015-07-17 09:48:22 -0700 |
---|---|---|
committer | Nicholas Hallahan <nick@theoutpost.io> | 2015-07-17 09:48:22 -0700 |
commit | d5eca7b8d13f7e3eb045da472d44c9075397c259 (patch) | |
tree | 8280354915dd29a3959beec54bee9d6f8a6a5fdd | |
parent | aafcdd2ef0e4cb42c45d213b90a02c73a142d249 (diff) | |
parent | 38351554f45e02c1c7b59beeb11f5675d22f19b3 (diff) | |
download | qtlocation-mapboxgl-d5eca7b8d13f7e3eb045da472d44c9075397c259.tar.gz |
Merge remote-tracking branch 'mapbox/master' into android-annotations #1716
50 files changed, 710 insertions, 321 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 5867b2d138..45b1959a45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.5.1 + +### iOS + +- Added support for CocoaPods 0.38.0. ([#1876](https://github.com/mapbox/mapbox-gl-native/pull/1876)) + ## 0.5.0 ### Core diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index c6d5e1475d..82aef65b65 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -67,7 +67,10 @@ public: void renderStill(StillImageCallback callback); // Triggers a synchronous or asynchronous render. - void renderSync(); + bool renderSync(); + + // Nudges transitions one step, possibly notifying of the need for a rerender. + void nudgeTransitions(bool forceRerender); // Notifies the Map thread that the state has changed and an update might be necessary. void update(Update update = Update::Nothing); @@ -79,8 +82,8 @@ public: void setClasses(const std::vector<std::string>&); std::vector<std::string> getClasses() const; - void setDefaultTransitionDuration(Duration = Duration::zero()); - Duration getDefaultTransitionDuration(); + void setDefaultTransitionDuration(const Duration& = Duration::zero()); + Duration getDefaultTransitionDuration() const; void setStyleURL(const std::string& url); void setStyleJSON(const std::string& json, const std::string& base = ""); std::string getStyleURL() const; @@ -91,27 +94,27 @@ public: void setGestureInProgress(bool); // Position - void moveBy(double dx, double dy, Duration = Duration::zero()); - void setLatLng(LatLng latLng, Duration = Duration::zero()); + void moveBy(double dx, double dy, const Duration& = Duration::zero()); + void setLatLng(LatLng latLng, const Duration& = Duration::zero()); LatLng getLatLng() const; void resetPosition(); // Scale - void scaleBy(double ds, double cx = -1, double cy = -1, Duration = Duration::zero()); - void setScale(double scale, double cx = -1, double cy = -1, Duration = Duration::zero()); + void scaleBy(double ds, double cx = -1, double cy = -1, const Duration& = Duration::zero()); + void setScale(double scale, double cx = -1, double cy = -1, const Duration& = Duration::zero()); double getScale() const; - void setZoom(double zoom, Duration = Duration::zero()); + void setZoom(double zoom, const Duration& = Duration::zero()); double getZoom() const; - void setLatLngZoom(LatLng latLng, double zoom, Duration = Duration::zero()); - void fitBounds(LatLngBounds bounds, EdgeInsets padding, Duration duration = Duration::zero()); - void fitBounds(AnnotationSegment segment, EdgeInsets padding, Duration duration = Duration::zero()); + void setLatLngZoom(LatLng latLng, double zoom, const Duration& = Duration::zero()); + void fitBounds(LatLngBounds bounds, EdgeInsets padding, const Duration& duration = Duration::zero()); + void fitBounds(AnnotationSegment segment, EdgeInsets padding, const Duration& duration = Duration::zero()); void resetZoom(); double getMinZoom() const; double getMaxZoom() const; // Rotation - void rotateBy(double sx, double sy, double ex, double ey, Duration = Duration::zero()); - void setBearing(double degrees, Duration = Duration::zero()); + void rotateBy(double sx, double sy, double ex, double ey, const Duration& = Duration::zero()); + void setBearing(double degrees, const Duration& = Duration::zero()); void setBearing(double degrees, double cx, double cy); double getBearing() const; void resetNorth(); diff --git a/ios/MapboxGL.podspec b/ios/MapboxGL.podspec index 0e4d27be83..9795c44adf 100644 --- a/ios/MapboxGL.podspec +++ b/ios/MapboxGL.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |m| m.name = 'MapboxGL' - m.version = '0.4.5-symbols' + m.version = '0.5.2-symbols' m.summary = 'Open source vector map solution for iOS with full styling capabilities.' m.description = 'Open source OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa bindings.' diff --git a/platform/default/default_styles.cpp b/platform/default/default_styles.cpp index a631008a4b..e25d96e4c9 100644 --- a/platform/default/default_styles.cpp +++ b/platform/default/default_styles.cpp @@ -7,7 +7,8 @@ const std::vector<std::pair<std::string, std::string>> defaultStyles = { { "asset://styles/mapbox-streets-v7.json", "Mapbox Streets" }, { "asset://styles/emerald-v7.json", "Emerald" }, { "asset://styles/light-v7.json", "Light" }, - { "asset://styles/dark-v7.json", "Dark" } + { "asset://styles/dark-v7.json", "Dark" }, + { "asset://styles/satellite-v7.json", "Satellite" } }; } // end namespace util diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 6cb46e28a9..e807d21c6d 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -703,9 +703,11 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) _mbglMap->setSourceTileCacheSize(cacheSize); - _mbglMap->renderSync(); + bool needsRerender = _mbglMap->renderSync(); [self updateUserLocationAnnotationView]; + + _mbglMap->nudgeTransitions(needsRerender); } } diff --git a/src/mbgl/annotation/sprite_store.cpp b/src/mbgl/annotation/sprite_store.cpp index 1c6511d8e8..8d2231a2b7 100644 --- a/src/mbgl/annotation/sprite_store.cpp +++ b/src/mbgl/annotation/sprite_store.cpp @@ -54,7 +54,9 @@ std::shared_ptr<const SpriteImage> SpriteStore::getSprite(const std::string& nam if (it != sprites.end()) { return it->second; } else { - Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str()); + if (!sprites.empty()) { + Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str()); + } return nullptr; } } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 37cd3be335..d983a9c518 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -48,7 +48,7 @@ void Map::renderStill(StillImageCallback callback) { FrameData{ view.getFramebufferSize() }, callback); } -void Map::renderSync() { +bool Map::renderSync() { if (renderState == RenderState::never) { view.notifyMapChange(MapChangeWillStartRenderingMap); } @@ -69,9 +69,13 @@ void Map::renderSync() { view.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered); } + return result.needsRerender; +} + +void Map::nudgeTransitions(bool forceRerender) { if (transform->needsTransition()) { update(Update(transform->updateTransitions(Clock::now()))); - } else if (result.needsRerender) { + } else if (forceRerender) { update(); } } @@ -116,12 +120,12 @@ void Map::setGestureInProgress(bool inProgress) { #pragma mark - Position -void Map::moveBy(double dx, double dy, Duration duration) { +void Map::moveBy(double dx, double dy, const Duration& duration) { transform->moveBy(dx, dy, duration); update(); } -void Map::setLatLng(LatLng latLng, Duration duration) { +void Map::setLatLng(LatLng latLng, const Duration& duration) { transform->setLatLng(latLng, duration); update(); } @@ -140,12 +144,12 @@ void Map::resetPosition() { #pragma mark - Scale -void Map::scaleBy(double ds, double cx, double cy, Duration duration) { +void Map::scaleBy(double ds, double cx, double cy, const Duration& duration) { transform->scaleBy(ds, cx, cy, duration); update(Update::Zoom); } -void Map::setScale(double scale, double cx, double cy, Duration duration) { +void Map::setScale(double scale, double cx, double cy, const Duration& duration) { transform->setScale(scale, cx, cy, duration); update(Update::Zoom); } @@ -154,7 +158,7 @@ double Map::getScale() const { return transform->getScale(); } -void Map::setZoom(double zoom, Duration duration) { +void Map::setZoom(double zoom, const Duration& duration) { transform->setZoom(zoom, duration); update(Update::Zoom); } @@ -163,12 +167,12 @@ double Map::getZoom() const { return transform->getZoom(); } -void Map::setLatLngZoom(LatLng latLng, double zoom, Duration duration) { +void Map::setLatLngZoom(LatLng latLng, double zoom, const Duration& duration) { transform->setLatLngZoom(latLng, zoom, duration); update(Update::Zoom); } -void Map::fitBounds(LatLngBounds bounds, EdgeInsets padding, Duration duration) { +void Map::fitBounds(LatLngBounds bounds, EdgeInsets padding, const Duration& duration) { AnnotationSegment segment = { {bounds.ne.latitude, bounds.sw.longitude}, bounds.sw, @@ -178,7 +182,7 @@ void Map::fitBounds(LatLngBounds bounds, EdgeInsets padding, Duration duration) fitBounds(segment, padding, duration); } -void Map::fitBounds(AnnotationSegment segment, EdgeInsets padding, Duration duration) { +void Map::fitBounds(AnnotationSegment segment, EdgeInsets padding, const Duration& duration) { if (segment.empty()) { return; } @@ -243,12 +247,12 @@ uint16_t Map::getHeight() const { #pragma mark - Rotation -void Map::rotateBy(double sx, double sy, double ex, double ey, Duration duration) { +void Map::rotateBy(double sx, double sy, double ex, double ey, const Duration& duration) { transform->rotateBy(sx, sy, ex, ey, duration); update(); } -void Map::setBearing(double degrees, Duration duration) { +void Map::setBearing(double degrees, const Duration& duration) { transform->setAngle(-degrees * M_PI / 180, duration); update(); } @@ -416,12 +420,12 @@ std::vector<std::string> Map::getClasses() const { return data->getClasses(); } -void Map::setDefaultTransitionDuration(Duration duration) { +void Map::setDefaultTransitionDuration(const Duration& duration) { data->setDefaultTransitionDuration(duration); update(Update::DefaultTransitionDuration); } -Duration Map::getDefaultTransitionDuration() { +Duration Map::getDefaultTransitionDuration() const { return data->getDefaultTransitionDuration(); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 4447ecc4f0..61614dd0e4 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -131,10 +131,13 @@ void MapContext::loadStyleJSON(const std::string& json, const std::string& base) assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); style->setJSON(json, base); - style->cascade(data.getClasses()); - style->setDefaultTransitionDuration(data.getDefaultTransitionDuration()); style->setObserver(this); + // force style cascade, causing all pending transitions to complete. + style->cascade(); + + updated |= static_cast<UpdateType>(Update::DefaultTransitionDuration); + updated |= static_cast<UpdateType>(Update::Classes); updated |= static_cast<UpdateType>(Update::Zoom); asyncUpdate->send(); @@ -240,45 +243,37 @@ void MapContext::updateAnnotationTiles(const std::unordered_set<TileID, TileID:: } } - cascadeClasses(); - updated |= static_cast<UpdateType>(Update::Classes); asyncUpdate->send(); annotationManager->resetStaleTiles(); } -void MapContext::cascadeClasses() { - style->cascade(data.getClasses()); -} - void MapContext::update() { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - const auto now = Clock::now(); - data.setAnimationTime(now); + if (!style) { + updated = static_cast<UpdateType>(Update::Nothing); + return; + } - if (style) { - if (updated & static_cast<UpdateType>(Update::DefaultTransitionDuration)) { - style->setDefaultTransitionDuration(data.getDefaultTransitionDuration()); - } + data.setAnimationTime(Clock::now()); - if (updated & static_cast<UpdateType>(Update::Classes)) { - cascadeClasses(); - } + if (updated & static_cast<UpdateType>(Update::Classes)) { + style->cascade(); + } - if (updated & static_cast<UpdateType>(Update::Classes) || + if (updated & static_cast<UpdateType>(Update::Classes) || updated & static_cast<UpdateType>(Update::Zoom)) { - style->recalculate(transformState.getNormalizedZoom(), now); - } + style->recalculate(transformState.getNormalizedZoom()); + } - style->update(transformState, *texturePool); + style->update(transformState, *texturePool); - if (data.mode == MapMode::Continuous) { - view.invalidate(); - } else if (callback && style->isLoaded()) { - renderSync(transformState, frameData); - } + if (data.mode == MapMode::Continuous) { + view.invalidate(); + } else if (callback && style->isLoaded()) { + renderSync(transformState, frameData); } updated = static_cast<UpdateType>(Update::Nothing); @@ -332,7 +327,7 @@ MapContext::RenderResult MapContext::renderSync(const TransformState& state, con glObjectStore.performCleanup(); if (!painter) { - painter = std::make_unique<Painter>(data.pixelRatio); + painter = std::make_unique<Painter>(data); painter->setup(); } diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 2e60d8eae0..8c8c90ff8b 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -72,9 +72,6 @@ public: void onResourceLoadingFailed(std::exception_ptr error) override; private: - // Style-related updates. - void cascadeClasses(); - // Update the state indicated by the accumulated Update flags, then render. void update(); diff --git a/src/mbgl/map/map_data.hpp b/src/mbgl/map/map_data.hpp index 75ada0615e..aadc8dcd64 100644 --- a/src/mbgl/map/map_data.hpp +++ b/src/mbgl/map/map_data.hpp @@ -20,10 +20,14 @@ class MapData { using Lock = std::lock_guard<std::mutex>; public: - inline MapData(MapMode mode_, const float pixelRatio_) : mode(mode_), pixelRatio(pixelRatio_) { + inline MapData(MapMode mode_, const float pixelRatio_) + : mode(mode_) + , pixelRatio(pixelRatio_) + , animationTime(Duration::zero()) + , defaultFadeDuration(std::chrono::milliseconds(300)) + , defaultTransitionDuration(Duration::zero()) + , defaultTransitionDelay(Duration::zero()) { assert(pixelRatio > 0); - setAnimationTime(TimePoint::min()); - setDefaultTransitionDuration(Duration::zero()); } // Adds the class if it's not yet set. Returns true when it added the class, and false when it @@ -69,17 +73,34 @@ public: // has a bug that doesn't allow TimePoints to be atomic. return TimePoint(animationTime); } - inline void setAnimationTime(TimePoint timePoint) { + inline void setAnimationTime(const TimePoint& timePoint) { animationTime = timePoint.time_since_epoch(); }; + inline Duration getDefaultFadeDuration() const { + return defaultFadeDuration; + } + + inline void setDefaultFadeDuration(const Duration& duration) { + defaultFadeDuration = duration; + } + inline Duration getDefaultTransitionDuration() const { return defaultTransitionDuration; } - inline void setDefaultTransitionDuration(Duration duration) { + + inline void setDefaultTransitionDuration(const Duration& duration) { defaultTransitionDuration = duration; } + inline Duration getDefaultTransitionDelay() const { + return defaultTransitionDelay; + } + + inline void setDefaultTransitionDelay(const Duration& delay) { + defaultTransitionDelay = delay; + } + util::exclusive<AnnotationManager> getAnnotationManager() { return util::exclusive<AnnotationManager>( &annotationManager, @@ -100,7 +121,9 @@ private: std::atomic<uint8_t> debug { false }; std::atomic<uint8_t> collisionDebug { false }; std::atomic<Duration> animationTime; + std::atomic<Duration> defaultFadeDuration; std::atomic<Duration> defaultTransitionDuration; + std::atomic<Duration> defaultTransitionDelay; // TODO: make private public: diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 4ca64747bc..a7ebf300f5 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -240,14 +240,8 @@ bool Source::handlePartialTile(const TileID& id, Worker&) { return true; } - // The signal is only emitted if there was an actual change on the tile. The - // tile can be in a "partial" state waiting for resources and get reparsed on - // the arrival of new resources that were needed by another tile. - size_t bucketCount = data->countBuckets(); - return data->reparse([this, data, bucketCount]() { - if (data->countBuckets() > bucketCount) { - emitTileLoaded(false); - } + return data->reparse([this, data]() { + emitTileLoaded(false); }); } diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 15183c0e40..dd56f33f51 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -44,11 +44,6 @@ Bucket* TileWorker::getBucket(const StyleLayer& layer) const { return it->second.get(); } -size_t TileWorker::countBuckets() const { - std::lock_guard<std::mutex> lock(bucketsMutex); - return buckets.size(); -} - TileParseResult TileWorker::parse(const GeometryTile& geometryTile) { partialParse = false; diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp index 2306bf1acf..da5c766506 100644 --- a/src/mbgl/map/tile_worker.hpp +++ b/src/mbgl/map/tile_worker.hpp @@ -41,7 +41,6 @@ public: ~TileWorker(); Bucket* getBucket(const StyleLayer&) const; - size_t countBuckets() const; TileParseResult parse(const GeometryTile&); void redoPlacement(float angle, bool collisionDebug); diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 12698a1e81..b39614888b 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -53,7 +53,7 @@ bool Transform::resize(const std::array<uint16_t, 2> size) { #pragma mark - Position -void Transform::moveBy(const double dx, const double dy, const Duration duration) { +void Transform::moveBy(const double dx, const double dy, const Duration& duration) { if (std::isnan(dx) || std::isnan(dy)) { return; } @@ -61,7 +61,7 @@ void Transform::moveBy(const double dx, const double dy, const Duration duration _moveBy(dx, dy, duration); } -void Transform::_moveBy(const double dx, const double dy, const Duration duration) { +void Transform::_moveBy(const double dx, const double dy, const Duration& duration) { double x = state.x + std::cos(state.angle) * dx + std::sin( state.angle) * dy; double y = state.y + std::cos(state.angle) * dy + std::sin(-state.angle) * dx; @@ -95,7 +95,7 @@ void Transform::_moveBy(const double dx, const double dy, const Duration duratio } } -void Transform::setLatLng(const LatLng latLng, const Duration duration) { +void Transform::setLatLng(const LatLng latLng, const Duration& duration) { if (std::isnan(latLng.latitude) || std::isnan(latLng.longitude)) { return; } @@ -109,7 +109,7 @@ void Transform::setLatLng(const LatLng latLng, const Duration duration) { _setScaleXY(state.scale, xn, yn, duration); } -void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const Duration duration) { +void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const Duration& duration) { if (std::isnan(latLng.latitude) || std::isnan(latLng.longitude) || std::isnan(zoom)) { return; } @@ -132,7 +132,7 @@ void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const Dura #pragma mark - Zoom -void Transform::scaleBy(const double ds, const double cx, const double cy, const Duration duration) { +void Transform::scaleBy(const double ds, const double cx, const double cy, const Duration& duration) { if (std::isnan(ds) || std::isnan(cx) || std::isnan(cy)) { return; } @@ -149,7 +149,7 @@ void Transform::scaleBy(const double ds, const double cx, const double cy, const } void Transform::setScale(const double scale, const double cx, const double cy, - const Duration duration) { + const Duration& duration) { if (std::isnan(scale) || std::isnan(cx) || std::isnan(cy)) { return; } @@ -157,7 +157,7 @@ void Transform::setScale(const double scale, const double cx, const double cy, _setScale(scale, cx, cy, duration); } -void Transform::setZoom(const double zoom, const Duration duration) { +void Transform::setZoom(const double zoom, const Duration& duration) { if (std::isnan(zoom)) { return; } @@ -173,7 +173,7 @@ double Transform::getScale() const { return state.scale; } -void Transform::_setScale(double new_scale, double cx, double cy, const Duration duration) { +void Transform::_setScale(double new_scale, double cx, double cy, const Duration& duration) { // Ensure that we don't zoom in further than the maximum allowed. if (new_scale < state.min_scale) { new_scale = state.min_scale; @@ -205,7 +205,7 @@ void Transform::_setScale(double new_scale, double cx, double cy, const Duration } void Transform::_setScaleXY(const double new_scale, const double xn, const double yn, - const Duration duration) { + const Duration& duration) { double scale = new_scale; double x = xn; double y = yn; @@ -254,7 +254,7 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl #pragma mark - Angle void Transform::rotateBy(const double start_x, const double start_y, const double end_x, - const double end_y, const Duration duration) { + const double end_y, const Duration& duration) { if (std::isnan(start_x) || std::isnan(start_y) || std::isnan(end_x) || std::isnan(end_y)) { return; } @@ -286,7 +286,7 @@ void Transform::rotateBy(const double start_x, const double start_y, const doubl _setAngle(ang, duration); } -void Transform::setAngle(const double new_angle, const Duration duration) { +void Transform::setAngle(const double new_angle, const Duration& duration) { if (std::isnan(new_angle)) { return; } @@ -314,7 +314,7 @@ void Transform::setAngle(const double new_angle, const double cx, const double c } } -void Transform::_setAngle(double new_angle, const Duration duration) { +void Transform::_setAngle(double new_angle, const Duration& duration) { double angle = _normalizeAngle(new_angle, state.angle); state.angle = _normalizeAngle(state.angle, angle); @@ -352,7 +352,7 @@ double Transform::getAngle() const { void Transform::startTransition(std::function<Update(double)> frame, std::function<void()> finish, - Duration duration) { + const Duration& duration) { if (transitionFinishFn) { transitionFinishFn(); } @@ -360,7 +360,7 @@ void Transform::startTransition(std::function<Update(double)> frame, transitionStart = Clock::now(); transitionDuration = duration; - transitionFrameFn = [frame, this](TimePoint now) { + transitionFrameFn = [frame, this](const TimePoint now) { float t = std::chrono::duration<float>(now - transitionStart) / transitionDuration; if (t >= 1.0) { Update result = frame(1.0); @@ -381,7 +381,7 @@ bool Transform::needsTransition() const { return !!transitionFrameFn; } -UpdateType Transform::updateTransitions(const TimePoint now) { +UpdateType Transform::updateTransitions(const TimePoint& now) { return static_cast<UpdateType>(transitionFrameFn ? transitionFrameFn(now) : Update::Nothing); } diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index c2c4aad2de..badb811afb 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -23,27 +23,27 @@ public: bool resize(std::array<uint16_t, 2> size); // Position - void moveBy(double dx, double dy, Duration = Duration::zero()); - void setLatLng(LatLng latLng, Duration = Duration::zero()); - void setLatLngZoom(LatLng latLng, double zoom, Duration = Duration::zero()); + void moveBy(double dx, double dy, const Duration& = Duration::zero()); + void setLatLng(LatLng latLng, const Duration& = Duration::zero()); + void setLatLngZoom(LatLng latLng, double zoom, const Duration& = Duration::zero()); inline const LatLng getLatLng() const { return state.getLatLng(); } // Zoom - void scaleBy(double ds, double cx = -1, double cy = -1, Duration = Duration::zero()); - void setScale(double scale, double cx = -1, double cy = -1, Duration = Duration::zero()); - void setZoom(double zoom, Duration = Duration::zero()); + void scaleBy(double ds, double cx = -1, double cy = -1, const Duration& = Duration::zero()); + void setScale(double scale, double cx = -1, double cy = -1, const Duration& = Duration::zero()); + void setZoom(double zoom, const Duration& = Duration::zero()); double getZoom() const; double getScale() const; // Angle - void rotateBy(double sx, double sy, double ex, double ey, Duration = Duration::zero()); - void setAngle(double angle, Duration = Duration::zero()); + void rotateBy(double sx, double sy, double ex, double ey, const Duration& = Duration::zero()); + void setAngle(double angle, const Duration& = Duration::zero()); void setAngle(double angle, double cx, double cy); double getAngle() const; // Transitions bool needsTransition() const; - UpdateType updateTransitions(TimePoint now); + UpdateType updateTransitions(const TimePoint& now); void cancelTransitions(); // Gesture @@ -53,10 +53,10 @@ public: const TransformState getState() const { return state; } private: - void _moveBy(double dx, double dy, Duration = Duration::zero()); - void _setScale(double scale, double cx, double cy, Duration = Duration::zero()); - void _setScaleXY(double new_scale, double xn, double yn, Duration = Duration::zero()); - void _setAngle(double angle, Duration = Duration::zero()); + void _moveBy(double dx, double dy, const Duration& = Duration::zero()); + void _setScale(double scale, double cx, double cy, const Duration& = Duration::zero()); + void _setScaleXY(double new_scale, double xn, double yn, const Duration& = Duration::zero()); + void _setAngle(double angle, const Duration& = Duration::zero()); View &view; @@ -64,11 +64,11 @@ private: void startTransition(std::function<Update(double)> frame, std::function<void()> finish, - Duration); + const Duration& duration); TimePoint transitionStart; Duration transitionDuration; - std::function<Update(TimePoint)> transitionFrameFn; + std::function<Update(const TimePoint)> transitionFrameFn; std::function<void()> transitionFinishFn; }; diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 57b42aaaf2..c9ee33910b 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -98,10 +98,6 @@ Bucket* VectorTileData::getBucket(const StyleLayer& layer) { return tileWorker.getBucket(layer); } -size_t VectorTileData::countBuckets() const { - return tileWorker.countBuckets(); -} - void VectorTileData::redoPlacement(float angle, bool collisionDebug) { if (angle == currentAngle && collisionDebug == currentCollisionDebug) return; diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp index 3b73ded0ca..e0e8be29bf 100644 --- a/src/mbgl/map/vector_tile_data.hpp +++ b/src/mbgl/map/vector_tile_data.hpp @@ -23,7 +23,6 @@ public: ~VectorTileData(); Bucket* getBucket(const StyleLayer&) override; - size_t countBuckets() const; void request(float pixelRatio, const std::function<void()>& callback); diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp index 478520c510..cb36a1d834 100644 --- a/src/mbgl/renderer/frame_history.cpp +++ b/src/mbgl/renderer/frame_history.cpp @@ -3,7 +3,7 @@ using namespace mbgl; // Record frame history that will be used to calculate fading params -void FrameHistory::record(TimePoint now, float zoom) { +void FrameHistory::record(const TimePoint& now, float zoom) { // first frame ever if (!history.size()) { history.emplace_back(FrameSnapshot{TimePoint::min(), zoom}); @@ -15,7 +15,7 @@ void FrameHistory::record(TimePoint now, float zoom) { } } -bool FrameHistory::needsAnimation(const Duration duration) const { +bool FrameHistory::needsAnimation(const Duration& duration) const { if (!history.size()) { return false; } @@ -47,7 +47,7 @@ bool FrameHistory::needsAnimation(const Duration duration) const { return false; } -FadeProperties FrameHistory::getFadeProperties(Duration duration) { +FadeProperties FrameHistory::getFadeProperties(const Duration& duration) { const TimePoint currentTime = Clock::now(); // Remove frames until only one is outside the duration, or until there are only three diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp index 15ca92e469..ef52b2a5ec 100644 --- a/src/mbgl/renderer/frame_history.hpp +++ b/src/mbgl/renderer/frame_history.hpp @@ -11,8 +11,8 @@ namespace mbgl { struct FrameSnapshot { - explicit inline FrameSnapshot(TimePoint now_, float z_) : now(now_), z(z_) {} - TimePoint now; + explicit inline FrameSnapshot(const TimePoint& now_, float z_) : now(now_), z(z_) {} + const TimePoint now; float z; }; @@ -26,10 +26,10 @@ struct FadeProperties { class FrameHistory { public: // Record frame history that will be used to calculate fading params - void record(TimePoint now, float zoom); + void record(const TimePoint& now, float zoom); - bool needsAnimation(Duration) const; - FadeProperties getFadeProperties(Duration); + bool needsAnimation(const Duration& duration) const; + FadeProperties getFadeProperties(const Duration& duration); public: std::deque<FrameSnapshot> history; diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 33f1687a95..7570b6a74d 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -3,6 +3,7 @@ #include <mbgl/map/source.hpp> #include <mbgl/map/tile.hpp> #include <mbgl/map/map_context.hpp> +#include <mbgl/map/map_data.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/gl/debugging.hpp> @@ -41,14 +42,14 @@ using namespace mbgl; -Painter::Painter(const float pixelRatio_) : pixelRatio(pixelRatio_) { +Painter::Painter(MapData& data_) : data(data_) { } Painter::~Painter() { } bool Painter::needsAnimation() const { - return frameHistory.needsAnimation(std::chrono::milliseconds(300)); + return frameHistory.needsAnimation(data.getDefaultFadeDuration()) || state.isChanging(); } void Painter::setup() { @@ -165,7 +166,7 @@ void Painter::prepareTile(const Tile& tile) { config.stencilFunc = { GL_EQUAL, ref, mask }; } -void Painter::render(const Style& style, TransformState state_, const FrameData& frame_, TimePoint time) { +void Painter::render(const Style& style, TransformState state_, const FrameData& frame_, const TimePoint& time) { state = state_; frame = frame_; diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index f7342b15c9..869aaa49cf 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -81,7 +81,7 @@ struct RenderItem { class Painter : private util::noncopyable { public: - Painter(float pixelRatio); + Painter(MapData& data); ~Painter(); void setup(); @@ -96,7 +96,7 @@ public: void render(const Style& style, TransformState state, const FrameData& frame, - TimePoint time); + const TimePoint& time); // Renders debug information for a tile. void renderTileDebug(const Tile& tile); @@ -191,7 +191,7 @@ public: }(); private: - const float pixelRatio; + MapData& data; TransformState state; FrameData frame; diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp index b5d9e343e8..aa3fcba5d2 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp @@ -2,6 +2,7 @@ #include <mbgl/renderer/debug_bucket.hpp> #include <mbgl/map/tile.hpp> #include <mbgl/map/tile_data.hpp> +#include <mbgl/map/map_data.hpp> #include <mbgl/shader/plain_shader.hpp> #include <mbgl/util/string.hpp> #include <mbgl/gl/debugging.hpp> @@ -28,7 +29,7 @@ void Painter::renderDebugText(DebugBucket& bucket, const mat4 &matrix) { // Draw white outline plainShader->u_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }}; - lineWidth(4.0f * pixelRatio); + lineWidth(4.0f * data.pixelRatio); bucket.drawLines(*plainShader); #ifndef GL_ES_VERSION_2_0 @@ -39,7 +40,7 @@ void Painter::renderDebugText(DebugBucket& bucket, const mat4 &matrix) { // Draw black text. plainShader->u_color = {{ 0.0f, 0.0f, 0.0f, 1.0f }}; - lineWidth(2.0f * pixelRatio); + lineWidth(2.0f * data.pixelRatio); bucket.drawLines(*plainShader); config.depthTest = true; @@ -60,6 +61,6 @@ void Painter::renderDebugFrame(const mat4 &matrix) { // draw tile outline tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET(0)); plainShader->u_color = {{ 1.0f, 0.0f, 0.0f, 1.0f }}; - lineWidth(4.0f * pixelRatio); + lineWidth(4.0f * data.pixelRatio); MBGL_CHECK_ERROR(glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)tileBorderBuffer.index())); } diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index 5f5a89d419..1ef9214102 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -5,6 +5,7 @@ #include <mbgl/style/style_layout.hpp> #include <mbgl/map/sprite.hpp> #include <mbgl/map/tile_id.hpp> +#include <mbgl/map/map_data.hpp> #include <mbgl/shader/line_shader.hpp> #include <mbgl/shader/linesdf_shader.hpp> #include <mbgl/shader/linepattern_shader.hpp> @@ -26,7 +27,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const // the distance over which the line edge fades out. // Retina devices need a smaller distance to avoid aliasing. - float antialiasing = 1.0 / pixelRatio; + float antialiasing = 1.0 / data.pixelRatio; float blur = properties.blur + antialiasing; float edgeWidth = properties.width / 2.0; @@ -61,7 +62,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const linesdfShader->u_matrix = vtxMatrix; linesdfShader->u_exmatrix = extrudeMatrix; linesdfShader->u_linewidth = {{ outset, inset }}; - linesdfShader->u_ratio = pixelRatio; + linesdfShader->u_ratio = data.pixelRatio; linesdfShader->u_blur = blur; linesdfShader->u_color = color; @@ -80,7 +81,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }}; linesdfShader->u_tex_y_b = posB.y; linesdfShader->u_image = 0; - linesdfShader->u_sdfgamma = lineAtlas->width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * pixelRatio) / 2; + linesdfShader->u_sdfgamma = lineAtlas->width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * data.pixelRatio) / 2; linesdfShader->u_mix = properties.dash_array.t; bucket.drawLineSDF(*linesdfShader); @@ -96,7 +97,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const linepatternShader->u_matrix = vtxMatrix; linepatternShader->u_exmatrix = extrudeMatrix; linepatternShader->u_linewidth = {{ outset, inset }}; - linepatternShader->u_ratio = pixelRatio; + linepatternShader->u_ratio = data.pixelRatio; linepatternShader->u_blur = blur; linepatternShader->u_pattern_size_a = {{imagePosA.size[0] * factor * properties.image.fromScale, imagePosA.size[1]}}; @@ -120,7 +121,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const lineShader->u_matrix = vtxMatrix; lineShader->u_exmatrix = extrudeMatrix; lineShader->u_linewidth = {{ outset, inset }}; - lineShader->u_ratio = pixelRatio; + lineShader->u_ratio = data.pixelRatio; lineShader->u_blur = blur; lineShader->u_color = color; diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index d0757d6297..6d12768e2f 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -8,6 +8,7 @@ #include <mbgl/shader/icon_shader.hpp> #include <mbgl/shader/box_shader.hpp> #include <mbgl/map/tile_id.hpp> +#include <mbgl/map/map_data.hpp> #include <mbgl/util/math.hpp> #include <cmath> @@ -52,7 +53,7 @@ void Painter::renderSDF(SymbolBucket &bucket, sdfShader.u_zoom = (state.getNormalizedZoom() - zoomAdjust) * 10; // current zoom level - FadeProperties f = frameHistory.getFadeProperties(std::chrono::milliseconds(300)); + FadeProperties f = frameHistory.getFadeProperties(data.getDefaultFadeDuration()); sdfShader.u_fadedist = f.fadedist * 10; sdfShader.u_minfadezoom = std::floor(f.minfadezoom * 10); sdfShader.u_maxfadezoom = std::floor(f.maxfadezoom * 10); @@ -60,7 +61,7 @@ void Painter::renderSDF(SymbolBucket &bucket, // The default gamma value has to be adjust for the current pixelratio so that we're not // drawing blurry font on retina screens. - const float gamma = 0.105 * sdfFontSize / fontSize / pixelRatio; + const float gamma = 0.105 * sdfFontSize / fontSize / data.pixelRatio; const float sdfPx = 8.0f; const float blurOffset = 1.19f; diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index cfa56c9922..c99b725e7f 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -160,7 +160,7 @@ bool SymbolBucket::needsDependencies(const GeometryTileLayer& layer, util::mergeLines(features); } - if (glyphStore.requestGlyphRangesIfNeeded(layout.text.font, ranges)) { + if (!glyphStore.hasGlyphRanges(layout.text.font, ranges)) { return true; } diff --git a/src/mbgl/style/applied_class_properties.cpp b/src/mbgl/style/applied_class_properties.cpp index d42102b2a2..6df075b202 100644 --- a/src/mbgl/style/applied_class_properties.cpp +++ b/src/mbgl/style/applied_class_properties.cpp @@ -2,7 +2,7 @@ namespace mbgl { -AppliedClassProperty::AppliedClassProperty(ClassID class_id, TimePoint begin_, TimePoint end_, const PropertyValue &value_) +AppliedClassProperty::AppliedClassProperty(ClassID class_id, const TimePoint& begin_, const TimePoint& end_, const PropertyValue &value_) : name(class_id), begin(begin_), end(end_), @@ -10,35 +10,35 @@ AppliedClassProperty::AppliedClassProperty(ClassID class_id, TimePoint begin_, T // Returns the ID of the most recent ClassID AppliedClassProperties::mostRecent() const { - return properties.size() ? properties.back().name : ClassID::Fallback; + return propertyValues.empty() ? ClassID::Fallback : propertyValues.back().name; } -void AppliedClassProperties::add(ClassID class_id, TimePoint begin, TimePoint end, const PropertyValue &value) { - properties.emplace_back(class_id, begin, end, value); +void AppliedClassProperties::add(ClassID class_id, const TimePoint& begin, const TimePoint& end, const PropertyValue &value) { + propertyValues.emplace_back(class_id, begin, end, value); } bool AppliedClassProperties::hasTransitions() const { - return properties.size() > 1; + return propertyValues.size() > 1; } // Erase all items in the property list that are before a completed transition. // Then, if the only remaining property is a Fallback value, remove it too. -void AppliedClassProperties::cleanup(TimePoint now) { +void AppliedClassProperties::cleanup(const TimePoint& now) { // Iterate backwards, but without using the rbegin/rend interface since we need forward // iterators to use .erase(). - for (auto it = properties.end(), begin = properties.begin(); it != begin;) { + for (auto it = propertyValues.end(), begin = propertyValues.begin(); it != begin;) { // If the property is finished, break iteration and delete all remaining items. if ((--it)->end <= now) { // Removes all items that precede the current iterator, but *not* the element currently // pointed to by the iterator. This preserves the last completed transition as the // first element in the property list. - properties.erase(begin, it); + propertyValues.erase(begin, it); // Also erase the pivot element if it's a fallback value. This means we can remove the // entire applied properties object as well, because we already have the fallback // value set as the default. if (it->name == ClassID::Fallback) { - properties.erase(it); + propertyValues.erase(it); } break; } @@ -46,7 +46,7 @@ void AppliedClassProperties::cleanup(TimePoint now) { } bool AppliedClassProperties::empty() const { - return properties.empty(); + return propertyValues.empty(); } } diff --git a/src/mbgl/style/applied_class_properties.hpp b/src/mbgl/style/applied_class_properties.hpp index 6a0d2a6fba..fbba966143 100644 --- a/src/mbgl/style/applied_class_properties.hpp +++ b/src/mbgl/style/applied_class_properties.hpp @@ -11,7 +11,7 @@ namespace mbgl { class AppliedClassProperty { public: - AppliedClassProperty(ClassID class_id, TimePoint begin, TimePoint end, const PropertyValue &value); + AppliedClassProperty(ClassID class_id, const TimePoint& begin, const TimePoint& end, const PropertyValue &value); public: const ClassID name; @@ -23,14 +23,14 @@ public: class AppliedClassProperties { public: - std::list<AppliedClassProperty> properties; + std::list<AppliedClassProperty> propertyValues; public: // Returns the ID of the most recent ClassID mostRecent() const; - void add(ClassID class_id, TimePoint begin, TimePoint end, const PropertyValue &value); + void add(ClassID class_id, const TimePoint& begin, const TimePoint& end, const PropertyValue &value); + void cleanup(const TimePoint& now); bool hasTransitions() const; - void cleanup(TimePoint now); bool empty() const; }; diff --git a/src/mbgl/style/piecewisefunction_properties.hpp b/src/mbgl/style/piecewisefunction_properties.hpp index 0440655ba5..f05ee68647 100644 --- a/src/mbgl/style/piecewisefunction_properties.hpp +++ b/src/mbgl/style/piecewisefunction_properties.hpp @@ -11,7 +11,6 @@ template <typename T> struct PiecewiseConstantFunction { inline PiecewiseConstantFunction(const std::vector<std::pair<float, T>> &values_, std::chrono::duration<float> duration_) : values(values_), duration(duration_) {} inline PiecewiseConstantFunction(T &value, std::chrono::duration<float> duration_) : values({{ 0, value }}), duration(duration_) {} - inline PiecewiseConstantFunction() : values(), duration(std::chrono::milliseconds(300)) {} T evaluate(float z, const ZoomHistory &zoomHistory) const; private: diff --git a/src/mbgl/style/property_transition.hpp b/src/mbgl/style/property_transition.hpp index 584d67db55..4515fdc921 100644 --- a/src/mbgl/style/property_transition.hpp +++ b/src/mbgl/style/property_transition.hpp @@ -8,6 +8,8 @@ namespace mbgl { struct PropertyTransition { + explicit inline PropertyTransition(const Duration& duration_, const Duration& delay_) + : duration(duration_), delay(delay_) {} Duration duration = Duration::zero(); Duration delay = Duration::zero(); }; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index e091c92f53..5f92bb2664 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -7,6 +7,7 @@ #include <mbgl/style/style_layer.hpp> #include <mbgl/style/style_parser.hpp> #include <mbgl/style/style_bucket.hpp> +#include <mbgl/style/property_transition.hpp> #include <mbgl/geometry/glyph_atlas.hpp> #include <mbgl/geometry/sprite_atlas.hpp> #include <mbgl/geometry/line_atlas.hpp> @@ -21,9 +22,9 @@ namespace mbgl { -Style::Style(MapData& data_, uv_loop_t* loop) +Style::Style(MapData& data_, uv_loop_t*) : data(data_), - glyphStore(std::make_unique<GlyphStore>(loop)), + glyphStore(std::make_unique<GlyphStore>()), glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)), spriteStore(std::make_unique<SpriteStore>()), spriteAtlas(std::make_unique<SpriteAtlas>(512, 512, data.pixelRatio, *spriteStore)), @@ -41,7 +42,7 @@ void Style::setJSON(const std::string& json, const std::string&) { return; } - StyleParser parser; + StyleParser parser(data); parser.parse(doc); sources = parser.getSources(); @@ -86,25 +87,25 @@ void Style::update(const TransformState& transform, } } -void Style::cascade(const std::vector<std::string>& classes) { - TimePoint now = Clock::now(); - +void Style::cascade() { for (const auto& layer : layers) { - layer->setClasses(classes, now, defaultTransition); + layer->setClasses(data.getClasses(), + data.getAnimationTime(), + PropertyTransition { data.getDefaultTransitionDuration(), data.getDefaultTransitionDelay() }); } } -void Style::recalculate(float z, TimePoint now) { +void Style::recalculate(float z) { uv::writelock lock(mtx); for (const auto& source : sources) { source->enabled = false; } - zoomHistory.update(z, now); + zoomHistory.update(z, data.getAnimationTime()); for (const auto& layer : layers) { - layer->updateProperties(z, now, zoomHistory); + layer->updateProperties(z, data.getAnimationTime(), zoomHistory); if (!layer->bucket) { continue; } @@ -126,10 +127,6 @@ Source* Style::getSource(const std::string& id) const { return it != sources.end() ? it->get() : nullptr; } -void Style::setDefaultTransitionDuration(Duration duration) { - defaultTransition.duration = duration; -} - bool Style::hasTransitions() const { for (const auto& layer : layers) { if (layer->hasTransitions()) { diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index d6b762a830..6d8a7ae522 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -54,10 +54,9 @@ public: // a tile is ready so observers can render the tile. void update(const TransformState&, TexturePool&); - void cascade(const std::vector<std::string>&); - void recalculate(float z, TimePoint now); + void cascade(); + void recalculate(float z); - void setDefaultTransitionDuration(Duration); bool hasTransitions() const; std::exception_ptr getLastError() const { @@ -101,7 +100,6 @@ private: std::exception_ptr lastError; - PropertyTransition defaultTransition; std::unique_ptr<uv::rwlock> mtx; ZoomHistory zoomHistory; diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index 8713b73b12..ad96c38c3c 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -28,7 +28,7 @@ bool StyleLayer::isVisible() const { } } -void StyleLayer::setClasses(const std::vector<std::string> &class_names, const TimePoint now, +void StyleLayer::setClasses(const std::vector<std::string> &class_names, const TimePoint& now, const PropertyTransition &defaultTransition) { // Stores all keys that we have already added transitions for. std::set<PropertyKey> already_applied; @@ -69,7 +69,7 @@ void StyleLayer::setClasses(const std::vector<std::string> &class_names, const T // Helper function for applying all properties of a a single class that haven't been applied yet. void StyleLayer::applyClassProperties(const ClassID class_id, - std::set<PropertyKey> &already_applied, TimePoint now, + std::set<PropertyKey> &already_applied, const TimePoint& now, const PropertyTransition &defaultTransition) { auto style_it = styles.find(class_id); if (style_it == styles.end()) { @@ -134,13 +134,13 @@ private: }; template <typename T> -void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, const TimePoint now, const ZoomHistory &zoomHistory) { +void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { auto it = appliedStyle.find(key); if (it != appliedStyle.end()) { AppliedClassProperties &applied = it->second; // Iterate through all properties that we need to apply in order. const PropertyEvaluator<T> evaluator(z, zoomHistory); - for (auto& property : applied.properties) { + for (auto& property : applied.propertyValues) { if (now >= property.begin) { // We overwrite the current property with the new value. target = mapbox::util::apply_visitor(evaluator, property.value); @@ -152,13 +152,13 @@ void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, c } template <typename T> -void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, const float z, const TimePoint now, const ZoomHistory &zoomHistory) { +void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { auto it = appliedStyle.find(key); if (it != appliedStyle.end()) { AppliedClassProperties &applied = it->second; // Iterate through all properties that we need to apply in order. const PropertyEvaluator<T> evaluator(z, zoomHistory); - for (auto& property : applied.properties) { + for (auto& property : applied.propertyValues) { if (now >= property.end) { // We overwrite the current property with the new value. target = mapbox::util::apply_visitor(evaluator, property.value); @@ -174,7 +174,7 @@ void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, cons } template <> -void StyleLayer::applyStyleProperties<FillProperties>(const float z, const TimePoint now, const ZoomHistory &zoomHistory) { +void StyleLayer::applyStyleProperties<FillProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { properties.set<FillProperties>(); FillProperties &fill = properties.get<FillProperties>(); applyStyleProperty(PropertyKey::FillAntialias, fill.antialias, z, now, zoomHistory); @@ -187,7 +187,7 @@ void StyleLayer::applyStyleProperties<FillProperties>(const float z, const TimeP } template <> -void StyleLayer::applyStyleProperties<LineProperties>(const float z, const TimePoint now, const ZoomHistory &zoomHistory) { +void StyleLayer::applyStyleProperties<LineProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { properties.set<LineProperties>(); LineProperties &line = properties.get<LineProperties>(); applyTransitionedStyleProperty(PropertyKey::LineOpacity, line.opacity, z, now, zoomHistory); @@ -201,11 +201,11 @@ void StyleLayer::applyStyleProperties<LineProperties>(const float z, const TimeP applyStyleProperty(PropertyKey::LineImage, line.image, z, now, zoomHistory); // for scaling dasharrays - applyStyleProperty(PropertyKey::LineWidth, line.dash_line_width, std::floor(z), TimePoint::max(), zoomHistory); + applyStyleProperty(PropertyKey::LineWidth, line.dash_line_width, std::floor(z), now, zoomHistory); } template <> -void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const TimePoint now, const ZoomHistory &zoomHistory) { +void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { properties.set<SymbolProperties>(); SymbolProperties &symbol = properties.get<SymbolProperties>(); applyTransitionedStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now, zoomHistory); @@ -228,7 +228,7 @@ void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const Tim } template <> -void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const TimePoint now, const ZoomHistory &zoomHistory) { +void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { properties.set<RasterProperties>(); RasterProperties &raster = properties.get<RasterProperties>(); applyTransitionedStyleProperty(PropertyKey::RasterOpacity, raster.opacity, z, now, zoomHistory); @@ -241,7 +241,7 @@ void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const Tim } template <> -void StyleLayer::applyStyleProperties<BackgroundProperties>(const float z, const TimePoint now, const ZoomHistory &zoomHistory) { +void StyleLayer::applyStyleProperties<BackgroundProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { properties.set<BackgroundProperties>(); BackgroundProperties &background = properties.get<BackgroundProperties>(); applyTransitionedStyleProperty(PropertyKey::BackgroundOpacity, background.opacity, z, now, zoomHistory); @@ -249,7 +249,7 @@ void StyleLayer::applyStyleProperties<BackgroundProperties>(const float z, const applyStyleProperty(PropertyKey::BackgroundImage, background.image, z, now, zoomHistory); } -void StyleLayer::updateProperties(float z, const TimePoint now, ZoomHistory &zoomHistory) { +void StyleLayer::updateProperties(float z, const TimePoint& now, ZoomHistory &zoomHistory) { cleanupAppliedStyleProperties(now); switch (type) { @@ -271,20 +271,12 @@ bool StyleLayer::hasTransitions() const { return false; } - -void StyleLayer::cleanupAppliedStyleProperties(TimePoint now) { - auto it = appliedStyle.begin(); - const auto end = appliedStyle.end(); - while (it != end) { - AppliedClassProperties &applied_properties = it->second; - applied_properties.cleanup(now); - +void StyleLayer::cleanupAppliedStyleProperties(const TimePoint& now) { + for (auto it = appliedStyle.begin(); it != appliedStyle.end();) { + AppliedClassProperties& appliedPropertyValues = it->second; + appliedPropertyValues.cleanup(now); // If the current properties object is empty, remove it from the map entirely. - if (applied_properties.empty()) { - appliedStyle.erase(it++); - } else { - ++it; - } + appliedPropertyValues.empty() ? appliedStyle.erase(it++) : ++it; } } diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp index 774ed39012..97bd479b25 100644 --- a/src/mbgl/style/style_layer.hpp +++ b/src/mbgl/style/style_layer.hpp @@ -40,10 +40,10 @@ public: // Updates the StyleProperties information in this layer by evaluating all // pending transitions and applied classes in order. - void updateProperties(float z, TimePoint now, ZoomHistory &zoomHistory); + void updateProperties(float z, const TimePoint& now, ZoomHistory &zoomHistory); // Sets the list of classes and creates transitions to the currently applied values. - void setClasses(const std::vector<std::string> &class_names, TimePoint now, + void setClasses(const std::vector<std::string> &class_names, const TimePoint& now, const PropertyTransition &defaultTransition); bool hasTransitions() const; @@ -51,16 +51,16 @@ public: private: // Applies all properties from a class, if they haven't been applied already. void applyClassProperties(ClassID class_id, std::set<PropertyKey> &already_applied, - TimePoint now, const PropertyTransition &defaultTransition); + const TimePoint& now, const PropertyTransition &defaultTransition); // Sets the properties of this object by evaluating all pending transitions and // aplied classes in order. - template <typename T> void applyStyleProperties(float z, TimePoint now, const ZoomHistory &zoomHistory); - template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, TimePoint now, const ZoomHistory &zoomHistory); - template <typename T> void applyTransitionedStyleProperty(PropertyKey key, T &, float z, TimePoint now, const ZoomHistory &zoomHistory); + template <typename T> void applyStyleProperties(float z, const TimePoint& now, const ZoomHistory &zoomHistory); + template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, const TimePoint& now, const ZoomHistory &zoomHistory); + template <typename T> void applyTransitionedStyleProperty(PropertyKey key, T &, float z, const TimePoint& now, const ZoomHistory &zoomHistory); // Removes all expired style transitions. - void cleanupAppliedStyleProperties(TimePoint now); + void cleanupAppliedStyleProperties(const TimePoint& now); public: // The name of this layer. diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 53313a548c..4767bdafa3 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -2,6 +2,7 @@ #include <mbgl/map/source.hpp> #include <mbgl/style/style_layer.hpp> #include <mbgl/map/annotation.hpp> +#include <mbgl/map/map_data.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/vec.hpp> #include <mbgl/util/uv_detail.hpp> @@ -21,7 +22,8 @@ namespace mbgl { using JSVal = const rapidjson::Value&; -StyleParser::StyleParser() { +StyleParser::StyleParser(MapData& data_) + : data(data_) { } void StyleParser::parse(JSVal document) { @@ -399,13 +401,13 @@ template <typename T> StyleParser::Result<PiecewiseConstantFunction<T>> StyleParser::parsePiecewiseConstantFunction(JSVal value, Duration duration) { if (!value.HasMember("stops")) { Log::Warning(Event::ParseStyle, "function must specify a function type"); - return Result<PiecewiseConstantFunction<T>> { StyleParserFailure, {} }; + return Result<PiecewiseConstantFunction<T>> { StyleParserFailure, { {}, duration } }; } auto stops = parseStops<T>(value["stops"], ""); if (!std::get<0>(stops)) { - return Result<PiecewiseConstantFunction<T>> { StyleParserFailure, {} }; + return Result<PiecewiseConstantFunction<T>> { StyleParserFailure, { {}, duration } }; } return Result<PiecewiseConstantFunction<T>> { StyleParserSuccess, { std::get<1>(stops), duration } }; @@ -578,20 +580,21 @@ template<> StyleParser::Result<RotationAlignmentType> StyleParser::parseProperty } template<> StyleParser::Result<PropertyTransition> StyleParser::parseProperty(JSVal value, const char */*property_name*/) { - PropertyTransition transition; + PropertyTransition transition { data.getDefaultTransitionDuration(), data.getDefaultTransitionDelay() }; if (value.IsObject()) { + bool parsed = false; if (value.HasMember("duration") && value["duration"].IsNumber()) { transition.duration = std::chrono::milliseconds(value["duration"].GetUint()); + parsed = true; } if (value.HasMember("delay") && value["delay"].IsNumber()) { transition.delay = std::chrono::milliseconds(value["delay"].GetUint()); + parsed = true; + } + if (!parsed) { + return Result<PropertyTransition> { StyleParserFailure, std::move(transition) }; } } - - if (transition.duration == Duration::zero() && transition.delay == Duration::zero()) { - return Result<PropertyTransition> { StyleParserFailure, std::move(transition) }; - } - return Result<PropertyTransition> { StyleParserSuccess, std::move(transition) }; } @@ -653,7 +656,7 @@ template<> StyleParser::Result<Function<Color>> StyleParser::parseProperty(JSVal } template<> StyleParser::Result<PiecewiseConstantFunction<Faded<std::vector<float>>>> StyleParser::parseProperty(JSVal value, const char *property_name, JSVal transition) { - Duration duration = std::chrono::milliseconds(300); + Duration duration = data.getDefaultFadeDuration(); if (transition.HasMember("duration")) { duration = std::chrono::milliseconds(transition["duration"].GetUint()); } @@ -667,13 +670,12 @@ template<> StyleParser::Result<PiecewiseConstantFunction<Faded<std::vector<float return Result<PiecewiseConstantFunction<Faded<std::vector<float>>>> { std::get<0>(floatarray), { parsed, duration } }; } else { Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers, or a number array function", property_name); - return Result<PiecewiseConstantFunction<Faded<std::vector<float>>>> { StyleParserFailure, {} }; + return Result<PiecewiseConstantFunction<Faded<std::vector<float>>>> { StyleParserFailure, { {}, duration } }; } } template<> StyleParser::Result<PiecewiseConstantFunction<Faded<std::string>>> StyleParser::parseProperty(JSVal value, const char *property_name, JSVal transition) { - - Duration duration = std::chrono::milliseconds(300); + Duration duration = data.getDefaultFadeDuration(); if (transition.HasMember("duration")) { duration = std::chrono::milliseconds(transition["duration"].GetUint()); } @@ -686,7 +688,7 @@ template<> StyleParser::Result<PiecewiseConstantFunction<Faded<std::string>>> St return Result<PiecewiseConstantFunction<Faded<std::string>>> { StyleParserSuccess, { parsed, duration } }; } else { Log::Warning(Event::ParseStyle, "value of '%s' must be string or a string function", property_name); - return Result<PiecewiseConstantFunction<Faded<std::string>>> { StyleParserFailure, {} }; + return Result<PiecewiseConstantFunction<Faded<std::string>>> { StyleParserFailure, { {}, duration } }; } } diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp index 2daa5e14d8..5f0c509ebf 100644 --- a/src/mbgl/style/style_parser.hpp +++ b/src/mbgl/style/style_parser.hpp @@ -31,7 +31,7 @@ public: template<typename T> using Result = std::pair<Status, T>; - StyleParser(); + StyleParser(MapData& data); void parse(JSVal document); @@ -117,6 +117,9 @@ private: // URL template for glyph PBFs. std::string glyph_url; + + // Obtain default transition duration from map data. + MapData& data; }; } diff --git a/src/mbgl/style/zoom_history.hpp b/src/mbgl/style/zoom_history.hpp index 2debff8d44..9eb76e5ec1 100644 --- a/src/mbgl/style/zoom_history.hpp +++ b/src/mbgl/style/zoom_history.hpp @@ -13,12 +13,12 @@ struct ZoomHistory { TimePoint lastIntegerZoomTime; bool first = true; - void update(float z, TimePoint now) { + void update(float z, const TimePoint& now) { if (first) { first = false; lastIntegerZoom = std::floor(z); - lastIntegerZoomTime = TimePoint(Duration(0)); + lastIntegerZoomTime = TimePoint(Duration::zero()); lastZoom = z; } diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index 0f507deb44..17c1524a88 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -1,95 +1,98 @@ #include <mbgl/text/glyph_store.hpp> -#include <mbgl/text/glyph_pbf.hpp> -#include <mbgl/text/font_stack.hpp> +#include <mbgl/text/font_stack.hpp> +#include <mbgl/text/glyph_pbf.hpp> #include <mbgl/util/exception.hpp> -#include <mbgl/util/uv_detail.hpp> +#include <mbgl/util/thread_context.hpp> namespace mbgl { -GlyphStore::GlyphStore(uv_loop_t* loop) - : asyncEmitGlyphRangeLoaded(std::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoaded(); })), - asyncEmitGlyphRangeLoadedingFailed(std::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoadingFailed(); })), - observer(nullptr) { - asyncEmitGlyphRangeLoaded->unref(); - asyncEmitGlyphRangeLoadedingFailed->unref(); +GlyphStore::GlyphStore() { } GlyphStore::~GlyphStore() { - observer = nullptr; -} - -void GlyphStore::setURL(const std::string &url) { - glyphURL = url; } -bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStackName, - const std::set<GlyphRange>& glyphRanges) { - bool requestIsNeeded = false; - - if (glyphRanges.empty()) { - return requestIsNeeded; - } +void GlyphStore::requestGlyphRange(const std::string& fontStackName, const GlyphRange& range) { + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); auto successCallback = [this, fontStackName](GlyphPBF* glyph) { - auto fontStack = createFontStack(fontStackName); try { - glyph->parse(**fontStack); - asyncEmitGlyphRangeLoaded->send(); + { + auto fontStack = createFontStack(fontStackName); + glyph->parse(**fontStack); + } + emitGlyphRangeLoaded(); } catch (const std::exception&) { - std::lock_guard<std::mutex> lock(errorMessageMutex); - errorMessage = "Failed to parse [" + glyph->getURL() + "]"; - asyncEmitGlyphRangeLoadedingFailed->send(); + std::string message = "Failed to parse [" + glyph->getURL() + "]"; + emitGlyphRangeLoadingFailed(message); } }; auto failureCallback = [this](const std::string& message) { - std::lock_guard<std::mutex> lock(errorMessageMutex); - errorMessage = message; - asyncEmitGlyphRangeLoadedingFailed->send(); + emitGlyphRangeLoadingFailed(message); }; std::lock_guard<std::mutex> lock(rangesMutex); auto& rangeSets = ranges[fontStackName]; + const auto& rangeSetsIt = rangeSets.find(range); + if (rangeSetsIt != rangeSets.end()) { + return; + } + + rangeSets.emplace(range, std::make_unique<GlyphPBF>(glyphURL, fontStackName, range, + successCallback, failureCallback)); +} + + +bool GlyphStore::hasGlyphRanges(const std::string& fontStackName, const std::set<GlyphRange>& glyphRanges) { + if (glyphRanges.empty()) { + return true; + } + + std::lock_guard<std::mutex> lock(rangesMutex); + const auto& rangeSets = ranges[fontStackName]; + + bool hasRanges = true; + for (const auto& range : glyphRanges) { - const auto& rangeSets_it = rangeSets.find(range); - if (rangeSets_it == rangeSets.end()) { - auto glyph = std::make_unique<GlyphPBF>(glyphURL, fontStackName, range, - successCallback, failureCallback); - rangeSets.emplace(range, std::move(glyph)); - requestIsNeeded = true; + const auto& rangeSetsIt = rangeSets.find(range); + if (rangeSetsIt == rangeSets.end()) { + // Post the request to the Map thread. + workQueue.push(std::bind(&GlyphStore::requestGlyphRange, this, fontStackName, range)); + hasRanges = false; continue; } - if (!rangeSets_it->second->isParsed()) { - requestIsNeeded = true; + if (!rangeSetsIt->second->isParsed()) { + hasRanges = false; } } - return requestIsNeeded; + return hasRanges; } -util::exclusive<FontStack> GlyphStore::createFontStack(const std::string &fontStack) { +util::exclusive<FontStack> GlyphStore::createFontStack(const std::string& fontStack) { auto lock = std::make_unique<std::lock_guard<std::mutex>>(stacksMutex); - auto stack_it = stacks.find(fontStack); - if (stack_it == stacks.end()) { - stack_it = stacks.emplace(fontStack, std::make_unique<FontStack>()).first; + auto it = stacks.find(fontStack); + if (it == stacks.end()) { + it = stacks.emplace(fontStack, std::make_unique<FontStack>()).first; } - return { stack_it->second.get(), std::move(lock) }; + return { it->second.get(), std::move(lock) }; } util::exclusive<FontStack> GlyphStore::getFontStack(const std::string &fontStack) { auto lock = std::make_unique<std::lock_guard<std::mutex>>(stacksMutex); - const auto& stack_it = stacks.find(fontStack); - if (stack_it == stacks.end()) { + const auto& it = stacks.find(fontStack); + if (it == stacks.end()) { return { nullptr, nullptr }; } - return { stack_it->second.get(), std::move(lock) }; + return { it->second.get(), std::move(lock) }; } void GlyphStore::setObserver(Observer* observer_) { @@ -102,13 +105,12 @@ void GlyphStore::emitGlyphRangeLoaded() { } } -void GlyphStore::emitGlyphRangeLoadingFailed() { +void GlyphStore::emitGlyphRangeLoadingFailed(const std::string& message) { if (!observer) { return; } - std::lock_guard<std::mutex> lock(errorMessageMutex); - auto error = std::make_exception_ptr(util::GlyphRangeLoadingException(errorMessage)); + auto error = std::make_exception_ptr(util::GlyphRangeLoadingException(message)); observer->onGlyphRangeLoadingFailed(error); } diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp index a1f69b9943..5d0f498c71 100644 --- a/src/mbgl/text/glyph_store.hpp +++ b/src/mbgl/text/glyph_store.hpp @@ -2,19 +2,14 @@ #define MBGL_TEXT_GLYPH_STORE #include <mbgl/text/glyph.hpp> - #include <mbgl/util/exclusive.hpp> +#include <mbgl/util/run_loop.hpp> +#include <mbgl/util/work_queue.hpp> +#include <exception> #include <set> #include <string> #include <unordered_map> -#include <exception> - -typedef struct uv_loop_s uv_loop_t; - -namespace uv { -class async; -} namespace mbgl { @@ -32,26 +27,25 @@ public: virtual void onGlyphRangeLoadingFailed(std::exception_ptr error) = 0; }; - GlyphStore(uv_loop_t* loop); + GlyphStore(); ~GlyphStore(); - // Asynchronously request for GlyphRanges and when it gets loaded, notifies the - // observer subscribed to this object. Successive requests for the same range are - // going to be discarded. Returns true if a request was made or false if all the - // GlyphRanges are already available, and thus, no request is performed. - bool requestGlyphRangesIfNeeded(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges); + util::exclusive<FontStack> getFontStack(const std::string& fontStack); - util::exclusive<FontStack> getFontStack(const std::string &fontStack); + bool hasGlyphRanges(const std::string& fontStackName, const std::set<GlyphRange>& glyphRanges); - void setURL(const std::string &url); + void setURL(const std::string &url) { + glyphURL = url; + } void setObserver(Observer* observer); private: void emitGlyphRangeLoaded(); - void emitGlyphRangeLoadingFailed(); + void emitGlyphRangeLoadingFailed(const std::string& message); util::exclusive<FontStack> createFontStack(const std::string &fontStack); + void requestGlyphRange(const std::string& fontStackName, const GlyphRange& range); std::string glyphURL; @@ -61,13 +55,9 @@ private: std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks; std::mutex stacksMutex; - std::string errorMessage; - std::mutex errorMessageMutex; - - std::unique_ptr<uv::async> asyncEmitGlyphRangeLoaded; - std::unique_ptr<uv::async> asyncEmitGlyphRangeLoadedingFailed; + util::WorkQueue workQueue; - Observer* observer; + Observer* observer = nullptr; }; } diff --git a/src/mbgl/util/run_loop.cpp b/src/mbgl/util/run_loop.cpp index 7f277c9885..5c95959460 100644 --- a/src/mbgl/util/run_loop.cpp +++ b/src/mbgl/util/run_loop.cpp @@ -15,7 +15,7 @@ RunLoop::~RunLoop() { } void RunLoop::withMutex(std::function<void()>&& fn) { - std::lock_guard<std::mutex> lock(mutex); + std::lock_guard<std::recursive_mutex> lock(mutex); fn(); } diff --git a/src/mbgl/util/run_loop.hpp b/src/mbgl/util/run_loop.hpp index 2175ea977a..7f56c18dcd 100644 --- a/src/mbgl/util/run_loop.hpp +++ b/src/mbgl/util/run_loop.hpp @@ -19,6 +19,10 @@ public: RunLoop(uv_loop_t*); ~RunLoop(); + static RunLoop* Get() { + return current.get(); + } + static uv_loop_t* getLoop() { return current.get()->get(); } @@ -37,6 +41,25 @@ public: async.send(); } + // Post the cancellable work fn(args...) to this RunLoop. + template <class Fn, class... Args> + std::unique_ptr<WorkRequest> + invokeCancellable(Fn&& fn, Args&&... args) { + auto flag = std::make_shared<bool>(); + *flag = false; + + auto tuple = std::make_tuple(std::move(args)...); + auto task = std::make_shared<Invoker<Fn, decltype(tuple)>>( + std::move(fn), + std::move(tuple), + flag); + + withMutex([&] { queue.push(task); }); + async.send(); + + return std::make_unique<WorkRequest>(task); + } + // Invoke fn(args...) on this RunLoop, then invoke callback(results...) on the current RunLoop. template <class Fn, class Cb, class... Args> std::unique_ptr<WorkRequest> @@ -85,7 +108,7 @@ private: void operator()() override { // Lock the mutex while processing so that cancel() will block. - std::lock_guard<std::mutex> lock(mutex); + std::lock_guard<std::recursive_mutex> lock(mutex); if (!canceled || !*canceled) { invoke(std::make_index_sequence<std::tuple_size<P>::value>{}); } @@ -100,7 +123,7 @@ private: // If the task has completed and the after callback has executed, this will // do nothing. void cancel() override { - std::lock_guard<std::mutex> lock(mutex); + std::lock_guard<std::recursive_mutex> lock(mutex); *canceled = true; } @@ -110,7 +133,7 @@ private: func(std::get<I>(std::forward<P>(params))...); } - std::mutex mutex; + std::recursive_mutex mutex; std::shared_ptr<bool> canceled; F func; @@ -123,7 +146,7 @@ private: void process(); Queue queue; - std::mutex mutex; + std::recursive_mutex mutex; uv::async async; static uv::tls<RunLoop> current; diff --git a/src/mbgl/util/transition.cpp b/src/mbgl/util/transition.cpp index 55de25f0c5..bab5e12fdd 100644 --- a/src/mbgl/util/transition.cpp +++ b/src/mbgl/util/transition.cpp @@ -10,7 +10,7 @@ UnitBezier ease(0, 0, 0.25, 1); transition::~transition() {} template <typename T> -transition::state ease_transition<T>::update(TimePoint now) const { +transition::state ease_transition<T>::update(const TimePoint& now) const { float t = progress(now); if (t >= 1) { value = to; diff --git a/src/mbgl/util/transition.hpp b/src/mbgl/util/transition.hpp index de9fffb669..5cfbc0a7ca 100644 --- a/src/mbgl/util/transition.hpp +++ b/src/mbgl/util/transition.hpp @@ -14,18 +14,18 @@ public: complete }; - inline transition(TimePoint start_, Duration duration_) + inline transition(const TimePoint& start_, const Duration& duration_) : start(start_), duration(duration_) {} - inline float progress(TimePoint now) const { + inline float progress(const TimePoint& now) const { if (duration == Duration::zero()) return 1; if (start > now) return 0; return std::chrono::duration<float>(now - start) / duration; } - virtual state update(TimePoint now) const = 0; + virtual state update(const TimePoint& now) const = 0; virtual ~transition(); protected: @@ -36,13 +36,13 @@ protected: template <typename T> class ease_transition : public transition { public: - ease_transition(T from_, T to_, T& value_, TimePoint start_, Duration duration_) + ease_transition(T from_, T to_, T& value_, const TimePoint& start_, const Duration& duration_) : transition(start_, duration_), from(from_), to(to_), value(value_) {} - state update(TimePoint now) const; + state update(const TimePoint& now) const; private: const T from, to; @@ -53,12 +53,12 @@ private: template <typename T> class timeout : public transition { public: - timeout(T final_value_, T& value_, TimePoint start_, Duration duration_) + timeout(T final_value_, T& value_, const TimePoint& start_, const Duration& duration_) : transition(start_, duration_), final_value(final_value_), value(value_) {} - state update(TimePoint now) const { + state update(const TimePoint& now) const { if (progress(now) >= 1) { value = final_value; return complete; diff --git a/src/mbgl/util/work_queue.cpp b/src/mbgl/util/work_queue.cpp new file mode 100644 index 0000000000..7e1406bba0 --- /dev/null +++ b/src/mbgl/util/work_queue.cpp @@ -0,0 +1,37 @@ +#include <mbgl/util/work_queue.hpp> + +#include <mbgl/util/run_loop.hpp> + +namespace mbgl { +namespace util { + +WorkQueue::WorkQueue() : runLoop(RunLoop::Get()) { +} + +WorkQueue::~WorkQueue() { + assert(runLoop == RunLoop::Get()); + + // Cancel all pending WorkRequests. + while (!queue.empty()) { + queue.pop(); + } +} + +void WorkQueue::push(std::function<void()>&& fn) { + std::lock_guard<std::mutex> lock(queueMutex); + + auto workRequest = runLoop->invokeCancellable(std::bind(&WorkQueue::pop, this, std::move(fn))); + queue.push(std::move(workRequest)); +} + +void WorkQueue::pop(const std::function<void()>& fn) { + assert(runLoop == RunLoop::Get()); + + fn(); + + std::lock_guard<std::mutex> lock(queueMutex); + queue.pop(); +} + +} +} diff --git a/src/mbgl/util/work_queue.hpp b/src/mbgl/util/work_queue.hpp new file mode 100644 index 0000000000..dcec5668b9 --- /dev/null +++ b/src/mbgl/util/work_queue.hpp @@ -0,0 +1,36 @@ +#ifndef MBGL_UTIL_WORK_QUEUE +#define MBGL_UTIL_WORK_QUEUE + +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/util/work_request.hpp> + +#include <functional> +#include <memory> +#include <mutex> +#include <queue> + +namespace mbgl { +namespace util { + +class RunLoop; + +class WorkQueue : private util::noncopyable { +public: + WorkQueue(); + virtual ~WorkQueue(); + + void push(std::function<void()>&&); + +private: + void pop(const std::function<void()>&); + + std::queue<std::unique_ptr<WorkRequest>> queue; + std::mutex queueMutex; + + RunLoop* runLoop; +}; + +} +} + +#endif diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp index 60adbc803e..516d2f5dba 100644 --- a/src/mbgl/util/worker.cpp +++ b/src/mbgl/util/worker.cpp @@ -14,11 +14,7 @@ namespace mbgl { class Worker::Impl { public: - explicit Impl(FileSource* fs) { - // FIXME: Workers should not access the FileSource but it - // is currently needed because of GlyphsPBF. See #1664. - util::ThreadContext::setFileSource(fs); - } + Impl() = default; void parseRasterTile(RasterBucket* bucket, std::string data, std::function<void (TileParseResult)> callback) { std::unique_ptr<util::Image> image(new util::Image(data)); @@ -59,7 +55,7 @@ public: Worker::Worker(std::size_t count) { util::ThreadContext context = {"Worker", util::ThreadType::Worker, util::ThreadPriority::Low}; for (std::size_t i = 0; i < count; i++) { - threads.emplace_back(std::make_unique<util::Thread<Impl>>(context, util::ThreadContext::getFileSource())); + threads.emplace_back(std::make_unique<util::Thread<Impl>>(context)); } } diff --git a/test/miscellaneous/style_parser.cpp b/test/miscellaneous/style_parser.cpp index 7a38ba054d..e88d798411 100644 --- a/test/miscellaneous/style_parser.cpp +++ b/test/miscellaneous/style_parser.cpp @@ -3,6 +3,9 @@ #include <mbgl/style/style_parser.hpp> #include <mbgl/util/io.hpp> +#include <mbgl/map/mode.hpp> +#include <mbgl/map/map_data.hpp> + #include <rapidjson/document.h> #include "../fixtures/fixture_log_observer.hpp" @@ -35,7 +38,11 @@ TEST_P(StyleParserTest, ParseStyle) { FixtureLogObserver* observer = new FixtureLogObserver(); Log::setObserver(std::unique_ptr<Log::Observer>(observer)); - StyleParser parser; + MapMode mapMode = MapMode::Continuous; + const float pixelRatio = 1.0f; + + MapData data(mapMode, pixelRatio); + StyleParser parser(data); parser.parse(styleDoc); for (auto it = infoDoc.MemberBegin(), end = infoDoc.MemberEnd(); it != end; it++) { diff --git a/test/miscellaneous/work_queue.cpp b/test/miscellaneous/work_queue.cpp new file mode 100644 index 0000000000..a5f616fe5b --- /dev/null +++ b/test/miscellaneous/work_queue.cpp @@ -0,0 +1,63 @@ +#include "../fixtures/util.hpp" + +#include <mbgl/util/run_loop.hpp> +#include <mbgl/util/thread.hpp> +#include <mbgl/util/work_queue.hpp> + +#include <thread> + +using namespace mbgl::util; + +class TestThread { +public: + TestThread(WorkQueue* queue_) : queue(queue_) {} + + void send(std::function<void()>&& fn) { + EXPECT_TRUE(ThreadContext::currentlyOn(ThreadType::Map)); + + queue->push(std::move(fn)); + } + +private: + WorkQueue* queue; +}; + +TEST(WorkQueue, push) { + RunLoop loop(uv_default_loop()); + + WorkQueue queue; + Thread<TestThread> thread({"Test", ThreadType::Map, ThreadPriority::Regular}, &queue); + + uint8_t count = 0; + + auto endTest = [&]() { + EXPECT_TRUE(ThreadContext::currentlyOn(ThreadType::Main)); + + if (++count == 4) { + loop.stop(); + } + }; + + thread.invoke(&TestThread::send, endTest); + thread.invoke(&TestThread::send, endTest); + thread.invoke(&TestThread::send, endTest); + thread.invoke(&TestThread::send, endTest); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); +} + +TEST(WorkQueue, cancel) { + RunLoop loop(uv_default_loop()); + + WorkQueue queue; + + auto work = [&]() { + FAIL() << "Should never be called"; + }; + + queue.push(work); + queue.push(work); + queue.push(work); + queue.push(work); + queue.push(work); +} diff --git a/test/style/glyph_store.cpp b/test/style/glyph_store.cpp new file mode 100644 index 0000000000..fb4355b98b --- /dev/null +++ b/test/style/glyph_store.cpp @@ -0,0 +1,225 @@ +#include "../fixtures/fixture_log_observer.hpp" +#include "../fixtures/mock_file_source.hpp" +#include "../fixtures/util.hpp" + +#include <mbgl/text/font_stack.hpp> +#include <mbgl/text/glyph_store.hpp> +#include <mbgl/util/run_loop.hpp> +#include <mbgl/util/thread.hpp> + +using namespace mbgl; + +using GlyphStoreTestCallback = std::function<void(GlyphStore*, std::exception_ptr)>; + +struct GlyphStoreParams { + const std::string url; + const std::string stack; + const std::set<GlyphRange> ranges; +}; + +class GlyphStoreThread : public GlyphStore::Observer { +public: + GlyphStoreThread(FileSource* fileSource, GlyphStoreTestCallback callback) : callback_(callback) { + util::ThreadContext::setFileSource(fileSource); + } + + void loadGlyphStore(const GlyphStoreParams& params) { + glyphStore_.reset(new GlyphStore()); + + glyphStore_->setObserver(this); + glyphStore_->setURL(params.url); + + ASSERT_FALSE(glyphStore_->hasGlyphRanges(params.stack, params.ranges)); + } + + void unloadGlyphStore() { + glyphStore_->setObserver(nullptr); + glyphStore_.reset(); + } + + void onGlyphRangeLoaded() override { + callback_(glyphStore_.get(), nullptr); + } + + void onGlyphRangeLoadingFailed(std::exception_ptr error) override { + callback_(glyphStore_.get(), error); + } + +private: + std::unique_ptr<GlyphStore> glyphStore_; + GlyphStoreTestCallback callback_; +}; + +class GlyphStoreTest : public testing::Test { +protected: + void runTest(const GlyphStoreParams& params, FileSource* fileSource, GlyphStoreTestCallback callback) { + util::RunLoop loop(uv_default_loop()); + + async_ = std::make_unique<uv::async>(loop.get(), [&]{ loop.stop(); }); + async_->unref(); + + const util::ThreadContext context = {"Map", util::ThreadType::Map, util::ThreadPriority::Regular}; + + util::Thread<GlyphStoreThread> tester(context, fileSource, callback); + tester.invoke(&GlyphStoreThread::loadGlyphStore, params); + + uv_run(loop.get(), UV_RUN_DEFAULT); + + tester.invoke(&GlyphStoreThread::unloadGlyphStore); + } + + void stopTest() { + testDone = true; + async_->send(); + } + + bool isDone() const { + return testDone; + } + +private: + bool testDone = false; + + std::unique_ptr<uv::async> async_; +}; + +TEST_F(GlyphStoreTest, LoadingSuccess) { + GlyphStoreParams params = { + "test/fixtures/resources/glyphs.pbf", + "Test Stack", + {{0, 255}, {256, 511}} + }; + + auto callback = [this, ¶ms](GlyphStore* store, std::exception_ptr error) { + ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + // We need to check if the test is over because checking + // if the GlyphStore has glyphs below will cause more requests + // to happen and we don't want this endless loop. + if (isDone()) { + return; + } + + ASSERT_EQ(error, nullptr); + + if (!store->hasGlyphRanges(params.stack, params.ranges)) { + return; + } + + ASSERT_FALSE(store->hasGlyphRanges("Foobar", params.ranges)); + ASSERT_FALSE(store->hasGlyphRanges("Foobar", {{512, 767}})); + ASSERT_FALSE(store->hasGlyphRanges("Test Stack", {{512, 767}})); + + auto fontStack = store->getFontStack(params.stack); + ASSERT_FALSE(fontStack->getMetrics().empty()); + ASSERT_FALSE(fontStack->getSDFs().empty()); + + stopTest(); + }; + + MockFileSource fileSource(MockFileSource::Success, ""); + runTest(params, &fileSource, callback); +} + +TEST_F(GlyphStoreTest, LoadingFail) { + GlyphStoreParams params = { + "test/fixtures/resources/glyphs.pbf", + "Test Stack", + {{0, 255}, {256, 511}} + }; + + auto callback = [this, ¶ms](GlyphStore* store, std::exception_ptr error) { + ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + if (isDone()) { + return; + } + + ASSERT_TRUE(error != nullptr); + + auto fontStack = store->getFontStack(params.stack); + ASSERT_EQ(*fontStack, nullptr); + + for (const auto& range : params.ranges) { + ASSERT_FALSE(store->hasGlyphRanges(params.stack, {range})); + } + + ASSERT_FALSE(store->hasGlyphRanges(params.stack, params.ranges)); + ASSERT_FALSE(store->hasGlyphRanges("Foobar", params.ranges)); + ASSERT_FALSE(store->hasGlyphRanges("Foobar", {{512, 767}})); + + stopTest(); + }; + + MockFileSource fileSource(MockFileSource::RequestFail, "glyphs.pbf"); + runTest(params, &fileSource, callback); +} + +TEST_F(GlyphStoreTest, LoadingCorrupted) { + GlyphStoreParams params = { + "test/fixtures/resources/glyphs.pbf", + "Test Stack", + {{0, 255}, {256, 511}} + }; + + auto callback = [this, ¶ms](GlyphStore* store, std::exception_ptr error) { + ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + if (isDone()) { + return; + } + + ASSERT_TRUE(error != nullptr); + + for (const auto& range : params.ranges) { + ASSERT_FALSE(store->hasGlyphRanges(params.stack, {range})); + } + + ASSERT_FALSE(store->hasGlyphRanges(params.stack, params.ranges)); + ASSERT_FALSE(store->hasGlyphRanges("Foobar", params.ranges)); + ASSERT_FALSE(store->hasGlyphRanges("Foobar", {{512, 767}})); + + stopTest(); + }; + + MockFileSource fileSource(MockFileSource::RequestWithCorruptedData, "glyphs.pbf"); + runTest(params, &fileSource, callback); +} + +TEST_F(GlyphStoreTest, LoadingCancel) { + GlyphStoreParams params = { + "test/fixtures/resources/glyphs.pbf", + "Test Stack", + {{0, 255}, {256, 511}} + }; + + auto callback = [this](GlyphStore*, std::exception_ptr) { + FAIL() << "Should never be called"; + }; + + MockFileSource fileSource(MockFileSource::SuccessWithDelay, "glyphs.pbf"); + fileSource.setOnRequestDelayedCallback([this]{ + stopTest(); + }); + runTest(params, &fileSource, callback); +} + +TEST_F(GlyphStoreTest, InvalidURL) { + GlyphStoreParams params = { + "foo bar", + "Test Stack", + {{0, 255}, {256, 511}} + }; + + auto callback = [this, ¶ms](GlyphStore* store, std::exception_ptr error) { + ASSERT_TRUE(error != nullptr); + + auto fontStack = store->getFontStack(params.stack); + ASSERT_EQ(*fontStack, nullptr); + + stopTest(); + }; + + MockFileSource fileSource(MockFileSource::Success, ""); + runTest(params, &fileSource, callback); +} diff --git a/test/style/pending_resources.cpp b/test/style/pending_resources.cpp index 4513d18645..3ba59657de 100644 --- a/test/style/pending_resources.cpp +++ b/test/style/pending_resources.cpp @@ -21,11 +21,6 @@ class PendingResources : public ::testing::TestWithParam<std::string> { // the Map object after that. The idea here is to test if these pending requests // are getting canceled correctly if on shutdown. TEST_P(PendingResources, DeleteMapObjectWithPendingRequest) { - // TODO: The glyphs test is blocked by the issue #1664. - if (GetParam() == "glyphs.pbf") { - return; - } - util::RunLoop loop(uv_default_loop()); auto display = std::make_shared<mbgl::HeadlessDisplay>(); diff --git a/test/test.gypi b/test/test.gypi index 461719e33e..142445d984 100644 --- a/test/test.gypi +++ b/test/test.gypi @@ -69,6 +69,7 @@ 'miscellaneous/thread.cpp', 'miscellaneous/tile.cpp', 'miscellaneous/transform.cpp', + 'miscellaneous/work_queue.cpp', 'miscellaneous/variant.cpp', 'storage/storage.hpp', @@ -87,6 +88,7 @@ 'storage/http_other_loop.cpp', 'storage/http_reading.cpp', + 'style/glyph_store.cpp', 'style/pending_resources.cpp', 'style/resource_loading.cpp', 'style/sprite.cpp', |