Merge remote-tracking branch 'mapbox/master' into android-annotations #1716
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
~VectorTileData();
|
||||
|
||||
Bucket* getBucket(const StyleLayer&) override;
|
||||
size_t countBuckets() const;
|
||||
|
||||
void request(float pixelRatio,
|
||||
const std::function<void()>& callback);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 } };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
util::WorkQueue workQueue;
|
||||
|
||||
std::unique_ptr<uv::async> asyncEmitGlyphRangeLoaded;
|
||||
std::unique_ptr<uv::async> asyncEmitGlyphRangeLoadedingFailed;
|
||||
|
||||
Observer* observer;
|
||||
Observer* observer = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
37
src/mbgl/util/work_queue.cpp
Normal file
37
src/mbgl/util/work_queue.cpp
Normal file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
36
src/mbgl/util/work_queue.hpp
Normal file
36
src/mbgl/util/work_queue.hpp
Normal file
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
63
test/miscellaneous/work_queue.cpp
Normal file
63
test/miscellaneous/work_queue.cpp
Normal file
@@ -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);
|
||||
}
|
||||
225
test/style/glyph_store.cpp
Normal file
225
test/style/glyph_store.cpp
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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>();
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user