Merge remote-tracking branch 'origin/master' into HEAD
Conflicts: src/mbgl/renderer/painter_fill.cpp
This commit is contained in:
2
.mason
2
.mason
Submodule .mason updated: ace19da711...abdc131273
@@ -25,8 +25,10 @@ matrix:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
|
||||
packages: [ 'gdb', 'clang-3.5', 'libstdc++-4.9-dev', 'libstdc++6', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ]
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.3
|
||||
env: FLAVOR=osx BUILDTYPE=Debug
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.3
|
||||
env: FLAVOR=ios BUILDTYPE=Release
|
||||
- os: linux
|
||||
env: FLAVOR=android ANDROID_ABI=arm-v7 BUILDTYPE=Release
|
||||
|
||||
11
README.md
11
README.md
@@ -58,7 +58,15 @@ pod 'MapboxGL'
|
||||
|
||||
#### Manually
|
||||
|
||||
1. Install [appledoc](http://appledoc.gentlebytes.com/appledoc/) for API docs generation. We recommend [`2.2v963`](https://github.com/tomaz/appledoc/releases/tag/v2.2-963), which currently isn't available in Homebrew.
|
||||
1. Install [appledoc](http://appledoc.gentlebytes.com/appledoc/) 2.2v963 for API docs generation (only this exact version works).
|
||||
|
||||
```
|
||||
curl -L -o appledoc.zip https://github.com/tomaz/appledoc/releases/download/v2.2-963/appledoc.zip
|
||||
unzip appledoc.zip
|
||||
cp appledoc /usr/local/bin
|
||||
cp -Rf Templates/ ~/.appledoc
|
||||
```
|
||||
|
||||
1. Run `make ipackage`. The packaging script will produce the statically-linked `libMapboxGL.a`, `MapboxGL.bundle` for resources, a `Headers` folder, and a `Docs` folder with HTML API documentation.
|
||||
1. Copy the contents of `build/ios/pkg/static` into your project. It should happen automatically, but ensure that:
|
||||
- `Headers` is in your *Header Search Paths* (`HEADER_SEARCH_PATHS`) build setting.
|
||||
@@ -82,6 +90,7 @@ pod 'MapboxGL'
|
||||
|
||||
If you want to build from source and/or contribute to development of the project, run `make iproj`, which will create and open an Xcode project which can build the entire library from source as well as an Objective-C test app. If you don't have an Apple Developer account, change the destination from "My Mac" to a simulator such as "iPhone 6" before you run and build the app.
|
||||
|
||||
#### Testing
|
||||
You can run `make itest` to run the included integration tests. Requires `gem install xcpretty`. If you want to run the tests in Xcode instead, first `make ipackage` to create a local static library version, then open `test/ios/ios-tests.xcodeproj`, and lastly `Command + U` on the `Mapbox GL Tests` application target.
|
||||
|
||||
Target devices: iPhone 4S and above (5, 5c, 5s, 6, 6 Plus) and iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2).
|
||||
|
||||
@@ -29,7 +29,7 @@ enum class Event : uint8_t {
|
||||
ParseStyle,
|
||||
ParseTile,
|
||||
Render,
|
||||
ResourceLoader,
|
||||
Style,
|
||||
Database,
|
||||
HttpRequest,
|
||||
Sprite,
|
||||
@@ -47,7 +47,7 @@ MBGL_DEFINE_ENUM_CLASS(EventClass, Event, {
|
||||
{ Event::ParseStyle, "ParseStyle" },
|
||||
{ Event::ParseTile, "ParseTile" },
|
||||
{ Event::Render, "Render" },
|
||||
{ Event::ResourceLoader, "ResourceLoader" },
|
||||
{ Event::Style, "Style" },
|
||||
{ Event::Database, "Database" },
|
||||
{ Event::HttpRequest, "HttpRequest" },
|
||||
{ Event::Sprite, "Sprite" },
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
[super viewDidLoad];
|
||||
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"asset://styles/mapbox-streets-v7.json"];
|
||||
self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds accessToken:nil styleURL:url];
|
||||
self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds styleURL:url];
|
||||
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
self.mapView.delegate = self;
|
||||
self.mapView.zoomEnabled = NO;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z `which appledoc` ]; then
|
||||
echo "Unable to find appledoc. Consider installing it from source or Homebrew."
|
||||
echo "Unable to find appledoc. See https://github.com/mapbox/mapbox-gl-native#manually"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -148,6 +148,8 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
@property (atomic) NSURLSession *session;
|
||||
@property (atomic) NSData *digicertCert;
|
||||
@property (atomic) NSData *geoTrustCert;
|
||||
@property (atomic) NSData *testServerCert;
|
||||
@property (atomic) BOOL usesTestServer;
|
||||
|
||||
// Main thread only
|
||||
@property (nonatomic) CLLocationManager *locationManager;
|
||||
@@ -239,6 +241,10 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
NSString *testURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMetricsTestServerURL"];
|
||||
if (testURL != nil) {
|
||||
MGLMapboxEventsAPIBase = testURL;
|
||||
_usesTestServer = YES;
|
||||
} else {
|
||||
// Explicitly Set For Clarity
|
||||
_usesTestServer = NO;
|
||||
}
|
||||
|
||||
_paused = YES;
|
||||
@@ -256,6 +262,10 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
if (cerPath != nil) {
|
||||
_digicertCert = [NSData dataWithContentsOfFile:cerPath];
|
||||
}
|
||||
cerPath = [resourceBundle pathForResource:@"star_tilestream_net" ofType:@"der"];
|
||||
if (cerPath != nil) {
|
||||
_testServerCert = [NSData dataWithContentsOfFile:cerPath];
|
||||
}
|
||||
|
||||
// Events Control
|
||||
_eventQueue = [[NSMutableArray alloc] init];
|
||||
@@ -848,7 +858,7 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
// Look for a pinned certificate in the server's certificate chain
|
||||
long numKeys = SecTrustGetCertificateCount(serverTrust);
|
||||
|
||||
BOOL found = false;
|
||||
BOOL found = NO;
|
||||
// Try GeoTrust Cert First
|
||||
for (int lc = 0; lc < numKeys; lc++) {
|
||||
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc);
|
||||
@@ -858,7 +868,7 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
if ([remoteCertificateData isEqualToData:_geoTrustCert]) {
|
||||
// Found the certificate; continue connecting
|
||||
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
found = true;
|
||||
found = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -873,11 +883,27 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
if ([remoteCertificateData isEqualToData:_digicertCert]) {
|
||||
// Found the certificate; continue connecting
|
||||
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
found = true;
|
||||
found = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && _usesTestServer) {
|
||||
// See if this is test server
|
||||
for (int lc = 0; lc < numKeys; lc++) {
|
||||
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc);
|
||||
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
|
||||
|
||||
// Compare Remote Key With Local Version
|
||||
if ([remoteCertificateData isEqualToData:_testServerCert]) {
|
||||
// Found the certificate; continue connecting
|
||||
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
found = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// The certificate wasn't found in GeoTrust nor Digicert. Cancel the connection.
|
||||
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
|
||||
BIN
platform/ios/resources/star_tilestream_net.der
Normal file
BIN
platform/ios/resources/star_tilestream_net.der
Normal file
Binary file not shown.
@@ -15,4 +15,10 @@ brew install git
|
||||
mapbox_time "install_awscli" \
|
||||
brew install awscli
|
||||
|
||||
mapbox_time "install_appledoc" \
|
||||
wget https://github.com/tomaz/appledoc/releases/download/v2.2-963/appledoc.zip && \
|
||||
tar xvzf appledoc.zip && \
|
||||
cp appledoc /usr/local/bin && \
|
||||
cp -Rf Templates/ ~/.appledoc
|
||||
|
||||
mkdir -p ${KIF_SCREENSHOTS}
|
||||
|
||||
@@ -98,7 +98,7 @@ cp -prv styles/styles "${OUTPUT}/static/${NAME}.bundle/styles"
|
||||
|
||||
step "Creating API Docs..."
|
||||
if [ -z `which appledoc` ]; then
|
||||
echo "Unable to find appledoc. Consider installing it from source or Homebrew."
|
||||
echo "Unable to find appledoc. See https://github.com/mapbox/mapbox-gl-native#manually"
|
||||
exit 1
|
||||
fi
|
||||
DOCS_OUTPUT="${OUTPUT}/static/Docs"
|
||||
|
||||
@@ -2,19 +2,12 @@
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/still_image.hpp>
|
||||
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
|
||||
#include <mbgl/geometry/glyph_atlas.hpp>
|
||||
#include <mbgl/geometry/sprite_atlas.hpp>
|
||||
#include <mbgl/geometry/line_atlas.hpp>
|
||||
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
|
||||
@@ -34,10 +27,6 @@ MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, Map
|
||||
envScope(env, ThreadType::Map, "Map"),
|
||||
updated(static_cast<UpdateType>(Update::Nothing)),
|
||||
asyncUpdate(std::make_unique<uv::async>(loop, [this] { update(); })),
|
||||
glyphStore(std::make_unique<GlyphStore>(loop, env)),
|
||||
glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)),
|
||||
spriteAtlas(std::make_unique<SpriteAtlas>(512, 512)),
|
||||
lineAtlas(std::make_unique<LineAtlas>(512, 512)),
|
||||
texturePool(std::make_unique<TexturePool>()) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
@@ -51,14 +40,9 @@ MapContext::~MapContext() {
|
||||
|
||||
// Explicit resets currently necessary because these abandon resources that need to be
|
||||
// cleaned up by env.performCleanup();
|
||||
resourceLoader.reset();
|
||||
style.reset();
|
||||
painter.reset();
|
||||
texturePool.reset();
|
||||
lineAtlas.reset();
|
||||
spriteAtlas.reset();
|
||||
glyphAtlas.reset();
|
||||
glyphStore.reset();
|
||||
|
||||
env.performCleanup();
|
||||
|
||||
@@ -116,21 +100,11 @@ void MapContext::setStyleJSON(const std::string& json, const std::string& base)
|
||||
void MapContext::loadStyleJSON(const std::string& json, const std::string& base) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
resourceLoader.reset();
|
||||
style.reset();
|
||||
|
||||
style = std::make_unique<Style>();
|
||||
style->base = base;
|
||||
style->loadJSON((const uint8_t *)json.c_str());
|
||||
style = std::make_unique<Style>(json, base, asyncUpdate->get()->loop, env);
|
||||
style->cascade(data.getClasses());
|
||||
style->setDefaultTransitionDuration(data.getDefaultTransitionDuration());
|
||||
|
||||
glyphStore->setURL(style->glyph_url);
|
||||
|
||||
resourceLoader = std::make_unique<ResourceLoader>();
|
||||
resourceLoader->setObserver(this);
|
||||
resourceLoader->setStyle(style.get());
|
||||
resourceLoader->setGlyphStore(glyphStore.get());
|
||||
style->setObserver(this);
|
||||
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
@@ -138,7 +112,7 @@ void MapContext::loadStyleJSON(const std::string& json, const std::string& base)
|
||||
void MapContext::updateTiles() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
resourceLoader->update(data, transformState, *glyphAtlas, *spriteAtlas, *texturePool);
|
||||
style->update(data, transformState, *texturePool);
|
||||
}
|
||||
|
||||
void MapContext::updateAnnotationTiles(const std::vector<TileID>& ids) {
|
||||
@@ -177,7 +151,7 @@ void MapContext::update() {
|
||||
|
||||
updateTiles();
|
||||
|
||||
if (style->isLoaded() && resourceLoader->getSprite()->isLoaded()) {
|
||||
if (style->isLoaded()) {
|
||||
if (!data.getFullyLoaded()) {
|
||||
data.setFullyLoaded(true);
|
||||
}
|
||||
@@ -220,7 +194,7 @@ void MapContext::render() {
|
||||
assert(style);
|
||||
|
||||
if (!painter) {
|
||||
painter = std::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas);
|
||||
painter = std::make_unique<Painter>();
|
||||
painter->setup();
|
||||
}
|
||||
|
||||
@@ -240,7 +214,7 @@ void MapContext::render() {
|
||||
|
||||
double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
const SpritePosition pos = resourceLoader->getSprite()->getSpritePosition(symbol);
|
||||
const SpritePosition pos = style->sprite->getSpritePosition(symbol);
|
||||
return -pos.height / pos.pixelRatio / 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/map/update.hpp>
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/map/resource_loader.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
@@ -20,20 +20,15 @@ namespace mbgl {
|
||||
|
||||
class View;
|
||||
class MapData;
|
||||
class GlyphStore;
|
||||
class GlyphAtlas;
|
||||
class SpriteAtlas;
|
||||
class LineAtlas;
|
||||
class TexturePool;
|
||||
class Painter;
|
||||
class Sprite;
|
||||
class Style;
|
||||
class Worker;
|
||||
class StillImage;
|
||||
struct LatLng;
|
||||
struct LatLngBounds;
|
||||
|
||||
class MapContext : public ResourceLoader::Observer {
|
||||
class MapContext : public Style::Observer {
|
||||
public:
|
||||
MapContext(uv_loop_t*, View&, FileSource&, MapData&);
|
||||
~MapContext();
|
||||
@@ -59,7 +54,7 @@ public:
|
||||
void setSourceTileCacheSize(size_t size);
|
||||
void onLowMemory();
|
||||
|
||||
// ResourceLoader::Observer implementation.
|
||||
// Style::Observer implementation.
|
||||
void onTileDataChanged() override;
|
||||
void onResourceLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
@@ -81,14 +76,9 @@ private:
|
||||
UpdateType updated { static_cast<UpdateType>(Update::Nothing) };
|
||||
std::unique_ptr<uv::async> asyncUpdate;
|
||||
|
||||
std::unique_ptr<GlyphStore> glyphStore;
|
||||
std::unique_ptr<GlyphAtlas> glyphAtlas;
|
||||
std::unique_ptr<SpriteAtlas> spriteAtlas;
|
||||
std::unique_ptr<LineAtlas> lineAtlas;
|
||||
std::unique_ptr<TexturePool> texturePool;
|
||||
std::unique_ptr<Painter> painter;
|
||||
std::unique_ptr<Style> style;
|
||||
std::unique_ptr<ResourceLoader> resourceLoader;
|
||||
|
||||
std::string styleURL;
|
||||
std::string styleJSON;
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
#include <mbgl/map/resource_loader.hpp>
|
||||
|
||||
#include <mbgl/geometry/sprite_atlas.hpp>
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/sprite.hpp>
|
||||
#include <mbgl/map/transform.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
ResourceLoader::ResourceLoader() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
}
|
||||
|
||||
ResourceLoader::~ResourceLoader() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
for (const auto& source : style_->sources) {
|
||||
source->setObserver(nullptr);
|
||||
}
|
||||
|
||||
if (sprite_) {
|
||||
sprite_->setObserver(nullptr);
|
||||
}
|
||||
|
||||
if (glyphStore_) {
|
||||
glyphStore_->setObserver(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceLoader::setObserver(Observer* observer) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
assert(!observer_);
|
||||
|
||||
observer_ = observer;
|
||||
}
|
||||
|
||||
void ResourceLoader::setStyle(Style* style) {
|
||||
assert(style);
|
||||
|
||||
style_ = style;
|
||||
|
||||
for (const auto& source : style->sources) {
|
||||
source->setObserver(this);
|
||||
source->load();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceLoader::setGlyphStore(GlyphStore* glyphStore) {
|
||||
assert(glyphStore);
|
||||
|
||||
if (glyphStore_) {
|
||||
glyphStore_->setObserver(nullptr);
|
||||
}
|
||||
|
||||
glyphStore_ = glyphStore;
|
||||
glyphStore_->setObserver(this);
|
||||
}
|
||||
|
||||
void ResourceLoader::update(MapData& data,
|
||||
const TransformState& transform,
|
||||
GlyphAtlas& glyphAtlas,
|
||||
SpriteAtlas& spriteAtlas,
|
||||
TexturePool& texturePool) {
|
||||
if (!style_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float pixelRatio = transform.getPixelRatio();
|
||||
if (!sprite_ || !sprite_->hasPixelRatio(pixelRatio)) {
|
||||
sprite_ = std::make_unique<Sprite>(style_->getSpriteURL(), pixelRatio);
|
||||
sprite_->setObserver(this);
|
||||
|
||||
spriteAtlas.resize(pixelRatio);
|
||||
spriteAtlas.setSprite(sprite_);
|
||||
}
|
||||
|
||||
bool allTilesUpdated = true;
|
||||
for (const auto& source : style_->sources) {
|
||||
if (!source->update(data, transform, *style_, glyphAtlas, *glyphStore_,
|
||||
spriteAtlas, sprite_, texturePool, shouldReparsePartialTiles_)) {
|
||||
allTilesUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
// We can only stop updating "partial" tiles when all of them
|
||||
// were notified of the arrival of the new resources.
|
||||
if (allTilesUpdated) {
|
||||
shouldReparsePartialTiles_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceLoader::onGlyphRangeLoaded() {
|
||||
shouldReparsePartialTiles_ = true;
|
||||
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void ResourceLoader::onGlyphRangeLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void ResourceLoader::onSourceLoaded() {
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void ResourceLoader::onSourceLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void ResourceLoader::onTileLoaded(bool isNewTile) {
|
||||
if (isNewTile) {
|
||||
shouldReparsePartialTiles_ = true;
|
||||
}
|
||||
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void ResourceLoader::onTileLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void ResourceLoader::onSpriteLoaded() {
|
||||
shouldReparsePartialTiles_ = true;
|
||||
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void ResourceLoader::onSpriteLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void ResourceLoader::emitTileDataChanged() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
if (observer_) {
|
||||
observer_->onTileDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceLoader::emitResourceLoadingFailed(std::exception_ptr error) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
try {
|
||||
if (error) {
|
||||
std::rethrow_exception(error);
|
||||
}
|
||||
} catch(const std::exception& e) {
|
||||
Log::Error(Event::ResourceLoader, e.what());
|
||||
}
|
||||
|
||||
if (observer_) {
|
||||
observer_->onResourceLoadingFailed(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
#ifndef MBGL_MAP_RESOURCE_LOADER
|
||||
#define MBGL_MAP_RESOURCE_LOADER
|
||||
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/sprite.hpp>
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class GlyphAtlas;
|
||||
class GlyphStore;
|
||||
class MapData;
|
||||
class SpriteAtlas;
|
||||
class Style;
|
||||
class TexturePool;
|
||||
class TransformState;
|
||||
|
||||
// ResourceLoader is responsible for loading and updating the Source(s) owned
|
||||
// by the Style. The Source object currently owns all the tiles, thus this
|
||||
// class will notify its observers of any change on these tiles which will
|
||||
// ultimately cause a new rendering to be triggered.
|
||||
class ResourceLoader : public GlyphStore::Observer,
|
||||
public Source::Observer,
|
||||
public Sprite::Observer,
|
||||
private util::noncopyable {
|
||||
public:
|
||||
class Observer {
|
||||
public:
|
||||
virtual ~Observer() = default;
|
||||
|
||||
virtual void onTileDataChanged() = 0;
|
||||
virtual void onResourceLoadingFailed(std::exception_ptr error) = 0;
|
||||
};
|
||||
|
||||
ResourceLoader();
|
||||
~ResourceLoader();
|
||||
|
||||
void setObserver(Observer* observer);
|
||||
|
||||
// The style object currently owns all the sources. When setting
|
||||
// a new style we will go through all of them and try to load.
|
||||
void setStyle(Style* style);
|
||||
|
||||
// TODO: Move GlyphStore to ResourceLoader. We cannot do it now
|
||||
// because we reset the ResourceLoader every time we change the
|
||||
// style.
|
||||
void setGlyphStore(GlyphStore* glyphStore);
|
||||
|
||||
// Fetch the tiles needed by the current viewport and emit a signal when
|
||||
// a tile is ready so observers can render the tile.
|
||||
void update(MapData&, const TransformState&, GlyphAtlas&, SpriteAtlas&, TexturePool&);
|
||||
|
||||
// FIXME: There is probably a better place for this.
|
||||
inline util::ptr<Sprite> getSprite() const {
|
||||
return sprite_;
|
||||
}
|
||||
|
||||
// GlyphStore::Observer implementation.
|
||||
void onGlyphRangeLoaded() override;
|
||||
void onGlyphRangeLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
// Source::Observer implementation.
|
||||
void onSourceLoaded() override;
|
||||
void onSourceLoadingFailed(std::exception_ptr error) override;
|
||||
void onTileLoaded(bool isNewTile) override;
|
||||
void onTileLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
// Sprite::Observer implementation.
|
||||
void onSpriteLoaded() override;
|
||||
void onSpriteLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
private:
|
||||
void emitTileDataChanged();
|
||||
void emitResourceLoadingFailed(std::exception_ptr error);
|
||||
|
||||
bool shouldReparsePartialTiles_ = false;
|
||||
|
||||
util::ptr<Sprite> sprite_;
|
||||
|
||||
GlyphStore* glyphStore_ = nullptr;
|
||||
Style* style_ = nullptr;
|
||||
|
||||
Observer* observer_ = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -42,11 +42,7 @@ using namespace mbgl;
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
|
||||
|
||||
Painter::Painter(SpriteAtlas& spriteAtlas_, GlyphAtlas& glyphAtlas_, LineAtlas& lineAtlas_)
|
||||
: spriteAtlas(spriteAtlas_)
|
||||
, glyphAtlas(glyphAtlas_)
|
||||
, lineAtlas(lineAtlas_)
|
||||
{
|
||||
Painter::Painter() {
|
||||
}
|
||||
|
||||
Painter::~Painter() {
|
||||
@@ -173,6 +169,10 @@ void Painter::prepareTile(const Tile& tile) {
|
||||
void Painter::render(const Style& style, TransformState state_, TimePoint time) {
|
||||
state = state_;
|
||||
|
||||
glyphAtlas = style.glyphAtlas.get();
|
||||
spriteAtlas = style.spriteAtlas.get();
|
||||
lineAtlas = style.lineAtlas.get();
|
||||
|
||||
std::set<Source*> sources;
|
||||
for (const auto& source : style.sources) {
|
||||
if (source->enabled) {
|
||||
@@ -193,9 +193,9 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
|
||||
|
||||
tileStencilBuffer.upload();
|
||||
tileBorderBuffer.upload();
|
||||
spriteAtlas.upload();
|
||||
lineAtlas.upload();
|
||||
glyphAtlas.upload();
|
||||
spriteAtlas->upload();
|
||||
lineAtlas->upload();
|
||||
glyphAtlas->upload();
|
||||
|
||||
for (const auto& item : order) {
|
||||
if (item.bucket && item.bucket->needsUpload()) {
|
||||
@@ -391,8 +391,8 @@ void Painter::renderBackground(const StyleLayer &layer_desc) {
|
||||
if ((properties.opacity >= 1.0f) != (pass == RenderPass::Opaque))
|
||||
return;
|
||||
|
||||
SpriteAtlasPosition imagePosA = spriteAtlas.getPosition(properties.image.from, true);
|
||||
SpriteAtlasPosition imagePosB = spriteAtlas.getPosition(properties.image.to, true);
|
||||
SpriteAtlasPosition imagePosA = spriteAtlas->getPosition(properties.image.from, true);
|
||||
SpriteAtlasPosition imagePosB = spriteAtlas->getPosition(properties.image.to, true);
|
||||
float zoomFraction = state.getZoomFraction();
|
||||
|
||||
useProgram(patternShader->program);
|
||||
@@ -441,7 +441,7 @@ void Painter::renderBackground(const StyleLayer &layer_desc) {
|
||||
|
||||
backgroundBuffer.bind();
|
||||
patternShader->bind(0);
|
||||
spriteAtlas.bind(true);
|
||||
spriteAtlas->bind(true);
|
||||
} else {
|
||||
Color color = properties.color;
|
||||
color[0] *= properties.opacity;
|
||||
|
||||
@@ -79,7 +79,7 @@ struct RenderItem {
|
||||
|
||||
class Painter : private util::noncopyable {
|
||||
public:
|
||||
Painter(SpriteAtlas&, GlyphAtlas&, LineAtlas&);
|
||||
Painter();
|
||||
~Painter();
|
||||
|
||||
void setup();
|
||||
@@ -204,9 +204,9 @@ private:
|
||||
public:
|
||||
FrameHistory frameHistory;
|
||||
|
||||
SpriteAtlas& spriteAtlas;
|
||||
GlyphAtlas& glyphAtlas;
|
||||
LineAtlas& lineAtlas;
|
||||
SpriteAtlas* spriteAtlas;
|
||||
GlyphAtlas* glyphAtlas;
|
||||
LineAtlas* lineAtlas;
|
||||
|
||||
std::unique_ptr<PlainShader> plainShader;
|
||||
std::unique_ptr<OutlineShader> outlineShader;
|
||||
|
||||
@@ -63,8 +63,8 @@ void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const
|
||||
// Image fill.
|
||||
if (pass == RenderPass::Translucent) {
|
||||
|
||||
const SpriteAtlasPosition posA = spriteAtlas.getPosition(properties.image.from, true);
|
||||
const SpriteAtlasPosition posB = spriteAtlas.getPosition(properties.image.to, true);
|
||||
const SpriteAtlasPosition posA = spriteAtlas->getPosition(properties.image.from, true);
|
||||
const SpriteAtlasPosition posB = spriteAtlas->getPosition(properties.image.to, true);
|
||||
float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z) / id.overscaling;
|
||||
|
||||
mat3 patternMatrixA;
|
||||
@@ -91,7 +91,7 @@ void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const
|
||||
patternShader->u_patternmatrix_b = patternMatrixB;
|
||||
|
||||
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
|
||||
spriteAtlas.bind(true);
|
||||
spriteAtlas->bind(true);
|
||||
|
||||
// Draw the actual triangles into the color & stencil buffer.
|
||||
config.depthMask = GL_TRUE;
|
||||
|
||||
@@ -66,9 +66,9 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
linesdfShader->u_blur = blur;
|
||||
linesdfShader->u_color = color;
|
||||
|
||||
LinePatternPos posA = lineAtlas.getDashPosition(properties.dash_array.from, layout.cap == CapType::Round);
|
||||
LinePatternPos posB = lineAtlas.getDashPosition(properties.dash_array.to, layout.cap == CapType::Round);
|
||||
lineAtlas.bind();
|
||||
LinePatternPos posA = lineAtlas->getDashPosition(properties.dash_array.from, layout.cap == CapType::Round);
|
||||
LinePatternPos posB = lineAtlas->getDashPosition(properties.dash_array.to, layout.cap == CapType::Round);
|
||||
lineAtlas->bind();
|
||||
|
||||
float patternratio = std::pow(2.0, std::floor(std::log2(state.getScale())) - id.z) / 8.0 * id.overscaling;
|
||||
float scaleXA = patternratio / posA.width / properties.dash_line_width / properties.dash_array.fromScale;
|
||||
@@ -81,14 +81,14 @@ 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 * state.getPixelRatio()) / 2;
|
||||
linesdfShader->u_sdfgamma = lineAtlas->width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * state.getPixelRatio()) / 2;
|
||||
linesdfShader->u_mix = properties.dash_array.t;
|
||||
|
||||
bucket.drawLineSDF(*linesdfShader);
|
||||
|
||||
} else if (properties.image.from.size()) {
|
||||
SpriteAtlasPosition imagePosA = spriteAtlas.getPosition(properties.image.from, true);
|
||||
SpriteAtlasPosition imagePosB = spriteAtlas.getPosition(properties.image.to, true);
|
||||
SpriteAtlasPosition imagePosA = spriteAtlas->getPosition(properties.image.from, true);
|
||||
SpriteAtlasPosition imagePosB = spriteAtlas->getPosition(properties.image.to, true);
|
||||
|
||||
float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z) * id.overscaling;
|
||||
|
||||
@@ -110,7 +110,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
linepatternShader->u_opacity = properties.opacity;
|
||||
|
||||
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
|
||||
spriteAtlas.bind(true);
|
||||
spriteAtlas->bind(true);
|
||||
config.depthRange = { strata + strata_epsilon, 1.0f }; // may or may not matter
|
||||
|
||||
bucket.drawLinePatterns(*linepatternShader);
|
||||
|
||||
@@ -162,7 +162,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
|
||||
const float fontSize = properties.icon.size != 0 ? properties.icon.size : layout.icon.max_size;
|
||||
const float fontScale = fontSize / 1.0f;
|
||||
|
||||
spriteAtlas.bind(state.isChanging() || layout.placement == PlacementType::Line || angleOffset != 0 || fontScale != 1 || sdf);
|
||||
spriteAtlas->bind(state.isChanging() || layout.placement == PlacementType::Line || angleOffset != 0 || fontScale != 1 || sdf);
|
||||
|
||||
if (sdf) {
|
||||
renderSDF(bucket,
|
||||
@@ -171,7 +171,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
|
||||
layout.icon,
|
||||
properties.icon,
|
||||
1.0f,
|
||||
{{ float(spriteAtlas.getWidth()) / 4.0f, float(spriteAtlas.getHeight()) / 4.0f }},
|
||||
{{ float(spriteAtlas->getWidth()) / 4.0f, float(spriteAtlas->getHeight()) / 4.0f }},
|
||||
*sdfIconShader,
|
||||
&SymbolBucket::drawIcons);
|
||||
} else {
|
||||
@@ -189,7 +189,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
|
||||
useProgram(iconShader->program);
|
||||
iconShader->u_matrix = vtxMatrix;
|
||||
iconShader->u_exmatrix = exMatrix;
|
||||
iconShader->u_texsize = {{ float(spriteAtlas.getWidth()) / 4.0f, float(spriteAtlas.getHeight()) / 4.0f }};
|
||||
iconShader->u_texsize = {{ float(spriteAtlas->getWidth()) / 4.0f, float(spriteAtlas->getHeight()) / 4.0f }};
|
||||
|
||||
// adjust min/max zooms for variable font sies
|
||||
float zoomAdjust = std::log(fontSize / layout.icon.max_size) / std::log(2);
|
||||
@@ -207,7 +207,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
|
||||
}
|
||||
|
||||
if (bucket.hasTextData()) {
|
||||
glyphAtlas.bind();
|
||||
glyphAtlas->bind();
|
||||
|
||||
renderSDF(bucket,
|
||||
id,
|
||||
@@ -215,7 +215,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
|
||||
layout.text,
|
||||
properties.text,
|
||||
24.0f,
|
||||
{{ float(glyphAtlas.width) / 4, float(glyphAtlas.height) / 4 }},
|
||||
{{ float(glyphAtlas->width) / 4, float(glyphAtlas->height) / 4 }},
|
||||
*sdfGlyphShader,
|
||||
&SymbolBucket::drawGlyphs);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/map/sprite.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/style_parser.hpp>
|
||||
#include <mbgl/style/style_bucket.hpp>
|
||||
#include <mbgl/geometry/glyph_atlas.hpp>
|
||||
#include <mbgl/geometry/sprite_atlas.hpp>
|
||||
#include <mbgl/geometry/line_atlas.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
@@ -15,15 +19,77 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
Style::Style()
|
||||
: mtx(std::make_unique<uv::rwlock>()),
|
||||
Style::Style(const std::string& data, const std::string&,
|
||||
uv_loop_t* loop, Environment& env)
|
||||
: glyphStore(std::make_unique<GlyphStore>(loop, env)),
|
||||
glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)),
|
||||
spriteAtlas(std::make_unique<SpriteAtlas>(512, 512)),
|
||||
lineAtlas(std::make_unique<LineAtlas>(512, 512)),
|
||||
mtx(std::make_unique<uv::rwlock>()),
|
||||
workers(4) {
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<0>((const char *const)data.c_str());
|
||||
if (doc.HasParseError()) {
|
||||
Log::Error(Event::ParseStyle, "Error parsing style JSON at %i: %s", doc.GetErrorOffset(), doc.GetParseError());
|
||||
return;
|
||||
}
|
||||
|
||||
StyleParser parser;
|
||||
parser.parse(doc);
|
||||
|
||||
sources = parser.getSources();
|
||||
layers = parser.getLayers();
|
||||
|
||||
spriteURL = parser.getSprite();
|
||||
glyphStore->setURL(parser.getGlyphURL());
|
||||
|
||||
for (const auto& source : sources) {
|
||||
source->setObserver(this);
|
||||
source->load();
|
||||
}
|
||||
|
||||
glyphStore->setObserver(this);
|
||||
}
|
||||
|
||||
// Note: This constructor is seemingly empty, but we need to declare it anyway
|
||||
// because this file includes uv_detail.hpp, which has the declarations necessary
|
||||
// for deleting the std::unique_ptr<uv::rwlock>.
|
||||
Style::~Style() {}
|
||||
Style::~Style() {
|
||||
for (const auto& source : sources) {
|
||||
source->setObserver(nullptr);
|
||||
}
|
||||
|
||||
glyphStore->setObserver(nullptr);
|
||||
|
||||
if (sprite) {
|
||||
sprite->setObserver(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Style::update(MapData& data,
|
||||
const TransformState& transform,
|
||||
TexturePool& texturePool) {
|
||||
const float pixelRatio = transform.getPixelRatio();
|
||||
if (!sprite || !sprite->hasPixelRatio(pixelRatio)) {
|
||||
sprite = std::make_unique<Sprite>(spriteURL, pixelRatio);
|
||||
sprite->setObserver(this);
|
||||
|
||||
spriteAtlas->resize(pixelRatio);
|
||||
spriteAtlas->setSprite(sprite);
|
||||
}
|
||||
|
||||
bool allTilesUpdated = true;
|
||||
for (const auto& source : sources) {
|
||||
if (!source->update(data, transform, *this, *glyphAtlas, *glyphStore,
|
||||
*spriteAtlas, sprite, texturePool, shouldReparsePartialTiles)) {
|
||||
allTilesUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
// We can only stop updating "partial" tiles when all of them
|
||||
// were notified of the arrival of the new resources.
|
||||
if (allTilesUpdated) {
|
||||
shouldReparsePartialTiles = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Style::cascade(const std::vector<std::string>& classes) {
|
||||
TimePoint now = Clock::now();
|
||||
@@ -50,10 +116,6 @@ void Style::recalculate(float z, TimePoint now) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &Style::getSpriteURL() const {
|
||||
return sprite_url;
|
||||
}
|
||||
|
||||
void Style::setDefaultTransitionDuration(Duration duration) {
|
||||
defaultTransition.duration = duration;
|
||||
}
|
||||
@@ -67,44 +129,89 @@ bool Style::hasTransitions() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Style::loadJSON(const uint8_t *const data) {
|
||||
uv::writelock lock(mtx);
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<0>((const char *const)data);
|
||||
if (doc.HasParseError()) {
|
||||
Log::Error(Event::ParseStyle, "Error parsing style JSON at %i: %s", doc.GetErrorOffset(), doc.GetParseError());
|
||||
return;
|
||||
}
|
||||
|
||||
StyleParser parser;
|
||||
parser.parse(doc);
|
||||
|
||||
sources = parser.getSources();
|
||||
layers = parser.getLayers();
|
||||
sprite_url = parser.getSprite();
|
||||
glyph_url = parser.getGlyphURL();
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
bool Style::isLoaded() const {
|
||||
// TODO: move loading into Style
|
||||
if (!loaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& source : sources) {
|
||||
if (!source->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move sprite into Style
|
||||
// if (sprite && !sprite.isLoaded()) {
|
||||
// return false;
|
||||
// }
|
||||
if (sprite && !sprite->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Style::setObserver(Observer* observer_) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
assert(!observer);
|
||||
|
||||
observer = observer_;
|
||||
}
|
||||
|
||||
void Style::onGlyphRangeLoaded() {
|
||||
shouldReparsePartialTiles = true;
|
||||
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void Style::onGlyphRangeLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void Style::onSourceLoaded() {
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void Style::onSourceLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void Style::onTileLoaded(bool isNewTile) {
|
||||
if (isNewTile) {
|
||||
shouldReparsePartialTiles = true;
|
||||
}
|
||||
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void Style::onTileLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void Style::onSpriteLoaded() {
|
||||
shouldReparsePartialTiles = true;
|
||||
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void Style::onSpriteLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void Style::emitTileDataChanged() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
if (observer) {
|
||||
observer->onTileDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Style::emitResourceLoadingFailed(std::exception_ptr error) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
try {
|
||||
if (error) {
|
||||
std::rethrow_exception(error);
|
||||
}
|
||||
} catch(const std::exception& e) {
|
||||
Log::Error(Event::Style, e.what());
|
||||
}
|
||||
|
||||
if (observer) {
|
||||
observer->onResourceLoadingFailed(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include <mbgl/style/property_transition.hpp>
|
||||
#include <mbgl/style/zoom_history.hpp>
|
||||
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/sprite.hpp>
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
|
||||
#include <mbgl/util/uv.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
@@ -16,33 +20,77 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Source;
|
||||
class Environment;
|
||||
class GlyphAtlas;
|
||||
class GlyphStore;
|
||||
class SpriteAtlas;
|
||||
class LineAtlas;
|
||||
class StyleLayer;
|
||||
|
||||
class Style : public util::noncopyable {
|
||||
class Style : public GlyphStore::Observer,
|
||||
public Source::Observer,
|
||||
public Sprite::Observer,
|
||||
public util::noncopyable {
|
||||
public:
|
||||
Style();
|
||||
Style(const std::string& data,
|
||||
const std::string& base,
|
||||
uv_loop_t*, Environment&);
|
||||
~Style();
|
||||
|
||||
void loadJSON(const uint8_t *const data);
|
||||
class Observer {
|
||||
public:
|
||||
virtual ~Observer() = default;
|
||||
|
||||
virtual void onTileDataChanged() = 0;
|
||||
virtual void onResourceLoadingFailed(std::exception_ptr error) = 0;
|
||||
};
|
||||
|
||||
void setObserver(Observer*);
|
||||
|
||||
bool isLoaded() const;
|
||||
|
||||
// Fetch the tiles needed by the current viewport and emit a signal when
|
||||
// a tile is ready so observers can render the tile.
|
||||
void update(MapData&, const TransformState&, TexturePool&);
|
||||
|
||||
void cascade(const std::vector<std::string>&);
|
||||
void recalculate(float z, TimePoint now);
|
||||
|
||||
void setDefaultTransitionDuration(Duration);
|
||||
bool hasTransitions() const;
|
||||
|
||||
const std::string &getSpriteURL() const;
|
||||
std::unique_ptr<GlyphStore> glyphStore;
|
||||
std::unique_ptr<GlyphAtlas> glyphAtlas;
|
||||
util::ptr<Sprite> sprite;
|
||||
std::unique_ptr<SpriteAtlas> spriteAtlas;
|
||||
std::unique_ptr<LineAtlas> lineAtlas;
|
||||
|
||||
std::vector<util::ptr<Source>> sources;
|
||||
std::vector<util::ptr<StyleLayer>> layers;
|
||||
std::string glyph_url;
|
||||
std::string base;
|
||||
|
||||
private:
|
||||
bool loaded = false;
|
||||
std::string sprite_url;
|
||||
// GlyphStore::Observer implementation.
|
||||
void onGlyphRangeLoaded() override;
|
||||
void onGlyphRangeLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
// Source::Observer implementation.
|
||||
void onSourceLoaded() override;
|
||||
void onSourceLoadingFailed(std::exception_ptr error) override;
|
||||
void onTileLoaded(bool isNewTile) override;
|
||||
void onTileLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
// Sprite::Observer implementation.
|
||||
void onSpriteLoaded() override;
|
||||
void onSpriteLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
void emitTileDataChanged();
|
||||
void emitResourceLoadingFailed(std::exception_ptr error);
|
||||
|
||||
bool shouldReparsePartialTiles = false;
|
||||
|
||||
Observer* observer = nullptr;
|
||||
|
||||
std::string spriteURL;
|
||||
PropertyTransition defaultTransition;
|
||||
std::unique_ptr<uv::rwlock> mtx;
|
||||
ZoomHistory zoomHistory;
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#import "MapboxGL.h"
|
||||
#import "OHHTTPStubs.h"
|
||||
|
||||
const NSUInteger MGLMaximumEventsPerFlush = 20;
|
||||
const NSTimeInterval MGLFlushInterval = 60;
|
||||
|
||||
@interface MGLMapboxEvents (Testing)
|
||||
|
||||
- (NSString *)appBundleId;
|
||||
@@ -18,9 +21,6 @@
|
||||
- (NSMutableArray *)eventQueue;
|
||||
- (void)postEvents:(NSArray *)events;
|
||||
- (NSTimer *)timer;
|
||||
- (NSUInteger)flushAt;
|
||||
- (NSTimeInterval)flushAfter;
|
||||
- (void)setFlushAfter:(NSTimeInterval)newFlushAfter;
|
||||
- (void)flush;
|
||||
- (void)startTimer;
|
||||
|
||||
@@ -28,15 +28,12 @@
|
||||
|
||||
@interface MetricsTests : KIFTestCase
|
||||
|
||||
@property (nonatomic) NSTimeInterval defaultFlushAfter;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MetricsTests
|
||||
|
||||
- (void)beforeAll {
|
||||
[tester acknowledgeSystemAlert];
|
||||
self.defaultFlushAfter = [[MGLMapboxEvents sharedManager] flushAfter];
|
||||
}
|
||||
|
||||
- (void)beforeEach {
|
||||
@@ -44,8 +41,6 @@
|
||||
[MGLMapboxEvents resumeMetricsCollection];
|
||||
|
||||
[MGLAccountManager setAccessToken:@"pk.eyJ1IjoianVzdGluIiwiYSI6IlpDbUJLSUEifQ.4mG8vhelFMju6HpIY-Hi5A"];
|
||||
|
||||
[[MGLMapboxEvents sharedManager] setFlushAfter:self.defaultFlushAfter];
|
||||
}
|
||||
|
||||
- (void)afterEach {
|
||||
@@ -76,7 +71,6 @@
|
||||
|
||||
- (void)testFlushAtThreshold {
|
||||
NSUInteger startCount = [[[MGLMapboxEvents sharedManager] eventQueue] count];
|
||||
NSUInteger flushAt = [[MGLMapboxEvents sharedManager] flushAt];
|
||||
|
||||
XCTestExpectation *queueItemsExpectation = [self expectationWithDescription:@"queue should contain events"];
|
||||
|
||||
@@ -89,7 +83,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
for (NSUInteger i = 0; i < (flushAt - startCount - 1); i++) {
|
||||
for (NSUInteger i = 0; i < (MGLMaximumEventsPerFlush - startCount - 1); i++) {
|
||||
[self pushFakeEvent];
|
||||
}
|
||||
|
||||
@@ -146,8 +140,6 @@
|
||||
|
||||
[self waitForExpectationsWithTimeout:1.0 handler:nil];
|
||||
|
||||
[[MGLMapboxEvents sharedManager] setFlushAfter:5];
|
||||
|
||||
id eventsMock = [OCMockObject partialMockForObject:[MGLMapboxEvents sharedManager]];
|
||||
[[[eventsMock expect] andForwardToRealObject] startTimer];
|
||||
[self pushFakeEvent];
|
||||
@@ -155,7 +147,7 @@
|
||||
|
||||
XCTAssertEqual([[[MGLMapboxEvents sharedManager] eventQueue] count], 1);
|
||||
XCTAssertNotNil([[MGLMapboxEvents sharedManager] timer]);
|
||||
XCTAssertEqual([[MGLMapboxEvents sharedManager] flushAfter], [[[MGLMapboxEvents sharedManager] timer] timeInterval]);
|
||||
XCTAssertEqual(MGLFlushInterval, [[[MGLMapboxEvents sharedManager] timer] timeInterval]);
|
||||
}
|
||||
|
||||
- (void)testTimerFiresFlush {
|
||||
@@ -174,11 +166,10 @@
|
||||
|
||||
[self waitForExpectationsWithTimeout:1.0 handler:nil];
|
||||
|
||||
[[MGLMapboxEvents sharedManager] setFlushAfter:5];
|
||||
[self pushFakeEvent];
|
||||
id eventsMock = [OCMockObject partialMockForObject:[MGLMapboxEvents sharedManager]];
|
||||
[[eventsMock expect] flush];
|
||||
[eventsMock verifyWithDelay:[[MGLMapboxEvents sharedManager] flushAfter]];
|
||||
[eventsMock verifyWithDelay:MGLFlushInterval];
|
||||
}
|
||||
|
||||
- (void)testFlushPostsEvents {
|
||||
|
||||
@@ -55,6 +55,15 @@
|
||||
<Test
|
||||
Identifier = "MapViewTests/testDelegateRegionWillChange">
|
||||
</Test>
|
||||
<Test
|
||||
Identifier = "MetricsTests/testFlushPostsEvents">
|
||||
</Test>
|
||||
<Test
|
||||
Identifier = "MetricsTests/testPostEventsNetworkRequest">
|
||||
</Test>
|
||||
<Test
|
||||
Identifier = "MetricsTests/testTimerFiresFlush">
|
||||
</Test>
|
||||
</SkippedTests>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../fixtures/util.hpp"
|
||||
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/style_parser.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
@@ -22,27 +22,23 @@ class StyleParserTest : public ::testing::TestWithParam<std::string> {};
|
||||
TEST_P(StyleParserTest, ParseStyle) {
|
||||
const std::string &base = "test/fixtures/style_parser/" + GetParam();
|
||||
|
||||
const std::string style_path = base + ".style.json";
|
||||
const std::string info = util::read_file(base + ".info.json");
|
||||
rapidjson::Document infoDoc;
|
||||
infoDoc.Parse<0>(util::read_file(base + ".info.json").c_str());
|
||||
ASSERT_FALSE(infoDoc.HasParseError());
|
||||
ASSERT_TRUE(infoDoc.IsObject());
|
||||
|
||||
// Parse settings.
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<0>((const char *const)info.c_str());
|
||||
ASSERT_FALSE(doc.HasParseError());
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
|
||||
std::ifstream stylefile(style_path);
|
||||
ASSERT_TRUE(stylefile.good());
|
||||
std::stringstream stylejson;
|
||||
stylejson << stylefile.rdbuf();
|
||||
rapidjson::Document styleDoc;
|
||||
styleDoc.Parse<0>(util::read_file(base + ".style.json").c_str());
|
||||
ASSERT_FALSE(styleDoc.HasParseError());
|
||||
ASSERT_TRUE(styleDoc.IsObject());
|
||||
|
||||
FixtureLogObserver* observer = new FixtureLogObserver();
|
||||
Log::setObserver(std::unique_ptr<Log::Observer>(observer));
|
||||
|
||||
Style style;
|
||||
style.loadJSON((const uint8_t *)stylejson.str().c_str());
|
||||
StyleParser parser;
|
||||
parser.parse(styleDoc);
|
||||
|
||||
for (auto it = doc.MemberBegin(), end = doc.MemberEnd(); it != end; it++) {
|
||||
for (auto it = infoDoc.MemberBegin(), end = infoDoc.MemberEnd(); it != end; it++) {
|
||||
const std::string name { it->name.GetString(), it->name.GetStringLength() };
|
||||
const rapidjson::Value &value = it->value;
|
||||
ASSERT_EQ(true, value.IsObject());
|
||||
|
||||
@@ -3,14 +3,10 @@
|
||||
#include "mock_file_source.hpp"
|
||||
#include "mock_view.hpp"
|
||||
|
||||
#include <mbgl/geometry/glyph_atlas.hpp>
|
||||
#include <mbgl/geometry/sprite_atlas.hpp>
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
#include <mbgl/map/resource_loader.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
@@ -21,7 +17,7 @@ using namespace mbgl;
|
||||
|
||||
namespace {
|
||||
|
||||
class MockMapContext : public ResourceLoader::Observer {
|
||||
class MockMapContext : public Style::Observer {
|
||||
public:
|
||||
MockMapContext(uv_loop_t* loop,
|
||||
View& view,
|
||||
@@ -30,36 +26,19 @@ public:
|
||||
: env_(fileSource),
|
||||
envScope_(env_, ThreadType::Map, "Map"),
|
||||
data_(view, MapMode::Still),
|
||||
glyphStore_(std::make_unique<GlyphStore>(loop, env_)),
|
||||
glyphAtlas_(std::make_unique<GlyphAtlas>(1024, 1024)),
|
||||
spriteAtlas_(std::make_unique<SpriteAtlas>(512, 512)),
|
||||
texturePool_(std::make_unique<TexturePool>()),
|
||||
style_(std::make_unique<Style>()),
|
||||
resourceLoader_(std::make_unique<ResourceLoader>()),
|
||||
asyncUpdate(std::make_unique<uv::async>(loop, [this] { update(); })),
|
||||
callback_(callback) {
|
||||
asyncUpdate->unref();
|
||||
|
||||
data_.transform.resize(1000, 1000, 1.0, 1000, 1000);
|
||||
data_.transform.setLatLngZoom({0, 0}, 16);
|
||||
|
||||
const std::string style = util::read_file("test/fixtures/resources/style.json");
|
||||
style_->loadJSON(reinterpret_cast<const uint8_t *>(style.c_str()));
|
||||
|
||||
glyphStore_->setURL(style_->glyph_url);
|
||||
|
||||
resourceLoader_->setGlyphStore(glyphStore_.get());
|
||||
resourceLoader_->setObserver(this);
|
||||
resourceLoader_->setStyle(style_.get());
|
||||
style_ = std::make_unique<Style>(style, "", loop, env_),
|
||||
style_->setObserver(this);
|
||||
}
|
||||
|
||||
~MockMapContext() {
|
||||
resourceLoader_.reset();
|
||||
style_.reset();
|
||||
texturePool_.reset();
|
||||
spriteAtlas_.reset();
|
||||
glyphAtlas_.reset();
|
||||
glyphStore_.reset();
|
||||
env_.performCleanup();
|
||||
}
|
||||
|
||||
void update() {
|
||||
@@ -69,19 +48,16 @@ public:
|
||||
data_.transform.updateTransitions(now);
|
||||
|
||||
transformState_ = data_.transform.currentState();
|
||||
|
||||
resourceLoader_->update(
|
||||
data_, transformState_, *glyphAtlas_, *spriteAtlas_, *texturePool_);
|
||||
style_->update(data_, transformState_, texturePool_);
|
||||
}
|
||||
|
||||
// ResourceLoader::Observer implementation.
|
||||
// Style::Observer implementation.
|
||||
void onTileDataChanged() override {
|
||||
util::ptr<Sprite> sprite = resourceLoader_->getSprite();
|
||||
if (sprite && sprite->isLoaded() && style_->isLoaded()) {
|
||||
update();
|
||||
|
||||
if (style_->isLoaded()) {
|
||||
callback_(nullptr);
|
||||
}
|
||||
|
||||
asyncUpdate->send();
|
||||
};
|
||||
|
||||
void onResourceLoadingFailed(std::exception_ptr error) override {
|
||||
@@ -94,15 +70,9 @@ private:
|
||||
|
||||
MapData data_;
|
||||
TransformState transformState_;
|
||||
TexturePool texturePool_;
|
||||
|
||||
std::unique_ptr<GlyphStore> glyphStore_;
|
||||
std::unique_ptr<GlyphAtlas> glyphAtlas_;
|
||||
std::unique_ptr<SpriteAtlas> spriteAtlas_;
|
||||
std::unique_ptr<TexturePool> texturePool_;
|
||||
std::unique_ptr<Style> style_;
|
||||
std::unique_ptr<ResourceLoader> resourceLoader_;
|
||||
|
||||
std::unique_ptr<uv::async> asyncUpdate;
|
||||
|
||||
std::function<void(std::exception_ptr error)> callback_;
|
||||
};
|
||||
@@ -118,7 +88,13 @@ void runTestCase(MockFileSource::Type type,
|
||||
FixtureLogObserver* log = new FixtureLogObserver();
|
||||
Log::setObserver(std::unique_ptr<Log::Observer>(log));
|
||||
|
||||
auto callback = [&loop, ¶m](std::exception_ptr error) {
|
||||
auto callback = [type, &loop, ¶m](std::exception_ptr error) {
|
||||
if (type == MockFileSource::Success) {
|
||||
EXPECT_TRUE(error == nullptr);
|
||||
} else {
|
||||
EXPECT_TRUE(error != nullptr);
|
||||
}
|
||||
|
||||
try {
|
||||
if (error) {
|
||||
std::rethrow_exception(error);
|
||||
@@ -150,7 +126,7 @@ void runTestCase(MockFileSource::Type type,
|
||||
|
||||
const FixtureLogObserver::LogMessage logMessage {
|
||||
EventSeverity::Error,
|
||||
Event::ResourceLoader,
|
||||
Event::Style,
|
||||
int64_t(-1),
|
||||
message,
|
||||
};
|
||||
@@ -167,21 +143,21 @@ void runTestCase(MockFileSource::Type type,
|
||||
|
||||
}
|
||||
|
||||
class ResourceLoaderTest : public ::testing::TestWithParam<std::string> {
|
||||
class ResourceLoading : public ::testing::TestWithParam<std::string> {
|
||||
};
|
||||
|
||||
TEST_P(ResourceLoaderTest, Success) {
|
||||
TEST_P(ResourceLoading, Success) {
|
||||
runTestCase(MockFileSource::Success, GetParam(), std::string());
|
||||
}
|
||||
|
||||
TEST_P(ResourceLoaderTest, RequestFail) {
|
||||
TEST_P(ResourceLoading, RequestFail) {
|
||||
std::stringstream message;
|
||||
message << "Failed to load [test/fixtures/resources/" << GetParam() << "]: Failed by the test case";
|
||||
|
||||
runTestCase(MockFileSource::RequestFail, GetParam(), message.str());
|
||||
}
|
||||
|
||||
TEST_P(ResourceLoaderTest, RequestWithCorruptedData) {
|
||||
TEST_P(ResourceLoading, RequestWithCorruptedData) {
|
||||
const std::string param(GetParam());
|
||||
|
||||
std::stringstream message;
|
||||
@@ -200,5 +176,5 @@ TEST_P(ResourceLoaderTest, RequestWithCorruptedData) {
|
||||
runTestCase(MockFileSource::RequestWithCorruptedData, GetParam(), message.str());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResourceLoader, ResourceLoaderTest,
|
||||
INSTANTIATE_TEST_CASE_P(Style, ResourceLoading,
|
||||
::testing::Values("source.json", "sprite.json", "sprite.png", "vector.pbf", "glyphs.pbf"));
|
||||
@@ -58,11 +58,6 @@
|
||||
'miscellaneous/variant.cpp',
|
||||
'miscellaneous/worker.cpp',
|
||||
|
||||
'resources/mock_file_source.cpp',
|
||||
'resources/mock_file_source.hpp',
|
||||
'resources/mock_view.hpp',
|
||||
'resources/resource_loader.cpp',
|
||||
|
||||
'storage/storage.hpp',
|
||||
'storage/storage.cpp',
|
||||
'storage/cache_response.cpp',
|
||||
@@ -78,6 +73,11 @@
|
||||
'storage/http_load.cpp',
|
||||
'storage/http_other_loop.cpp',
|
||||
'storage/http_reading.cpp',
|
||||
|
||||
'style/mock_file_source.cpp',
|
||||
'style/mock_file_source.hpp',
|
||||
'style/mock_view.hpp',
|
||||
'style/resource_loading.cpp',
|
||||
],
|
||||
'libraries': [
|
||||
'<@(uv_static_libs)',
|
||||
|
||||
Reference in New Issue
Block a user