Merge branch 'master' of https://github.com/mapbox/mapbox-gl-native into android-mason
Conflicts: gyp/common.gypi include/mbgl/geometry/vao.hpp include/mbgl/platform/event.hpp include/mbgl/platform/gl.hpp platform/default/http_request_baton_curl.cpp src/storage/response.cpp
This commit is contained in:
2
Makefile
2
Makefile
@@ -55,7 +55,7 @@ build/macosx/Makefile: macosx/mapboxgl-app.gyp config.gypi
|
||||
|
||||
.PHONY: build/test/test.xcodeproj
|
||||
build/test/test.xcodeproj: test/test.gyp config.gypi
|
||||
deps/run_gyp test/test.gyp -Iconfig.gypi -Dplatform=osx --depth=. -Goutput_dir=.. --generator-output=./build -f xcode
|
||||
deps/run_gyp test/test.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. -Goutput_dir=.. --generator-output=./build -f xcode
|
||||
|
||||
.PHONY: build/macosx/mapboxgl-app.xcodeproj
|
||||
build/macosx/mapboxgl-app.xcodeproj: macosx/mapboxgl-app.gyp config.gypi
|
||||
|
||||
@@ -24,7 +24,12 @@
|
||||
],
|
||||
'variables': {
|
||||
'ldflags': [
|
||||
'-llog -landroid -lEGL -lGLESv2 -lstdc++ -latomic '
|
||||
'-llog',
|
||||
'-landroid',
|
||||
'-lEGL',
|
||||
'-lGLESv2',
|
||||
'-lstdc++',
|
||||
'-latomic',
|
||||
'<@(png_ldflags)',
|
||||
'<@(sqlite3_ldflags)',
|
||||
'<@(openssl_ldflags)',
|
||||
|
||||
@@ -14,7 +14,16 @@
|
||||
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
|
||||
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
||||
'GCC_ENABLE_CPP_RTTI':'YES',
|
||||
'OTHER_CPLUSPLUSFLAGS': [ '-Wall', '-Wextra', '-Wshadow', '-Wno-variadic-macros', '-frtti', '-fexceptions' ],
|
||||
'OTHER_CPLUSPLUSFLAGS': [
|
||||
'-Werror',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wshadow',
|
||||
'-Wno-variadic-macros',
|
||||
'-frtti',
|
||||
'-fexceptions',
|
||||
'-Wno-error=unused-parameter',
|
||||
],
|
||||
'GCC_WARN_PEDANTIC': 'YES',
|
||||
'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE',
|
||||
},
|
||||
@@ -23,7 +32,8 @@
|
||||
'cflags_cc': [
|
||||
'-Wno-unknown-pragmas', # We are using '#pragma mark', but it is only available on Darwin.
|
||||
'-Wno-literal-suffix', # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61653
|
||||
'-Wno-unknown-warning-option'
|
||||
'-Wno-unknown-warning-option',
|
||||
'-Wno-error=unused-parameter',
|
||||
],
|
||||
}],
|
||||
],
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
'<@(uv_cflags)',
|
||||
'<@(curl_cflags)',
|
||||
'<@(nu_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
],
|
||||
'cflags': [
|
||||
'<@(uv_cflags)',
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
#if GL_ARB_vertex_array_object
|
||||
class VertexArrayObject : public util::noncopyable {
|
||||
public:
|
||||
inline VertexArrayObject() {};
|
||||
@@ -28,7 +27,9 @@ public:
|
||||
if (bound_shader == 0) {
|
||||
vertexBuffer.bind();
|
||||
shader.bind(offset);
|
||||
storeBinding(shader, vertexBuffer.getID(), 0, offset);
|
||||
if (vao) {
|
||||
storeBinding(shader, vertexBuffer.getID(), 0, offset);
|
||||
}
|
||||
} else {
|
||||
verifyBinding(shader, vertexBuffer.getID(), 0, offset);
|
||||
}
|
||||
@@ -41,7 +42,9 @@ public:
|
||||
vertexBuffer.bind();
|
||||
elementsBuffer.bind();
|
||||
shader.bind(offset);
|
||||
storeBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset);
|
||||
if (vao) {
|
||||
storeBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset);
|
||||
}
|
||||
} else {
|
||||
verifyBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset);
|
||||
}
|
||||
@@ -65,30 +68,6 @@ private:
|
||||
char *bound_offset = 0;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class VertexArrayObject : public util::noncopyable {
|
||||
public:
|
||||
inline VertexArrayObject() {};
|
||||
|
||||
inline VertexArrayObject(VertexArrayObject &&) noexcept {};
|
||||
|
||||
template <typename Shader, typename VertexBuffer>
|
||||
inline void bind(Shader& shader, VertexBuffer &vertexBuffer, char *offset) {
|
||||
vertexBuffer.bind();
|
||||
shader.bind(offset);
|
||||
}
|
||||
|
||||
template <typename Shader, typename VertexBuffer, typename ElementsBuffer>
|
||||
inline void bind(Shader& shader, VertexBuffer &vertexBuffer, ElementsBuffer &elementsBuffer, char *offset) {
|
||||
vertexBuffer.bind();
|
||||
elementsBuffer.bind();
|
||||
shader.bind(offset);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
~HeadlessView();
|
||||
|
||||
void createContext();
|
||||
void loadExtensions();
|
||||
|
||||
void resize(uint16_t width, uint16_t height, float pixelRatio);
|
||||
std::unique_ptr<uint32_t[]> readPixels();
|
||||
|
||||
@@ -33,6 +33,7 @@ enum class Event : uint8_t {
|
||||
HttpRequest,
|
||||
Sprite,
|
||||
Image,
|
||||
OpenGL,
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(EventClass, Event, {
|
||||
@@ -46,6 +47,7 @@ MBGL_DEFINE_ENUM_CLASS(EventClass, Event, {
|
||||
{ Event::HttpRequest, "HttpRequest" },
|
||||
{ Event::Sprite, "Sprite" },
|
||||
{ Event::Image, "Image" },
|
||||
{ Event::OpenGL, "OpenGL" },
|
||||
{ Event(-1), "Unknown" },
|
||||
});
|
||||
|
||||
|
||||
@@ -3,35 +3,22 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef NVIDIA
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
extern PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
|
||||
|
||||
#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
|
||||
#elif __APPLE__
|
||||
#if __APPLE__
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#define glGenVertexArrays glGenVertexArraysOES
|
||||
#define glBindVertexArray glBindVertexArrayOES
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
#define GL_ARB_vertex_array_object 1
|
||||
#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
|
||||
// #define glGenVertexArrays glGenVertexArraysOES
|
||||
// #define glBindVertexArray glBindVertexArrayOES
|
||||
// #define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
// #define GL_ARB_vertex_array_object 1
|
||||
// #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
|
||||
#elif TARGET_IPHONE_SIMULATOR
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#elif TARGET_OS_MAC
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/gl.h>
|
||||
#if GL_APPLE_vertex_array_object
|
||||
#define GL_ARB_vertex_array_object 1
|
||||
#define glGenVertexArrays glGenVertexArraysAPPLE
|
||||
#define glBindVertexArray glBindVertexArrayAPPLE
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported Apple platform
|
||||
#endif
|
||||
@@ -39,7 +26,6 @@
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
|
||||
#else
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
@@ -48,8 +34,19 @@
|
||||
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
typedef void (* PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
typedef void (* PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
|
||||
typedef void (* PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
|
||||
typedef GLboolean (* PFNGLISVERTEXARRAYPROC) (GLuint array);
|
||||
extern PFNGLBINDVERTEXARRAYPROC BindVertexArray;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
|
||||
extern PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
|
||||
extern PFNGLISVERTEXARRAYPROC IsVertexArray;
|
||||
|
||||
|
||||
// Debug group markers, useful for debuggin on iOS
|
||||
#if defined(__APPLE__) && defined(DEBUG) && defined(GL_EXT_debug_marker)
|
||||
#if __APPLE__ && defined(DEBUG) && defined(GL_EXT_debug_marker)
|
||||
// static int indent = 0;
|
||||
inline void start_group(const std::string &str) {
|
||||
glPushGroupMarkerEXT(0, str.c_str());
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace bgi = bg::index;
|
||||
typedef bgm::point<float, 2, bg::cs::cartesian> Point;
|
||||
typedef bgm::box<Point> Box;
|
||||
typedef std::pair<Box, PlacementBox> PlacementValue;
|
||||
typedef bgi::rtree<PlacementValue, bgi::rstar<16>> Tree;
|
||||
typedef bgi::rtree<PlacementValue, bgi::linear<16,4>> Tree;
|
||||
|
||||
class Collision {
|
||||
|
||||
|
||||
@@ -93,8 +93,8 @@ Image::Image(const std::string &source_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
width = CGImageGetWidth(image);
|
||||
height = CGImageGetHeight(image);
|
||||
width = uint32_t(CGImageGetWidth(image));
|
||||
height = uint32_t(CGImageGetHeight(image));
|
||||
CGRect rect = {{ 0, 0 }, { static_cast<CGFloat>(width), static_cast<CGFloat>(height) }};
|
||||
|
||||
img = ::std::unique_ptr<char[]>(new char[width * height * 4]());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <mbgl/platform/default/glfw_view.hpp>
|
||||
#include <mbgl/platform/gl.hpp>
|
||||
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
@@ -26,6 +27,10 @@ void GLFWView::initialize(mbgl::Map *map_) {
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
|
||||
#endif
|
||||
|
||||
#ifdef GL_ES_VERSION_2_0
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
@@ -63,6 +68,25 @@ void GLFWView::initialize(mbgl::Map *map_) {
|
||||
glfwSetScrollCallback(window, scroll);
|
||||
glfwSetKeyCallback(window, key);
|
||||
|
||||
|
||||
const std::string extensions = (char *)glGetString(GL_EXTENSIONS);
|
||||
{
|
||||
using namespace mbgl;
|
||||
|
||||
|
||||
if (extensions.find("GL_ARB_vertex_array_object") != std::string::npos) {
|
||||
gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)glfwGetProcAddress("glBindVertexArrayARB");
|
||||
gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)glfwGetProcAddress("glDeleteVertexArraysARB");
|
||||
gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)glfwGetProcAddress("glGenVertexArraysARB");
|
||||
gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)glfwGetProcAddress("glIsVertexArrayARB");
|
||||
} else if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) {
|
||||
gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)glfwGetProcAddress("glBindVertexArrayAPPLE");
|
||||
gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)glfwGetProcAddress("glDeleteVertexArraysAPPLE");
|
||||
gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)glfwGetProcAddress("glGenVertexArraysAPPLE");
|
||||
gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)glfwGetProcAddress("glIsVertexArrayAPPLE");
|
||||
}
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,16 +11,62 @@ static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MBGL_USE_CGL
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
typedef void (* CGLProc)(void);
|
||||
CGLProc CGLGetProcAddress(const char *proc) {
|
||||
static CFBundleRef framework = nullptr;
|
||||
if (!framework) {
|
||||
framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
||||
if (!framework) {
|
||||
throw std::runtime_error("Failed to load OpenGL.framework");
|
||||
}
|
||||
}
|
||||
|
||||
CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, proc, kCFStringEncodingASCII);
|
||||
CGLProc symbol = (CGLProc)CFBundleGetFunctionPointerForName(framework, name);
|
||||
CFRelease(name);
|
||||
return symbol;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
|
||||
HeadlessView::HeadlessView()
|
||||
: display_(std::make_shared<HeadlessDisplay>()) {
|
||||
createContext();
|
||||
loadExtensions();
|
||||
}
|
||||
|
||||
HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display)
|
||||
: display_(display) {
|
||||
createContext();
|
||||
loadExtensions();
|
||||
}
|
||||
|
||||
void HeadlessView::loadExtensions() {
|
||||
make_active();
|
||||
const std::string extensions = (char *)glGetString(GL_EXTENSIONS);
|
||||
|
||||
#ifdef MBGL_USE_CGL
|
||||
if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) {
|
||||
gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)CGLGetProcAddress("glBindVertexArrayAPPLE");
|
||||
gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)CGLGetProcAddress("glDeleteVertexArraysAPPLE");
|
||||
gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)CGLGetProcAddress("glGenVertexArraysAPPLE");
|
||||
gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)CGLGetProcAddress("glIsVertexArrayAPPLE");
|
||||
}
|
||||
#endif
|
||||
#ifdef MBGL_USE_GLX
|
||||
if (extensions.find("GL_ARB_vertex_array_object") != std::string::npos) {
|
||||
gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)glXGetProcAddress((const GLubyte *)"glBindVertexArrayARB");
|
||||
gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)glXGetProcAddress((const GLubyte *)"glDeleteVertexArraysARB");
|
||||
gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)glXGetProcAddress((const GLubyte *)"glGenVertexArraysARB");
|
||||
gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)glXGetProcAddress((const GLubyte *)"glIsVertexArrayARB");
|
||||
}
|
||||
#endif
|
||||
make_inactive();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <mbgl/storage/http_request_baton.hpp>
|
||||
#include <mbgl/util/uv-messenger.h>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/time.hpp>
|
||||
#ifdef __ANDROID__
|
||||
#include "../../android/cpp/NativeMapView.hpp"
|
||||
@@ -23,7 +21,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -77,24 +75,81 @@ static std::queue<CURL *> handles;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
struct CURLContext {
|
||||
util::ptr<HTTPRequestBaton> baton;
|
||||
uv_poll_t *poll_handle = nullptr;
|
||||
curl_socket_t sockfd = 0;
|
||||
struct Context {
|
||||
const util::ptr<HTTPRequestBaton> baton;
|
||||
CURL *handle = nullptr;
|
||||
curl_slist *headers = nullptr;
|
||||
|
||||
CURLContext(const util::ptr<HTTPRequestBaton> &baton_) : baton(baton_) {
|
||||
Context(const util::ptr<HTTPRequestBaton> &baton_) : baton(baton_) {
|
||||
assert(baton);
|
||||
baton->ptr = this;
|
||||
|
||||
if (!handles.empty()) {
|
||||
handle = handles.front();
|
||||
handles.pop();
|
||||
} else {
|
||||
handle = curl_easy_init();
|
||||
}
|
||||
}
|
||||
|
||||
~CURLContext() {
|
||||
// We are destructing the poll handle in a CURL callback already.
|
||||
assert(!poll_handle);
|
||||
~Context() {
|
||||
baton->ptr = nullptr;
|
||||
|
||||
// Once the CURLContext gets destroyed, CURL doesn't need any headers anymore.
|
||||
if (headers) {
|
||||
curl_slist_free_all(headers);
|
||||
headers = nullptr;
|
||||
}
|
||||
|
||||
CURLMcode error = curl_multi_remove_handle(multi, handle);
|
||||
if (error != CURLM_OK) {
|
||||
baton->response = std::unique_ptr<Response>(new Response());
|
||||
baton->response->code = -1;
|
||||
baton->response->message = curl_multi_strerror(error);
|
||||
}
|
||||
|
||||
curl_easy_setopt(handle, CURLOPT_PRIVATE, nullptr);
|
||||
curl_easy_reset(handle);
|
||||
handles.push(handle);
|
||||
handle = nullptr;
|
||||
|
||||
if (baton->async) {
|
||||
uv_async_send(baton->async);
|
||||
baton->async = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Socket {
|
||||
private:
|
||||
uv_poll_t poll_handle;
|
||||
|
||||
public:
|
||||
const curl_socket_t sockfd = 0;
|
||||
|
||||
public:
|
||||
Socket(curl_socket_t sockfd_) : sockfd(sockfd_) {
|
||||
uv_poll_init_socket(loop, &poll_handle, sockfd);
|
||||
poll_handle.data = this;
|
||||
}
|
||||
|
||||
void start(int events, uv_poll_cb cb) {
|
||||
uv_poll_start(&poll_handle, events, cb);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
assert(poll_handle.data);
|
||||
poll_handle.data = nullptr;
|
||||
uv_poll_stop(&poll_handle);
|
||||
uv_close((uv_handle_t *)&poll_handle, [](uv_handle_t *handle) {
|
||||
delete (Socket *)handle->data;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
// Make the destructor private to ensure that we can only close the Socket
|
||||
// with stop(), and disallow manual deletion.
|
||||
~Socket() {
|
||||
assert(!poll_handle.data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,59 +163,22 @@ void curl_share_unlock(CURL *, curl_lock_data, void *) {
|
||||
uv_mutex_unlock(&share_mutex);
|
||||
}
|
||||
|
||||
// This function must run in the CURL thread.
|
||||
// It is either called when the request is completed, or when we try to cancel the request.
|
||||
void finish_request(const util::ptr<HTTPRequestBaton> &baton) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
if (baton->ptr) {
|
||||
CURL *handle = (CURL *)baton->ptr;
|
||||
CURLMcode error = curl_multi_remove_handle(multi, handle);
|
||||
if (error != CURLM_OK) {
|
||||
baton->response = std::make_unique<Response>();
|
||||
baton->response->code = -1;
|
||||
baton->response->message = curl_multi_strerror(error);
|
||||
}
|
||||
|
||||
// Destroy the shared pointer. We still have one pointing to it
|
||||
CURLContext *context = nullptr;
|
||||
curl_easy_getinfo(handle, CURLINFO_PRIVATE, (char *)&context);
|
||||
curl_easy_setopt(handle, CURLOPT_PRIVATE, nullptr);
|
||||
delete context;
|
||||
|
||||
// TODO: delete the headers object again.
|
||||
|
||||
curl_easy_reset(handle);
|
||||
handles.push(handle);
|
||||
baton->ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void curl_perform(uv_poll_t *req, int, int events) {
|
||||
int running_handles;
|
||||
int flags = 0;
|
||||
CURLContext *context = (CURLContext *)req->data;
|
||||
CURLMsg *message;
|
||||
int pending;
|
||||
|
||||
uv_timer_stop(&timeout);
|
||||
|
||||
if (events & UV_READABLE) {
|
||||
flags |= CURL_CSELECT_IN;
|
||||
}
|
||||
if (events & UV_WRITABLE) {
|
||||
flags |= CURL_CSELECT_OUT;
|
||||
}
|
||||
|
||||
curl_multi_socket_action(multi, context->sockfd, flags, &running_handles);
|
||||
void check_multi_info() {
|
||||
CURLMsg *message = nullptr;
|
||||
int pending = 0;
|
||||
|
||||
while ((message = curl_multi_info_read(multi, &pending))) {
|
||||
switch (message->msg) {
|
||||
case CURLMSG_DONE: {
|
||||
CURLContext *ctx = nullptr;
|
||||
curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&ctx);
|
||||
Context *context = nullptr;
|
||||
curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&context);
|
||||
assert(context);
|
||||
|
||||
// Make a copy so that the Baton stays around even after we are calling finish_request
|
||||
util::ptr<HTTPRequestBaton> baton = ctx->baton;
|
||||
auto baton = context->baton;
|
||||
|
||||
// This request is complete. We are removing the pointer to the CURL easy handle again
|
||||
// to prevent this request from getting canceled.
|
||||
context->baton->ptr = nullptr;
|
||||
|
||||
// Add human-readable error code
|
||||
if (message->data.result != CURLE_OK) {
|
||||
@@ -202,16 +220,8 @@ void curl_perform(uv_poll_t *req, int, int events) {
|
||||
}
|
||||
}
|
||||
|
||||
// We're currently in the CURL request thread.
|
||||
finish_request(baton);
|
||||
|
||||
if (baton->async) {
|
||||
uv_async_send(baton->async);
|
||||
baton->async = nullptr;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
delete context;
|
||||
} break;
|
||||
|
||||
default:
|
||||
// This should never happen, because there are no other message types.
|
||||
@@ -220,63 +230,71 @@ void curl_perform(uv_poll_t *req, int, int events) {
|
||||
}
|
||||
}
|
||||
|
||||
int handle_socket(CURL *handle, curl_socket_t sockfd, int action, void *, void *socketp) {
|
||||
CURLContext *context = nullptr;
|
||||
curl_easy_getinfo(handle, CURLINFO_PRIVATE, (char *)&context);
|
||||
void curl_perform(uv_poll_t *req, int /* status */, int events) {
|
||||
int flags = 0;
|
||||
|
||||
if (!socketp && action != CURL_POLL_REMOVE) {
|
||||
// We haven't initialized the socket yet, so we need to do this now.
|
||||
assert(context->sockfd == 0);
|
||||
context->sockfd = sockfd;
|
||||
assert(!context->poll_handle);
|
||||
context->poll_handle = new uv_poll_t;
|
||||
uv_poll_init_socket(loop, context->poll_handle, sockfd);
|
||||
context->poll_handle->data = context;
|
||||
curl_multi_assign(multi, sockfd, context);
|
||||
uv_timer_stop(&timeout);
|
||||
|
||||
if (events & UV_READABLE) {
|
||||
flags |= CURL_CSELECT_IN;
|
||||
}
|
||||
if (events & UV_WRITABLE) {
|
||||
flags |= CURL_CSELECT_OUT;
|
||||
}
|
||||
|
||||
if (context) {
|
||||
if (action == CURL_POLL_IN || action == CURL_POLL_INOUT) {
|
||||
uv_poll_start(context->poll_handle, UV_READABLE, curl_perform);
|
||||
}
|
||||
if (action == CURL_POLL_OUT || action == CURL_POLL_INOUT) {
|
||||
uv_poll_start(context->poll_handle, UV_WRITABLE, curl_perform);
|
||||
}
|
||||
if (action == CURL_POLL_REMOVE && socketp) {
|
||||
uv_poll_stop(context->poll_handle);
|
||||
uv_close((uv_handle_t *)context->poll_handle, [](uv_handle_t *poll_handle) {
|
||||
delete (uv_poll_t *)poll_handle;
|
||||
});
|
||||
context->poll_handle = nullptr;
|
||||
curl_multi_assign(multi, sockfd, NULL);
|
||||
Socket *context = (Socket *)req->data;
|
||||
int running_handles = 0;
|
||||
curl_multi_socket_action(multi, context->sockfd, flags, &running_handles);
|
||||
|
||||
check_multi_info();
|
||||
}
|
||||
|
||||
int handle_socket(CURL * /* handle */, curl_socket_t s, int action, void * /* userp */, void *socketp) {
|
||||
Socket *socket = (Socket *)socketp;
|
||||
if (!socket && action != CURL_POLL_REMOVE) {
|
||||
socket = new Socket(s);
|
||||
curl_multi_assign(multi, s, (void *)socket);
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
socket->start(UV_READABLE, curl_perform);
|
||||
break;
|
||||
case CURL_POLL_OUT:
|
||||
socket->start(UV_WRITABLE, curl_perform);
|
||||
break;
|
||||
case CURL_POLL_REMOVE:
|
||||
if (socket) {
|
||||
socket->stop();
|
||||
curl_multi_assign(multi, s, NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
|
||||
void on_timeout(uv_timer_t *, int = 0) {
|
||||
void on_timeout(uv_timer_t * /* req */, int /* status */) {
|
||||
#else
|
||||
void on_timeout(uv_timer_t *) {
|
||||
void on_timeout(uv_timer_t * /* req */) {
|
||||
#endif
|
||||
int running_handles;
|
||||
CURLMcode error = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &running_handles);
|
||||
if (error != CURLM_OK) {
|
||||
throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(error));
|
||||
}
|
||||
|
||||
check_multi_info();
|
||||
}
|
||||
|
||||
void start_timeout(CURLM *, long timeout_ms, void *) {
|
||||
void start_timeout(CURLM * /* multi */, long timeout_ms, void * /* userp */) {
|
||||
if (timeout_ms <= 0) {
|
||||
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
|
||||
on_timeout(&timeout, 0);
|
||||
#else
|
||||
on_timeout(&timeout);
|
||||
#endif
|
||||
} else {
|
||||
uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
|
||||
timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in a bit */
|
||||
}
|
||||
uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
|
||||
}
|
||||
|
||||
void thread_init(void *) {
|
||||
@@ -285,6 +303,10 @@ void thread_init(void *) {
|
||||
#endif
|
||||
thread_id = uv_thread_self();
|
||||
|
||||
if (curl_global_init(CURL_GLOBAL_ALL)) {
|
||||
throw std::runtime_error("Could not init cURL");
|
||||
}
|
||||
|
||||
uv_timer_init(loop, &timeout);
|
||||
|
||||
CURLSHcode share_error;
|
||||
@@ -300,7 +322,6 @@ void thread_init(void *) {
|
||||
throw std::runtime_error(std::string("CURL share error: ") + curl_share_strerror(share_error));
|
||||
}
|
||||
|
||||
|
||||
CURLMcode multi_error;
|
||||
multi = curl_multi_init();
|
||||
|
||||
@@ -311,7 +332,6 @@ void thread_init(void *) {
|
||||
multi_error = curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, start_timeout);
|
||||
if (multi_error != CURLM_OK) {
|
||||
throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(multi_error));
|
||||
|
||||
}
|
||||
|
||||
// Main event loop. This will not return until the request loop is terminated.
|
||||
@@ -329,7 +349,9 @@ void thread_init(void *) {
|
||||
// This function is called when we have new data for a request. We just append it to the string
|
||||
// containing the previous data.
|
||||
size_t curl_write_cb(void *const contents, const size_t size, const size_t nmemb, void *const userp) {
|
||||
((std::string *)userp)->append((char *)contents, size * nmemb);
|
||||
auto &response = *(std::unique_ptr<Response> *)userp;
|
||||
assert(response);
|
||||
response->data.append((char *)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
@@ -350,7 +372,8 @@ size_t header_matches(const char *const header, const char *const buffer, const
|
||||
size_t curl_header_cb(char * const buffer, const size_t size, const size_t nmemb, void *const userp) {
|
||||
const size_t length = size * nmemb;
|
||||
|
||||
Response *response = static_cast<Response *>(userp);
|
||||
auto &response = *(std::unique_ptr<Response> *)userp;
|
||||
assert(response);
|
||||
|
||||
size_t begin = std::string::npos;
|
||||
if ((begin = header_matches("last-modified: ", buffer, length)) != std::string::npos) {
|
||||
@@ -371,40 +394,30 @@ size_t curl_header_cb(char * const buffer, const size_t size, const size_t nmemb
|
||||
// This function must run in the CURL thread.
|
||||
void start_request(void *const ptr) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
std::unique_ptr<util::ptr<HTTPRequestBaton>> baton_guard { (util::ptr<HTTPRequestBaton> *)ptr };
|
||||
util::ptr<HTTPRequestBaton> &baton = *baton_guard.get();
|
||||
assert(baton);
|
||||
|
||||
CURL *handle = nullptr;
|
||||
if (!handles.empty()) {
|
||||
handle = handles.front();
|
||||
handles.pop();
|
||||
} else {
|
||||
handle = curl_easy_init();
|
||||
}
|
||||
// The Context object stores information that we need to retain throughout the request, such
|
||||
// as the actual CURL easy handle, the baton, and the list of headers. The Context itself is
|
||||
// stored in both the CURL easy handle's PRIVATE field, and the baton's `ptr` field.
|
||||
auto context = new Context(*(util::ptr<HTTPRequestBaton> *)ptr);
|
||||
delete (util::ptr<HTTPRequestBaton> *)ptr;
|
||||
|
||||
baton->ptr = handle;
|
||||
|
||||
// Wrap this in a unique_ptr for now so that it destructs until we assign it the the CURL handle.
|
||||
std::unique_ptr<CURLContext> context = std::make_unique<CURLContext>(baton);
|
||||
|
||||
if (baton->response) {
|
||||
if (!baton->response->etag.empty()) {
|
||||
const std::string header = std::string("If-None-Match: ") + baton->response->etag;
|
||||
if (context->baton->response) {
|
||||
if (!context->baton->response->etag.empty()) {
|
||||
const std::string header = std::string("If-None-Match: ") + context->baton->response->etag;
|
||||
context->headers = curl_slist_append(context->headers, header.c_str());
|
||||
} else if (baton->response->modified) {
|
||||
const std::string time = std::string("If-Modified-Since: ") +
|
||||
util::rfc1123(baton->response->modified);
|
||||
} else if (context->baton->response->modified) {
|
||||
const std::string time =
|
||||
std::string("If-Modified-Since: ") + util::rfc1123(context->baton->response->modified);
|
||||
context->headers = curl_slist_append(context->headers, time.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (context->headers) {
|
||||
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, context->headers);
|
||||
curl_easy_setopt(context->handle, CURLOPT_HTTPHEADER, context->headers);
|
||||
}
|
||||
|
||||
if (!baton->response) {
|
||||
baton->response = std::make_unique<Response>();
|
||||
if (!context->baton->response) {
|
||||
context->baton->response = std::unique_ptr<Response>(new Response());
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
@@ -414,35 +427,35 @@ void start_request(void *const ptr) {
|
||||
#endif
|
||||
|
||||
// Carry on the shared pointer in the private information of the CURL handle.
|
||||
curl_easy_setopt(handle, CURLOPT_PRIVATE, context.release());
|
||||
curl_easy_setopt(handle, CURLOPT_CAINFO, ca_path.c_str());
|
||||
curl_easy_setopt(handle, CURLOPT_URL, baton->path.c_str());
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &baton->response->data);
|
||||
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, curl_header_cb);
|
||||
curl_easy_setopt(handle, CURLOPT_HEADERDATA, baton->response.get());
|
||||
curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate");
|
||||
curl_easy_setopt(handle, CURLOPT_SHARE, share);
|
||||
curl_easy_setopt(context->handle, CURLOPT_PRIVATE, context);
|
||||
curl_easy_setopt(context->handle, CURLOPT_CAINFO, ca_path.c_str());
|
||||
curl_easy_setopt(context->handle, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(context->handle, CURLOPT_URL, context->baton->path.c_str());
|
||||
curl_easy_setopt(context->handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
|
||||
curl_easy_setopt(context->handle, CURLOPT_WRITEDATA, &context->baton->response);
|
||||
curl_easy_setopt(context->handle, CURLOPT_HEADERFUNCTION, curl_header_cb);
|
||||
curl_easy_setopt(context->handle, CURLOPT_HEADERDATA, &context->baton->response);
|
||||
curl_easy_setopt(context->handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate");
|
||||
|
||||
// Start requesting the information.
|
||||
curl_multi_add_handle(multi, handle);
|
||||
curl_multi_add_handle(multi, context->handle);
|
||||
}
|
||||
|
||||
// This function must run in the CURL thread.
|
||||
void stop_request(void *const ptr) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
std::unique_ptr<util::ptr<HTTPRequestBaton>> baton_guard { (util::ptr<HTTPRequestBaton> *)ptr };
|
||||
util::ptr<HTTPRequestBaton> &baton = *baton_guard.get();
|
||||
auto baton = *(util::ptr<HTTPRequestBaton> *)ptr;
|
||||
delete (util::ptr<HTTPRequestBaton> *)ptr;
|
||||
assert(baton);
|
||||
|
||||
if (baton->async) {
|
||||
baton->type = HTTPResponseType::Canceled;
|
||||
|
||||
// We can still stop the request because it is still in progress.
|
||||
finish_request(baton);
|
||||
assert(baton->ptr);
|
||||
|
||||
uv_async_send(baton->async);
|
||||
baton->async = nullptr;
|
||||
// We can still stop the request because it is still in progress.
|
||||
delete (Context *)baton->ptr;
|
||||
assert(!baton->ptr);
|
||||
} else {
|
||||
// If the async handle is gone, it means that the actual request has been completed before
|
||||
// we got a chance to cancel it. In this case, this is a no-op. It is likely that
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
#include <mbgl/geometry/vao.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
#if GL_ARB_vertex_array_object
|
||||
|
||||
VertexArrayObject::~VertexArrayObject() {
|
||||
if (!gl::DeleteVertexArrays) return;
|
||||
|
||||
if (vao) {
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
gl::DeleteVertexArrays(1, &vao);
|
||||
}
|
||||
}
|
||||
|
||||
void VertexArrayObject::bindVertexArrayObject() {
|
||||
if (!vao) {
|
||||
glGenVertexArrays(1, &vao);
|
||||
if (!gl::GenVertexArrays || !gl::BindVertexArray) {
|
||||
static bool reported = false;
|
||||
if (!reported) {
|
||||
Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
|
||||
reported = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
glBindVertexArray(vao);
|
||||
|
||||
if (!vao) {
|
||||
gl::GenVertexArrays(1, &vao);
|
||||
}
|
||||
gl::BindVertexArray(vao);
|
||||
}
|
||||
|
||||
void VertexArrayObject::verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer,
|
||||
@@ -41,6 +51,4 @@ void VertexArrayObject::storeBinding(Shader &shader, GLuint vertexBuffer, GLuint
|
||||
bound_elements_buffer = elementsBuffer;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,10 @@ void TileData::request() {
|
||||
void TileData::cancel() {
|
||||
if (state != State::obsolete) {
|
||||
state = State::obsolete;
|
||||
req.reset();
|
||||
if (req) {
|
||||
req->cancel();
|
||||
req.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,17 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef NVIDIA
|
||||
PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
|
||||
#endif
|
||||
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
PFNGLBINDVERTEXARRAYPROC BindVertexArray = nullptr;
|
||||
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays = nullptr;
|
||||
PFNGLGENVERTEXARRAYSPROC GenVertexArrays = nullptr;
|
||||
PFNGLISVERTEXARRAYPROC IsVertexArray = nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void _CHECK_GL_ERROR(const char *cmd, const char *file, int line) {
|
||||
std::cout << cmd << ";" << std::endl;
|
||||
|
||||
@@ -49,7 +49,11 @@ void PrerenderedTexture::bindFramebuffer() {
|
||||
// Create depth/stencil buffer
|
||||
glGenRenderbuffers(1, &fbo_depth_stencil);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth_stencil);
|
||||
#ifdef GL_ES_VERSION_2_0
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, properties.size, properties.size);
|
||||
#else
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, properties.size, properties.size);
|
||||
#endif
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace mbgl {
|
||||
|
||||
int64_t Response::parseCacheControl(const char *value) {
|
||||
if (value) {
|
||||
uint64_t seconds = 0;
|
||||
unsigned long long seconds = 0;
|
||||
// TODO: cache-control may contain other information as well:
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||
if (std::sscanf(value, "max-age=%llu", reinterpret_cast<unsigned long long *>(&seconds)) == 1) {
|
||||
if (std::sscanf(value, "max-age=%llu", &seconds) == 1) {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count() +
|
||||
seconds;
|
||||
|
||||
@@ -17,9 +17,21 @@
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <libgen.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
std::string base_directory;
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
std::string defaultCacheDatabase() {
|
||||
// Disables the cache.
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ServerEnvironment : public ::testing::Environment {
|
||||
public:
|
||||
@@ -28,8 +40,13 @@ public:
|
||||
if (pid < 0) {
|
||||
throw std::runtime_error("Cannot create web server");
|
||||
} else if (pid == 0) {
|
||||
char *arg[] = { nullptr };
|
||||
int ret = execv((base_directory + "bin/server.py").c_str(), arg);
|
||||
#ifdef __linux__
|
||||
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
||||
#endif
|
||||
const auto executable = base_directory + "bin/server.py";
|
||||
const char *port = "2900";
|
||||
char *arg[] = { const_cast<char *>(executable.c_str()), const_cast<char *>(port), nullptr };
|
||||
int ret = execv(executable.c_str(), arg);
|
||||
// This call should not return. In case execve failed, we exit anyway.
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to start server: %s\n", strerror(errno));
|
||||
@@ -56,9 +73,14 @@ ServerEnvironment* env = nullptr;
|
||||
|
||||
GTEST_API_ int main(int argc, char *argv[]) {
|
||||
// Note: glibc's dirname() **modifies** the argument and can't handle static strings.
|
||||
std::string argv0 { argv[0] }; argv0 = dirname(const_cast<char *>(argv0.c_str()));
|
||||
std::string file { __FILE__ }; file = dirname(const_cast<char *>(file.c_str()));
|
||||
base_directory = argv0 + "/" + file + "/suite/";
|
||||
if (file[0] == '/') {
|
||||
// If __FILE__ is an absolute path, we don't have to guess from the argv 0.
|
||||
base_directory = file + "/suite/";
|
||||
} else {
|
||||
std::string argv0 { argv[0] }; argv0 = dirname(const_cast<char *>(argv0.c_str()));
|
||||
base_directory = argv0 + "/" + file + "/suite/";
|
||||
}
|
||||
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
env = new ServerEnvironment();
|
||||
@@ -66,6 +88,15 @@ GTEST_API_ int main(int argc, char *argv[]) {
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
void rewriteLocalScheme(rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) {
|
||||
ASSERT_TRUE(value.IsString());
|
||||
auto string = std::string { value.GetString(),value.GetStringLength() };
|
||||
if (string.compare(0, 8, "local://") == 0) {
|
||||
string.replace(0, 8, "http://127.0.0.1:2900/");
|
||||
value.SetString(string.data(), string.size(), allocator);
|
||||
}
|
||||
}
|
||||
|
||||
class HeadlessTest : public ::testing::TestWithParam<std::string> {};
|
||||
|
||||
TEST_P(HeadlessTest, render) {
|
||||
@@ -76,17 +107,40 @@ TEST_P(HeadlessTest, render) {
|
||||
std::string style = util::read_file(base_directory + "tests/" + base + "/style.json");
|
||||
std::string info = util::read_file(base_directory + "tests/" + base + "/info.json");
|
||||
|
||||
std::size_t pos = 0;
|
||||
while ((pos = style.find("local://", pos)) != std::string::npos) {
|
||||
style.replace(pos, 8, "http://localhost:2900/");
|
||||
}
|
||||
|
||||
// Parse style.
|
||||
rapidjson::Document styleDoc;
|
||||
styleDoc.Parse<0>((const char *const)style.c_str());
|
||||
ASSERT_FALSE(styleDoc.HasParseError());
|
||||
ASSERT_TRUE(styleDoc.IsObject());
|
||||
|
||||
// Rewrite "local://" to "http://127.0.0.1:2900/".
|
||||
if (styleDoc.HasMember("sprite")) {
|
||||
rewriteLocalScheme(styleDoc["sprite"], styleDoc.GetAllocator());
|
||||
}
|
||||
|
||||
if (styleDoc.HasMember("glyphs")) {
|
||||
rewriteLocalScheme(styleDoc["glyphs"], styleDoc.GetAllocator());
|
||||
}
|
||||
|
||||
if (styleDoc.HasMember("sources")) {
|
||||
auto &sources = styleDoc["sources"];
|
||||
ASSERT_TRUE(sources.IsObject());
|
||||
for (auto source = sources.MemberBegin(), end = sources.MemberEnd(); source != end; source++) {
|
||||
if (source->value.HasMember("tiles")) {
|
||||
auto &tiles = source->value["tiles"];
|
||||
ASSERT_TRUE(tiles.IsArray());
|
||||
for (rapidjson::SizeType i = 0; i < tiles.Size(); i++) {
|
||||
rewriteLocalScheme(tiles[i], styleDoc.GetAllocator());
|
||||
}
|
||||
}
|
||||
|
||||
if (source->value.HasMember("url")) {
|
||||
rewriteLocalScheme(source->value["url"], styleDoc.GetAllocator());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the JSON object back into a stringified version.
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
styleDoc.Accept(writer);
|
||||
|
||||
@@ -198,9 +198,19 @@
|
||||
'../mapboxgl.gyp:mbgl-standalone',
|
||||
'<(platform_library)',
|
||||
],
|
||||
'variables': {
|
||||
'cflags_cc': [
|
||||
'-I<(boost_root)/include',
|
||||
]
|
||||
},
|
||||
'conditions': [
|
||||
['OS == "mac"', { 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)', '-framework Foundation' ] }
|
||||
['OS == "mac"', {
|
||||
'xcode_settings': {
|
||||
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
|
||||
'OTHER_LDFLAGS': [ '<@(ldflags)', '-framework Foundation' ]
|
||||
},
|
||||
}, {
|
||||
'cflags_cc': [ '<@(cflags_cc)' ],
|
||||
'libraries': [ '<@(ldflags)'],
|
||||
}]
|
||||
]
|
||||
|
||||
@@ -43,7 +43,7 @@ while test $# -gt 0; do
|
||||
;;
|
||||
|
||||
--libs)
|
||||
echo -L${CONFIG_MBGL_PREFIX}/lib -lmbgl -lmbgl-${CONFIG_MBGL_PLATFORM} -lmbgl-headless ${CONFIG_MBGL_LDFLAGS}
|
||||
echo -L${CONFIG_MBGL_PREFIX}/lib -lmbgl-core -lmbgl-${CONFIG_MBGL_PLATFORM} -lmbgl-headless ${CONFIG_MBGL_LDFLAGS}
|
||||
;;
|
||||
|
||||
--includedir)
|
||||
|
||||
Reference in New Issue
Block a user