summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLeith Bade <leith@mapbox.com>2014-12-05 23:16:49 +1100
committerLeith Bade <leith@mapbox.com>2014-12-05 23:16:49 +1100
commitde9eb00276684a10f49a1c490f55266b80238155 (patch)
treefc713b06541bb1af04e95c70f2e383bcb86a164a /src
parentc348c141c5c5754c962d9b7e94af83f097e30487 (diff)
parentff640132de0fe855314a8fd86adae3a2fb33237b (diff)
downloadqtlocation-mapboxgl-de9eb00276684a10f49a1c490f55266b80238155.tar.gz
Merge branch 'master' of github.com:mapbox/mapbox-gl-native into android-mason
Conflicts: .gitignore gyp/mbgl-ios.gypi gyp/mbgl-linux.gypi gyp/mbgl-osx.gypi include/mbgl/map/map.hpp src/mbgl/map/map.cpp src/mbgl/storage/caching_http_file_source.cpp
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clipper/clipper.cpp2
-rwxr-xr-xsrc/clipper/clipper.hpp398
-rw-r--r--src/csscolorparser/csscolorparser.cpp2
-rw-r--r--src/csscolorparser/csscolorparser.hpp44
-rwxr-xr-xsrc/libtess2/bucketalloc.c2
-rwxr-xr-xsrc/libtess2/bucketalloc.h2
-rwxr-xr-xsrc/libtess2/dict.c2
-rwxr-xr-xsrc/libtess2/mesh.h2
-rwxr-xr-xsrc/libtess2/priorityq.c2
-rwxr-xr-xsrc/libtess2/tess.h2
-rwxr-xr-xsrc/libtess2/tesselator.h209
-rw-r--r--src/mbgl/geometry/anchor.hpp25
-rw-r--r--src/mbgl/geometry/binpack.hpp100
-rw-r--r--src/mbgl/geometry/buffer.hpp118
-rw-r--r--src/mbgl/geometry/debug_font_buffer.cpp (renamed from src/geometry/debug_font_buffer.cpp)4
-rw-r--r--src/mbgl/geometry/debug_font_buffer.hpp17
-rw-r--r--src/mbgl/geometry/debug_font_data.hpp (renamed from src/geometry/debug_font_data.hpp)0
-rw-r--r--src/mbgl/geometry/elements_buffer.cpp (renamed from src/geometry/elements_buffer.cpp)0
-rw-r--r--src/mbgl/geometry/elements_buffer.hpp64
-rw-r--r--src/mbgl/geometry/fill_buffer.cpp (renamed from src/geometry/fill_buffer.cpp)1
-rw-r--r--src/mbgl/geometry/fill_buffer.hpp21
-rw-r--r--src/mbgl/geometry/geometry.hpp77
-rw-r--r--src/mbgl/geometry/glyph_atlas.cpp (renamed from src/geometry/glyph_atlas.cpp)1
-rw-r--r--src/mbgl/geometry/glyph_atlas.hpp54
-rw-r--r--src/mbgl/geometry/icon_buffer.cpp (renamed from src/geometry/icon_buffer.cpp)0
-rw-r--r--src/mbgl/geometry/icon_buffer.hpp22
-rw-r--r--src/mbgl/geometry/line_buffer.cpp (renamed from src/geometry/line_buffer.cpp)0
-rw-r--r--src/mbgl/geometry/line_buffer.hpp39
-rw-r--r--src/mbgl/geometry/resample.cpp (renamed from src/geometry/resample.cpp)0
-rw-r--r--src/mbgl/geometry/resample.hpp13
-rw-r--r--src/mbgl/geometry/sprite_atlas.cpp (renamed from src/geometry/sprite_atlas.cpp)0
-rw-r--r--src/mbgl/geometry/sprite_atlas.hpp82
-rw-r--r--src/mbgl/geometry/static_vertex_buffer.cpp (renamed from src/geometry/static_vertex_buffer.cpp)0
-rw-r--r--src/mbgl/geometry/static_vertex_buffer.hpp26
-rw-r--r--src/mbgl/geometry/text_buffer.cpp (renamed from src/geometry/text_buffer.cpp)0
-rw-r--r--src/mbgl/geometry/text_buffer.hpp25
-rw-r--r--src/mbgl/geometry/vao.cpp (renamed from src/geometry/vao.cpp)5
-rw-r--r--src/mbgl/geometry/vao.hpp73
-rw-r--r--src/mbgl/map/map.cpp (renamed from src/map/map.cpp)69
-rw-r--r--src/mbgl/map/raster_tile_data.cpp (renamed from src/map/raster_tile_data.cpp)0
-rw-r--r--src/mbgl/map/raster_tile_data.hpp33
-rw-r--r--src/mbgl/map/source.cpp (renamed from src/map/source.cpp)8
-rw-r--r--src/mbgl/map/source.hpp86
-rw-r--r--src/mbgl/map/sprite.cpp (renamed from src/map/sprite.cpp)0
-rw-r--r--src/mbgl/map/sprite.hpp79
-rw-r--r--src/mbgl/map/tile.cpp (renamed from src/map/tile.cpp)8
-rw-r--r--src/mbgl/map/tile_data.cpp (renamed from src/map/tile_data.cpp)12
-rw-r--r--src/mbgl/map/tile_data.hpp88
-rw-r--r--src/mbgl/map/tile_parser.cpp (renamed from src/map/tile_parser.cpp)1
-rw-r--r--src/mbgl/map/tile_parser.hpp77
-rw-r--r--src/mbgl/map/transform.cpp (renamed from src/map/transform.cpp)0
-rw-r--r--src/mbgl/map/transform_state.cpp (renamed from src/map/transform_state.cpp)1
-rw-r--r--src/mbgl/map/vector_tile.cpp (renamed from src/map/vector_tile.cpp)0
-rw-r--r--src/mbgl/map/vector_tile.hpp118
-rw-r--r--src/mbgl/map/vector_tile_data.cpp (renamed from src/map/vector_tile_data.cpp)0
-rw-r--r--src/mbgl/map/vector_tile_data.hpp74
-rw-r--r--src/mbgl/platform/gl.cpp (renamed from src/platform/gl.cpp)0
-rw-r--r--src/mbgl/platform/log.cpp (renamed from src/platform/log.cpp)0
-rw-r--r--src/mbgl/renderer/bucket.hpp24
-rw-r--r--src/mbgl/renderer/debug_bucket.cpp (renamed from src/renderer/debug_bucket.cpp)1
-rw-r--r--src/mbgl/renderer/debug_bucket.hpp35
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp (renamed from src/renderer/fill_bucket.cpp)0
-rw-r--r--src/mbgl/renderer/fill_bucket.hpp88
-rw-r--r--src/mbgl/renderer/frame_history.cpp (renamed from src/renderer/frame_history.cpp)0
-rw-r--r--src/mbgl/renderer/frame_history.hpp40
-rw-r--r--src/mbgl/renderer/line_bucket.cpp (renamed from src/renderer/line_bucket.cpp)0
-rw-r--r--src/mbgl/renderer/line_bucket.hpp62
-rw-r--r--src/mbgl/renderer/painter.cpp (renamed from src/renderer/painter.cpp)2
-rw-r--r--src/mbgl/renderer/painter.hpp259
-rw-r--r--src/mbgl/renderer/painter_clipping.cpp (renamed from src/renderer/painter_clipping.cpp)0
-rw-r--r--src/mbgl/renderer/painter_debug.cpp (renamed from src/renderer/painter_debug.cpp)2
-rw-r--r--src/mbgl/renderer/painter_fill.cpp (renamed from src/renderer/painter_fill.cpp)0
-rw-r--r--src/mbgl/renderer/painter_line.cpp (renamed from src/renderer/painter_line.cpp)0
-rw-r--r--src/mbgl/renderer/painter_prerender.cpp (renamed from src/renderer/painter_prerender.cpp)0
-rw-r--r--src/mbgl/renderer/painter_raster.cpp (renamed from src/renderer/painter_raster.cpp)0
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp (renamed from src/renderer/painter_symbol.cpp)0
-rw-r--r--src/mbgl/renderer/prerendered_texture.cpp (renamed from src/renderer/prerendered_texture.cpp)0
-rw-r--r--src/mbgl/renderer/prerendered_texture.hpp38
-rw-r--r--src/mbgl/renderer/raster_bucket.cpp (renamed from src/renderer/raster_bucket.cpp)0
-rw-r--r--src/mbgl/renderer/raster_bucket.hpp38
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp (renamed from src/renderer/symbol_bucket.cpp)0
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp114
-rw-r--r--src/mbgl/shader/dot.fragment.glsl (renamed from src/shader/dot.fragment.glsl)0
-rw-r--r--src/mbgl/shader/dot.vertex.glsl (renamed from src/shader/dot.vertex.glsl)0
-rw-r--r--src/mbgl/shader/dot_shader.cpp (renamed from src/shader/dot_shader.cpp)0
-rw-r--r--src/mbgl/shader/dot_shader.hpp26
-rw-r--r--src/mbgl/shader/gaussian.fragment.glsl (renamed from src/shader/gaussian.fragment.glsl)0
-rw-r--r--src/mbgl/shader/gaussian.vertex.glsl (renamed from src/shader/gaussian.vertex.glsl)0
-rw-r--r--src/mbgl/shader/gaussian_shader.cpp (renamed from src/shader/gaussian_shader.cpp)0
-rw-r--r--src/mbgl/shader/gaussian_shader.hpp25
-rw-r--r--src/mbgl/shader/icon.fragment.glsl (renamed from src/shader/icon.fragment.glsl)0
-rw-r--r--src/mbgl/shader/icon.vertex.glsl (renamed from src/shader/icon.vertex.glsl)0
-rw-r--r--src/mbgl/shader/icon_shader.cpp (renamed from src/shader/icon_shader.cpp)0
-rw-r--r--src/mbgl/shader/icon_shader.hpp41
-rw-r--r--src/mbgl/shader/line.fragment.glsl (renamed from src/shader/line.fragment.glsl)0
-rw-r--r--src/mbgl/shader/line.vertex.glsl (renamed from src/shader/line.vertex.glsl)0
-rw-r--r--src/mbgl/shader/line_shader.cpp (renamed from src/shader/line_shader.cpp)0
-rw-r--r--src/mbgl/shader/line_shader.hpp32
-rw-r--r--src/mbgl/shader/linejoin.fragment.glsl (renamed from src/shader/linejoin.fragment.glsl)0
-rw-r--r--src/mbgl/shader/linejoin.vertex.glsl (renamed from src/shader/linejoin.vertex.glsl)0
-rw-r--r--src/mbgl/shader/linejoin_shader.cpp (renamed from src/shader/linejoin_shader.cpp)0
-rw-r--r--src/mbgl/shader/linejoin_shader.hpp27
-rw-r--r--src/mbgl/shader/linepattern.fragment.glsl (renamed from src/shader/linepattern.fragment.glsl)0
-rw-r--r--src/mbgl/shader/linepattern.vertex.glsl (renamed from src/shader/linepattern.vertex.glsl)0
-rw-r--r--src/mbgl/shader/linepattern_shader.cpp (renamed from src/shader/linepattern_shader.cpp)0
-rw-r--r--src/mbgl/shader/linepattern_shader.hpp33
-rw-r--r--src/mbgl/shader/outline.fragment.glsl (renamed from src/shader/outline.fragment.glsl)0
-rw-r--r--src/mbgl/shader/outline.vertex.glsl (renamed from src/shader/outline.vertex.glsl)0
-rw-r--r--src/mbgl/shader/outline_shader.cpp (renamed from src/shader/outline_shader.cpp)0
-rw-r--r--src/mbgl/shader/outline_shader.hpp25
-rw-r--r--src/mbgl/shader/pattern.fragment.glsl (renamed from src/shader/pattern.fragment.glsl)0
-rw-r--r--src/mbgl/shader/pattern.vertex.glsl (renamed from src/shader/pattern.vertex.glsl)0
-rw-r--r--src/mbgl/shader/pattern_shader.cpp (renamed from src/shader/pattern_shader.cpp)0
-rw-r--r--src/mbgl/shader/pattern_shader.hpp29
-rw-r--r--src/mbgl/shader/plain.fragment.glsl (renamed from src/shader/plain.fragment.glsl)0
-rw-r--r--src/mbgl/shader/plain.vertex.glsl (renamed from src/shader/plain.vertex.glsl)0
-rw-r--r--src/mbgl/shader/plain_shader.cpp (renamed from src/shader/plain_shader.cpp)0
-rw-r--r--src/mbgl/shader/plain_shader.hpp24
-rw-r--r--src/mbgl/shader/raster.fragment.glsl (renamed from src/shader/raster.fragment.glsl)0
-rw-r--r--src/mbgl/shader/raster.vertex.glsl (renamed from src/shader/raster.vertex.glsl)0
-rw-r--r--src/mbgl/shader/raster_shader.cpp (renamed from src/shader/raster_shader.cpp)0
-rw-r--r--src/mbgl/shader/raster_shader.hpp31
-rw-r--r--src/mbgl/shader/sdf.fragment.glsl (renamed from src/shader/sdf.fragment.glsl)0
-rw-r--r--src/mbgl/shader/sdf.vertex.glsl (renamed from src/shader/sdf.vertex.glsl)0
-rw-r--r--src/mbgl/shader/sdf_shader.cpp (renamed from src/shader/sdf_shader.cpp)0
-rw-r--r--src/mbgl/shader/sdf_shader.hpp53
-rw-r--r--src/mbgl/shader/shader.cpp (renamed from src/shader/shader.cpp)0
-rw-r--r--src/mbgl/shader/shader.hpp28
-rw-r--r--src/mbgl/shader/uniform.cpp (renamed from src/shader/uniform.cpp)0
-rw-r--r--src/mbgl/shader/uniform.hpp53
-rw-r--r--src/mbgl/storage/base_request.cpp (renamed from src/storage/base_request.cpp)0
-rw-r--r--src/mbgl/storage/base_request.hpp62
-rw-r--r--src/mbgl/storage/caching_http_file_source.cpp130
-rw-r--r--src/mbgl/storage/file_request.cpp (renamed from src/storage/file_request.cpp)0
-rw-r--r--src/mbgl/storage/file_request.hpp27
-rw-r--r--src/mbgl/storage/file_request_baton.cpp (renamed from src/storage/file_request_baton.cpp)0
-rw-r--r--src/mbgl/storage/file_request_baton.hpp36
-rw-r--r--src/mbgl/storage/http_request.cpp (renamed from src/storage/http_request.cpp)0
-rw-r--r--src/mbgl/storage/http_request.hpp58
-rw-r--r--src/mbgl/storage/http_request_baton.cpp (renamed from src/storage/http_request_baton.cpp)0
-rw-r--r--src/mbgl/storage/request.cpp (renamed from src/storage/request.cpp)0
-rw-r--r--src/mbgl/storage/response.cpp (renamed from src/storage/response.cpp)0
-rw-r--r--src/mbgl/storage/sqlite_store.cpp (renamed from src/storage/sqlite_store.cpp)0
-rw-r--r--src/mbgl/storage/sqlite_store.hpp49
-rw-r--r--src/mbgl/style/applied_class_properties.cpp (renamed from src/style/applied_class_properties.cpp)0
-rw-r--r--src/mbgl/style/applied_class_properties.hpp39
-rw-r--r--src/mbgl/style/class_dictionary.cpp (renamed from src/style/class_dictionary.cpp)0
-rw-r--r--src/mbgl/style/class_dictionary.hpp37
-rw-r--r--src/mbgl/style/class_properties.cpp (renamed from src/style/class_properties.cpp)0
-rw-r--r--src/mbgl/style/class_properties.hpp43
-rw-r--r--src/mbgl/style/filter_expression.cpp (renamed from src/style/filter_expression.cpp)0
-rw-r--r--src/mbgl/style/filter_expression.hpp125
-rw-r--r--src/mbgl/style/filter_expression_private.hpp118
-rw-r--r--src/mbgl/style/function_properties.cpp (renamed from src/style/function_properties.cpp)0
-rw-r--r--src/mbgl/style/function_properties.hpp55
-rw-r--r--src/mbgl/style/property_fallback.cpp (renamed from src/style/property_fallback.cpp)0
-rw-r--r--src/mbgl/style/property_fallback.hpp29
-rw-r--r--src/mbgl/style/property_key.hpp70
-rw-r--r--src/mbgl/style/property_transition.hpp15
-rw-r--r--src/mbgl/style/property_value.hpp21
-rw-r--r--src/mbgl/style/style.cpp (renamed from src/style/style.cpp)0
-rw-r--r--src/mbgl/style/style.hpp68
-rw-r--r--src/mbgl/style/style_bucket.cpp (renamed from src/style/style_bucket.cpp)0
-rw-r--r--src/mbgl/style/style_bucket.hpp112
-rw-r--r--src/mbgl/style/style_layer.cpp (renamed from src/style/style_layer.cpp)0
-rw-r--r--src/mbgl/style/style_layer.hpp89
-rw-r--r--src/mbgl/style/style_layer_group.cpp (renamed from src/style/style_layer_group.cpp)1
-rw-r--r--src/mbgl/style/style_layer_group.hpp23
-rw-r--r--src/mbgl/style/style_parser.cpp (renamed from src/style/style_parser.cpp)0
-rw-r--r--src/mbgl/style/style_parser.hpp113
-rw-r--r--src/mbgl/style/style_properties.cpp (renamed from src/style/style_properties.cpp)0
-rw-r--r--src/mbgl/style/style_properties.hpp114
-rw-r--r--src/mbgl/style/style_source.cpp (renamed from src/style/style_source.cpp)0
-rw-r--r--src/mbgl/style/style_source.hpp41
-rw-r--r--src/mbgl/style/types.cpp (renamed from src/style/types.cpp)0
-rw-r--r--src/mbgl/style/types.hpp196
-rw-r--r--src/mbgl/style/value.cpp (renamed from src/style/value.cpp)14
-rw-r--r--src/mbgl/style/value.hpp45
-rw-r--r--src/mbgl/style/value_comparison.hpp109
-rw-r--r--src/mbgl/text/collision.cpp (renamed from src/text/collision.cpp)0
-rw-r--r--src/mbgl/text/collision.hpp58
-rw-r--r--src/mbgl/text/glyph.cpp (renamed from src/text/glyph.cpp)0
-rw-r--r--src/mbgl/text/glyph.hpp60
-rw-r--r--src/mbgl/text/glyph_store.cpp (renamed from src/text/glyph_store.cpp)4
-rw-r--r--src/mbgl/text/glyph_store.hpp99
-rw-r--r--src/mbgl/text/placement.cpp (renamed from src/text/placement.cpp)0
-rw-r--r--src/mbgl/text/placement.hpp31
-rw-r--r--src/mbgl/text/rotation_range.cpp (renamed from src/text/rotation_range.cpp)0
-rw-r--r--src/mbgl/text/rotation_range.hpp54
-rw-r--r--src/mbgl/text/types.hpp113
-rw-r--r--src/mbgl/util/box.hpp15
-rw-r--r--src/mbgl/util/clip_ids.cpp (renamed from src/util/clip_ids.cpp)0
-rw-r--r--src/mbgl/util/clip_ids.hpp38
-rw-r--r--src/mbgl/util/compression.cpp (renamed from src/util/compression.cpp)0
-rw-r--r--src/mbgl/util/compression.hpp15
-rw-r--r--src/mbgl/util/constants.cpp27
-rw-r--r--src/mbgl/util/constants.hpp31
-rw-r--r--src/mbgl/util/error.hpp20
-rw-r--r--src/mbgl/util/interpolate.hpp27
-rw-r--r--src/mbgl/util/io.cpp (renamed from src/util/io.cpp)0
-rw-r--r--src/mbgl/util/io.hpp15
-rw-r--r--src/mbgl/util/mapbox.cpp (renamed from src/util/mapbox.cpp)0
-rw-r--r--src/mbgl/util/mapbox.hpp17
-rw-r--r--src/mbgl/util/mat3.cpp (renamed from src/util/mat3.cpp)0
-rw-r--r--src/mbgl/util/mat3.hpp42
-rw-r--r--src/mbgl/util/mat4.cpp (renamed from src/util/mat4.cpp)0
-rw-r--r--src/mbgl/util/math.cpp (renamed from src/util/math.cpp)0
-rw-r--r--src/mbgl/util/optional.hpp69
-rw-r--r--src/mbgl/util/parsedate.c (renamed from src/util/parsedate.c)0
-rw-r--r--src/mbgl/util/pbf.hpp184
-rw-r--r--src/mbgl/util/queue.h92
-rw-r--r--src/mbgl/util/raster.cpp (renamed from src/util/raster.cpp)0
-rw-r--r--src/mbgl/util/raster.hpp74
-rw-r--r--src/mbgl/util/rect.hpp22
-rw-r--r--src/mbgl/util/sqlite3.cpp (renamed from src/util/sqlite3.cpp)0
-rw-r--r--src/mbgl/util/sqlite3.hpp74
-rw-r--r--src/mbgl/util/stopwatch.cpp (renamed from src/util/stopwatch.cpp)3
-rw-r--r--src/mbgl/util/stopwatch.hpp40
-rw-r--r--src/mbgl/util/texture_pool.cpp (renamed from src/util/texture_pool.cpp)0
-rw-r--r--src/mbgl/util/texture_pool.hpp25
-rw-r--r--src/mbgl/util/time.cpp (renamed from src/util/time.cpp)0
-rw-r--r--src/mbgl/util/token.hpp50
-rw-r--r--src/mbgl/util/transition.cpp (renamed from src/util/transition.cpp)0
-rw-r--r--src/mbgl/util/transition.hpp77
-rw-r--r--src/mbgl/util/unitbezier.hpp121
-rw-r--r--src/mbgl/util/url.cpp (renamed from src/util/url.cpp)0
-rw-r--r--src/mbgl/util/url.hpp15
-rw-r--r--src/mbgl/util/utf.hpp24
-rw-r--r--src/mbgl/util/uv-channel.c (renamed from src/util/uv-channel.c)0
-rw-r--r--src/mbgl/util/uv-channel.h29
-rw-r--r--src/mbgl/util/uv-messenger.c (renamed from src/util/uv-messenger.c)0
-rw-r--r--src/mbgl/util/uv-worker.c (renamed from src/util/uv-worker.c)0
-rw-r--r--src/mbgl/util/uv-worker.h41
-rw-r--r--src/mbgl/util/uv.cpp (renamed from src/util/uv.cpp)0
-rw-r--r--src/mbgl/util/uv_detail.hpp177
-rwxr-xr-xsrc/rapidjson/document.h821
-rwxr-xr-xsrc/rapidjson/filestream.h46
-rwxr-xr-xsrc/rapidjson/internal/pow10.h54
-rwxr-xr-xsrc/rapidjson/internal/stack.h82
-rwxr-xr-xsrc/rapidjson/internal/strfunc.h24
-rwxr-xr-xsrc/rapidjson/prettywriter.h156
-rwxr-xr-xsrc/rapidjson/rapidjson.h525
-rwxr-xr-xsrc/rapidjson/reader.h692
-rwxr-xr-xsrc/rapidjson/stringbuffer.h49
-rwxr-xr-xsrc/rapidjson/writer.h241
245 files changed, 9448 insertions, 82 deletions
diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp
index ea468d69e4..f5d8cd3c95 100755
--- a/src/clipper/clipper.cpp
+++ b/src/clipper/clipper.cpp
@@ -38,7 +38,7 @@
* *
*******************************************************************************/
-#include <clipper/clipper.hpp>
+#include "clipper.hpp"
#include <cmath>
#include <vector>
#include <algorithm>
diff --git a/src/clipper/clipper.hpp b/src/clipper/clipper.hpp
new file mode 100755
index 0000000000..84870141e7
--- /dev/null
+++ b/src/clipper/clipper.hpp
@@ -0,0 +1,398 @@
+/*******************************************************************************
+* *
+* Author : Angus Johnson *
+* Version : 6.1.3a *
+* Date : 22 January 2014 *
+* Website : http://www.angusj.com *
+* Copyright : Angus Johnson 2010-2014 *
+* *
+* License: *
+* Use, modification & distribution is subject to Boost Software License Ver 1. *
+* http://www.boost.org/LICENSE_1_0.txt *
+* *
+* Attributions: *
+* The code in this library is an extension of Bala Vatti's clipping algorithm: *
+* "A generic solution to polygon clipping" *
+* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
+* http://portal.acm.org/citation.cfm?id=129906 *
+* *
+* Computer graphics and geometric modeling: implementation and algorithms *
+* By Max K. Agoston *
+* Springer; 1 edition (January 4, 2005) *
+* http://books.google.com/books?q=vatti+clipping+agoston *
+* *
+* See also: *
+* "Polygon Offsetting by Computing Winding Numbers" *
+* Paper no. DETC2005-85513 pp. 565-575 *
+* ASME 2005 International Design Engineering Technical Conferences *
+* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
+* September 24-28, 2005 , Long Beach, California, USA *
+* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
+* *
+*******************************************************************************/
+
+#ifndef clipper_hpp
+#define clipper_hpp
+
+#define CLIPPER_VERSION "6.1.3"
+
+//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
+//improve performance but coordinate values are limited to the range +/- 46340
+//#define use_int32
+
+//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
+//#define use_xyz
+
+//use_lines: Enables line clipping. Adds a very minor cost to performance.
+//#define use_lines
+
+//use_deprecated: Enables support for the obsolete OffsetPaths() function
+//which has been replace with the ClipperOffset class.
+#define use_deprecated
+
+#include <vector>
+#include <set>
+#include <stdexcept>
+#include <cstring>
+#include <cstdlib>
+#include <ostream>
+#include <functional>
+
+namespace ClipperLib {
+
+enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
+enum PolyType { ptSubject, ptClip };
+//By far the most widely used winding rules for polygon filling are
+//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
+//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
+//see http://glprogramming.com/red/chapter11.html
+enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
+
+#ifdef use_int32
+typedef int cInt;
+typedef unsigned int cUInt;
+#else
+typedef signed long long cInt;
+typedef unsigned long long cUInt;
+#endif
+
+struct IntPoint {
+ cInt X;
+ cInt Y;
+#ifdef use_xyz
+ cInt Z;
+ IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
+#else
+ IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
+#endif
+
+ friend inline bool operator== (const IntPoint& a, const IntPoint& b)
+ {
+ return a.X == b.X && a.Y == b.Y;
+ }
+ friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
+ {
+ return a.X != b.X || a.Y != b.Y;
+ }
+};
+//------------------------------------------------------------------------------
+
+typedef std::vector< IntPoint > Path;
+typedef std::vector< Path > Paths;
+
+inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
+inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
+
+std::ostream& operator <<(std::ostream &s, const IntPoint &p);
+std::ostream& operator <<(std::ostream &s, const Path &p);
+std::ostream& operator <<(std::ostream &s, const Paths &p);
+
+struct DoublePoint
+{
+ double X;
+ double Y;
+ DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
+ DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
+};
+//------------------------------------------------------------------------------
+
+#ifdef use_xyz
+typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt);
+#endif
+
+enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
+enum JoinType {jtSquare, jtRound, jtMiter};
+enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
+#ifdef use_deprecated
+ enum EndType_ {etClosed, etButt = 2, etSquare, etRound};
+#endif
+
+class PolyNode;
+typedef std::vector< PolyNode* > PolyNodes;
+
+class PolyNode
+{
+public:
+ PolyNode();
+ Path Contour;
+ PolyNodes Childs;
+ PolyNode* Parent;
+ PolyNode* GetNext() const;
+ bool IsHole() const;
+ bool IsOpen() const;
+ int ChildCount() const;
+private:
+ unsigned Index; //node index in Parent.Childs
+ bool m_IsOpen;
+ JoinType m_jointype;
+ EndType m_endtype;
+ PolyNode* GetNextSiblingUp() const;
+ void AddChild(PolyNode& child);
+ friend class Clipper; //to access Index
+ friend class ClipperOffset;
+};
+
+class PolyTree: public PolyNode
+{
+public:
+ ~PolyTree(){Clear();};
+ PolyNode* GetFirst() const;
+ void Clear();
+ int Total() const;
+private:
+ PolyNodes AllNodes;
+ friend class Clipper; //to access AllNodes
+};
+
+bool Orientation(const Path &poly);
+double Area(const Path &poly);
+int PointInPolygon(const IntPoint &pt, const Path &path);
+
+#ifdef use_deprecated
+ void OffsetPaths(const Paths &in_polys, Paths &out_polys,
+ double delta, JoinType jointype, EndType_ endtype, double limit = 0);
+#endif
+
+void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
+void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
+void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
+
+void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
+void CleanPolygon(Path& poly, double distance = 1.415);
+void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
+void CleanPolygons(Paths& polys, double distance = 1.415);
+
+void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
+void MinkowskiSum(const Path& pattern, const Paths& paths,
+ Paths& solution, PolyFillType pathFillType, bool pathIsClosed);
+void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
+
+void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
+void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
+void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
+
+void ReversePath(Path& p);
+void ReversePaths(Paths& p);
+
+struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
+
+//enums that are used internally ...
+enum EdgeSide { esLeft = 1, esRight = 2};
+
+//forward declarations (for stuff used internally) ...
+struct TEdge;
+struct IntersectNode;
+struct LocalMinima;
+struct Scanbeam;
+struct OutPt;
+struct OutRec;
+struct Join;
+
+typedef std::vector < OutRec* > PolyOutList;
+typedef std::vector < TEdge* > EdgeList;
+typedef std::vector < Join* > JoinList;
+typedef std::vector < IntersectNode* > IntersectList;
+
+
+//------------------------------------------------------------------------------
+
+//ClipperBase is the ancestor to the Clipper class. It should not be
+//instantiated directly. This class simply abstracts the conversion of sets of
+//polygon coordinates into edge objects that are stored in a LocalMinima list.
+class ClipperBase
+{
+public:
+ ClipperBase();
+ virtual ~ClipperBase();
+ bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
+ bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
+ virtual void Clear();
+ IntRect GetBounds();
+ bool PreserveCollinear() {return m_PreserveCollinear;};
+ void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
+protected:
+ void DisposeLocalMinimaList();
+ TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
+ void PopLocalMinima();
+ virtual void Reset();
+ TEdge* ProcessBound(TEdge* E, bool IsClockwise);
+ void InsertLocalMinima(LocalMinima *newLm);
+ void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed);
+ TEdge* DescendToMin(TEdge *&E);
+ void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
+ LocalMinima *m_CurrentLM;
+ LocalMinima *m_MinimaList;
+ bool m_UseFullRange;
+ EdgeList m_edges;
+ bool m_PreserveCollinear;
+ bool m_HasOpenPaths;
+};
+//------------------------------------------------------------------------------
+
+class Clipper : public virtual ClipperBase
+{
+public:
+ Clipper(int initOptions = 0);
+ ~Clipper();
+ bool Execute(ClipType clipType,
+ Paths &solution,
+ PolyFillType subjFillType = pftEvenOdd,
+ PolyFillType clipFillType = pftEvenOdd);
+ bool Execute(ClipType clipType,
+ PolyTree &polytree,
+ PolyFillType subjFillType = pftEvenOdd,
+ PolyFillType clipFillType = pftEvenOdd);
+ bool ReverseSolution() {return m_ReverseOutput;};
+ void ReverseSolution(bool value) {m_ReverseOutput = value;};
+ bool StrictlySimple() {return m_StrictSimple;};
+ void StrictlySimple(bool value) {m_StrictSimple = value;};
+ //set the callback function for z value filling on intersections (otherwise Z is 0)
+#ifdef use_xyz
+ void ZFillFunction(TZFillCallback zFillFunc);
+#endif
+protected:
+ void Reset();
+ virtual bool ExecuteInternal();
+private:
+ PolyOutList m_PolyOuts;
+ JoinList m_Joins;
+ JoinList m_GhostJoins;
+ IntersectList m_IntersectList;
+ ClipType m_ClipType;
+ std::set< cInt, std::greater<cInt> > m_Scanbeam;
+ TEdge *m_ActiveEdges;
+ TEdge *m_SortedEdges;
+ bool m_ExecuteLocked;
+ PolyFillType m_ClipFillType;
+ PolyFillType m_SubjFillType;
+ bool m_ReverseOutput;
+ bool m_UsingPolyTree;
+ bool m_StrictSimple;
+#ifdef use_xyz
+ TZFillCallback m_ZFill; //custom callback
+#endif
+ void SetWindingCount(TEdge& edge);
+ bool IsEvenOddFillType(const TEdge& edge) const;
+ bool IsEvenOddAltFillType(const TEdge& edge) const;
+ void InsertScanbeam(const cInt Y);
+ cInt PopScanbeam();
+ void InsertLocalMinimaIntoAEL(const cInt botY);
+ void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
+ void AddEdgeToSEL(TEdge *edge);
+ void CopyAELToSEL();
+ void DeleteFromSEL(TEdge *e);
+ void DeleteFromAEL(TEdge *e);
+ void UpdateEdgeIntoAEL(TEdge *&e);
+ void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
+ bool IsContributing(const TEdge& edge) const;
+ bool IsTopHorz(const cInt XPos);
+ void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
+ void DoMaxima(TEdge *e);
+ void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam);
+ void ProcessHorizontals(bool IsTopOfScanbeam);
+ void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam);
+ void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
+ OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
+ OutRec* GetOutRec(int idx);
+ void AppendPolygon(TEdge *e1, TEdge *e2);
+ void IntersectEdges(TEdge *e1, TEdge *e2,
+ const IntPoint &pt, bool protect = false);
+ OutRec* CreateOutRec();
+ OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
+ void DisposeAllOutRecs();
+ void DisposeOutRec(PolyOutList::size_type index);
+ bool ProcessIntersections(const cInt botY, const cInt topY);
+ void BuildIntersectList(const cInt botY, const cInt topY);
+ void ProcessIntersectList();
+ void ProcessEdgesAtTopOfScanbeam(const cInt topY);
+ void BuildResult(Paths& polys);
+ void BuildResult2(PolyTree& polytree);
+ void SetHoleState(TEdge *e, OutRec *outrec);
+ void DisposeIntersectNodes();
+ bool FixupIntersectionOrder();
+ void FixupOutPolygon(OutRec &outrec);
+ bool IsHole(TEdge *e);
+ bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
+ void FixHoleLinkage(OutRec &outrec);
+ void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
+ void ClearJoins();
+ void ClearGhostJoins();
+ void AddGhostJoin(OutPt *op, const IntPoint offPt);
+ bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2);
+ void JoinCommonEdges();
+ void DoSimplePolygons();
+ void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
+ void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
+#ifdef use_xyz
+ void SetZ(IntPoint& pt, TEdge& e);
+#endif
+};
+//------------------------------------------------------------------------------
+
+class ClipperOffset
+{
+public:
+ ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
+ ~ClipperOffset();
+ void AddPath(const Path& path, JoinType joinType, EndType endType);
+ void AddPaths(const Paths& paths, JoinType joinType, EndType endType);
+ void Execute(Paths& solution, double delta);
+ void Execute(PolyTree& solution, double delta);
+ void Clear();
+ double MiterLimit;
+ double ArcTolerance;
+private:
+ Paths m_destPolys;
+ Path m_srcPoly;
+ Path m_destPoly;
+ std::vector<DoublePoint> m_normals;
+ double m_delta, m_sinA, m_sin, m_cos;
+ double m_miterLim, m_StepsPerRad;
+ IntPoint m_lowest;
+ PolyNode m_polyNodes;
+
+ void FixOrientations();
+ void DoOffset(double delta);
+ void OffsetPoint(int j, int& k, JoinType jointype);
+ void DoSquare(int j, int k);
+ void DoMiter(int j, int k, double r);
+ void DoRound(int j, int k);
+};
+//------------------------------------------------------------------------------
+
+class clipperException : public std::exception
+{
+ public:
+ clipperException(const char* description): m_descr(description) {}
+ virtual ~clipperException() throw() {}
+ virtual const char* what() const throw() {return m_descr.c_str();}
+ private:
+ std::string m_descr;
+};
+//------------------------------------------------------------------------------
+
+} //ClipperLib namespace
+
+#endif //clipper_hpp
+
+
diff --git a/src/csscolorparser/csscolorparser.cpp b/src/csscolorparser/csscolorparser.cpp
index 938470f192..7ba989fde8 100644
--- a/src/csscolorparser/csscolorparser.cpp
+++ b/src/csscolorparser/csscolorparser.cpp
@@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include <csscolorparser/csscolorparser.hpp>
+#include "csscolorparser.hpp"
#include <cstdint>
#include <vector>
diff --git a/src/csscolorparser/csscolorparser.hpp b/src/csscolorparser/csscolorparser.hpp
new file mode 100644
index 0000000000..6caf796943
--- /dev/null
+++ b/src/csscolorparser/csscolorparser.hpp
@@ -0,0 +1,44 @@
+// (c) Dean McNamee <dean@gmail.com>, 2012.
+// C++ port by Konstantin Käfer <mail@kkaefer.com>, 2014.
+//
+// https://github.com/deanm/css-color-parser-js
+// https://github.com/kkaefer/css-color-parser-cpp
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef CSS_COLOR_PARSER_CPP
+#define CSS_COLOR_PARSER_CPP
+
+#include <string>
+
+namespace CSSColorParser {
+
+struct Color {
+ inline Color() {}
+ inline Color(unsigned char r_, unsigned char g_, unsigned char b_, float a_)
+ : r(r_), g(g_), b(b_), a(a_) {}
+ unsigned char r = 0, g = 0, b = 0;
+ float a = 1.0f;
+};
+
+Color parse(const std::string& css_str);
+
+}
+
+#endif
diff --git a/src/libtess2/bucketalloc.c b/src/libtess2/bucketalloc.c
index df1a83c76c..efb2b9813b 100755
--- a/src/libtess2/bucketalloc.c
+++ b/src/libtess2/bucketalloc.c
@@ -35,7 +35,7 @@ extern "C" {
#include <stdio.h>
#include <stdlib.h>
-#include <libtess2/tesselator.h>
+#include "tesselator.h"
//#define CHECK_BOUNDS
diff --git a/src/libtess2/bucketalloc.h b/src/libtess2/bucketalloc.h
index 7168cd7aa7..077d768136 100755
--- a/src/libtess2/bucketalloc.h
+++ b/src/libtess2/bucketalloc.h
@@ -36,7 +36,7 @@
extern "C" {
#endif
-#include <libtess2/tesselator.h>
+#include "tesselator.h"
struct BucketAlloc *createBucketAlloc( TESSalloc* alloc, const char *name,
unsigned int itemSize, unsigned int bucketSize );
diff --git a/src/libtess2/dict.c b/src/libtess2/dict.c
index 53c66568d1..dd7bade2c8 100755
--- a/src/libtess2/dict.c
+++ b/src/libtess2/dict.c
@@ -30,7 +30,7 @@
*/
#include <stddef.h>
-#include <libtess2/tesselator.h>
+#include "tesselator.h"
#include "bucketalloc.h"
#include "dict.h"
diff --git a/src/libtess2/mesh.h b/src/libtess2/mesh.h
index d6142716a9..1e16a194c1 100755
--- a/src/libtess2/mesh.h
+++ b/src/libtess2/mesh.h
@@ -32,7 +32,7 @@
#ifndef MESH_H
#define MESH_H
-#include <libtess2/tesselator.h>
+#include "tesselator.h"
typedef struct TESSmesh TESSmesh;
typedef struct TESSvertex TESSvertex;
diff --git a/src/libtess2/priorityq.c b/src/libtess2/priorityq.c
index 49e1c012f5..6229b6bfce 100755
--- a/src/libtess2/priorityq.c
+++ b/src/libtess2/priorityq.c
@@ -32,7 +32,7 @@
//#include "tesos.h"
#include <stddef.h>
#include <assert.h>
-#include <libtess2/tesselator.h>
+#include "tesselator.h"
#include "priorityq.h"
diff --git a/src/libtess2/tess.h b/src/libtess2/tess.h
index e4673b34ff..8ed75600d2 100755
--- a/src/libtess2/tess.h
+++ b/src/libtess2/tess.h
@@ -37,7 +37,7 @@
#include "mesh.h"
#include "dict.h"
#include "priorityq.h"
-#include <libtess2/tesselator.h>
+#include "tesselator.h"
#ifdef __cplusplus
extern "C" {
diff --git a/src/libtess2/tesselator.h b/src/libtess2/tesselator.h
new file mode 100755
index 0000000000..74ca18e27d
--- /dev/null
+++ b/src/libtess2/tesselator.h
@@ -0,0 +1,209 @@
+/*
+** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+** Copyright (C) [dates of first publication] Silicon Graphics, Inc.
+** All Rights Reserved.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+** of the Software, and to permit persons to whom the Software is furnished to do so,
+** subject to the following conditions:
+**
+** The above copyright notice including the dates of first publication and either this
+** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
+** included in all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
+** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+** OR OTHER DEALINGS IN THE SOFTWARE.
+**
+** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
+** be used in advertising or otherwise to promote the sale, use or other dealings in
+** this Software without prior written authorization from Silicon Graphics, Inc.
+*/
+/*
+** Author: Mikko Mononen, July 2009.
+*/
+
+#ifndef TESSELATOR_H
+#define TESSELATOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// See OpenGL Red Book for description of the winding rules
+// http://www.glprogramming.com/red/chapter11.html
+enum TessWindingRule
+{
+ TESS_WINDING_ODD,
+ TESS_WINDING_NONZERO,
+ TESS_WINDING_POSITIVE,
+ TESS_WINDING_NEGATIVE,
+ TESS_WINDING_ABS_GEQ_TWO,
+};
+
+// The contents of the tessGetElements() depends on element type being passed to tessTesselate().
+// Tesselation result element types:
+// TESS_POLYGONS
+// Each element in the element array is polygon defined as 'polySize' number of vertex indices.
+// If a polygon has than 'polySize' vertices, the remaining indices are stored as TESS_UNDEF.
+// Example, drawing a polygon:
+// const int nelems = tessGetElementCount(tess);
+// const TESSindex* elems = tessGetElements(tess);
+// for (int i = 0; i < nelems; i++) {
+// const TESSindex* poly = &elems[i * polySize];
+// glBegin(GL_POLYGON);
+// for (int j = 0; j < polySize; j++) {
+// if (poly[j] == TESS_UNDEF) break;
+// glVertex2fv(&verts[poly[j]*vertexSize]);
+// }
+// glEnd();
+// }
+//
+// TESS_CONNECTED_POLYGONS
+// Each element in the element array is polygon defined as 'polySize' number of vertex indices,
+// followed by 'polySize' indices to neighour polygons, that is each element is 'polySize' * 2 indices.
+// If a polygon has than 'polySize' vertices, the remaining indices are stored as TESS_UNDEF.
+// If a polygon edge is a boundary, that is, not connected to another polygon, the neighbour index is TESS_UNDEF.
+// Example, flood fill based on seed polygon:
+// const int nelems = tessGetElementCount(tess);
+// const TESSindex* elems = tessGetElements(tess);
+// unsigned char* visited = (unsigned char*)calloc(nelems);
+// TESSindex stack[50];
+// int nstack = 0;
+// stack[nstack++] = seedPoly;
+// visited[startPoly] = 1;
+// while (nstack > 0) {
+// TESSindex idx = stack[--nstack];
+// const TESSindex* poly = &elems[idx * polySize * 2];
+// const TESSindex* nei = &poly[polySize];
+// for (int i = 0; i < polySize; i++) {
+// if (poly[i] == TESS_UNDEF) break;
+// if (nei[i] != TESS_UNDEF && !visited[nei[i]])
+// stack[nstack++] = nei[i];
+// visited[nei[i]] = 1;
+// }
+// }
+// }
+//
+// TESS_BOUNDARY_CONTOURS
+// Each element in the element array is [base index, count] pair defining a range of vertices for a contour.
+// The first value is index to first vertex in contour and the second value is number of vertices in the contour.
+// Example, drawing contours:
+// const int nelems = tessGetElementCount(tess);
+// const TESSindex* elems = tessGetElements(tess);
+// for (int i = 0; i < nelems; i++) {
+// const TESSindex base = elems[i * 2];
+// const TESSindex count = elems[i * 2 + 1];
+// glBegin(GL_LINE_LOOP);
+// for (int j = 0; j < count; j++) {
+// glVertex2fv(&verts[(base+count) * vertexSize]);
+// }
+// glEnd();
+// }
+//
+enum TessElementType
+{
+ TESS_POLYGONS,
+ TESS_CONNECTED_POLYGONS,
+ TESS_BOUNDARY_CONTOURS,
+};
+
+typedef float TESSreal;
+typedef int TESSindex;
+typedef struct TESStesselator TESStesselator;
+typedef struct TESSalloc TESSalloc;
+
+#define TESS_UNDEF (~(TESSindex)0)
+
+// Custom memory allocator interface.
+// The internal memory allocator allocates mesh edges, vertices and faces
+// as well as dictionary nodes and active regions in buckets and uses simple
+// freelist to speed up the allocation. The bucket size should roughly match your
+// expected input data. For example if you process only hundreds of vertices,
+// a bucket size of 128 might be ok, where as when processing thousands of vertices
+// bucket size of 1024 might be approproate. The bucket size is a compromise between
+// how often to allocate memory from the system versus how much extra space the system
+// should allocate. Reasonable defaults are show in commects below, they will be used if
+// the bucket sizes are zero.
+//
+// The use may left the memrealloc to be null. In that case, the tesselator will not try to
+// dynamically grow int's internal arrays. The tesselator only needs the reallocation when it
+// has found intersecting segments and needs to add new vertex. This defency can be cured by
+// allocating some extra vertices beforehand. The 'extraVertices' variable allows to specify
+// number of expected extra vertices.
+struct TESSalloc
+{
+ void *(*memalloc)( void *userData, unsigned int size );
+ void *(*memrealloc)( void *userData, void* ptr, unsigned int size );
+ void (*memfree)( void *userData, void *ptr );
+ void* userData; // User data passed to the allocator functions.
+ int meshEdgeBucketSize; // 512
+ int meshVertexBucketSize; // 512
+ int meshFaceBucketSize; // 256
+ int dictNodeBucketSize; // 512
+ int regionBucketSize; // 256
+ int extraVertices; // Number of extra vertices allocated for the priority queue.
+};
+
+// tessNewTess() - Creates a new tesselator.
+// Use tessDeleteTess() to delete the tesselator.
+// Returns:
+// new tesselator object.
+TESStesselator* tessNewTess( TESSalloc* alloc );
+
+// tessDeleteTess() - Deletes a tesselator.
+// Parameters:
+// tess - pointer to tesselator object to be deleted.
+void tessDeleteTess( TESStesselator *tess );
+
+// tessAddContour() - Adds a contour to be tesselated.
+// The type of the vertex coordinates is assumed to be TESSreal.
+// Parameters:
+// tess - pointer to tesselator object.
+// size - number of coordinates per vertex. Must be 2 or 3.
+// pointer - pointer to the first coordinate of the first vertex in the array.
+// stride - defines offset in bytes between consecutive vertices.
+// count - number of vertices in contour.
+void tessAddContour( TESStesselator *tess, int size, const void* pointer, int stride, int count );
+
+// tessTesselate() - tesselate contours.
+// Parameters:
+// tess - pointer to tesselator object.
+// windingRule - winding rules used for tesselation, must be one of TessWindingRule.
+// elementType - defines the tesselation result element type, must be one of TessElementType.
+// polySize - defines maximum vertices per polygons if output is polygons.
+// vertexSize - defines the number of coordinates in tesselation result vertex, must be 2 or 3.
+// normal - defines the normal of the input contours, of null the normal is calculated automatically.
+// Returns:
+// 1 if succeed, 0 if failed.
+int tessTesselate( TESStesselator *tess, int windingRule, int elementType, int polySize, int vertexSize, const TESSreal* normal );
+
+// tessGetVertexCount() - Returns number of vertices in the tesselated output.
+int tessGetVertexCount( TESStesselator *tess );
+
+// tessGetVertices() - Returns pointer to first coordinate of first vertex.
+const TESSreal* tessGetVertices( TESStesselator *tess );
+
+// tessGetVertexIndices() - Returns pointer to first vertex index.
+// Vertex indices can be used to map the generated vertices to the original vertices.
+// Every point added using tessAddContour() will get a new index starting at 0.
+// New vertices generated at the intersections of segments are assigned value TESS_UNDEF.
+const TESSindex* tessGetVertexIndices( TESStesselator *tess );
+
+// tessGetElementCount() - Returns number of elements in the the tesselated output.
+int tessGetElementCount( TESStesselator *tess );
+
+// tessGetElements() - Returns pointer to the first element.
+const TESSindex* tessGetElements( TESStesselator *tess );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TESSELATOR_H
diff --git a/src/mbgl/geometry/anchor.hpp b/src/mbgl/geometry/anchor.hpp
new file mode 100644
index 0000000000..d30394f0b9
--- /dev/null
+++ b/src/mbgl/geometry/anchor.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_GEOMETRY_ANCHOR
+#define MBGL_GEOMETRY_ANCHOR
+
+#include <vector>
+
+namespace mbgl {
+
+struct Anchor {
+ float x = 0.0f;
+ float y = 0.0f;
+ float angle = 0.0f;
+ float scale = 0.0f;
+ int segment = -1;
+
+ explicit Anchor(float x_, float y_, float angle_, float scale_)
+ : x(x_), y(y_), angle(angle_), scale(scale_) {}
+ explicit Anchor(float x_, float y_, float angle_, float scale_, int segment_)
+ : x(x_), y(y_), angle(angle_), scale(scale_), segment(segment_) {}
+};
+
+typedef std::vector<Anchor> Anchors;
+
+}
+
+#endif \ No newline at end of file
diff --git a/src/mbgl/geometry/binpack.hpp b/src/mbgl/geometry/binpack.hpp
new file mode 100644
index 0000000000..9aadaa202c
--- /dev/null
+++ b/src/mbgl/geometry/binpack.hpp
@@ -0,0 +1,100 @@
+#ifndef MBGL_GEOMETRY_BINPACK
+#define MBGL_GEOMETRY_BINPACK
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/rect.hpp>
+#include <cstdint>
+#include <list>
+
+namespace mbgl {
+
+template <typename T>
+class BinPack : private util::noncopyable {
+public:
+ BinPack(T width, T height)
+ : free(1, Rect<uint16_t>{ 0, 0, width, height }) {}
+public:
+ Rect<T> allocate(T width, T height) {
+ // Find the smallest free rect angle
+ auto smallest = free.end();
+ for (auto it = free.begin(); it != free.end(); ++it) {
+ const Rect<T>& ref = *it;
+ const Rect<T>& rect = *smallest;
+ if (width <= ref.w && height <= ref.h) {
+ if (smallest == free.end() || (ref.y <= rect.y && ref.x <= rect.x)) {
+ smallest = it;
+ }
+ }
+ }
+
+ if (smallest == free.end()) {
+ // There's no space left for this char.
+ return Rect<uint16_t>{ 0, 0, 0, 0 };
+ } else {
+ Rect<T> rect = *smallest;
+ free.erase(smallest);
+
+ // Shorter/Longer Axis Split Rule (SAS)
+ // http://clb.demon.fi/files/RectangleBinPack.pdf p. 15
+ // Ignore the dimension of R and just split long the shorter dimension
+ // See Also: http://www.cs.princeton.edu/~chazelle/pubs/blbinpacking.pdf
+ if (rect.w < rect.h) {
+ // split horizontally
+ // +--+---+
+ // |__|___| <-- b1
+ // +------+ <-- b2
+ if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, height);
+ if (rect.h > height) free.emplace_back(rect.x, rect.y + height, rect.w, rect.h - height);
+ } else {
+ // split vertically
+ // +--+---+
+ // |__| | <-- b1
+ // +--|---+ <-- b2
+ if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, rect.h);
+ if (rect.h > height) free.emplace_back(rect.x, rect.y + height, width, rect.h - height);
+ }
+
+ return Rect<uint16_t>{ rect.x, rect.y, width, height };
+ }
+ }
+
+
+ void release(Rect<T> rect) {
+ // Simple algorithm to recursively merge the newly released cell with its
+ // neighbor. This doesn't merge more than two cells at a time, and fails
+ // for complicated merges.
+ for (auto it = free.begin(); it != free.end(); ++it) {
+ Rect<T> ref = *it;
+ if (ref.y == rect.y && ref.h == rect.h && ref.x + ref.w == rect.x) {
+ ref.w += rect.w;
+ }
+ else if (ref.x == rect.x && ref.w == rect.w && ref.y + ref.h == rect.y) {
+ ref.h += rect.h;
+ }
+ else if (rect.y == ref.y && rect.h == ref.h && rect.x + rect.w == ref.x) {
+ ref.x = rect.x;
+ ref.w += rect.w;
+ }
+ else if (rect.x == ref.x && rect.w == ref.w && rect.y + rect.h == ref.y) {
+ ref.y = rect.y;
+ ref.h += rect.h;
+ } else {
+ continue;
+ }
+
+ free.erase(it);
+ release(ref);
+ return;
+
+ }
+
+ free.emplace_back(rect);
+ };
+
+private:
+ std::list<Rect<T>> free;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/geometry/buffer.hpp b/src/mbgl/geometry/buffer.hpp
new file mode 100644
index 0000000000..80cc6b9d1a
--- /dev/null
+++ b/src/mbgl/geometry/buffer.hpp
@@ -0,0 +1,118 @@
+#ifndef MBGL_GEOMETRY_BUFFER
+#define MBGL_GEOMETRY_BUFFER
+
+#include <mbgl/platform/gl.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <cstdlib>
+#include <cassert>
+#include <stdexcept>
+
+namespace mbgl {
+
+template <
+ size_t item_size,
+ int bufferType = GL_ARRAY_BUFFER,
+ size_t defaultLength = 8192,
+ bool retainAfterUpload = false
+>
+class Buffer : private util::noncopyable {
+public:
+ ~Buffer() {
+ cleanup();
+ if (buffer != 0) {
+ glDeleteBuffers(1, &buffer);
+ buffer = 0;
+ }
+ }
+
+ // Returns the number of elements in this buffer. This is not the number of
+ // bytes, but rather the number of coordinates with associated information.
+ inline size_t index() const {
+ return pos / itemSize;
+ }
+
+ inline bool empty() const {
+ return pos == 0;
+ }
+
+ // Transfers this buffer to the GPU and binds the buffer to the GL context.
+ void bind(bool force = false) {
+ if (buffer == 0) {
+ glGenBuffers(1, &buffer);
+ force = true;
+ }
+ glBindBuffer(bufferType, buffer);
+ if (force) {
+ if (array == nullptr) {
+ throw std::runtime_error("Buffer was already deleted or doesn't contain elements");
+ }
+
+ glBufferData(bufferType, pos, array, GL_STATIC_DRAW);
+ if (!retainAfterUpload) {
+ cleanup();
+ }
+ }
+ }
+
+ void cleanup() {
+ if (array) {
+ free(array);
+ array = nullptr;
+ }
+ }
+
+ inline GLuint getID() const {
+ return buffer;
+ }
+
+protected:
+ // increase the buffer size by at least /required/ bytes.
+ inline void *addElement() {
+ if (buffer != 0) {
+ throw std::runtime_error("Can't add elements after buffer was bound to GPU");
+ }
+ if (length < pos + itemSize) {
+ while (length < pos + itemSize) length += defaultLength;
+ array = realloc(array, length);
+ if (array == nullptr) {
+ throw std::runtime_error("Buffer reallocation failed");
+ }
+ }
+ pos += itemSize;
+ return static_cast<char *>(array) + (pos - itemSize);
+ }
+
+ // Get a pointer to the item at a given index.
+ inline void *getElement(size_t i) {
+ if (array == nullptr) {
+ throw std::runtime_error("Buffer was already deleted or doesn't contain elements");
+ }
+
+ if (i * itemSize >= pos) {
+ throw new std::runtime_error("Can't get element after array bounds");
+ } else {
+ return static_cast<char *>(array) + (i * itemSize);
+ }
+ }
+
+public:
+ static const size_t itemSize = item_size;
+
+private:
+ // CPU buffer
+ void *array = nullptr;
+
+ // Byte position where we are writing.
+ size_t pos = 0;
+
+ // Number of bytes that are valid in this buffer.
+ size_t length = 0;
+
+ // GL buffer ID
+ GLuint buffer = 0;
+};
+
+}
+
+#endif
diff --git a/src/geometry/debug_font_buffer.cpp b/src/mbgl/geometry/debug_font_buffer.cpp
index 6c233f88df..1ec71463e5 100644
--- a/src/geometry/debug_font_buffer.cpp
+++ b/src/mbgl/geometry/debug_font_buffer.cpp
@@ -1,10 +1,10 @@
#include <mbgl/geometry/debug_font_buffer.hpp>
+#include <mbgl/geometry/debug_font_data.hpp>
+
#include <mbgl/platform/gl.hpp>
#include <cmath>
#include <cstring>
-#include "debug_font_data.hpp"
-
using namespace mbgl;
void DebugFontBuffer::addText(const char *text, double left, double baseline, double scale) {
diff --git a/src/mbgl/geometry/debug_font_buffer.hpp b/src/mbgl/geometry/debug_font_buffer.hpp
new file mode 100644
index 0000000000..802b5dbaac
--- /dev/null
+++ b/src/mbgl/geometry/debug_font_buffer.hpp
@@ -0,0 +1,17 @@
+#ifndef MBGL_GEOMETRY_DEBUG_FONT_BUFFER
+#define MBGL_GEOMETRY_DEBUG_FONT_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+
+namespace mbgl {
+
+class DebugFontBuffer : public Buffer<
+ 4 // 2 bytes per coordinate, 2 coordinates
+> {
+public:
+ void addText(const char *text, double left, double baseline, double scale = 1);
+};
+
+}
+
+#endif
diff --git a/src/geometry/debug_font_data.hpp b/src/mbgl/geometry/debug_font_data.hpp
index 26c54cb480..26c54cb480 100644
--- a/src/geometry/debug_font_data.hpp
+++ b/src/mbgl/geometry/debug_font_data.hpp
diff --git a/src/geometry/elements_buffer.cpp b/src/mbgl/geometry/elements_buffer.cpp
index 79af1b7e35..79af1b7e35 100644
--- a/src/geometry/elements_buffer.cpp
+++ b/src/mbgl/geometry/elements_buffer.cpp
diff --git a/src/mbgl/geometry/elements_buffer.hpp b/src/mbgl/geometry/elements_buffer.hpp
new file mode 100644
index 0000000000..9255337cb5
--- /dev/null
+++ b/src/mbgl/geometry/elements_buffer.hpp
@@ -0,0 +1,64 @@
+#ifndef MBGL_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER
+#define MBGL_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+#include <mbgl/geometry/vao.hpp>
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <array>
+
+namespace mbgl {
+
+template <int count>
+struct ElementGroup : public util::noncopyable {
+ std::array<VertexArrayObject, count> array;
+ uint32_t vertex_length;
+ uint32_t elements_length;
+
+ ElementGroup() : vertex_length(0), elements_length(0) {}
+ ElementGroup(uint32_t vertex_length_, uint32_t elements_length_)
+ : vertex_length(vertex_length_),
+ elements_length(elements_length_) {
+ }
+
+ ElementGroup(ElementGroup &&rhs) noexcept
+ : array(std::move(rhs.array)),
+ vertex_length(rhs.vertex_length),
+ elements_length(rhs.elements_length) {};
+};
+
+class TriangleElementsBuffer : public Buffer<
+ 6, // bytes per triangle (3 * unsigned short == 6 bytes)
+ GL_ELEMENT_ARRAY_BUFFER
+> {
+public:
+ typedef uint16_t element_type;
+
+ void add(element_type a, element_type b, element_type c);
+};
+
+
+class LineElementsBuffer : public Buffer<
+ 4, // bytes per triangle (2 * unsigned short == 6 bytes)
+ GL_ELEMENT_ARRAY_BUFFER
+> {
+public:
+ typedef uint16_t element_type;
+
+ void add(element_type a, element_type b);
+};
+
+class PointElementsBuffer : public Buffer<
+ 2, // bytes per point (1 unsigned short)
+ GL_ELEMENT_ARRAY_BUFFER
+> {
+public:
+ typedef uint16_t element_type;
+
+ void add(element_type a);
+};
+
+}
+
+#endif
diff --git a/src/geometry/fill_buffer.cpp b/src/mbgl/geometry/fill_buffer.cpp
index c75ad3477d..3392699431 100644
--- a/src/geometry/fill_buffer.cpp
+++ b/src/mbgl/geometry/fill_buffer.cpp
@@ -1,4 +1,5 @@
#include <mbgl/geometry/fill_buffer.hpp>
+
#include <mbgl/platform/gl.hpp>
#include <climits>
diff --git a/src/mbgl/geometry/fill_buffer.hpp b/src/mbgl/geometry/fill_buffer.hpp
new file mode 100644
index 0000000000..2cd1637fa1
--- /dev/null
+++ b/src/mbgl/geometry/fill_buffer.hpp
@@ -0,0 +1,21 @@
+#ifndef MBGL_GEOMETRY_FILL_BUFFER
+#define MBGL_GEOMETRY_FILL_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+#include <vector>
+#include <cstdint>
+
+namespace mbgl {
+
+class FillVertexBuffer : public Buffer<
+ 4 // bytes per coordinates (2 * unsigned short == 4 bytes)
+> {
+public:
+ typedef int16_t vertex_type;
+
+ void add(vertex_type x, vertex_type y);
+};
+
+}
+
+#endif
diff --git a/src/mbgl/geometry/geometry.hpp b/src/mbgl/geometry/geometry.hpp
new file mode 100644
index 0000000000..484d17b36d
--- /dev/null
+++ b/src/mbgl/geometry/geometry.hpp
@@ -0,0 +1,77 @@
+#ifndef MBGL_GEOMETRY_GEOMETRY
+#define MBGL_GEOMETRY_GEOMETRY
+
+#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <cstdlib>
+
+namespace mbgl {
+
+class Geometry : private util::noncopyable {
+
+public:
+ inline explicit Geometry(pbf& data);
+
+ enum command : uint8_t {
+ end = 0,
+ move_to = 1,
+ line_to = 2,
+ close = 7
+ };
+
+ inline command next(int32_t &rx, int32_t &ry);
+
+private:
+ pbf& data;
+ uint8_t cmd;
+ uint32_t length;
+ int32_t x, y;
+ int32_t ox, oy;
+};
+
+Geometry::Geometry(pbf& data_)
+ : data(data_),
+ cmd(1),
+ length(0),
+ x(0), y(0),
+ ox(0), oy(0) {}
+
+Geometry::command Geometry::next(int32_t &rx, int32_t &ry) {
+ if (data.data < data.end) {
+ if (length == 0) {
+ uint32_t cmd_length = static_cast<uint32_t>(data.varint());
+ cmd = cmd_length & 0x7;
+ length = cmd_length >> 3;
+ }
+
+ --length;
+
+ if (cmd == move_to || cmd == line_to) {
+ rx = (x += data.svarint());
+ ry = (y += data.svarint());
+
+ if (cmd == move_to) {
+ ox = x;
+ oy = y;
+ return move_to;
+ } else {
+ return line_to;
+ }
+ } else if (cmd == close) {
+ rx = ox;
+ ry = oy;
+ return close;
+ } else {
+ fprintf(stderr, "unknown command: %d\n", cmd);
+ // TODO: gracefully handle geometry parse failures
+ return end;
+ }
+ } else {
+ return end;
+ }
+}
+
+}
+
+#endif
diff --git a/src/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp
index 40459821fd..bafcf2b000 100644
--- a/src/geometry/glyph_atlas.cpp
+++ b/src/mbgl/geometry/glyph_atlas.cpp
@@ -1,5 +1,6 @@
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/map/vector_tile.hpp>
+
#include <mbgl/platform/gl.hpp>
#include <mbgl/platform/platform.hpp>
diff --git a/src/mbgl/geometry/glyph_atlas.hpp b/src/mbgl/geometry/glyph_atlas.hpp
new file mode 100644
index 0000000000..7b3c223fe5
--- /dev/null
+++ b/src/mbgl/geometry/glyph_atlas.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_GEOMETRY_GLYPH_ATLAS
+#define MBGL_GEOMETRY_GLYPH_ATLAS
+
+#include <mbgl/geometry/binpack.hpp>
+#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <string>
+#include <set>
+#include <map>
+#include <mutex>
+#include <atomic>
+
+namespace mbgl {
+
+class GlyphAtlas : public util::noncopyable {
+public:
+
+private:
+ struct GlyphValue {
+ GlyphValue(const Rect<uint16_t>& rect_, uint64_t id)
+ : rect(rect_), ids({ id }) {}
+ Rect<uint16_t> rect;
+ std::set<uint64_t> ids;
+ };
+
+ Rect<uint16_t> addGlyph_impl(uint64_t tile_id, const std::string& face_name,
+ const SDFGlyph& glyph);
+public:
+ GlyphAtlas(uint16_t width, uint16_t height);
+
+ Rect<uint16_t> addGlyph(uint64_t tile_id, const std::string& face_name,
+ const SDFGlyph& glyph);
+ void addGlyphs(uint64_t tileid, std::u32string const& text, std::string const& stackname,
+ FontStack const& fontStack, GlyphPositions & face);
+ void removeGlyphs(uint64_t tile_id);
+ void bind();
+
+public:
+ const uint16_t width = 0;
+ const uint16_t height = 0;
+
+private:
+ std::mutex mtx;
+ BinPack<uint16_t> bin;
+ std::map<std::string, std::map<uint32_t, GlyphValue>> index;
+ std::unique_ptr<char[]> data;
+ std::atomic<bool> dirty;
+ uint32_t texture = 0;
+};
+
+};
+
+#endif
diff --git a/src/geometry/icon_buffer.cpp b/src/mbgl/geometry/icon_buffer.cpp
index c571dfa69e..c571dfa69e 100644
--- a/src/geometry/icon_buffer.cpp
+++ b/src/mbgl/geometry/icon_buffer.cpp
diff --git a/src/mbgl/geometry/icon_buffer.hpp b/src/mbgl/geometry/icon_buffer.hpp
new file mode 100644
index 0000000000..08c9687004
--- /dev/null
+++ b/src/mbgl/geometry/icon_buffer.hpp
@@ -0,0 +1,22 @@
+#ifndef MBGL_GEOMETRY_ICON_BUFFER
+#define MBGL_GEOMETRY_ICON_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+
+#include <array>
+
+namespace mbgl {
+
+ class IconVertexBuffer : public Buffer<
+ 20
+ > {
+ public:
+ static const double angleFactor;
+
+ size_t add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float angle, float minzoom, std::array<float, 2> range, float maxzoom, float labelminzoom);
+
+ };
+
+}
+
+#endif
diff --git a/src/geometry/line_buffer.cpp b/src/mbgl/geometry/line_buffer.cpp
index 50a6e66b93..50a6e66b93 100644
--- a/src/geometry/line_buffer.cpp
+++ b/src/mbgl/geometry/line_buffer.cpp
diff --git a/src/mbgl/geometry/line_buffer.hpp b/src/mbgl/geometry/line_buffer.hpp
new file mode 100644
index 0000000000..1c217b59d2
--- /dev/null
+++ b/src/mbgl/geometry/line_buffer.hpp
@@ -0,0 +1,39 @@
+#ifndef MBGL_GEOMETRY_LINE_BUFFER
+#define MBGL_GEOMETRY_LINE_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+
+namespace mbgl {
+
+class LineVertexBuffer : public Buffer<
+ 8 // 2 coordinates per vertex + 1 linesofar + 1 extrude coord pair == 4 (== 8 bytes)
+> {
+public:
+ typedef int16_t vertex_type;
+
+ /*
+ * Scale the extrusion vector so that the normal length is this value.
+ * Contains the "texture" normals (-1..1). This is distinct from the extrude
+ * normals for line joins, because the x-value remains 0 for the texture
+ * normal array, while the extrude normal actually moves the vertex to create
+ * the acute/bevelled line join.
+ */
+ static const int8_t extrudeScale = 63;
+
+ /*
+ * Add a vertex to this buffer
+ *
+ * @param {number} x vertex position
+ * @param {number} y vertex position
+ * @param {number} ex extrude normal
+ * @param {number} ey extrude normal
+ * @param {number} tx texture normal
+ * @param {number} ty texture normal
+ */
+ size_t add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar = 0);
+};
+
+
+}
+
+#endif
diff --git a/src/geometry/resample.cpp b/src/mbgl/geometry/resample.cpp
index abb3ef1e3c..abb3ef1e3c 100644
--- a/src/geometry/resample.cpp
+++ b/src/mbgl/geometry/resample.cpp
diff --git a/src/mbgl/geometry/resample.hpp b/src/mbgl/geometry/resample.hpp
new file mode 100644
index 0000000000..bcfe4ca53d
--- /dev/null
+++ b/src/mbgl/geometry/resample.hpp
@@ -0,0 +1,13 @@
+#ifndef MBGL_GEOMETRY_INTERPOLATE
+#define MBGL_GEOMETRY_INTERPOLATE
+
+#include <mbgl/geometry/anchor.hpp>
+#include <mbgl/util/math.hpp>
+
+namespace mbgl {
+
+Anchors resample(const std::vector<Coordinate> &vertices, float spacing,
+ float minScale, float maxScale, float tilePixelRatio, int start = 0);
+}
+
+#endif
diff --git a/src/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp
index 7dc8f60ae6..7dc8f60ae6 100644
--- a/src/geometry/sprite_atlas.cpp
+++ b/src/mbgl/geometry/sprite_atlas.cpp
diff --git a/src/mbgl/geometry/sprite_atlas.hpp b/src/mbgl/geometry/sprite_atlas.hpp
new file mode 100644
index 0000000000..9e0fe995bb
--- /dev/null
+++ b/src/mbgl/geometry/sprite_atlas.hpp
@@ -0,0 +1,82 @@
+#ifndef MBGL_GEOMETRY_SPRITE_ATLAS
+#define MBGL_GEOMETRY_SPRITE_ATLAS
+
+#include <mbgl/geometry/binpack.hpp>
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <string>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <set>
+#include <array>
+
+namespace mbgl {
+
+class Sprite;
+class SpritePosition;
+
+struct SpriteAtlasPosition {
+ std::array<float, 2> size;
+ std::array<float, 2> tl;
+ std::array<float, 2> br;
+};
+
+class SpriteAtlas : public util::noncopyable {
+public:
+ typedef uint16_t dimension;
+
+ // Add way to construct this from another SpriteAtlas (e.g. with another pixelRatio)
+ SpriteAtlas(dimension width, dimension height);
+ ~SpriteAtlas();
+
+ // Changes the pixel ratio.
+ bool resize(float newRatio);
+
+ // Changes the source sprite.
+ void setSprite(util::ptr<Sprite> sprite);
+
+ // Returns the coordinates of an image that is sourced from the sprite image.
+ // This getter attempts to read the image from the sprite if it is already loaded.
+ // In that case, it copies it into the sprite atlas and returns the dimensions.
+ // Otherwise, it returns a 0/0/0/0 rect.
+ Rect<dimension> getImage(const std::string& name);
+
+ SpriteAtlasPosition getPosition(const std::string& name, bool repeating = false);
+
+ // Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out
+ // of date.
+ void bind(bool linear = false);
+
+ inline float getWidth() const { return width; }
+ inline float getHeight() const { return height; }
+ inline float getTextureWidth() const { return width * pixelRatio; }
+ inline float getTextureHeight() const { return height * pixelRatio; }
+ inline float getPixelRatio() const { return pixelRatio; }
+
+ const dimension width = 0;
+ const dimension height = 0;
+
+private:
+ void allocate();
+ Rect<SpriteAtlas::dimension> allocateImage(size_t width, size_t height);
+ void copy(const Rect<dimension>& dst, const SpritePosition& src);
+
+ std::recursive_mutex mtx;
+ float pixelRatio = 1.0f;
+ BinPack<dimension> bin;
+ util::ptr<Sprite> sprite;
+ std::map<std::string, Rect<dimension>> images;
+ std::set<std::string> uninitialized;
+ uint32_t *data = nullptr;
+ std::atomic<bool> dirty;
+ uint32_t texture = 0;
+ uint32_t filter = 0;
+ static const int buffer = 1;
+};
+
+};
+
+#endif
diff --git a/src/geometry/static_vertex_buffer.cpp b/src/mbgl/geometry/static_vertex_buffer.cpp
index c86211c50f..c86211c50f 100644
--- a/src/geometry/static_vertex_buffer.cpp
+++ b/src/mbgl/geometry/static_vertex_buffer.cpp
diff --git a/src/mbgl/geometry/static_vertex_buffer.hpp b/src/mbgl/geometry/static_vertex_buffer.hpp
new file mode 100644
index 0000000000..ce932269f0
--- /dev/null
+++ b/src/mbgl/geometry/static_vertex_buffer.hpp
@@ -0,0 +1,26 @@
+#ifndef MBGL_GEOMETRY_STATIC_VERTEX_BUFFER
+#define MBGL_GEOMETRY_STATIC_VERTEX_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+
+#include <vector>
+#include <cstddef>
+#include <cstdint>
+#include <cmath>
+
+namespace mbgl {
+
+class StaticVertexBuffer : public Buffer<
+ 4, // bytes per vertex (2 * signed short == 4 bytes)
+ GL_ARRAY_BUFFER,
+ 32 // default length
+> {
+public:
+ typedef int16_t vertex_type;
+
+ StaticVertexBuffer(std::initializer_list<std::pair<int16_t, int16_t>> init);
+};
+
+}
+
+#endif
diff --git a/src/geometry/text_buffer.cpp b/src/mbgl/geometry/text_buffer.cpp
index 295ff02efa..295ff02efa 100644
--- a/src/geometry/text_buffer.cpp
+++ b/src/mbgl/geometry/text_buffer.cpp
diff --git a/src/mbgl/geometry/text_buffer.hpp b/src/mbgl/geometry/text_buffer.hpp
new file mode 100644
index 0000000000..4687b32f97
--- /dev/null
+++ b/src/mbgl/geometry/text_buffer.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_GEOMETRY_TEXT_BUFFER
+#define MBGL_GEOMETRY_TEXT_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+#include <array>
+
+namespace mbgl {
+
+class TextVertexBuffer : public Buffer <
+ 16,
+ GL_ARRAY_BUFFER,
+ 32768
+> {
+public:
+ typedef int16_t vertex_type;
+
+ static const double angleFactor;
+
+ size_t add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float angle, float minzoom, std::array<float, 2> range, float maxzoom, float labelminzoom);
+};
+
+
+}
+
+#endif
diff --git a/src/geometry/vao.cpp b/src/mbgl/geometry/vao.cpp
index d2fd2727ef..66822ba5ce 100644
--- a/src/geometry/vao.cpp
+++ b/src/mbgl/geometry/vao.cpp
@@ -1,5 +1,6 @@
#include <mbgl/geometry/vao.hpp>
#include <mbgl/platform/log.hpp>
+#include <mbgl/util/string.hpp>
namespace mbgl {
@@ -31,8 +32,8 @@ void VertexArrayObject::verifyBinding(Shader &shader, GLuint vertexBuffer, GLuin
char *offset) {
if (bound_shader != shader.getID()) {
throw std::runtime_error(std::string("trying to rebind VAO to another shader from " +
- std::to_string(bound_shader) + "(" + bound_shader_name + ") to " +
- std::to_string(shader.getID()) + "(" + shader.name + ")" ));
+ util::toString(bound_shader) + "(" + bound_shader_name + ") to " +
+ util::toString(shader.getID()) + "(" + shader.name + ")" ));
} else if (bound_offset != offset) {
throw std::runtime_error("trying to bind VAO to another offset");
} else if (bound_vertex_buffer != vertexBuffer) {
diff --git a/src/mbgl/geometry/vao.hpp b/src/mbgl/geometry/vao.hpp
new file mode 100644
index 0000000000..2ecba731f7
--- /dev/null
+++ b/src/mbgl/geometry/vao.hpp
@@ -0,0 +1,73 @@
+#ifndef MBGL_GEOMETRY_VAO
+#define MBGL_GEOMETRY_VAO
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/platform/gl.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <stdexcept>
+
+namespace mbgl {
+
+class VertexArrayObject : public util::noncopyable {
+public:
+ inline VertexArrayObject() {};
+
+ inline VertexArrayObject(VertexArrayObject &&rhs) noexcept
+ : vao(rhs.vao),
+ bound_shader(rhs.bound_shader),
+ bound_shader_name(rhs.bound_shader_name),
+ bound_vertex_buffer(rhs.bound_vertex_buffer),
+ bound_elements_buffer(rhs.bound_elements_buffer),
+ bound_offset(rhs.bound_offset) {};
+
+ template <typename Shader, typename VertexBuffer>
+ inline void bind(Shader& shader, VertexBuffer &vertexBuffer, char *offset) {
+ bindVertexArrayObject();
+ if (bound_shader == 0) {
+ vertexBuffer.bind();
+ shader.bind(offset);
+ if (vao) {
+ storeBinding(shader, vertexBuffer.getID(), 0, offset);
+ }
+ } else {
+ verifyBinding(shader, vertexBuffer.getID(), 0, offset);
+ }
+ }
+
+ template <typename Shader, typename VertexBuffer, typename ElementsBuffer>
+ inline void bind(Shader& shader, VertexBuffer &vertexBuffer, ElementsBuffer &elementsBuffer, char *offset) {
+ bindVertexArrayObject();
+ if (bound_shader == 0) {
+ vertexBuffer.bind();
+ elementsBuffer.bind();
+ shader.bind(offset);
+ if (vao) {
+ storeBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset);
+ }
+ } else {
+ verifyBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset);
+ }
+ }
+
+ ~VertexArrayObject();
+
+private:
+ void bindVertexArrayObject();
+ void storeBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, char *offset);
+ void verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, char *offset);
+
+ GLuint vao = 0;
+
+ // For debug reasons, we're storing the bind information so that we can
+ // detect errors and report
+ GLuint bound_shader = 0;
+ const char *bound_shader_name = "";
+ GLuint bound_vertex_buffer = 0;
+ GLuint bound_elements_buffer = 0;
+ char *bound_offset = 0;
+};
+
+}
+
+#endif
diff --git a/src/map/map.cpp b/src/mbgl/map/map.cpp
index 89d84b48f0..b0a06e8711 100644
--- a/src/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -1,7 +1,8 @@
#include <mbgl/map/map.hpp>
-#include <mbgl/map/source.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/platform/platform.hpp>
+#include <mbgl/map/source.hpp>
+#include <mbgl/renderer/painter.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/util/transition.hpp>
#include <mbgl/util/time.hpp>
@@ -11,10 +12,10 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/std.hpp>
-#include <mbgl/util/mapbox.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_layer_group.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/util/texture_pool.hpp>
@@ -98,10 +99,11 @@ Map::Map(View& view_, FileSource& fileSource_)
#endif
transform(view_),
fileSource(fileSource_),
- glyphAtlas(1024, 1024),
- spriteAtlas(512, 512),
+ glyphAtlas(util::make_unique<GlyphAtlas>(1024, 1024)),
+ glyphStore(std::make_shared<GlyphStore>(fileSource)),
+ spriteAtlas(util::make_unique<SpriteAtlas>(512, 512)),
texturePool(std::make_shared<TexturePool>()),
- painter(spriteAtlas, glyphAtlas)
+ painter(util::make_unique<Painter>(*spriteAtlas, *glyphAtlas))
{
view.initialize(this);
// Make sure that we're doing an initial drawing in all cases.
@@ -149,11 +151,12 @@ void Map::start(bool startPaused) {
assert(std::this_thread::get_id() == mapThread);
// Remove all of these to make sure they are destructed in the correct thread.
- glyphStore.reset();
style.reset();
workers.reset();
activeSources.clear();
+ fileSource.clearLoop();
+
terminating = true;
// Closes all open handles on the loop. This means that the loop will automatically terminate.
@@ -182,7 +185,8 @@ void Map::start(bool startPaused) {
});
asyncCleanup = util::make_unique<uv::async>(**loop, [this]() {
- painter.cleanup();
+ assert(painter);
+ painter->cleanup();
});
// Do we need to pause first?
@@ -211,7 +215,7 @@ void Map::start(bool startPaused) {
});
}
-void Map::stop(stop_callback cb, void *data) {
+void Map::stop(std::function<void ()> callback) {
assert(std::this_thread::get_id() == mainThread);
assert(mainThread != mapThread);
assert(async);
@@ -220,7 +224,7 @@ void Map::stop(stop_callback cb, void *data) {
resume();
- if (cb) {
+ if (callback) {
// Wait until the render thread stopped. We are using this construct instead of plainly
// relying on the thread_join because the system might need to run things in the current
// thread that is required for the render thread to terminate correctly. This is for example
@@ -228,7 +232,7 @@ void Map::stop(stop_callback cb, void *data) {
// thread (== main thread) is blocked. The callback function should use an efficient waiting
// function to avoid a busy waiting loop.
while (!isStopped) {
- cb(data);
+ callback();
}
}
@@ -364,24 +368,17 @@ void Map::cleanup() {
}
void Map::terminate() {
- painter.terminate();
-}
-
-void Map::setReachability(bool reachable) {
- // Note: This function may be called from *any* thread.
- if (reachable) {
- fileSource.prepare([&]() {
- fileSource.retryAllPending();
- });
- }
+ assert(painter);
+ painter->terminate();
}
#pragma mark - Setup
void Map::setup() {
assert(std::this_thread::get_id() == mapThread);
+ assert(painter);
view.make_active();
- painter.setup();
+ painter->setup();
}
void Map::setStyleURL(const std::string &url) {
@@ -404,12 +401,8 @@ void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) {
}
style->loadJSON((const uint8_t *)styleJSON.c_str());
- if (!fileSource.hasLoop()) {
- fileSource.setLoop(**loop);
- glyphStore = std::make_shared<GlyphStore>(fileSource);
- }
fileSource.setBase(base);
- glyphStore->setURL(util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken()));
+ glyphStore->setURL(style->glyph_url);
style->setDefaultTransitionDuration(defaultTransitionDuration);
@@ -431,15 +424,6 @@ std::string Map::getStyleJSON() const {
return styleJSON;
}
-void Map::setAccessToken(std::string accessToken_) {
- // TODO: Make threadsafe.
- accessToken.swap(accessToken_);
-}
-
-std::string Map::getAccessToken() const {
- return accessToken;
-}
-
util::ptr<Sprite> Map::getSprite() {
const float pixelRatio = state.getPixelRatio();
const std::string &sprite_url = style->getSpriteURL();
@@ -604,7 +588,8 @@ void Map::stopRotating() {
void Map::setDebug(bool value) {
debug = value;
- painter.setDebug(debug);
+ assert(painter);
+ painter->setDebug(debug);
update();
}
@@ -700,8 +685,8 @@ void Map::updateSources(const util::ptr<StyleLayerGroup> &group) {
void Map::updateTiles() {
for (const auto& source : activeSources) {
source->source->update(*this, getWorker(),
- style, glyphAtlas, *glyphStore,
- spriteAtlas, getSprite(),
+ style, *glyphAtlas, *glyphStore,
+ *spriteAtlas, getSprite(),
*texturePool, fileSource, [this](){ update(); });
}
}
@@ -709,7 +694,6 @@ void Map::updateTiles() {
void Map::prepare() {
if (!fileSource.hasLoop()) {
fileSource.setLoop(**loop);
- glyphStore = std::make_shared<GlyphStore>(fileSource);
}
if (!style) {
@@ -744,14 +728,15 @@ void Map::prepare() {
style->updateProperties(state.getNormalizedZoom(), animationTime);
// Allow the sprite atlas to potentially pull new sprite images if needed.
- spriteAtlas.resize(state.getPixelRatio());
- spriteAtlas.setSprite(getSprite());
+ spriteAtlas->resize(state.getPixelRatio());
+ spriteAtlas->setSprite(getSprite());
updateTiles();
}
void Map::render() {
- painter.render(*style, activeSources,
+ assert(painter);
+ painter->render(*style, activeSources,
state, animationTime);
// Schedule another rerender when we definitely need a next frame.
if (transform.needsTransition() || style->hasTransitions()) {
diff --git a/src/map/raster_tile_data.cpp b/src/mbgl/map/raster_tile_data.cpp
index 6fac7862e7..6fac7862e7 100644
--- a/src/map/raster_tile_data.cpp
+++ b/src/mbgl/map/raster_tile_data.cpp
diff --git a/src/mbgl/map/raster_tile_data.hpp b/src/mbgl/map/raster_tile_data.hpp
new file mode 100644
index 0000000000..42070d9c61
--- /dev/null
+++ b/src/mbgl/map/raster_tile_data.hpp
@@ -0,0 +1,33 @@
+#ifndef MBGL_MAP_RASTER_TILE_DATA
+#define MBGL_MAP_RASTER_TILE_DATA
+
+#include <mbgl/map/tile.hpp>
+#include <mbgl/map/tile_data.hpp>
+#include <mbgl/renderer/raster_bucket.hpp>
+
+namespace mbgl {
+
+class Painter;
+class SourceInfo;
+class StyleLayer;
+class TexturePool;
+
+class RasterTileData : public TileData {
+ friend class TileParser;
+
+public:
+ RasterTileData(Tile::ID const& id, TexturePool&, const SourceInfo&);
+ ~RasterTileData();
+
+ virtual void parse();
+ virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix);
+ virtual bool hasData(StyleLayer const& layer_desc) const;
+
+protected:
+ StyleBucketRaster properties;
+ RasterBucket bucket;
+};
+
+}
+
+#endif
diff --git a/src/map/source.cpp b/src/mbgl/map/source.cpp
index 35f5072860..798cd41d1d 100644
--- a/src/map/source.cpp
+++ b/src/mbgl/map/source.cpp
@@ -10,6 +10,7 @@
#include <mbgl/util/vec.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/std.hpp>
+#include <mbgl/util/box.hpp>
#include <mbgl/util/mapbox.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/style/style_layer.hpp>
@@ -36,10 +37,9 @@ void Source::load(Map& map, FileSource& fileSource) {
return;
}
- std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken());
util::ptr<Source> source = shared_from_this();
- fileSource.request(ResourceType::JSON, url)->onload([source, &map](const Response &res) {
+ fileSource.request(ResourceType::JSON, info.url)->onload([source, &map](const Response &res) {
if (res.code != 200) {
Log::Warning(Event::General, "failed to load source TileJSON");
return;
@@ -88,13 +88,13 @@ size_t Source::getTileCount() const {
void Source::drawClippingMasks(Painter &painter) {
for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
- gl::group group(util::sprintf<32>("mask %d/%d/%d", tile.id.z, tile.id.y, tile.id.z));
+ gl::group group(std::string { "mask: " } + std::string(tile.id));
painter.drawClippingMask(tile.matrix, tile.clip);
}
}
void Source::render(Painter &painter, util::ptr<StyleLayer> layer_desc) {
- gl::group group(std::string("layer: ") + layer_desc->id);
+ gl::group group(std::string { "layer: " } + layer_desc->id);
for (const std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
if (tile.data && tile.data->state == TileData::State::parsed) {
diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp
new file mode 100644
index 0000000000..8976f67b05
--- /dev/null
+++ b/src/mbgl/map/source.hpp
@@ -0,0 +1,86 @@
+#ifndef MBGL_MAP_SOURCE
+#define MBGL_MAP_SOURCE
+
+#include <mbgl/map/tile.hpp>
+#include <mbgl/map/tile_data.hpp>
+#include <mbgl/style/style_source.hpp>
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/time.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <cstdint>
+#include <forward_list>
+#include <iosfwd>
+#include <map>
+
+namespace mbgl {
+
+class Map;
+class GlyphAtlas;
+class GlyphStore;
+class SpriteAtlas;
+class Sprite;
+class FileSource;
+class TexturePool;
+class Style;
+class Painter;
+class StyleLayer;
+class TransformState;
+struct box;
+
+class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
+public:
+ Source(SourceInfo&);
+
+ void load(Map&, FileSource&);
+ void update(Map&, uv::worker&,
+ util::ptr<Style>,
+ GlyphAtlas&, GlyphStore&,
+ SpriteAtlas&, util::ptr<Sprite>,
+ TexturePool&, FileSource&,
+ std::function<void ()> callback);
+
+ void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
+ void drawClippingMasks(Painter &painter);
+ size_t getTileCount() const;
+ void render(Painter &painter, util::ptr<StyleLayer> layer_desc);
+ void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix);
+ void finishRender(Painter &painter);
+
+ std::forward_list<Tile::ID> getIDs() const;
+ std::forward_list<Tile *> getLoadedTiles() const;
+ void updateClipIDs(const std::map<Tile::ID, ClipID> &mapping);
+
+private:
+ bool findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list<Tile::ID>& retain);
+ bool findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::forward_list<Tile::ID>& retain);
+ int32_t coveringZoomLevel(const TransformState&) const;
+ std::forward_list<Tile::ID> coveringTiles(const TransformState&) const;
+
+ TileData::State addTile(Map&, uv::worker&,
+ util::ptr<Style>,
+ GlyphAtlas&, GlyphStore&,
+ SpriteAtlas&, util::ptr<Sprite>,
+ FileSource&, TexturePool&,
+ const Tile::ID&,
+ std::function<void ()> callback);
+
+ TileData::State hasTile(const Tile::ID& id);
+
+ double getZoom(const TransformState &state) const;
+
+ SourceInfo& info;
+ bool loaded = false;
+
+ // Stores the time when this source was most recently updated.
+ timestamp updated = 0;
+
+ std::map<Tile::ID, std::unique_ptr<Tile>> tiles;
+ std::map<Tile::ID, std::weak_ptr<TileData>> tile_data;
+};
+
+}
+
+#endif
diff --git a/src/map/sprite.cpp b/src/mbgl/map/sprite.cpp
index c1f71e59d9..c1f71e59d9 100644
--- a/src/map/sprite.cpp
+++ b/src/mbgl/map/sprite.cpp
diff --git a/src/mbgl/map/sprite.hpp b/src/mbgl/map/sprite.hpp
new file mode 100644
index 0000000000..d4b54ba1b5
--- /dev/null
+++ b/src/mbgl/map/sprite.hpp
@@ -0,0 +1,79 @@
+#ifndef MBGL_STYLE_SPRITE
+#define MBGL_STYLE_SPRITE
+
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <cstdint>
+#include <atomic>
+#include <iosfwd>
+#include <string>
+#include <unordered_map>
+#include <future>
+
+namespace mbgl {
+
+class FileSource;
+
+class SpritePosition {
+public:
+ explicit SpritePosition() {}
+ explicit SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, float pixelRatio, bool sdf);
+
+ operator bool() const {
+ return !(width == 0 && height == 0 && x == 0 && y == 0);
+ }
+
+ uint16_t x = 0, y = 0;
+ uint16_t width = 0, height = 0;
+ float pixelRatio = 1.0f;
+ bool sdf = false;
+};
+
+class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable {
+private:
+ struct Key {};
+ void load(FileSource& fileSource);
+
+public:
+ Sprite(const Key &, const std::string& base_url, float pixelRatio);
+ static util::ptr<Sprite> Create(const std::string& base_url, float pixelRatio, FileSource& fileSource);
+
+ const SpritePosition &getSpritePosition(const std::string& name) const;
+
+ void waitUntilLoaded() const;
+ bool isLoaded() const;
+
+ operator bool() const;
+
+private:
+ const bool valid;
+
+public:
+ const float pixelRatio;
+ const std::string spriteURL;
+ const std::string jsonURL;
+ std::unique_ptr<util::Image> raster;
+
+private:
+ void parseJSON();
+ void parseImage();
+ void complete();
+
+private:
+ std::string body;
+ std::string image;
+ std::atomic<bool> loadedImage;
+ std::atomic<bool> loadedJSON;
+ std::unordered_map<std::string, SpritePosition> pos;
+ const SpritePosition empty;
+
+ std::promise<void> promise;
+ std::future<void> future;
+
+};
+
+}
+
+#endif
diff --git a/src/map/tile.cpp b/src/mbgl/map/tile.cpp
index 3070d3fd96..9f31048857 100644
--- a/src/map/tile.cpp
+++ b/src/mbgl/map/tile.cpp
@@ -1,5 +1,8 @@
#include <mbgl/map/tile.hpp>
#include <mbgl/util/vec.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/box.hpp>
+
#include <cassert>
@@ -52,6 +55,11 @@ bool Tile::ID::isChildOf(const Tile::ID &parent_id) const {
}
+Tile::ID::operator std::string() const {
+ return util::toString(z) + "/" + util::toString(x) + "/" + util::toString(y);
+}
+
+
// Taken from polymaps src/Layer.js
// https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383
diff --git a/src/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp
index c1354d490b..f89ff15baf 100644
--- a/src/map/tile_data.cpp
+++ b/src/mbgl/map/tile_data.cpp
@@ -11,12 +11,12 @@ using namespace mbgl;
TileData::TileData(Tile::ID const& id_, const SourceInfo& source_)
: id(id_),
+ name(id),
state(State::initial),
source(source_),
debugBucket(debugFontBuffer) {
// Initialize tile debug coordinates
- const std::string str = util::sprintf<32>("%d/%d/%d", id_.z, id_.x, id_.y);
- debugFontBuffer.addText(str.c_str(), 50, 200, 5);
+ debugFontBuffer.addText(name.c_str(), 50, 200, 5);
}
TileData::~TileData() {
@@ -24,7 +24,7 @@ TileData::~TileData() {
}
const std::string TileData::toString() const {
- return util::sprintf<32>("[tile %d/%d/%d]", id.z, id.x, id.y);
+ return std::string { "[tile " } + name + "]";
}
void TileData::request(uv::worker& worker, FileSource& fileSource,
@@ -34,9 +34,9 @@ void TileData::request(uv::worker& worker, FileSource& fileSource,
std::string url = source.tiles[(id.x + id.y) % source.tiles.size()];
url = util::replaceTokens(url, [&](const std::string &token) -> std::string {
- if (token == "z") return std::to_string(id.z);
- if (token == "x") return std::to_string(id.x);
- if (token == "y") return std::to_string(id.y);
+ if (token == "z") return util::toString(id.z);
+ if (token == "x") return util::toString(id.x);
+ if (token == "y") return util::toString(id.y);
if (token == "prefix") {
std::string prefix { 2 };
prefix[0] = "0123456789abcdef"[id.x % 16];
diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp
new file mode 100644
index 0000000000..1ae215b204
--- /dev/null
+++ b/src/mbgl/map/tile_data.hpp
@@ -0,0 +1,88 @@
+#ifndef MBGL_MAP_TILE_DATA
+#define MBGL_MAP_TILE_DATA
+
+#include <mbgl/map/tile.hpp>
+#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/geometry/debug_font_buffer.hpp>
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <atomic>
+#include <exception>
+#include <iosfwd>
+#include <string>
+#include <functional>
+
+namespace uv {
+class worker;
+}
+
+namespace mbgl {
+
+class Map;
+class FileSource;
+class Painter;
+class SourceInfo;
+class StyleLayer;
+class Request;
+
+class TileData : public std::enable_shared_from_this<TileData>,
+ private util::noncopyable {
+public:
+ struct exception : std::exception {};
+ struct geometry_too_long_exception : exception {};
+
+public:
+ typedef util::ptr<TileData> Ptr;
+
+ enum class State {
+ invalid,
+ initial,
+ loading,
+ loaded,
+ parsed,
+ obsolete
+ };
+
+public:
+ TileData(Tile::ID const& id, const SourceInfo&);
+ ~TileData();
+
+ void request(uv::worker&, FileSource&, float pixelRatio, std::function<void ()> callback);
+ void reparse(uv::worker&, std::function<void ()> callback);
+ void cancel();
+ const std::string toString() const;
+
+ inline bool ready() const {
+ return state == State::parsed;
+ }
+
+ // Override this in the child class.
+ virtual void parse() = 0;
+ virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) = 0;
+ virtual bool hasData(StyleLayer const& layer_desc) const = 0;
+
+
+public:
+ const Tile::ID id;
+ const std::string name;
+ std::atomic<State> state;
+
+public:
+ const SourceInfo& source;
+
+protected:
+ std::unique_ptr<Request> req;
+ std::string data;
+
+ // Contains the tile ID string for painting debug information.
+ DebugFontBuffer debugFontBuffer;
+
+public:
+ DebugBucket debugBucket;
+};
+
+}
+
+#endif
diff --git a/src/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp
index cbfd6fa7b3..1e12e5fc16 100644
--- a/src/map/tile_parser.cpp
+++ b/src/mbgl/map/tile_parser.cpp
@@ -1,5 +1,4 @@
#include <mbgl/map/tile_parser.hpp>
-
#include <mbgl/map/vector_tile_data.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
diff --git a/src/mbgl/map/tile_parser.hpp b/src/mbgl/map/tile_parser.hpp
new file mode 100644
index 0000000000..beae3af831
--- /dev/null
+++ b/src/mbgl/map/tile_parser.hpp
@@ -0,0 +1,77 @@
+#ifndef MBGL_MAP_TILE_PARSER
+#define MBGL_MAP_TILE_PARSER
+
+#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/util/ptr.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <cstdint>
+#include <iosfwd>
+#include <string>
+
+namespace mbgl {
+
+class Bucket;
+class TexturePool;
+class FontStack;
+class GlyphAtlas;
+class GlyphStore;
+class SpriteAtlas;
+class Sprite;
+class Style;
+class StyleBucket;
+class StyleBucketFill;
+class StyleBucketRaster;
+class StyleBucketLine;
+class StyleBucketSymbol;
+class StyleLayerGroup;
+class VectorTileData;
+class Collision;
+class TexturePool;
+
+class TileParser : private util::noncopyable
+{
+public:
+ TileParser(const std::string &data, VectorTileData &tile,
+ const util::ptr<const Style> &style,
+ GlyphAtlas & glyphAtlas,
+ GlyphStore & glyphStore,
+ SpriteAtlas & spriteAtlas,
+ const util::ptr<Sprite> &sprite,
+ TexturePool& texturePool);
+ ~TileParser();
+
+public:
+ void parse();
+
+private:
+ bool obsolete() const;
+ void parseStyleLayers(util::ptr<StyleLayerGroup> group);
+ std::unique_ptr<Bucket> createBucket(util::ptr<StyleBucket> bucket_desc);
+
+ std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill);
+ std::unique_ptr<Bucket> createRasterBucket(const StyleBucketRaster &raster);
+ std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line);
+ std::unique_ptr<Bucket> createSymbolBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketSymbol &symbol);
+
+ template <class Bucket> void addBucketGeometries(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter);
+
+private:
+ const VectorTile vector_data;
+ VectorTileData& tile;
+
+ // Cross-thread shared data.
+ util::ptr<const Style> style;
+ GlyphAtlas & glyphAtlas;
+ GlyphStore & glyphStore;
+ SpriteAtlas & spriteAtlas;
+ util::ptr<Sprite> sprite;
+ TexturePool& texturePool;
+
+ std::unique_ptr<Collision> collision;
+};
+
+}
+
+#endif
diff --git a/src/map/transform.cpp b/src/mbgl/map/transform.cpp
index d05d1f7446..d05d1f7446 100644
--- a/src/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
diff --git a/src/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index afc5b59ef1..a7da8ccab2 100644
--- a/src/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -1,5 +1,6 @@
#include <mbgl/map/transform_state.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/box.hpp>
using namespace mbgl;
diff --git a/src/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp
index ac7134fb0c..ac7134fb0c 100644
--- a/src/map/vector_tile.cpp
+++ b/src/mbgl/map/vector_tile.cpp
diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/map/vector_tile.hpp
new file mode 100644
index 0000000000..2d02ba3a0b
--- /dev/null
+++ b/src/mbgl/map/vector_tile.hpp
@@ -0,0 +1,118 @@
+#ifndef MBGL_MAP_VECTOR_TILE
+#define MBGL_MAP_VECTOR_TILE
+
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/style/value.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <cstdint>
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace mbgl {
+
+class VectorTileLayer;
+
+enum class FeatureType {
+ Unknown = 0,
+ Point = 1,
+ LineString = 2,
+ Polygon = 3
+};
+
+std::ostream& operator<<(std::ostream&, const FeatureType& type);
+
+class VectorTileFeature {
+public:
+ VectorTileFeature(pbf feature, const VectorTileLayer& layer);
+
+ uint64_t id = 0;
+ FeatureType type = FeatureType::Unknown;
+ std::map<std::string, Value> properties;
+ pbf geometry;
+};
+
+std::ostream& operator<<(std::ostream&, const VectorTileFeature& feature);
+
+
+class VectorTileTagExtractor {
+public:
+ VectorTileTagExtractor(const VectorTileLayer &layer);
+
+ void setTags(const pbf &pbf);
+ mapbox::util::optional<Value> getValue(const std::string &key) const;
+ void setType(FeatureType type);
+ FeatureType getType() const;
+
+private:
+ const VectorTileLayer &layer_;
+ pbf tags_;
+ FeatureType type_ = FeatureType::Unknown;
+};
+
+/*
+ * Allows iterating over the features of a VectorTileLayer using a
+ * BucketDescription as filter. Only features matching the descriptions will
+ * be returned (as pbf).
+ */
+class FilteredVectorTileLayer {
+public:
+ class iterator {
+ public:
+ iterator(const FilteredVectorTileLayer& filter, const pbf& data);
+ void operator++();
+ bool operator!=(const iterator& other) const;
+ const pbf& operator*() const;
+
+ private:
+ const FilteredVectorTileLayer& parent;
+ bool valid = false;
+ pbf feature;
+ pbf data;
+ };
+
+public:
+ FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression);
+
+ iterator begin() const;
+ iterator end() const;
+
+private:
+ const VectorTileLayer& layer;
+ const FilterExpression& filterExpression;
+};
+
+std::ostream& operator<<(std::ostream&, const PositionedGlyph& placement);
+
+class VectorTileLayer {
+public:
+ VectorTileLayer(pbf data);
+
+ const pbf data;
+ std::string name;
+ uint32_t extent = 4096;
+ std::vector<std::string> keys;
+ std::unordered_map<std::string, uint32_t> key_index;
+ std::vector<Value> values;
+ std::map<std::string, std::map<Value, Shaping>> shaping;
+};
+
+class VectorTile {
+public:
+ VectorTile();
+ VectorTile(pbf data);
+ VectorTile& operator=(VectorTile&& other);
+
+ std::map<std::string, const VectorTileLayer> layers;
+};
+
+
+
+}
+
+#endif
diff --git a/src/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp
index 06782057f6..06782057f6 100644
--- a/src/map/vector_tile_data.cpp
+++ b/src/mbgl/map/vector_tile_data.cpp
diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp
new file mode 100644
index 0000000000..b9bf55a1b3
--- /dev/null
+++ b/src/mbgl/map/vector_tile_data.hpp
@@ -0,0 +1,74 @@
+#ifndef MBGL_MAP_VECTOR_TILE_DATA
+#define MBGL_MAP_VECTOR_TILE_DATA
+
+#include <mbgl/map/tile.hpp>
+#include <mbgl/map/tile_data.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/fill_buffer.hpp>
+#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/geometry/line_buffer.hpp>
+#include <mbgl/geometry/text_buffer.hpp>
+
+#include <iosfwd>
+#include <memory>
+#include <unordered_map>
+
+namespace mbgl {
+
+class Bucket;
+class Painter;
+class SourceInfo;
+class StyleLayer;
+class TileParser;
+class GlyphAtlas;
+class GlyphStore;
+class SpriteAtlas;
+class Sprite;
+class TexturePool;
+class Style;
+
+class VectorTileData : public TileData {
+ friend class TileParser;
+
+public:
+ VectorTileData(Tile::ID const&,
+ float mapMaxZoom, util::ptr<Style>,
+ GlyphAtlas&, GlyphStore&,
+ SpriteAtlas&, util::ptr<Sprite>,
+ TexturePool&,
+ const SourceInfo&);
+ ~VectorTileData();
+
+ virtual void parse();
+ virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix);
+ virtual bool hasData(StyleLayer const& layer_desc) const;
+
+protected:
+ // Holds the actual geometries in this tile.
+ FillVertexBuffer fillVertexBuffer;
+ LineVertexBuffer lineVertexBuffer;
+ IconVertexBuffer iconVertexBuffer;
+ TextVertexBuffer textVertexBuffer;
+
+ TriangleElementsBuffer triangleElementsBuffer;
+ LineElementsBuffer lineElementsBuffer;
+ PointElementsBuffer pointElementsBuffer;
+
+ // Holds the buckets of this tile.
+ // They contain the location offsets in the buffers stored above
+ std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
+
+ GlyphAtlas& glyphAtlas;
+ GlyphStore& glyphStore;
+ SpriteAtlas& spriteAtlas;
+ util::ptr<Sprite> sprite;
+ TexturePool& texturePool;
+ util::ptr<Style> style;
+
+public:
+ const float depth;
+};
+
+}
+
+#endif
diff --git a/src/platform/gl.cpp b/src/mbgl/platform/gl.cpp
index 155fd70d95..155fd70d95 100644
--- a/src/platform/gl.cpp
+++ b/src/mbgl/platform/gl.cpp
diff --git a/src/platform/log.cpp b/src/mbgl/platform/log.cpp
index b83c7a9322..b83c7a9322 100644
--- a/src/platform/log.cpp
+++ b/src/mbgl/platform/log.cpp
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
new file mode 100644
index 0000000000..696bfb1110
--- /dev/null
+++ b/src/mbgl/renderer/bucket.hpp
@@ -0,0 +1,24 @@
+#ifndef MBGL_RENDERER_BUCKET
+#define MBGL_RENDERER_BUCKET
+
+#include <mbgl/map/tile.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <string>
+
+namespace mbgl {
+
+class Painter;
+class StyleLayer;
+
+class Bucket : private util::noncopyable {
+public:
+ virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) = 0;
+ virtual bool hasData() const = 0;
+ virtual ~Bucket() {}
+
+};
+
+}
+
+#endif
diff --git a/src/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp
index 58fbf8a35b..f089374564 100644
--- a/src/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/debug_bucket.cpp
@@ -1,5 +1,4 @@
#include <mbgl/renderer/debug_bucket.hpp>
-
#include <mbgl/renderer/painter.hpp>
#include <mbgl/platform/gl.hpp>
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp
new file mode 100644
index 0000000000..fb6cfb4cae
--- /dev/null
+++ b/src/mbgl/renderer/debug_bucket.hpp
@@ -0,0 +1,35 @@
+#ifndef MBGL_RENDERER_DEBUGBUCKET
+#define MBGL_RENDERER_DEBUGBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/geometry/debug_font_buffer.hpp>
+#include <mbgl/geometry/vao.hpp>
+
+#include <vector>
+
+#ifndef BUFFER_OFFSET
+#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+#endif
+
+namespace mbgl {
+
+class PlainShader;
+
+class DebugBucket : public Bucket {
+public:
+ DebugBucket(DebugFontBuffer& fontBuffer);
+
+ virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ virtual bool hasData() const;
+
+ void drawLines(PlainShader& shader);
+ void drawPoints(PlainShader& shader);
+
+private:
+ DebugFontBuffer& fontBuffer;
+ VertexArrayObject array;
+};
+
+}
+
+#endif
diff --git a/src/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index 0a7d77935d..0a7d77935d 100644
--- a/src/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp
new file mode 100644
index 0000000000..ae766ec28d
--- /dev/null
+++ b/src/mbgl/renderer/fill_bucket.hpp
@@ -0,0 +1,88 @@
+#ifndef MBGL_RENDERER_FILLBUCKET
+#define MBGL_RENDERER_FILLBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/fill_buffer.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <clipper/clipper.hpp>
+#include <libtess2/tesselator.h>
+
+#include <vector>
+#include <memory>
+
+#ifndef BUFFER_OFFSET
+#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+#endif
+
+namespace mbgl {
+
+class Style;
+class FillVertexBuffer;
+class TriangleElementsBuffer;
+class LineElementsBuffer;
+class BucketDescription;
+class OutlineShader;
+class PlainShader;
+class PatternShader;
+struct pbf;
+
+class FillBucket : public Bucket {
+
+ static void *alloc(void *data, unsigned int size);
+ static void *realloc(void *data, void *ptr, unsigned int size);
+ static void free(void *userData, void *ptr);
+
+ typedef ElementGroup<2> triangle_group_type;
+ typedef ElementGroup<1> line_group_type;
+
+public:
+ FillBucket(FillVertexBuffer& vertexBuffer,
+ TriangleElementsBuffer& triangleElementsBuffer,
+ LineElementsBuffer& lineElementsBuffer,
+ const StyleBucketFill& properties);
+ ~FillBucket();
+
+ virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ virtual bool hasData() const;
+
+ void addGeometry(pbf& data);
+ void tessellate();
+
+ void drawElements(PlainShader& shader);
+ void drawElements(PatternShader& shader);
+ void drawVertices(OutlineShader& shader);
+
+public:
+ const StyleBucketFill &properties;
+
+private:
+ TESSalloc *allocator;
+ TESStesselator *tesselator;
+ ClipperLib::Clipper clipper;
+
+ FillVertexBuffer& vertexBuffer;
+ TriangleElementsBuffer& triangleElementsBuffer;
+ LineElementsBuffer& lineElementsBuffer;
+
+ // hold information on where the vertices are located in the FillBuffer
+ const size_t vertex_start;
+ const size_t triangle_elements_start;
+ const size_t line_elements_start;
+ VertexArrayObject array;
+
+ std::vector<triangle_group_type> triangleGroups;
+ std::vector<line_group_type> lineGroups;
+
+ std::vector<ClipperLib::IntPoint> line;
+ bool hasVertices = false;
+
+ static const int vertexSize = 2;
+ static const int stride = sizeof(TESSreal) * vertexSize;
+ static const int vertices_per_group = 3;
+};
+
+}
+
+#endif
diff --git a/src/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index 8b69162a23..8b69162a23 100644
--- a/src/renderer/frame_history.cpp
+++ b/src/mbgl/renderer/frame_history.cpp
diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp
new file mode 100644
index 0000000000..61bb59da33
--- /dev/null
+++ b/src/mbgl/renderer/frame_history.hpp
@@ -0,0 +1,40 @@
+#ifndef MBGL_RENDERER_FRAME_HISTORY
+#define MBGL_RENDERER_FRAME_HISTORY
+
+#include <deque>
+#include <cassert>
+#include <cmath>
+
+#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/time.hpp>
+
+namespace mbgl {
+
+struct FrameSnapshot {
+ explicit inline FrameSnapshot(timestamp t_, float z_) : t(t_), z(z_) {}
+ float t;
+ float z;
+};
+
+struct FadeProperties {
+ float fadedist;
+ float minfadezoom;
+ float maxfadezoom;
+ float bump;
+};
+
+class FrameHistory {
+public:
+ // Record frame history that will be used to calculate fading params
+ void record(timestamp now, float zoom);
+
+ bool needsAnimation(timestamp duration) const;
+ FadeProperties getFadeProperties(timestamp duration);
+
+public:
+ std::deque<FrameSnapshot> history;
+};
+
+}
+
+#endif
diff --git a/src/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 8267cbaba2..8267cbaba2 100644
--- a/src/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
new file mode 100644
index 0000000000..7337ca80ad
--- /dev/null
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -0,0 +1,62 @@
+#ifndef MBGL_RENDERER_LINEBUCKET
+#define MBGL_RENDERER_LINEBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/line_buffer.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <vector>
+
+namespace mbgl {
+
+class Style;
+class LineVertexBuffer;
+class TriangleElementsBuffer;
+class LineShader;
+class LinejoinShader;
+class LinepatternShader;
+struct pbf;
+
+class LineBucket : public Bucket {
+ typedef ElementGroup<2> triangle_group_type;
+ typedef ElementGroup<1> point_group_type;
+
+public:
+ LineBucket(LineVertexBuffer& vertexBuffer,
+ TriangleElementsBuffer& triangleElementsBuffer,
+ PointElementsBuffer& pointElementsBuffer,
+ const StyleBucketLine& properties);
+
+ virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ virtual bool hasData() const;
+
+ void addGeometry(pbf& data);
+ void addGeometry(const std::vector<Coordinate>& line);
+
+ bool hasPoints() const;
+
+ void drawLines(LineShader& shader);
+ void drawLinePatterns(LinepatternShader& shader);
+ void drawPoints(LinejoinShader& shader);
+
+public:
+ const StyleBucketLine &properties;
+
+private:
+ LineVertexBuffer& vertexBuffer;
+ TriangleElementsBuffer& triangleElementsBuffer;
+ PointElementsBuffer& pointElementsBuffer;
+
+ const size_t vertex_start;
+ const size_t triangle_elements_start;
+ const size_t point_elements_start;
+
+ std::vector<triangle_group_type> triangleGroups;
+ std::vector<point_group_type> pointGroups;
+};
+
+}
+
+#endif
diff --git a/src/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index a08cf39dcb..bfc59942e7 100644
--- a/src/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -370,7 +370,7 @@ void Painter::renderLayer(util::ptr<StyleLayer> layer_desc, const Tile::ID* id,
void Painter::renderTileLayer(const Tile& tile, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) {
assert(tile.data);
if (tile.data->hasData(*layer_desc) || layer_desc->type == StyleLayerType::Raster) {
- gl::group group(util::sprintf<32>("render %d/%d/%d\n", tile.id.z, tile.id.y, tile.id.z));
+ gl::group group(std::string { "render " } + tile.data->name);
prepareTile(tile);
tile.data->render(*this, layer_desc, matrix);
}
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
new file mode 100644
index 0000000000..be4bd12710
--- /dev/null
+++ b/src/mbgl/renderer/painter.hpp
@@ -0,0 +1,259 @@
+#ifndef MBGL_RENDERER_PAINTER
+#define MBGL_RENDERER_PAINTER
+
+#include <mbgl/map/tile_data.hpp>
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/static_vertex_buffer.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/renderer/frame_history.hpp>
+#include <mbgl/style/types.hpp>
+
+#include <mbgl/shader/plain_shader.hpp>
+#include <mbgl/shader/outline_shader.hpp>
+#include <mbgl/shader/pattern_shader.hpp>
+#include <mbgl/shader/line_shader.hpp>
+#include <mbgl/shader/linejoin_shader.hpp>
+#include <mbgl/shader/linepattern_shader.hpp>
+#include <mbgl/shader/icon_shader.hpp>
+#include <mbgl/shader/raster_shader.hpp>
+#include <mbgl/shader/sdf_shader.hpp>
+#include <mbgl/shader/dot_shader.hpp>
+#include <mbgl/shader/gaussian_shader.hpp>
+
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <map>
+#include <unordered_map>
+#include <set>
+
+namespace mbgl {
+
+enum class RenderPass : bool { Opaque, Translucent };
+
+class Transform;
+class Style;
+class Tile;
+class Sprite;
+class SpriteAtlas;
+class GlyphAtlas;
+class Source;
+class StyleSource;
+class StyleLayerGroup;
+
+class FillBucket;
+class LineBucket;
+class SymbolBucket;
+class RasterBucket;
+class PrerenderedTexture;
+
+struct FillProperties;
+struct RasterProperties;
+
+class LayerDescription;
+class RasterTileData;
+
+class Painter : private util::noncopyable {
+public:
+ Painter(SpriteAtlas&, GlyphAtlas&);
+ ~Painter();
+
+ void setup();
+
+ // Perform cleanup tasks that prepare shutting down the app. This doesn't mean that the
+ // app will be shut down. That means all operations must be automatically be reversed (e.g. through
+ // lazy initialization) in case rendering continues.
+ void cleanup();
+
+ void terminate();
+
+ // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any
+ // tiles whatsoever.
+ void clear();
+
+ // Updates the default matrices to the current viewport dimensions.
+ void changeMatrix();
+
+ void render(const Style& style,
+ const std::set<util::ptr<StyleSource>>& sources,
+ TransformState state,
+ timestamp time);
+
+ void renderLayers(util::ptr<StyleLayerGroup> group);
+ void renderLayer(util::ptr<StyleLayer> layer_desc, const Tile::ID* id = nullptr, const mat4* matrix = nullptr);
+
+ // Renders a particular layer from a tile.
+ void renderTileLayer(const Tile& tile, util::ptr<StyleLayer> layer_desc, const mat4 &matrix);
+
+ // Renders debug information for a tile.
+ void renderTileDebug(const Tile& tile);
+
+ // Renders the red debug frame around a tile, visualizing its perimeter.
+ void renderDebugFrame(const mat4 &matrix);
+
+ void renderDebugText(DebugBucket& bucket, const mat4 &matrix);
+ void renderDebugText(const std::vector<std::string> &strings);
+ void renderFill(FillBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ void renderLine(LineBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ void renderSymbol(SymbolBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ void renderRaster(RasterBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ void renderBackground(util::ptr<StyleLayer> layer_desc);
+
+ float saturationFactor(float saturation);
+ float contrastFactor(float contrast);
+ std::array<float, 3> spinWeights(float spin_value);
+
+ void preparePrerender(RasterBucket &bucket);
+
+ void renderPrerenderedTexture(RasterBucket &bucket, const mat4 &matrix, const RasterProperties& properties);
+
+ void createPrerendered(RasterBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id);
+
+ void resize();
+
+ // Changes whether debug information is drawn onto the map
+ void setDebug(bool enabled);
+
+ // Opaque/Translucent pass setting
+ void setOpaque();
+ void setTranslucent();
+
+ // Configures the painter strata that is used for early z-culling of fragments.
+ void setStrata(float strata);
+
+ void drawClippingMasks(const std::set<util::ptr<StyleSource>> &sources);
+ void drawClippingMask(const mat4& matrix, const ClipID& clip);
+
+ void resetFramebuffer();
+ void bindFramebuffer();
+ void pushFramebuffer();
+ GLuint popFramebuffer();
+ void discardFramebuffers();
+
+ bool needsAnimation() const;
+
+private:
+ void setupShaders();
+ void deleteShaders();
+ mat4 translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor);
+
+ void prepareTile(const Tile& tile);
+
+ template <typename BucketProperties, typename StyleProperties>
+ void renderSDF(SymbolBucket &bucket,
+ const Tile::ID &id,
+ const mat4 &matrixSymbol,
+ const BucketProperties& bucketProperties,
+ const StyleProperties& styleProperties,
+ float scaleDivisor,
+ std::array<float, 2> texsize,
+ SDFShader& sdfShader,
+ void (SymbolBucket::*drawSDF)(SDFShader&));
+
+public:
+ void useProgram(uint32_t program);
+ void lineWidth(float lineWidth);
+ void depthMask(bool value);
+ void depthRange(float near, float far);
+
+public:
+ mat4 projMatrix;
+ mat4 nativeMatrix;
+ mat4 extrudeMatrix;
+
+ // used to composite images and flips the geometry upside down
+ const mat4 flipMatrix = []{
+ mat4 flip;
+ matrix::ortho(flip, 0, 4096, -4096, 0, 0, 1);
+ matrix::translate(flip, flip, 0, -4096, 0);
+ return flip;
+ }();
+
+ const mat4 identityMatrix = []{
+ mat4 identity;
+ matrix::identity(identity);
+ return identity;
+ }();
+
+private:
+ TransformState state;
+
+ bool debug = false;
+ int indent = 0;
+
+ uint32_t gl_program = 0;
+ float gl_lineWidth = 0;
+ bool gl_depthMask = true;
+ std::array<uint16_t, 2> gl_viewport = {{ 0, 0 }};
+ std::array<float, 2> gl_depthRange = {{ 0, 1 }};
+ float strata = 0;
+ RenderPass pass = RenderPass::Opaque;
+ const float strata_epsilon = 1.0f / (1 << 16);
+
+public:
+ FrameHistory frameHistory;
+
+ SpriteAtlas& spriteAtlas;
+ GlyphAtlas& glyphAtlas;
+
+ std::unique_ptr<PlainShader> plainShader;
+ std::unique_ptr<OutlineShader> outlineShader;
+ std::unique_ptr<LineShader> lineShader;
+ std::unique_ptr<LinejoinShader> linejoinShader;
+ std::unique_ptr<LinepatternShader> linepatternShader;
+ std::unique_ptr<PatternShader> patternShader;
+ std::unique_ptr<IconShader> iconShader;
+ std::unique_ptr<RasterShader> rasterShader;
+ std::unique_ptr<SDFGlyphShader> sdfGlyphShader;
+ std::unique_ptr<SDFIconShader> sdfIconShader;
+ std::unique_ptr<DotShader> dotShader;
+ std::unique_ptr<GaussianShader> gaussianShader;
+
+ StaticVertexBuffer backgroundBuffer = {
+ { -1, -1 }, { 1, -1 },
+ { -1, 1 }, { 1, 1 }
+ };
+
+ VertexArrayObject backgroundArray;
+
+ // Set up the stencil quad we're using to generate the stencil mask.
+ StaticVertexBuffer tileStencilBuffer = {
+ // top left triangle
+ { 0, 0 },
+ { 4096, 0 },
+ { 0, 4096 },
+
+ // bottom right triangle
+ { 4096, 0 },
+ { 0, 4096 },
+ { 4096, 4096 },
+ };
+
+ VertexArrayObject coveringPlainArray;
+ VertexArrayObject coveringRasterArray;
+ VertexArrayObject coveringGaussianArray;
+
+ // Set up the tile boundary lines we're using to draw the tile outlines.
+ StaticVertexBuffer tileBorderBuffer = {
+ { 0, 0 },
+ { 4096, 0 },
+ { 4096, 4096 },
+ { 0, 4096 },
+ { 0, 0 },
+ };
+
+ VertexArrayObject tileBorderArray;
+
+ // Framebuffer management
+ std::vector<GLuint> fbos;
+ std::vector<GLuint> fbos_color;
+ GLuint fbo_depth_stencil;
+ int fbo_level = -1;
+ bool fbo_depth_stencil_valid = false;
+
+};
+
+}
+
+#endif
diff --git a/src/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp
index dc625ded4e..dc625ded4e 100644
--- a/src/renderer/painter_clipping.cpp
+++ b/src/mbgl/renderer/painter_clipping.cpp
diff --git a/src/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
index 5bc36a233c..c4d273aa47 100644
--- a/src/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painter_debug.cpp
@@ -6,7 +6,7 @@
using namespace mbgl;
void Painter::renderTileDebug(const Tile& tile) {
- gl::group group(util::sprintf<32>("debug %d/%d/%d", tile.id.z, tile.id.y, tile.id.z));
+ gl::group group(std::string { "debug " } + std::string(tile.id));
assert(tile.data);
if (debug) {
prepareTile(tile);
diff --git a/src/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index f2759ffd61..f2759ffd61 100644
--- a/src/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
diff --git a/src/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
index 4bf50569ac..4bf50569ac 100644
--- a/src/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
diff --git a/src/renderer/painter_prerender.cpp b/src/mbgl/renderer/painter_prerender.cpp
index 22a2be9b64..22a2be9b64 100644
--- a/src/renderer/painter_prerender.cpp
+++ b/src/mbgl/renderer/painter_prerender.cpp
diff --git a/src/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index df655cdae8..df655cdae8 100644
--- a/src/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
diff --git a/src/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index 79625f1681..79625f1681 100644
--- a/src/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
diff --git a/src/renderer/prerendered_texture.cpp b/src/mbgl/renderer/prerendered_texture.cpp
index f17fe3b82a..f17fe3b82a 100644
--- a/src/renderer/prerendered_texture.cpp
+++ b/src/mbgl/renderer/prerendered_texture.cpp
diff --git a/src/mbgl/renderer/prerendered_texture.hpp b/src/mbgl/renderer/prerendered_texture.hpp
new file mode 100644
index 0000000000..3ccd24038d
--- /dev/null
+++ b/src/mbgl/renderer/prerendered_texture.hpp
@@ -0,0 +1,38 @@
+#ifndef MBGL_RENDERER_PRERENDERED_TEXTURE
+#define MBGL_RENDERER_PRERENDERED_TEXTURE
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/platform/gl.hpp>
+
+namespace mbgl {
+
+class StyleBucketRaster;
+class Painter;
+
+class PrerenderedTexture : private util::noncopyable {
+public:
+ PrerenderedTexture(const StyleBucketRaster &properties);
+ ~PrerenderedTexture();
+
+ void bindTexture();
+ void bindFramebuffer();
+ void unbindFramebuffer();
+
+ inline GLuint getTexture() const { return texture; }
+
+ void blur(Painter& painter, uint16_t passes);
+
+public:
+ const StyleBucketRaster &properties;
+
+private:
+ GLint previousFbo = 0;
+ GLuint fbo = 0;
+ GLuint texture = 0;
+ GLuint fboDepth= 0;
+ GLuint fboStencil = 0;
+};
+
+}
+
+#endif
diff --git a/src/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp
index 85bb66970e..85bb66970e 100644
--- a/src/renderer/raster_bucket.cpp
+++ b/src/mbgl/renderer/raster_bucket.cpp
diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp
new file mode 100644
index 0000000000..0a7651d7cc
--- /dev/null
+++ b/src/mbgl/renderer/raster_bucket.hpp
@@ -0,0 +1,38 @@
+#ifndef MBGL_RENDERER_RASTERBUCKET
+#define MBGL_RENDERER_RASTERBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/util/raster.hpp>
+#include <mbgl/renderer/prerendered_texture.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+
+
+namespace mbgl {
+
+class RasterShader;
+class StaticVertexBuffer;
+class VertexArrayObject;
+
+class RasterBucket : public Bucket {
+public:
+ RasterBucket(TexturePool&, const StyleBucketRaster&);
+
+ virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
+ virtual bool hasData() const;
+
+ bool setImage(const std::string &data);
+
+ const StyleBucketRaster &properties;
+ PrerenderedTexture texture;
+
+ void drawRaster(RasterShader& shader, StaticVertexBuffer &vertices, VertexArrayObject &array);
+
+ void drawRaster(RasterShader& shader, StaticVertexBuffer &vertices, VertexArrayObject &array, GLuint texture);
+
+ Raster raster;
+};
+
+}
+
+#endif
diff --git a/src/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index a005449628..a005449628 100644
--- a/src/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
new file mode 100644
index 0000000000..dd596b1a00
--- /dev/null
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -0,0 +1,114 @@
+#ifndef MBGL_RENDERER_SYMBOLBUCKET
+#define MBGL_RENDERER_SYMBOLBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/text_buffer.hpp>
+#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/text/types.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <memory>
+#include <map>
+#include <vector>
+
+namespace mbgl {
+
+class Style;
+class SDFShader;
+class IconShader;
+class DotShader;
+class Collision;
+class SpriteAtlas;
+class Sprite;
+class GlyphAtlas;
+class GlyphStore;
+class FontStack;
+
+class SymbolFeature {
+public:
+ pbf geometry;
+ std::u32string label;
+ std::string sprite;
+};
+
+
+class Symbol {
+public:
+ vec2<float> tl, tr, bl, br;
+ Rect<uint16_t> tex;
+ float angle;
+ float minScale = 0.0f;
+ float maxScale = std::numeric_limits<float>::infinity();
+ CollisionAnchor anchor;
+};
+
+typedef std::vector<Symbol> Symbols;
+
+
+class SymbolBucket : public Bucket {
+ typedef ElementGroup<1> TextElementGroup;
+ typedef ElementGroup<2> IconElementGroup;
+
+public:
+ SymbolBucket(const StyleBucketSymbol &properties, Collision &collision);
+
+ virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix);
+ virtual bool hasData() const;
+ virtual bool hasTextData() const;
+ virtual bool hasIconData() const;
+
+ void addFeatures(const VectorTileLayer &layer, const FilterExpression &filter,
+ const Tile::ID &id, SpriteAtlas &spriteAtlas, Sprite &sprite,
+ GlyphAtlas &glyphAtlas, GlyphStore &glyphStore);
+
+ void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, PlacementRange placementRange,
+ float zoom);
+
+ void drawGlyphs(SDFShader& shader);
+ void drawIcons(SDFShader& shader);
+ void drawIcons(IconShader& shader);
+
+private:
+
+ std::vector<SymbolFeature> processFeatures(const VectorTileLayer &layer, const FilterExpression &filter, GlyphStore &glyphStore, const Sprite &sprite);
+
+
+ void addFeature(const pbf &geom_pbf, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image);
+ void addFeature(const std::vector<Coordinate> &line, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image);
+
+
+ // Adds placed items to the buffer.
+ template <typename Buffer>
+ void addSymbols(Buffer &buffer, const PlacedGlyphs &symbols, float scale, PlacementRange placementRange);
+
+ // Adds glyphs to the glyph atlas so that they have a left/top/width/height coordinates associated to them that we can use for writing to a buffer.
+ static void addGlyphsToAtlas(uint64_t tileid, const std::string stackname, const std::u32string &string,
+ const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face);
+
+public:
+ const StyleBucketSymbol &properties;
+ bool sdfIcons = false;
+
+private:
+ Collision &collision;
+
+ struct {
+ TextVertexBuffer vertices;
+ TriangleElementsBuffer triangles;
+ std::vector<TextElementGroup> groups;
+ } text;
+
+ struct {
+ IconVertexBuffer vertices;
+ TriangleElementsBuffer triangles;
+ std::vector<IconElementGroup> groups;
+ } icon;
+
+};
+}
+
+#endif
diff --git a/src/shader/dot.fragment.glsl b/src/mbgl/shader/dot.fragment.glsl
index 6d998b5611..6d998b5611 100644
--- a/src/shader/dot.fragment.glsl
+++ b/src/mbgl/shader/dot.fragment.glsl
diff --git a/src/shader/dot.vertex.glsl b/src/mbgl/shader/dot.vertex.glsl
index 5310ae745e..5310ae745e 100644
--- a/src/shader/dot.vertex.glsl
+++ b/src/mbgl/shader/dot.vertex.glsl
diff --git a/src/shader/dot_shader.cpp b/src/mbgl/shader/dot_shader.cpp
index a897f410a7..a897f410a7 100644
--- a/src/shader/dot_shader.cpp
+++ b/src/mbgl/shader/dot_shader.cpp
diff --git a/src/mbgl/shader/dot_shader.hpp b/src/mbgl/shader/dot_shader.hpp
new file mode 100644
index 0000000000..2c4176f364
--- /dev/null
+++ b/src/mbgl/shader/dot_shader.hpp
@@ -0,0 +1,26 @@
+#ifndef MBGL_SHADER_SHADER_DOT
+#define MBGL_SHADER_SHADER_DOT
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class DotShader : public Shader {
+public:
+ DotShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<float, 4>> u_color = {"u_color", *this};
+ Uniform<float> u_size = {"u_size", *this};
+ Uniform<float> u_blur = {"u_blur", *this};
+
+private:
+ int32_t a_pos = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/gaussian.fragment.glsl b/src/mbgl/shader/gaussian.fragment.glsl
index ee8406e9e1..ee8406e9e1 100644
--- a/src/shader/gaussian.fragment.glsl
+++ b/src/mbgl/shader/gaussian.fragment.glsl
diff --git a/src/shader/gaussian.vertex.glsl b/src/mbgl/shader/gaussian.vertex.glsl
index 26a8394204..26a8394204 100644
--- a/src/shader/gaussian.vertex.glsl
+++ b/src/mbgl/shader/gaussian.vertex.glsl
diff --git a/src/shader/gaussian_shader.cpp b/src/mbgl/shader/gaussian_shader.cpp
index 9060f0ee71..9060f0ee71 100644
--- a/src/shader/gaussian_shader.cpp
+++ b/src/mbgl/shader/gaussian_shader.cpp
diff --git a/src/mbgl/shader/gaussian_shader.hpp b/src/mbgl/shader/gaussian_shader.hpp
new file mode 100644
index 0000000000..0f494f5c7e
--- /dev/null
+++ b/src/mbgl/shader/gaussian_shader.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_RENDERER_SHADER_GAUSSIAN
+#define MBGL_RENDERER_SHADER_GAUSSIAN
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class GaussianShader : public Shader {
+public:
+ GaussianShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<float, 2>> u_offset = {"u_offset", *this};
+ Uniform<int32_t> u_image = {"u_image", *this};
+
+private:
+ int32_t a_pos = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/icon.fragment.glsl b/src/mbgl/shader/icon.fragment.glsl
index 45b56793eb..45b56793eb 100644
--- a/src/shader/icon.fragment.glsl
+++ b/src/mbgl/shader/icon.fragment.glsl
diff --git a/src/shader/icon.vertex.glsl b/src/mbgl/shader/icon.vertex.glsl
index 8c69c40410..8c69c40410 100644
--- a/src/shader/icon.vertex.glsl
+++ b/src/mbgl/shader/icon.vertex.glsl
diff --git a/src/shader/icon_shader.cpp b/src/mbgl/shader/icon_shader.cpp
index 5c54177eb6..5c54177eb6 100644
--- a/src/shader/icon_shader.cpp
+++ b/src/mbgl/shader/icon_shader.cpp
diff --git a/src/mbgl/shader/icon_shader.hpp b/src/mbgl/shader/icon_shader.hpp
new file mode 100644
index 0000000000..645d7e21b6
--- /dev/null
+++ b/src/mbgl/shader/icon_shader.hpp
@@ -0,0 +1,41 @@
+#ifndef MBGL_SHADER_SHADER_ICON
+#define MBGL_SHADER_SHADER_ICON
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class IconShader : public Shader {
+public:
+ IconShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this};
+ Uniform<float> u_angle = {"u_angle", *this};
+ Uniform<float> u_zoom = {"u_zoom", *this};
+ Uniform<float> u_flip = {"u_flip", *this};
+ Uniform<float> u_fadedist = {"u_fadedist", *this};
+ Uniform<float> u_minfadezoom = {"u_minfadezoom", *this};
+ Uniform<float> u_maxfadezoom = {"u_maxfadezoom", *this};
+ Uniform<float> u_fadezoom = {"u_fadezoom", *this};
+ Uniform<float> u_opacity = {"u_opacity", *this};
+ Uniform<std::array<float, 2>> u_texsize = {"u_texsize", *this};
+
+private:
+ int32_t a_pos = -1;
+ int32_t a_offset = -1;
+ int32_t a_tex = -1;
+ int32_t a_angle = -1;
+ int32_t a_minzoom = -1;
+ int32_t a_maxzoom = -1;
+ int32_t a_rangeend = -1;
+ int32_t a_rangestart = -1;
+ int32_t a_labelminzoom = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/line.fragment.glsl b/src/mbgl/shader/line.fragment.glsl
index f4ac1458b3..f4ac1458b3 100644
--- a/src/shader/line.fragment.glsl
+++ b/src/mbgl/shader/line.fragment.glsl
diff --git a/src/shader/line.vertex.glsl b/src/mbgl/shader/line.vertex.glsl
index 1d8e687c95..1d8e687c95 100644
--- a/src/shader/line.vertex.glsl
+++ b/src/mbgl/shader/line.vertex.glsl
diff --git a/src/shader/line_shader.cpp b/src/mbgl/shader/line_shader.cpp
index 8353f4c6ca..8353f4c6ca 100644
--- a/src/shader/line_shader.cpp
+++ b/src/mbgl/shader/line_shader.cpp
diff --git a/src/mbgl/shader/line_shader.hpp b/src/mbgl/shader/line_shader.hpp
new file mode 100644
index 0000000000..b789330882
--- /dev/null
+++ b/src/mbgl/shader/line_shader.hpp
@@ -0,0 +1,32 @@
+#ifndef MBGL_SHADER_SHADER_LINE
+#define MBGL_SHADER_SHADER_LINE
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class LineShader : public Shader {
+public:
+ LineShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this};
+ Uniform<std::array<float, 4>> u_color = {"u_color", *this};
+ Uniform<std::array<float, 2>> u_linewidth = {"u_linewidth", *this};
+ Uniform<std::array<float, 2>> u_dasharray = {"u_dasharray", *this};
+ Uniform<float> u_ratio = {"u_ratio", *this};
+ Uniform<float> u_blur = {"u_blur", *this};
+
+private:
+ int32_t a_pos = -1;
+ int32_t a_extrude = -1;
+ int32_t a_linesofar = -1;
+};
+
+
+}
+
+#endif
diff --git a/src/shader/linejoin.fragment.glsl b/src/mbgl/shader/linejoin.fragment.glsl
index 705a57766e..705a57766e 100644
--- a/src/shader/linejoin.fragment.glsl
+++ b/src/mbgl/shader/linejoin.fragment.glsl
diff --git a/src/shader/linejoin.vertex.glsl b/src/mbgl/shader/linejoin.vertex.glsl
index 2e03561e5b..2e03561e5b 100644
--- a/src/shader/linejoin.vertex.glsl
+++ b/src/mbgl/shader/linejoin.vertex.glsl
diff --git a/src/shader/linejoin_shader.cpp b/src/mbgl/shader/linejoin_shader.cpp
index 050e180e00..050e180e00 100644
--- a/src/shader/linejoin_shader.cpp
+++ b/src/mbgl/shader/linejoin_shader.cpp
diff --git a/src/mbgl/shader/linejoin_shader.hpp b/src/mbgl/shader/linejoin_shader.hpp
new file mode 100644
index 0000000000..61406fd45c
--- /dev/null
+++ b/src/mbgl/shader/linejoin_shader.hpp
@@ -0,0 +1,27 @@
+#ifndef MBGL_SHADER_SHADER_LINEJOIN
+#define MBGL_SHADER_SHADER_LINEJOIN
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class LinejoinShader : public Shader {
+public:
+ LinejoinShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<float, 4>> u_color = {"u_color", *this};
+ Uniform<std::array<float, 2>> u_world = {"u_world", *this};
+ Uniform<std::array<float, 2>> u_linewidth = {"u_linewidth", *this};
+ Uniform<float> u_size = {"u_size", *this};
+
+private:
+ int32_t a_pos = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/linepattern.fragment.glsl b/src/mbgl/shader/linepattern.fragment.glsl
index 52ca823a3b..52ca823a3b 100644
--- a/src/shader/linepattern.fragment.glsl
+++ b/src/mbgl/shader/linepattern.fragment.glsl
diff --git a/src/shader/linepattern.vertex.glsl b/src/mbgl/shader/linepattern.vertex.glsl
index 4600ebf65b..4600ebf65b 100644
--- a/src/shader/linepattern.vertex.glsl
+++ b/src/mbgl/shader/linepattern.vertex.glsl
diff --git a/src/shader/linepattern_shader.cpp b/src/mbgl/shader/linepattern_shader.cpp
index 954dbd2b3f..954dbd2b3f 100644
--- a/src/shader/linepattern_shader.cpp
+++ b/src/mbgl/shader/linepattern_shader.cpp
diff --git a/src/mbgl/shader/linepattern_shader.hpp b/src/mbgl/shader/linepattern_shader.hpp
new file mode 100644
index 0000000000..bf85940b8a
--- /dev/null
+++ b/src/mbgl/shader/linepattern_shader.hpp
@@ -0,0 +1,33 @@
+#ifndef MBGL_SHADER_SHADER_LINEPATTERN
+#define MBGL_SHADER_SHADER_LINEPATTERN
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class LinepatternShader : public Shader {
+public:
+ LinepatternShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this};
+ Uniform<std::array<float, 2>> u_linewidth = {"u_linewidth", *this};
+ Uniform<std::array<float, 2>> u_pattern_size = {"u_pattern_size", *this};
+ Uniform<std::array<float, 2>> u_pattern_tl = {"u_pattern_tl", *this};
+ Uniform<std::array<float, 2>> u_pattern_br = {"u_pattern_br", *this};
+ Uniform<float> u_ratio = {"u_ratio", *this};
+ Uniform<float> u_point = {"u_point", *this};
+ Uniform<float> u_blur = {"u_blur", *this};
+ Uniform<float> u_fade = {"u_fade", *this};
+
+private:
+ int32_t a_pos = -1;
+ int32_t a_extrude = -1;
+ int32_t a_linesofar = -1;
+};
+}
+
+#endif
diff --git a/src/shader/outline.fragment.glsl b/src/mbgl/shader/outline.fragment.glsl
index eccda714e5..eccda714e5 100644
--- a/src/shader/outline.fragment.glsl
+++ b/src/mbgl/shader/outline.fragment.glsl
diff --git a/src/shader/outline.vertex.glsl b/src/mbgl/shader/outline.vertex.glsl
index 29c16e3ded..29c16e3ded 100644
--- a/src/shader/outline.vertex.glsl
+++ b/src/mbgl/shader/outline.vertex.glsl
diff --git a/src/shader/outline_shader.cpp b/src/mbgl/shader/outline_shader.cpp
index ddabfa5d0d..ddabfa5d0d 100644
--- a/src/shader/outline_shader.cpp
+++ b/src/mbgl/shader/outline_shader.cpp
diff --git a/src/mbgl/shader/outline_shader.hpp b/src/mbgl/shader/outline_shader.hpp
new file mode 100644
index 0000000000..f3e8175fd7
--- /dev/null
+++ b/src/mbgl/shader/outline_shader.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_SHADER_SHADER_OUTLINE
+#define MBGL_SHADER_SHADER_OUTLINE
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class OutlineShader : public Shader {
+public:
+ OutlineShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<float, 4>> u_color = {"u_color", *this};
+ Uniform<std::array<float, 2>> u_world = {"u_world", *this};
+
+private:
+ int32_t a_pos = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/pattern.fragment.glsl b/src/mbgl/shader/pattern.fragment.glsl
index ba6aed3023..ba6aed3023 100644
--- a/src/shader/pattern.fragment.glsl
+++ b/src/mbgl/shader/pattern.fragment.glsl
diff --git a/src/shader/pattern.vertex.glsl b/src/mbgl/shader/pattern.vertex.glsl
index f2de884ead..f2de884ead 100644
--- a/src/shader/pattern.vertex.glsl
+++ b/src/mbgl/shader/pattern.vertex.glsl
diff --git a/src/shader/pattern_shader.cpp b/src/mbgl/shader/pattern_shader.cpp
index 31374bc3e8..31374bc3e8 100644
--- a/src/shader/pattern_shader.cpp
+++ b/src/mbgl/shader/pattern_shader.cpp
diff --git a/src/mbgl/shader/pattern_shader.hpp b/src/mbgl/shader/pattern_shader.hpp
new file mode 100644
index 0000000000..9fabd8e18a
--- /dev/null
+++ b/src/mbgl/shader/pattern_shader.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_SHADER_SHADER_PATTERN
+#define MBGL_SHADER_SHADER_PATTERN
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class PatternShader : public Shader {
+public:
+ PatternShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<float, 2>> u_pattern_tl = {"u_pattern_tl", *this};
+ Uniform<std::array<float, 2>> u_pattern_br = {"u_pattern_br", *this};
+ Uniform<float> u_opacity = {"u_opacity", *this};
+ Uniform<float> u_mix = {"u_mix", *this};
+ Uniform<int32_t> u_image = {"u_image", *this};
+ UniformMatrix<3> u_patternmatrix = {"u_patternmatrix", *this};
+
+private:
+ int32_t a_pos = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/plain.fragment.glsl b/src/mbgl/shader/plain.fragment.glsl
index 8df552c171..8df552c171 100644
--- a/src/shader/plain.fragment.glsl
+++ b/src/mbgl/shader/plain.fragment.glsl
diff --git a/src/shader/plain.vertex.glsl b/src/mbgl/shader/plain.vertex.glsl
index 866c3cd2f3..866c3cd2f3 100644
--- a/src/shader/plain.vertex.glsl
+++ b/src/mbgl/shader/plain.vertex.glsl
diff --git a/src/shader/plain_shader.cpp b/src/mbgl/shader/plain_shader.cpp
index 8a37837b30..8a37837b30 100644
--- a/src/shader/plain_shader.cpp
+++ b/src/mbgl/shader/plain_shader.cpp
diff --git a/src/mbgl/shader/plain_shader.hpp b/src/mbgl/shader/plain_shader.hpp
new file mode 100644
index 0000000000..051501c3c9
--- /dev/null
+++ b/src/mbgl/shader/plain_shader.hpp
@@ -0,0 +1,24 @@
+#ifndef MBGL_SHADER_SHADER_PLAIN
+#define MBGL_SHADER_SHADER_PLAIN
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class PlainShader : public Shader {
+public:
+ PlainShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<float, 4>> u_color = {"u_color", *this};
+
+private:
+ int32_t a_pos = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/raster.fragment.glsl b/src/mbgl/shader/raster.fragment.glsl
index 333de76dc1..333de76dc1 100644
--- a/src/shader/raster.fragment.glsl
+++ b/src/mbgl/shader/raster.fragment.glsl
diff --git a/src/shader/raster.vertex.glsl b/src/mbgl/shader/raster.vertex.glsl
index 97e563f585..97e563f585 100644
--- a/src/shader/raster.vertex.glsl
+++ b/src/mbgl/shader/raster.vertex.glsl
diff --git a/src/shader/raster_shader.cpp b/src/mbgl/shader/raster_shader.cpp
index 7351f7d0c4..7351f7d0c4 100644
--- a/src/shader/raster_shader.cpp
+++ b/src/mbgl/shader/raster_shader.cpp
diff --git a/src/mbgl/shader/raster_shader.hpp b/src/mbgl/shader/raster_shader.hpp
new file mode 100644
index 0000000000..8cf97055a2
--- /dev/null
+++ b/src/mbgl/shader/raster_shader.hpp
@@ -0,0 +1,31 @@
+#ifndef MBGL_RENDERER_SHADER_RASTER
+#define MBGL_RENDERER_SHADER_RASTER
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class RasterShader : public Shader {
+public:
+ RasterShader();
+
+ void bind(char *offset);
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<int32_t> u_image = {"u_image", *this};
+ Uniform<float> u_opacity = {"u_opacity", *this};
+ Uniform<float> u_buffer = {"u_buffer", *this};
+ Uniform<float> u_brightness_low = {"u_brightness_low", *this};
+ Uniform<float> u_brightness_high = {"u_brightness_high", *this};
+ Uniform<float> u_saturation_factor = {"u_saturation_factor", *this};
+ Uniform<float> u_contrast_factor = {"u_contrast_factor", *this};
+ Uniform<std::array<float, 3>> u_spin_weights = {"u_spin_weights", *this};
+
+private:
+ int32_t a_pos = -1;
+};
+
+}
+
+#endif
diff --git a/src/shader/sdf.fragment.glsl b/src/mbgl/shader/sdf.fragment.glsl
index d72d61dab1..d72d61dab1 100644
--- a/src/shader/sdf.fragment.glsl
+++ b/src/mbgl/shader/sdf.fragment.glsl
diff --git a/src/shader/sdf.vertex.glsl b/src/mbgl/shader/sdf.vertex.glsl
index c5166ae46f..c5166ae46f 100644
--- a/src/shader/sdf.vertex.glsl
+++ b/src/mbgl/shader/sdf.vertex.glsl
diff --git a/src/shader/sdf_shader.cpp b/src/mbgl/shader/sdf_shader.cpp
index b86733c0e4..b86733c0e4 100644
--- a/src/shader/sdf_shader.cpp
+++ b/src/mbgl/shader/sdf_shader.cpp
diff --git a/src/mbgl/shader/sdf_shader.hpp b/src/mbgl/shader/sdf_shader.hpp
new file mode 100644
index 0000000000..0737c25ee1
--- /dev/null
+++ b/src/mbgl/shader/sdf_shader.hpp
@@ -0,0 +1,53 @@
+#ifndef MBGL_SHADER_SDF_SHADER
+#define MBGL_SHADER_SDF_SHADER
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/shader/uniform.hpp>
+
+namespace mbgl {
+
+class SDFShader : public Shader {
+public:
+ SDFShader();
+
+ virtual void bind(char *offset) = 0;
+
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this};
+ Uniform<std::array<float, 4>> u_color = {"u_color", *this};
+ Uniform<std::array<float, 2>> u_texsize = {"u_texsize", *this};
+ Uniform<float> u_buffer = {"u_buffer", *this};
+ Uniform<float> u_gamma = {"u_gamma", *this};
+ Uniform<float> u_angle = {"u_angle", *this};
+ Uniform<float> u_zoom = {"u_zoom", *this};
+ Uniform<float> u_flip = {"u_flip", *this};
+ Uniform<float> u_fadedist = {"u_fadedist", *this};
+ Uniform<float> u_minfadezoom = {"u_minfadezoom", *this};
+ Uniform<float> u_maxfadezoom = {"u_maxfadezoom", *this};
+ Uniform<float> u_fadezoom = {"u_fadezoom", *this};
+
+protected:
+ int32_t a_pos = -1;
+ int32_t a_offset = -1;
+ int32_t a_tex = -1;
+ int32_t a_angle = -1;
+ int32_t a_minzoom = -1;
+ int32_t a_maxzoom = -1;
+ int32_t a_rangeend = -1;
+ int32_t a_rangestart = -1;
+ int32_t a_labelminzoom = -1;
+};
+
+class SDFGlyphShader : public SDFShader {
+public:
+ void bind(char *offset);
+};
+
+class SDFIconShader : public SDFShader {
+public:
+ void bind(char *offset);
+};
+
+}
+
+#endif
diff --git a/src/shader/shader.cpp b/src/mbgl/shader/shader.cpp
index f083beaa48..f083beaa48 100644
--- a/src/shader/shader.cpp
+++ b/src/mbgl/shader/shader.cpp
diff --git a/src/mbgl/shader/shader.hpp b/src/mbgl/shader/shader.hpp
new file mode 100644
index 0000000000..27e831a510
--- /dev/null
+++ b/src/mbgl/shader/shader.hpp
@@ -0,0 +1,28 @@
+#ifndef MBGL_RENDERER_SHADER
+#define MBGL_RENDERER_SHADER
+
+#include <cstdint>
+#include <array>
+#include <mbgl/util/noncopyable.hpp>
+
+namespace mbgl {
+
+class Shader : private util::noncopyable {
+public:
+ Shader(const char *name, const char *vertex, const char *fragment);
+ ~Shader();
+ const char *name;
+ bool valid;
+ uint32_t program;
+
+ inline uint32_t getID() const {
+ return program;
+ }
+
+private:
+ bool compileShader(uint32_t *shader, uint32_t type, const char *source);
+};
+
+}
+
+#endif
diff --git a/src/shader/uniform.cpp b/src/mbgl/shader/uniform.cpp
index 24f179baf1..24f179baf1 100644
--- a/src/shader/uniform.cpp
+++ b/src/mbgl/shader/uniform.cpp
diff --git a/src/mbgl/shader/uniform.hpp b/src/mbgl/shader/uniform.hpp
new file mode 100644
index 0000000000..8579ae22c7
--- /dev/null
+++ b/src/mbgl/shader/uniform.hpp
@@ -0,0 +1,53 @@
+#ifndef MBGL_SHADER_UNIFORM
+#define MBGL_SHADER_UNIFORM
+
+#include <mbgl/shader/shader.hpp>
+#include <mbgl/platform/gl.hpp>
+
+namespace mbgl {
+
+template <typename T>
+class Uniform {
+public:
+ Uniform(const GLchar* name, const Shader& shader)
+ : location(glGetUniformLocation(shader.program, name)) {}
+
+ void operator=(const T& t) {
+ if (current != t) {
+ current = t;
+ bind(t);
+ }
+ }
+
+private:
+ void bind(const T&);
+
+ T current;
+ GLint location;
+};
+
+template <size_t C, size_t R = C>
+class UniformMatrix {
+public:
+ typedef std::array<float, C*R> T;
+
+ UniformMatrix(const GLchar* name, const Shader& shader)
+ : location(glGetUniformLocation(shader.program, name)) {}
+
+ void operator=(const T& t) {
+ if (current != t) {
+ current = t;
+ bind(t);
+ }
+ }
+
+private:
+ void bind(const T&);
+
+ T current;
+ GLint location;
+};
+
+}
+
+#endif
diff --git a/src/storage/base_request.cpp b/src/mbgl/storage/base_request.cpp
index 510bd7bf1c..510bd7bf1c 100644
--- a/src/storage/base_request.cpp
+++ b/src/mbgl/storage/base_request.cpp
diff --git a/src/mbgl/storage/base_request.hpp b/src/mbgl/storage/base_request.hpp
new file mode 100644
index 0000000000..5119c343e9
--- /dev/null
+++ b/src/mbgl/storage/base_request.hpp
@@ -0,0 +1,62 @@
+#ifndef MBGL_STORAGE_BASE_REQUEST
+#define MBGL_STORAGE_BASE_REQUEST
+
+#include <mbgl/storage/request_callback.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <string>
+#include <forward_list>
+#include <functional>
+#include <thread>
+
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_async_s uv_async_t;
+
+namespace mbgl {
+
+class Response;
+class Request;
+
+class BaseRequest {
+private:
+ // Make noncopyable and immovable
+ BaseRequest(const BaseRequest &) = delete;
+ BaseRequest(BaseRequest &&) = delete;
+ BaseRequest& operator=(const BaseRequest &) = delete;
+ BaseRequest& operator=(BaseRequest &&) = delete;
+
+public:
+ BaseRequest(const std::string &path);
+ virtual ~BaseRequest();
+
+ Callback *add(Callback &&callback, const util::ptr<BaseRequest> &request);
+ void remove(Callback *callback);
+
+ // Must be called by subclasses when a valid Response object is available. It will notify
+ // all listeners.
+ void notify();
+
+ // This function is called when the request ought to be stopped. Any subclass must make sure this
+ // is also called in its destructor. Calling this function repeatedly must be safe.
+ // This function must call notify().
+ virtual void cancel() = 0;
+
+ // This function is called when the request should be reattempted immediately. This is typically
+ // reaction to a network status change.
+ virtual void retryImmediately();
+
+public:
+ const std::thread::id threadId;
+ const std::string path;
+ std::unique_ptr<Response> response;
+
+protected:
+ // This object may hold a shared_ptr to itself. It does this to prevent destruction of this object
+ // while a request is in progress.
+ util::ptr<BaseRequest> self;
+ std::forward_list<std::unique_ptr<Callback>> callbacks;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/storage/caching_http_file_source.cpp b/src/mbgl/storage/caching_http_file_source.cpp
new file mode 100644
index 0000000000..cf09c58113
--- /dev/null
+++ b/src/mbgl/storage/caching_http_file_source.cpp
@@ -0,0 +1,130 @@
+#include <mbgl/storage/caching_http_file_source.hpp>
+#include <mbgl/storage/file_request.hpp>
+#include <mbgl/storage/http_request.hpp>
+#include <mbgl/storage/sqlite_store.hpp>
+#include <mbgl/storage/asset_request.hpp>
+#include <mbgl/util/uv-messenger.h>
+#include <mbgl/util/mapbox.hpp>
+#include <mbgl/util/std.hpp>
+
+#include <uv.h>
+
+namespace mbgl {
+
+CachingHTTPFileSource::CachingHTTPFileSource(const std::string &path_)
+ : path(path_) {}
+
+CachingHTTPFileSource::~CachingHTTPFileSource() {
+}
+
+void CachingHTTPFileSource::setLoop(uv_loop_t* loop_) {
+ threadId = std::this_thread::get_id();
+ store = !path.empty() ? util::ptr<SQLiteStore>(new SQLiteStore(loop_, path)) : nullptr;
+ loop = loop_;
+ queue = new uv_messenger_t;
+
+ uv_messenger_init(loop, queue, [](void *ptr) {
+ std::unique_ptr<std::function<void()>> fn { reinterpret_cast<std::function<void()> *>(ptr) };
+ (*fn)();
+ });
+ uv_unref((uv_handle_t *)&queue->async);
+}
+
+bool CachingHTTPFileSource::hasLoop() {
+ return loop;
+}
+
+void CachingHTTPFileSource::clearLoop() {
+ assert(std::this_thread::get_id() == threadId);
+ assert(loop);
+
+ uv_messenger_stop(queue, [](uv_messenger_t *msgr) {
+ delete msgr;
+ });
+
+ util::ptr<BaseRequest> req;
+
+ // Send a cancel() message to all requests that we are still holding.
+ for (const std::pair<std::string, std::weak_ptr<BaseRequest>> &pair : pending) {
+ if ((req = pair.second.lock())) {
+ req->cancel();
+ }
+ }
+
+ store.reset();
+}
+
+void CachingHTTPFileSource::setBase(std::string value) {
+ // TODO: Make threadsafe.
+ base.swap(value);
+}
+
+void CachingHTTPFileSource::setAccessToken(std::string value) {
+ // TODO: Make threadsafe.
+ accessToken.swap(value);
+}
+
+std::unique_ptr<Request> CachingHTTPFileSource::request(ResourceType type, const std::string& url_) {
+ assert(tstd::this_thread::get_id() == threadId);
+
+ std::string url = url_;
+
+ // Make URL absolute.
+ const size_t separator = url.find("://");
+ if (separator == std::string::npos) {
+ url = base + url;
+ }
+
+ // Normalize mapbox:// URLs.
+ switch (type) {
+ case ResourceType::Glyphs:
+ url = util::mapbox::normalizeGlyphsURL(url, accessToken);
+ default:
+ url = util::mapbox::normalizeSourceURL(url, accessToken);
+ }
+
+ util::ptr<BaseRequest> req;
+
+ // First, try to find an existing Request object.
+ auto it = pending.find(url);
+ if (it != pending.end()) {
+ req = it->second.lock();
+ }
+
+ if (!req) {
+ if (url.substr(0, 7) == "file://") {
+ req = std::make_shared<FileRequest>(url.substr(7), loop);
+ } else if (url.substr(0, 8) == "asset://") {
+ req = std::make_shared<AssetRequest>(url.substr(8), loop);
+ } else {
+ req = std::make_shared<HTTPRequest>(type, url, loop, store);
+ }
+
+ pending.emplace(url, req);
+ }
+
+ return util::make_unique<Request>(req);
+}
+
+void CachingHTTPFileSource::prepare(std::function<void()> fn) {
+ if (std::this_thread::get_id() == threadId) {
+ fn();
+ } else {
+ uv_messenger_send(queue, new std::function<void()>(std::move(fn)));
+ }
+}
+
+void CachingHTTPFileSource::setReachability(bool reachable) {
+ if (reachable && loop) {
+ prepare([this]() {
+ util::ptr<BaseRequest> req;
+ for (const std::pair<std::string, std::weak_ptr<BaseRequest>> &pair : pending) {
+ if ((req = pair.second.lock())) {
+ req->retryImmediately();
+ }
+ }
+ });
+ }
+}
+
+}
diff --git a/src/storage/file_request.cpp b/src/mbgl/storage/file_request.cpp
index 6cb882101d..6cb882101d 100644
--- a/src/storage/file_request.cpp
+++ b/src/mbgl/storage/file_request.cpp
diff --git a/src/mbgl/storage/file_request.hpp b/src/mbgl/storage/file_request.hpp
new file mode 100644
index 0000000000..3de2d5b60d
--- /dev/null
+++ b/src/mbgl/storage/file_request.hpp
@@ -0,0 +1,27 @@
+#ifndef MBGL_STORAGE_FILE_REQUEST
+#define MBGL_STORAGE_FILE_REQUEST
+
+#include <mbgl/storage/base_request.hpp>
+
+namespace mbgl {
+
+typedef struct uv_loop_s uv_loop_t;
+
+struct FileRequestBaton;
+
+class FileRequest : public BaseRequest {
+public:
+ FileRequest(const std::string &path, uv_loop_t *loop);
+ ~FileRequest();
+
+ void cancel();
+
+private:
+ FileRequestBaton *ptr = nullptr;
+
+ friend struct FileRequestBaton;
+};
+
+}
+
+#endif
diff --git a/src/storage/file_request_baton.cpp b/src/mbgl/storage/file_request_baton.cpp
index c661cd347a..c661cd347a 100644
--- a/src/storage/file_request_baton.cpp
+++ b/src/mbgl/storage/file_request_baton.cpp
diff --git a/src/mbgl/storage/file_request_baton.hpp b/src/mbgl/storage/file_request_baton.hpp
new file mode 100644
index 0000000000..0c3fa16da3
--- /dev/null
+++ b/src/mbgl/storage/file_request_baton.hpp
@@ -0,0 +1,36 @@
+#ifndef MBGL_STORAGE_FILE_REQUEST_BATON
+#define MBGL_STORAGE_FILE_REQUEST_BATON
+
+#include <mbgl/storage/file_request.hpp>
+#include <thread>
+
+#include <uv.h>
+
+namespace mbgl {
+
+struct FileRequestBaton {
+ FileRequestBaton(FileRequest *request_, const std::string &path, uv_loop_t *loop);
+ ~FileRequestBaton();
+
+ void cancel();
+ static void file_opened(uv_fs_t *req);
+ static void file_stated(uv_fs_t *req);
+ static void file_read(uv_fs_t *req);
+ static void file_closed(uv_fs_t *req);
+ static void notify_error(uv_fs_t *req);
+ static void cleanup(uv_fs_t *req);
+
+ const std::thread::id threadId;
+ FileRequest *request = nullptr;
+ uv_fs_t req;
+ uv_file fd = -1;
+ bool canceled = false;
+ std::string body;
+ uv_buf_t buffer;
+};
+
+
+}
+
+
+#endif
diff --git a/src/storage/http_request.cpp b/src/mbgl/storage/http_request.cpp
index 57e6c260ef..57e6c260ef 100644
--- a/src/storage/http_request.cpp
+++ b/src/mbgl/storage/http_request.cpp
diff --git a/src/mbgl/storage/http_request.hpp b/src/mbgl/storage/http_request.hpp
new file mode 100644
index 0000000000..7cc72101d5
--- /dev/null
+++ b/src/mbgl/storage/http_request.hpp
@@ -0,0 +1,58 @@
+#ifndef MBGL_STORAGE_HTTP_REQUEST
+#define MBGL_STORAGE_HTTP_REQUEST
+
+#include <mbgl/storage/resource_type.hpp>
+#include <mbgl/storage/base_request.hpp>
+#include <mbgl/storage/http_request_baton.hpp>
+
+#include <string>
+#include <memory>
+#include <cassert>
+#include <thread>
+
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_timer_s uv_timer_t;
+
+namespace mbgl {
+
+struct CacheRequestBaton;
+struct HTTPRequestBaton;
+struct CacheEntry;
+class SQLiteStore;
+
+class HTTPRequest : public BaseRequest {
+public:
+ HTTPRequest(ResourceType type, const std::string &path, uv_loop_t *loop, util::ptr<SQLiteStore> store);
+ ~HTTPRequest();
+
+ void cancel();
+ void retryImmediately();
+
+private:
+ void startCacheRequest();
+ void handleCacheResponse(std::unique_ptr<Response> &&response);
+ void startHTTPRequest(std::unique_ptr<Response> &&res);
+ void handleHTTPResponse(HTTPResponseType responseType, std::unique_ptr<Response> &&response);
+
+ void retryHTTPRequest(std::unique_ptr<Response> &&res, uint64_t timeout);
+
+ void removeCacheBaton();
+ void removeHTTPBaton();
+ void removeBackoffTimer();
+
+private:
+ const std::thread::id threadId;
+ uv_loop_t *const loop;
+ CacheRequestBaton *cacheBaton = nullptr;
+ util::ptr<HTTPRequestBaton> httpBaton;
+ uv_timer_t *backoffTimer = nullptr;
+ util::ptr<SQLiteStore> store;
+ const ResourceType type;
+ uint8_t attempts = 0;
+
+ friend struct HTTPRequestBaton;
+};
+
+}
+
+#endif
diff --git a/src/storage/http_request_baton.cpp b/src/mbgl/storage/http_request_baton.cpp
index d781a3bdf4..d781a3bdf4 100644
--- a/src/storage/http_request_baton.cpp
+++ b/src/mbgl/storage/http_request_baton.cpp
diff --git a/src/storage/request.cpp b/src/mbgl/storage/request.cpp
index 39fbd36789..39fbd36789 100644
--- a/src/storage/request.cpp
+++ b/src/mbgl/storage/request.cpp
diff --git a/src/storage/response.cpp b/src/mbgl/storage/response.cpp
index a08a6d31ce..a08a6d31ce 100644
--- a/src/storage/response.cpp
+++ b/src/mbgl/storage/response.cpp
diff --git a/src/storage/sqlite_store.cpp b/src/mbgl/storage/sqlite_store.cpp
index d382921dec..d382921dec 100644
--- a/src/storage/sqlite_store.cpp
+++ b/src/mbgl/storage/sqlite_store.cpp
diff --git a/src/mbgl/storage/sqlite_store.hpp b/src/mbgl/storage/sqlite_store.hpp
new file mode 100644
index 0000000000..988eca2597
--- /dev/null
+++ b/src/mbgl/storage/sqlite_store.hpp
@@ -0,0 +1,49 @@
+#ifndef MBGL_STORAGE_SQLITE_STORE
+#define MBGL_STORAGE_SQLITE_STORE
+
+#include <mbgl/storage/response.hpp>
+#include <mbgl/storage/resource_type.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <uv.h>
+
+#include <string>
+#include <thread>
+
+typedef struct uv_worker_s uv_worker_t;
+
+namespace mapbox {
+namespace sqlite {
+class Database;
+}
+}
+
+namespace mbgl {
+
+class SQLiteStore {
+public:
+ SQLiteStore(uv_loop_t *loop, const std::string &path);
+ ~SQLiteStore();
+
+ typedef void (*GetCallback)(std::unique_ptr<Response> &&entry, void *ptr);
+
+ void get(const std::string &path, GetCallback cb, void *ptr);
+ void put(const std::string &path, ResourceType type, const Response &entry);
+ void updateExpiration(const std::string &path, int64_t expires);
+
+private:
+ void createSchema();
+ void closeDatabase();
+ static void runGet(uv_work_t *req);
+ static void runPut(uv_work_t *req);
+ static void deliverResult(uv_work_t *req, int status);
+
+private:
+ const std::thread::id thread_id;
+ util::ptr<mapbox::sqlite::Database> db;
+ uv_worker_t *worker = nullptr;
+};
+
+}
+
+#endif
diff --git a/src/style/applied_class_properties.cpp b/src/mbgl/style/applied_class_properties.cpp
index 9037c6ad5d..9037c6ad5d 100644
--- a/src/style/applied_class_properties.cpp
+++ b/src/mbgl/style/applied_class_properties.cpp
diff --git a/src/mbgl/style/applied_class_properties.hpp b/src/mbgl/style/applied_class_properties.hpp
new file mode 100644
index 0000000000..827f15a2a1
--- /dev/null
+++ b/src/mbgl/style/applied_class_properties.hpp
@@ -0,0 +1,39 @@
+#ifndef MBGL_STYLE_APPLIED_CLASS_PROPERTIES
+#define MBGL_STYLE_APPLIED_CLASS_PROPERTIES
+
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/util/time.hpp>
+
+#include <list>
+
+namespace mbgl {
+
+class AppliedClassProperty {
+public:
+ AppliedClassProperty(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value);
+
+public:
+ const ClassID name;
+ const timestamp begin;
+ const timestamp end;
+ const PropertyValue value;
+};
+
+
+class AppliedClassProperties {
+public:
+ std::list<AppliedClassProperty> properties;
+
+public:
+ // Returns thie ID of the most recent
+ ClassID mostRecent() const;
+ void add(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value);
+ bool hasTransitions() const;
+ void cleanup(timestamp now);
+ bool empty() const;
+};
+
+}
+
+#endif
diff --git a/src/style/class_dictionary.cpp b/src/mbgl/style/class_dictionary.cpp
index ba7c0d55be..ba7c0d55be 100644
--- a/src/style/class_dictionary.cpp
+++ b/src/mbgl/style/class_dictionary.cpp
diff --git a/src/mbgl/style/class_dictionary.hpp b/src/mbgl/style/class_dictionary.hpp
new file mode 100644
index 0000000000..ecf80be3e3
--- /dev/null
+++ b/src/mbgl/style/class_dictionary.hpp
@@ -0,0 +1,37 @@
+#ifndef MBGL_STYLE_CLASS_DICTIONARY
+#define MBGL_STYLE_CLASS_DICTIONARY
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+namespace mbgl {
+
+enum class ClassID : uint32_t {
+ Fallback = 0, // These values are from the fallback properties
+ Default = 1, // These values are from the default style for a layer
+ Named = 2 // These values (and all subsequent IDs) are from a named style from the layer
+};
+
+class ClassDictionary {
+private:
+ ClassDictionary();
+
+public:
+ static ClassDictionary &Get();
+
+ // Returns an ID for a class name. If the class name does not yet have an ID, one is
+ // auto-generated and stored for future reference.
+ ClassID lookup(const std::string &class_name);
+
+ // Returns either Fallback, Default or Named, depending on the type of the class id.
+ ClassID normalize(ClassID id);
+
+private:
+ std::unordered_map<std::string, ClassID> store = { { "", ClassID::Default } };
+ uint32_t offset = 0;
+};
+
+}
+
+#endif
diff --git a/src/style/class_properties.cpp b/src/mbgl/style/class_properties.cpp
index e7bf855bfc..e7bf855bfc 100644
--- a/src/style/class_properties.cpp
+++ b/src/mbgl/style/class_properties.cpp
diff --git a/src/mbgl/style/class_properties.hpp b/src/mbgl/style/class_properties.hpp
new file mode 100644
index 0000000000..888a90c5d7
--- /dev/null
+++ b/src/mbgl/style/class_properties.hpp
@@ -0,0 +1,43 @@
+#ifndef MBGL_STYLE_CLASS_PROPERTIES
+#define MBGL_STYLE_CLASS_PROPERTIES
+
+#include <mbgl/style/property_key.hpp>
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/property_transition.hpp>
+
+#include <map>
+
+namespace mbgl {
+
+class ClassProperties {
+public:
+ inline ClassProperties() {}
+ inline ClassProperties(ClassProperties &&properties_)
+ : properties(std::move(properties_.properties)) {}
+
+ inline void set(PropertyKey key, const PropertyValue &value) {
+ properties.emplace(key, value);
+ }
+
+ inline void set(PropertyKey key, const PropertyTransition &transition) {
+ transitions.emplace(key, transition);
+ }
+
+ const PropertyTransition &getTransition(PropertyKey key, const PropertyTransition &defaultTransition) const;
+
+ // Route-through iterable interface so that you can iterate on the object as is.
+ inline std::map<PropertyKey, PropertyValue>::const_iterator begin() const {
+ return properties.begin();
+ }
+ inline std::map<PropertyKey, PropertyValue>::const_iterator end() const {
+ return properties.end();
+ }
+
+public:
+ std::map<PropertyKey, PropertyValue> properties;
+ std::map<PropertyKey, PropertyTransition> transitions;
+};
+
+}
+
+#endif
diff --git a/src/style/filter_expression.cpp b/src/mbgl/style/filter_expression.cpp
index 7d4f60b3ed..7d4f60b3ed 100644
--- a/src/style/filter_expression.cpp
+++ b/src/mbgl/style/filter_expression.cpp
diff --git a/src/mbgl/style/filter_expression.hpp b/src/mbgl/style/filter_expression.hpp
new file mode 100644
index 0000000000..8c6f447770
--- /dev/null
+++ b/src/mbgl/style/filter_expression.hpp
@@ -0,0 +1,125 @@
+#ifndef MBGL_STYLE_FILTER_EXPRESSION
+#define MBGL_STYLE_FILTER_EXPRESSION
+
+#include <mbgl/style/value.hpp>
+
+#include <rapidjson/document.h>
+
+#include <string>
+#include <vector>
+
+namespace mbgl {
+
+typedef mapbox::util::variant<
+ struct NullExpression,
+ struct EqualsExpression,
+ struct NotEqualsExpression,
+ struct LessThanExpression,
+ struct LessThanEqualsExpression,
+ struct GreaterThanExpression,
+ struct GreaterThanEqualsExpression,
+ struct InExpression,
+ struct NotInExpression,
+ struct AnyExpression,
+ struct AllExpression,
+ struct NoneExpression
+ > FilterExpression;
+
+FilterExpression parseFilterExpression(const rapidjson::Value&);
+
+template <class Extractor>
+bool evaluate(const FilterExpression&, const Extractor&);
+
+struct NullExpression {
+ template <class Extractor>
+ bool evaluate(const Extractor&) const { return true; }
+};
+
+struct EqualsExpression {
+ std::string key;
+ Value value;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct NotEqualsExpression {
+ std::string key;
+ Value value;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct LessThanExpression {
+ std::string key;
+ Value value;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct LessThanEqualsExpression {
+ std::string key;
+ Value value;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct GreaterThanExpression {
+ std::string key;
+ Value value;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct GreaterThanEqualsExpression {
+ std::string key;
+ Value value;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct InExpression {
+ std::string key;
+ std::vector<Value> values;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct NotInExpression {
+ std::string key;
+ std::vector<Value> values;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct AnyExpression {
+ std::vector<FilterExpression> expressions;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct AllExpression {
+ std::vector<FilterExpression> expressions;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+struct NoneExpression {
+ std::vector<FilterExpression> expressions;
+
+ template <class Extractor>
+ bool evaluate(const Extractor&) const;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/style/filter_expression_private.hpp b/src/mbgl/style/filter_expression_private.hpp
new file mode 100644
index 0000000000..381f8f617c
--- /dev/null
+++ b/src/mbgl/style/filter_expression_private.hpp
@@ -0,0 +1,118 @@
+#include <mbgl/util/optional.hpp>
+#include <mbgl/style/value_comparison.hpp>
+
+namespace mbgl {
+
+template <class Extractor>
+struct Evaluator : public mapbox::util::static_visitor<bool>
+{
+ const Extractor& extractor;
+
+ Evaluator(const Extractor& extractor_)
+ : extractor(extractor_) {}
+
+ template <class E>
+ bool operator()(const E& e) const { return e.evaluate(extractor); }
+};
+
+template <class Extractor>
+bool evaluate(const FilterExpression& expression, const Extractor& extractor) {
+ return mapbox::util::apply_visitor(Evaluator<Extractor>(extractor), expression);
+};
+
+template <class Extractor>
+bool EqualsExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ return actual && util::relaxed_equal(*actual, value);
+}
+
+template <class Extractor>
+bool NotEqualsExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ return !actual || util::relaxed_not_equal(*actual, value);
+}
+
+template <class Extractor>
+bool LessThanExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ return actual && util::relaxed_less(*actual, value);
+}
+
+template <class Extractor>
+bool LessThanEqualsExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ return actual && util::relaxed_less_equal(*actual, value);
+}
+
+template <class Extractor>
+bool GreaterThanExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ return actual && util::relaxed_greater(*actual, value);
+}
+
+template <class Extractor>
+bool GreaterThanEqualsExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ return actual && util::relaxed_greater_equal(*actual, value);
+}
+
+template <class Extractor>
+bool InExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ if (!actual)
+ return false;
+ for (const auto& v: values) {
+ if (util::relaxed_equal(*actual, v)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class Extractor>
+bool NotInExpression::evaluate(const Extractor& extractor) const {
+ mapbox::util::optional<Value> actual = extractor.getValue(key);
+ if (!actual)
+ return true;
+ for (const auto& v: values) {
+ if (util::relaxed_equal(*actual, v)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template <class Extractor>
+bool AnyExpression::evaluate(const Extractor& extractor) const {
+ Evaluator<Extractor> evaluator(extractor);
+ for (const auto& e: expressions) {
+ if (mapbox::util::apply_visitor(evaluator, e)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class Extractor>
+bool AllExpression::evaluate(const Extractor& extractor) const {
+ Evaluator<Extractor> evaluator(extractor);
+ for (const auto& e: expressions) {
+ if (!mapbox::util::apply_visitor(evaluator, e)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template <class Extractor>
+bool NoneExpression::evaluate(const Extractor& extractor) const {
+ Evaluator<Extractor> evaluator(extractor);
+ for (const auto& e: expressions) {
+ if (mapbox::util::apply_visitor(evaluator, e)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+}
diff --git a/src/style/function_properties.cpp b/src/mbgl/style/function_properties.cpp
index 69466c1f64..69466c1f64 100644
--- a/src/style/function_properties.cpp
+++ b/src/mbgl/style/function_properties.cpp
diff --git a/src/mbgl/style/function_properties.hpp b/src/mbgl/style/function_properties.hpp
new file mode 100644
index 0000000000..924f192330
--- /dev/null
+++ b/src/mbgl/style/function_properties.hpp
@@ -0,0 +1,55 @@
+#ifndef MBGL_STYLE_FUNCTION_PROPERTIES
+#define MBGL_STYLE_FUNCTION_PROPERTIES
+
+#include <mbgl/util/variant.hpp>
+
+#include <vector>
+
+namespace mbgl {
+
+template <typename T>
+struct ConstantFunction {
+ inline ConstantFunction(const T &value_) : value(value_) {}
+ inline T evaluate(float) const { return value; }
+
+private:
+ const T value;
+};
+
+template <typename T>
+struct StopsFunction {
+ inline StopsFunction(const std::vector<std::pair<float, T>> &values_, float base_) : values(values_), base(base_) {}
+ T evaluate(float z) const;
+
+private:
+ const std::vector<std::pair<float, T>> values;
+ const float base;
+};
+
+template <typename T>
+using Function = mapbox::util::variant<
+ std::false_type,
+ ConstantFunction<T>,
+ StopsFunction<T>
+>;
+
+template <typename T>
+struct FunctionEvaluator {
+ typedef T result_type;
+ inline FunctionEvaluator(float z_) : z(z_) {}
+
+ inline result_type operator()(const std::false_type &) {
+ return result_type();
+ }
+
+ template <template <typename> class Fn>
+ inline result_type operator()(const Fn<T>& fn) {
+ return fn.evaluate(z);
+ }
+private:
+ float z;
+};
+
+}
+
+#endif
diff --git a/src/style/property_fallback.cpp b/src/mbgl/style/property_fallback.cpp
index 965baf6c4b..965baf6c4b 100644
--- a/src/style/property_fallback.cpp
+++ b/src/mbgl/style/property_fallback.cpp
diff --git a/src/mbgl/style/property_fallback.hpp b/src/mbgl/style/property_fallback.hpp
new file mode 100644
index 0000000000..5c5eae0cd6
--- /dev/null
+++ b/src/mbgl/style/property_fallback.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_STYLE_PROPERTY_FALLBACK
+#define MBGL_STYLE_PROPERTY_FALLBACK
+
+#include <mbgl/style/property_key.hpp>
+#include <mbgl/style/property_value.hpp>
+
+#include <map>
+
+namespace mbgl {
+
+class PropertyFallbackValue {
+public:
+ static const PropertyValue &Get(PropertyKey key) {
+ auto it = properties.find(key);
+ if (it != properties.end()) {
+ return it->second;
+ } else {
+ return defaultProperty;
+ }
+ }
+
+private:
+ static const std::map<PropertyKey, PropertyValue> properties;
+ static const PropertyValue defaultProperty;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/style/property_key.hpp b/src/mbgl/style/property_key.hpp
new file mode 100644
index 0000000000..efeebf0242
--- /dev/null
+++ b/src/mbgl/style/property_key.hpp
@@ -0,0 +1,70 @@
+#ifndef MBGL_STYLE_PROPERTY_KEY
+#define MBGL_STYLE_PROPERTY_KEY
+
+namespace mbgl {
+
+enum class PropertyKey {
+ FillAntialias,
+ FillOpacity,
+ FillColor,
+ FillOutlineColor,
+ FillTranslate, // for transitions only
+ FillTranslateX,
+ FillTranslateY,
+ FillTranslateAnchor,
+ FillImage,
+
+ LineOpacity,
+ LineColor,
+ LineTranslate, // for transitions only
+ LineTranslateX,
+ LineTranslateY,
+ LineTranslateAnchor,
+ LineWidth,
+ LineGapWidth,
+ LineBlur,
+ LineDashArray, // for transitions only
+ LineDashLand,
+ LineDashGap,
+ LineImage,
+
+ IconOpacity,
+ IconRotate,
+ IconSize,
+ IconColor,
+ IconHaloColor,
+ IconHaloWidth,
+ IconHaloBlur,
+ IconTranslate, // for transitions only
+ IconTranslateX,
+ IconTranslateY,
+ IconTranslateAnchor,
+
+ TextOpacity,
+ TextSize,
+ TextColor,
+ TextHaloColor,
+ TextHaloWidth,
+ TextHaloBlur,
+ TextTranslate, // for transitions only
+ TextTranslateX,
+ TextTranslateY,
+ TextTranslateAnchor,
+
+ RasterOpacity,
+ RasterHueRotate,
+ RasterBrightness, // for transitions only
+ RasterBrightnessLow,
+ RasterBrightnessHigh,
+ RasterSaturation,
+ RasterContrast,
+ RasterFade,
+
+ BackgroundOpacity,
+ BackgroundColor,
+ BackgroundImage
+};
+
+}
+
+#endif
diff --git a/src/mbgl/style/property_transition.hpp b/src/mbgl/style/property_transition.hpp
new file mode 100644
index 0000000000..07b7cfe288
--- /dev/null
+++ b/src/mbgl/style/property_transition.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_STYLE_PROPERTY_TRANSITION
+#define MBGL_STYLE_PROPERTY_TRANSITION
+
+#include <cstdint>
+
+namespace mbgl {
+
+struct PropertyTransition {
+ uint16_t duration = 0;
+ uint16_t delay = 0;
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/src/mbgl/style/property_value.hpp b/src/mbgl/style/property_value.hpp
new file mode 100644
index 0000000000..1b22b31177
--- /dev/null
+++ b/src/mbgl/style/property_value.hpp
@@ -0,0 +1,21 @@
+#ifndef MBGL_STYLE_PROPERTY_VALUE
+#define MBGL_STYLE_PROPERTY_VALUE
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/function_properties.hpp>
+#include <mbgl/style/types.hpp>
+
+namespace mbgl {
+
+typedef mapbox::util::variant<
+ std::string,
+ TranslateAnchorType,
+ RotateAnchorType,
+ Function<bool>,
+ Function<float>,
+ Function<Color>
+> PropertyValue;
+
+}
+
+#endif
diff --git a/src/style/style.cpp b/src/mbgl/style/style.cpp
index 9669e0e4a7..9669e0e4a7 100644
--- a/src/style/style.cpp
+++ b/src/mbgl/style/style.cpp
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
new file mode 100644
index 0000000000..56f318ecbb
--- /dev/null
+++ b/src/mbgl/style/style.hpp
@@ -0,0 +1,68 @@
+#ifndef MBGL_STYLE_STYLE
+#define MBGL_STYLE_STYLE
+
+#include <mbgl/style/property_transition.hpp>
+#include <mbgl/style/style_source.hpp>
+
+#include <mbgl/util/time.hpp>
+#include <mbgl/util/uv.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include <set>
+
+namespace mbgl {
+
+class Sprite;
+class StyleLayer;
+class StyleLayerGroup;
+
+class Style {
+public:
+ struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} };
+
+public:
+ Style();
+ ~Style();
+
+ void loadJSON(const uint8_t *const data);
+
+ size_t layerCount() const;
+ void updateProperties(float z, timestamp t);
+
+ void setDefaultTransitionDuration(uint16_t duration_milliseconds = 0);
+
+ void setAppliedClasses(const std::vector<std::string> &classes);
+ const std::vector<std::string> &getAppliedClasses() const;
+ void toggleClass(const std::string &name);
+
+ // Updates the styling information to reflect the current array
+ // of applied classes.
+ void updateClasses();
+
+ bool hasTransitions() const;
+
+ const std::string &getSpriteURL() const;
+
+public:
+ util::ptr<StyleLayerGroup> layers;
+ std::vector<std::string> appliedClasses;
+ std::string glyph_url;
+
+private:
+ std::string sprite_url;
+
+private:
+ PropertyTransition defaultTransition;
+ bool initial_render_complete = false;
+
+ std::unique_ptr<uv::rwlock> mtx;
+};
+
+}
+
+#endif
diff --git a/src/style/style_bucket.cpp b/src/mbgl/style/style_bucket.cpp
index 9a40c2386b..9a40c2386b 100644
--- a/src/style/style_bucket.cpp
+++ b/src/mbgl/style/style_bucket.cpp
diff --git a/src/mbgl/style/style_bucket.hpp b/src/mbgl/style/style_bucket.hpp
new file mode 100644
index 0000000000..d84d35d5b2
--- /dev/null
+++ b/src/mbgl/style/style_bucket.hpp
@@ -0,0 +1,112 @@
+#ifndef MBGL_STYLE_STYLE_BUCKET
+#define MBGL_STYLE_STYLE_BUCKET
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/style/style_source.hpp>
+
+#include <mbgl/util/vec.hpp>
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <forward_list>
+
+namespace mbgl {
+
+class Source;
+
+class StyleBucketFill {
+public:
+ WindingType winding = WindingType::NonZero;
+};
+
+class StyleBucketLine {
+public:
+ CapType cap = CapType::Butt;
+ JoinType join = JoinType::Miter;
+ float miter_limit = 2.0f;
+ float round_limit = 1.0f;
+};
+
+class StyleBucketSymbol {
+public:
+ // Make movable only.
+ inline StyleBucketSymbol() = default;
+ inline StyleBucketSymbol(StyleBucketSymbol &&) = default;
+ inline StyleBucketSymbol& operator=(StyleBucketSymbol &&) = default;
+ inline StyleBucketSymbol(const StyleBucketSymbol &) = delete;
+ inline StyleBucketSymbol& operator=(const StyleBucketSymbol &) = delete;
+
+ PlacementType placement = PlacementType::Point;
+ float min_distance = 250.0f;
+ bool avoid_edges = false;
+
+ struct {
+ bool allow_overlap = false;
+ bool ignore_placement = false;
+ bool optional = false;
+ RotationAlignmentType rotation_alignment = RotationAlignmentType::Viewport;
+ float max_size = 1.0f;
+ std::string image;
+ float rotate = 0.0f;
+ float padding = 2.0f;
+ bool keep_upright = false;
+ vec2<float> offset = {0, 0};
+ } icon;
+
+ struct {
+ RotationAlignmentType rotation_alignment = RotationAlignmentType::Viewport;
+ std::string field;
+ std::string font;
+ float max_size = 16.0f;
+ float max_width = 15.0f * 24 /* em */;
+ float line_height = 1.2f * 24 /* em */;
+ float letter_spacing = 0.0f * 24 /* em */;
+ TextJustifyType justify = TextJustifyType::Center;
+ TextAnchorType anchor = TextAnchorType::Center;
+ float max_angle = 45.0f /* degrees */;
+ float rotate = 0.0f;
+ float slant = 0.0f;
+ float padding = 2.0f;
+ bool keep_upright = true;
+ TextTransformType transform = TextTransformType::None;
+ vec2<float> offset = {0, 0};
+ bool allow_overlap = false;
+ bool ignore_placement = false;
+ bool optional = false;
+ } text;
+};
+
+class StyleBucketRaster {
+public:
+ bool prerendered = false;
+ uint16_t size = 256;
+ float blur = 0.0f;
+ float buffer = 0.03125f;
+};
+
+typedef mapbox::util::variant<StyleBucketFill, StyleBucketLine, StyleBucketSymbol,
+ StyleBucketRaster, std::false_type> StyleBucketRender;
+
+
+class StyleBucket {
+public:
+ typedef util::ptr<StyleBucket> Ptr;
+
+ StyleBucket(StyleLayerType type);
+
+ std::string name;
+ util::ptr<StyleSource> style_source;
+ std::string source_layer;
+ FilterExpression filter;
+ StyleBucketRender render = std::false_type();
+ float min_zoom = -std::numeric_limits<float>::infinity();
+ float max_zoom = std::numeric_limits<float>::infinity();
+};
+
+
+
+};
+
+#endif
diff --git a/src/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp
index e58756afa4..e58756afa4 100644
--- a/src/style/style_layer.cpp
+++ b/src/mbgl/style/style_layer.cpp
diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp
new file mode 100644
index 0000000000..641dc1e71c
--- /dev/null
+++ b/src/mbgl/style/style_layer.hpp
@@ -0,0 +1,89 @@
+#ifndef MBGL_STYLE_STYLE_LAYER
+#define MBGL_STYLE_STYLE_LAYER
+
+#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/style/class_properties.hpp>
+#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/applied_class_properties.hpp>
+
+#include <mbgl/util/ptr.hpp>
+
+#include <vector>
+#include <string>
+#include <map>
+#include <set>
+
+namespace mbgl {
+
+class StyleBucket;
+class StyleLayerGroup;
+
+class StyleLayer {
+public:
+ StyleLayer(const std::string &id, std::map<ClassID, ClassProperties> &&styles);
+
+ template <typename T> const T &getProperties() {
+ if (properties.is<T>()) {
+ return properties.get<T>();
+ } else {
+ return defaultStyleProperties<T>();
+ }
+ }
+
+ // Determines whether this layer is the background layer.
+ bool isBackground() const;
+
+ // Updates the StyleProperties information in this layer by evaluating all
+ // pending transitions and applied classes in order.
+ void updateProperties(float z, timestamp now);
+
+ // Sets the list of classes and creates transitions to the currently applied values.
+ void setClasses(const std::vector<std::string> &class_names, timestamp now,
+ const PropertyTransition &defaultTransition);
+
+ bool hasTransitions() const;
+
+private:
+ // Applies all properties from a class, if they haven't been applied already.
+ void applyClassProperties(ClassID class_id, std::set<PropertyKey> &already_applied,
+ timestamp now, const PropertyTransition &defaultTransition);
+
+ // Sets the properties of this object by evaluating all pending transitions and
+ // aplied classes in order.
+ template <typename T> void applyStyleProperties(float z, timestamp now);
+ template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, timestamp now);
+ template <typename T> void applyTransitionedStyleProperty(PropertyKey key, T &, float z, timestamp now);
+
+ // Removes all expired style transitions.
+ void cleanupAppliedStyleProperties(timestamp now);
+
+public:
+ // The name of this layer.
+ const std::string id;
+
+ StyleLayerType type = StyleLayerType::Unknown;
+
+ // Bucket information, telling the renderer how to generate the geometries
+ // for this layer (feature property filters, tessellation instructions, ...).
+ util::ptr<StyleBucket> bucket;
+
+ // Contains all style classes that can be applied to this layer.
+ const std::map<ClassID, ClassProperties> styles;
+
+private:
+ // For every property, stores a list of applied property values, with
+ // optional transition times.
+ std::map<PropertyKey, AppliedClassProperties> appliedStyle;
+
+public:
+ // Stores the evaluated, and cascaded styling information, specific to this
+ // layer's type.
+ StyleProperties properties;
+
+ // Child layer array (if this layer has child layers).
+ util::ptr<StyleLayerGroup> layers;
+};
+
+}
+
+#endif
diff --git a/src/style/style_layer_group.cpp b/src/mbgl/style/style_layer_group.cpp
index a731aebdcb..0ca0fa0cce 100644
--- a/src/style/style_layer_group.cpp
+++ b/src/mbgl/style/style_layer_group.cpp
@@ -1,4 +1,3 @@
-
#include <mbgl/style/style_layer_group.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/style_layer_group.hpp b/src/mbgl/style/style_layer_group.hpp
new file mode 100644
index 0000000000..1af6e23bd7
--- /dev/null
+++ b/src/mbgl/style/style_layer_group.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_STYLE_STYLE_LAYER_GROUP
+#define MBGL_STYLE_STYLE_LAYER_GROUP
+
+#include <mbgl/style/style_layer.hpp>
+
+#include <vector>
+
+namespace mbgl {
+
+class StyleLayerGroup {
+public:
+ void setClasses(const std::vector<std::string> &class_names, timestamp now,
+ const PropertyTransition &defaultTransition);
+ void updateProperties(float z, timestamp t);
+
+ bool hasTransitions() const;
+public:
+ std::vector<util::ptr<StyleLayer>> layers;
+};
+
+}
+
+#endif
diff --git a/src/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp
index 2dec648aff..2dec648aff 100644
--- a/src/style/style_parser.cpp
+++ b/src/mbgl/style/style_parser.cpp
diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp
new file mode 100644
index 0000000000..c37e856034
--- /dev/null
+++ b/src/mbgl/style/style_parser.hpp
@@ -0,0 +1,113 @@
+#ifndef MBGL_STYLE_STYLE_PARSER
+#define MBGL_STYLE_STYLE_PARSER
+
+#include <rapidjson/document.h>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/style/class_properties.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <unordered_map>
+#include <forward_list>
+#include <tuple>
+
+namespace mbgl {
+
+enum class ClassID : uint32_t;
+
+class StyleLayer;
+class StyleLayerGroup;
+
+class StyleParser {
+public:
+ using JSVal = const rapidjson::Value&;
+
+ StyleParser();
+
+ void parse(JSVal document);
+
+ util::ptr<StyleLayerGroup> getLayers() {
+ return root;
+ }
+
+ std::string getSprite() const {
+ return sprite;
+ }
+
+ std::string getGlyphURL() const {
+ return glyph_url;
+ }
+
+private:
+ void parseConstants(JSVal value);
+ JSVal replaceConstant(JSVal value);
+
+ void parseSources(JSVal value);
+
+ std::unique_ptr<StyleLayerGroup> createLayers(JSVal value);
+ util::ptr<StyleLayer> createLayer(JSVal value);
+ void parseLayers();
+ void parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair);
+ void parsePaints(JSVal value, std::map<ClassID, ClassProperties> &paints);
+ void parsePaint(JSVal, ClassProperties &properties);
+ void parseReference(JSVal value, util::ptr<StyleLayer> &layer);
+ void parseBucket(JSVal value, util::ptr<StyleLayer> &layer);
+ void parseLayout(JSVal value, util::ptr<StyleLayer> &layer);
+ void parseSprite(JSVal value);
+ void parseGlyphURL(JSVal value);
+
+ // Parses optional properties into a render bucket.
+ template<typename T>
+ bool parseRenderProperty(JSVal value, T &target, const char *name);
+ template <typename Parser, typename T>
+ bool parseRenderProperty(JSVal value, T &target, const char *name);
+
+ // Parses optional properties into style class properties.
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value);
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, const std::vector<PropertyKey> &keys, ClassProperties &klass, JSVal value);
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, T &target, JSVal value);
+ template <typename T>
+ bool setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass);
+ template <typename T>
+ bool setProperty(JSVal value, const char *property_name, T &target);
+
+ template <typename T>
+ std::tuple<bool, T> parseProperty(JSVal value, const char *property_name);
+
+ template <typename T>
+ bool parseFunction(PropertyKey key, ClassProperties &klass, JSVal value);
+ template <typename T>
+ std::tuple<bool, Function<T>> parseFunction(JSVal value);
+ template <typename T>
+ T parseFunctionArgument(JSVal value);
+
+ FilterExpression parseFilter(JSVal);
+
+private:
+ std::unordered_map<std::string, const rapidjson::Value *> constants;
+
+ std::unordered_map<std::string, const util::ptr<StyleSource>> sources;
+
+ // This stores the root layer.
+ util::ptr<StyleLayerGroup> root;
+
+ // This maps ids to Layer objects, with all items being at the root level.
+ std::unordered_map<std::string, std::pair<JSVal, util::ptr<StyleLayer>>> layers;
+
+ // Store a stack of layers we're parsing right now. This is to prevent reference cycles.
+ std::forward_list<StyleLayer *> stack;
+
+ // Base URL of the sprite image.
+ std::string sprite;
+
+ // URL template for glyph PBFs.
+ std::string glyph_url;
+};
+
+}
+
+#endif
diff --git a/src/style/style_properties.cpp b/src/mbgl/style/style_properties.cpp
index 29730fb85b..29730fb85b 100644
--- a/src/style/style_properties.cpp
+++ b/src/mbgl/style/style_properties.cpp
diff --git a/src/mbgl/style/style_properties.hpp b/src/mbgl/style/style_properties.hpp
new file mode 100644
index 0000000000..c44b7c34c8
--- /dev/null
+++ b/src/mbgl/style/style_properties.hpp
@@ -0,0 +1,114 @@
+#ifndef MBGL_STYLE_STYLE_PROPERTIES
+#define MBGL_STYLE_STYLE_PROPERTIES
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/function_properties.hpp>
+
+#include <array>
+#include <string>
+#include <type_traits>
+#include <memory>
+
+namespace mbgl {
+
+struct FillProperties {
+ FillProperties() {}
+ bool antialias = true;
+ float opacity = 1.0f;
+ Color fill_color = {{ 0, 0, 0, 1 }};
+ Color stroke_color = {{ 0, 0, 0, -1 }};
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
+ std::string image;
+
+ inline bool isVisible() const {
+ return opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0);
+ }
+};
+
+struct LineProperties {
+ inline LineProperties() {}
+ float opacity = 1.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
+ float width = 1;
+ float gap_width = 0;
+ float blur = 0;
+ std::array<float, 2> dash_array = {{ 1, -1 }};
+ std::string image;
+
+ inline bool isVisible() const {
+ return opacity > 0 && color[3] > 0 && width > 0;
+ }
+};
+
+struct SymbolProperties {
+ inline SymbolProperties() {}
+
+ struct {
+ float opacity = 1.0f;
+ float rotate = 0.0f;
+ float size = 1.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ Color halo_color = {{ 0, 0, 0, 0 }};
+ float halo_width = 0.0f;
+ float halo_blur = 0.0f;
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
+ } icon;
+
+ struct {
+ float opacity = 1.0f;
+ float size = 16.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ Color halo_color = {{ 0, 0, 0, 0 }};
+ float halo_width = 0.0f;
+ float halo_blur = 0.0f;
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
+ } text;
+
+ inline bool isVisible() const {
+ return (icon.opacity > 0 && (icon.color[3] > 0 || icon.halo_color[3] > 0) && icon.size > 0) ||
+ (text.opacity > 0 && (text.color[3] > 0 || text.halo_color[3] > 0) && text.size > 0);
+ }
+};
+
+struct RasterProperties {
+ inline RasterProperties() {}
+ float opacity = 1.0f;
+ float hue_rotate = 0.0f;
+ std::array<float, 2> brightness = {{ 0, 1 }};
+ float saturation = 0.0f;
+ float contrast = 0.0f;
+ float fade = 0.0f;
+
+ inline bool isVisible() const {
+ return opacity > 0;
+ }
+};
+
+struct BackgroundProperties {
+ inline BackgroundProperties() {}
+ float opacity = 1.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ std::string image;
+};
+
+typedef mapbox::util::variant<
+ FillProperties,
+ LineProperties,
+ SymbolProperties,
+ RasterProperties,
+ BackgroundProperties,
+ std::false_type
+> StyleProperties;
+
+template <typename T>
+const T &defaultStyleProperties();
+
+}
+
+#endif
diff --git a/src/style/style_source.cpp b/src/mbgl/style/style_source.cpp
index f46a6fb09b..f46a6fb09b 100644
--- a/src/style/style_source.cpp
+++ b/src/mbgl/style/style_source.cpp
diff --git a/src/mbgl/style/style_source.hpp b/src/mbgl/style/style_source.hpp
new file mode 100644
index 0000000000..8c7d028880
--- /dev/null
+++ b/src/mbgl/style/style_source.hpp
@@ -0,0 +1,41 @@
+#ifndef MBGL_STYLE_STYLE_SOURCE
+#define MBGL_STYLE_STYLE_SOURCE
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/ptr.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <rapidjson/document.h>
+
+#include <vector>
+#include <string>
+
+namespace mbgl {
+
+class Source;
+
+class SourceInfo : private util::noncopyable {
+public:
+ SourceType type = SourceType::Vector;
+ std::string url;
+ std::vector<std::string> tiles;
+ uint16_t tile_size = 512;
+ uint16_t min_zoom = 0;
+ uint16_t max_zoom = 22;
+ std::string attribution;
+ std::array<float, 3> center = {{0, 0, 0}};
+ std::array<float, 4> bounds = {{-180, -90, 180, 90}};
+
+ void parseTileJSONProperties(const rapidjson::Value&);
+};
+
+
+class StyleSource : private util::noncopyable {
+public:
+ SourceInfo info;
+ bool enabled = false;
+ util::ptr<Source> source;
+};
+
+}
+
+#endif
diff --git a/src/style/types.cpp b/src/mbgl/style/types.cpp
index e69de29bb2..e69de29bb2 100644
--- a/src/style/types.cpp
+++ b/src/mbgl/style/types.cpp
diff --git a/src/mbgl/style/types.hpp b/src/mbgl/style/types.hpp
new file mode 100644
index 0000000000..2f7ca7683d
--- /dev/null
+++ b/src/mbgl/style/types.hpp
@@ -0,0 +1,196 @@
+#ifndef MBGL_STYLE_TYPES
+#define MBGL_STYLE_TYPES
+
+#include <mbgl/util/enum.hpp>
+
+#include <string>
+#include <array>
+
+namespace mbgl {
+
+// Stores a premultiplied color, with all four channels ranging from 0..1
+typedef std::array<float, 4> Color;
+
+// -------------------------------------------------------------------------------------------------
+
+enum class StyleLayerType : uint8_t {
+ Unknown,
+ Fill,
+ Line,
+ Symbol,
+ Raster,
+ Background
+};
+
+MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, {
+ { StyleLayerType::Unknown, "unknown" },
+ { StyleLayerType::Fill, "fill" },
+ { StyleLayerType::Line, "line" },
+ { StyleLayerType::Symbol, "symbol" },
+ { StyleLayerType::Raster, "raster" },
+ { StyleLayerType::Background, "background" },
+ { StyleLayerType(-1), "unknown" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class SourceType : uint8_t {
+ Vector,
+ Raster,
+ GeoJSON,
+ Video
+};
+
+MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, {
+ { SourceType::Vector, "vector" },
+ { SourceType::Raster, "raster" },
+ { SourceType::GeoJSON, "geojson" },
+ { SourceType::Video, "video" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class WindingType : bool {
+ EvenOdd,
+ NonZero,
+};
+
+MBGL_DEFINE_ENUM_CLASS(WindingTypeClass, WindingType, {
+ { WindingType::EvenOdd, "even-odd" },
+ { WindingType::NonZero, "non-zero" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class CapType : uint8_t {
+ Round,
+ Butt,
+ Square,
+};
+
+MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, {
+ { CapType::Round, "round" },
+ { CapType::Butt, "butt" },
+ { CapType::Square, "square" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class JoinType : uint8_t {
+ Miter,
+ Bevel,
+ Round
+};
+
+MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, {
+ { JoinType::Miter, "miter" },
+ { JoinType::Bevel, "bevel" },
+ { JoinType::Round, "round" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class TranslateAnchorType : bool {
+ Map,
+ Viewport
+};
+
+MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, {
+ { TranslateAnchorType::Map, "map" },
+ { TranslateAnchorType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class RotateAnchorType : bool {
+ Map,
+ Viewport,
+};
+
+MBGL_DEFINE_ENUM_CLASS(RotateAnchorTypeClass, RotateAnchorType, {
+ { RotateAnchorType::Map, "map" },
+ { RotateAnchorType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class PlacementType : bool {
+ Point,
+ Line,
+};
+
+MBGL_DEFINE_ENUM_CLASS(PlacementTypeClass, PlacementType, {
+ { PlacementType::Point, "point" },
+ { PlacementType::Line, "line" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class RotationAlignmentType : bool {
+ Map,
+ Viewport,
+};
+
+MBGL_DEFINE_ENUM_CLASS(RotationAlignmentTypeClass, RotationAlignmentType, {
+ { RotationAlignmentType::Map, "map" },
+ { RotationAlignmentType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class TextJustifyType : uint8_t {
+ Center,
+ Left,
+ Right
+};
+
+MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, {
+ { TextJustifyType::Center, "center" },
+ { TextJustifyType::Left, "left" },
+ { TextJustifyType::Right, "right" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class TextAnchorType : uint8_t {
+ Center,
+ Left,
+ Right,
+ Top,
+ Bottom,
+ TopLeft,
+ TopRight,
+ BottomLeft,
+ BottomRight
+};
+
+MBGL_DEFINE_ENUM_CLASS(TextAnchorTypeClass, TextAnchorType, {
+ { TextAnchorType::Center, "center" },
+ { TextAnchorType::Left, "left" },
+ { TextAnchorType::Right, "right" },
+ { TextAnchorType::Top, "top" },
+ { TextAnchorType::Bottom, "bottom" },
+ { TextAnchorType::TopLeft, "top-left" },
+ { TextAnchorType::TopRight, "top-right" },
+ { TextAnchorType::BottomLeft, "bottom-left" },
+ { TextAnchorType::BottomRight, "bottom-right" }
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class TextTransformType : uint8_t {
+ None,
+ Uppercase,
+ Lowercase,
+};
+
+MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, {
+ { TextTransformType::None, "none" },
+ { TextTransformType::Uppercase, "uppercase" },
+ { TextTransformType::Lowercase, "lowercase" },
+});
+
+}
+
+#endif
+
diff --git a/src/style/value.cpp b/src/mbgl/style/value.cpp
index bda9a089a8..ae51ce3783 100644
--- a/src/style/value.cpp
+++ b/src/mbgl/style/value.cpp
@@ -1,11 +1,5 @@
#include <mbgl/style/value.hpp>
-
-#pragma GCC diagnostic push
-#ifndef __clang__
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#endif
-#include <boost/lexical_cast.hpp>
-#pragma GCC diagnostic pop
+#include <mbgl/util/string.hpp>
mbgl::Value mbgl::parseValue(pbf data) {
while (data.next())
@@ -37,9 +31,9 @@ mbgl::Value mbgl::parseValue(pbf data) {
std::string mbgl::toString(const mbgl::Value& value) {
if (value.is<std::string>()) return value.get<std::string>();
else if (value.is<bool>()) return value.get<bool>() ? "true" : "false";
- else if (value.is<int64_t>()) return std::to_string(value.get<int64_t>());
- else if (value.is<uint64_t>()) return std::to_string(value.get<uint64_t>());
- else if (value.is<double>()) return boost::lexical_cast<std::string>(value.get<double>());
+ else if (value.is<int64_t>()) return util::toString(value.get<int64_t>());
+ else if (value.is<uint64_t>()) return util::toString(value.get<uint64_t>());
+ else if (value.is<double>()) return util::toString(value.get<double>());
else return "null";
}
diff --git a/src/mbgl/style/value.hpp b/src/mbgl/style/value.hpp
new file mode 100644
index 0000000000..87d6f4cda3
--- /dev/null
+++ b/src/mbgl/style/value.hpp
@@ -0,0 +1,45 @@
+#ifndef MBGL_STYLE_VALUE
+#define MBGL_STYLE_VALUE
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/pbf.hpp>
+#include <rapidjson/document.h>
+
+#include <cstdlib>
+#include <cerrno>
+
+namespace mbgl {
+
+typedef mapbox::util::variant<bool, int64_t, uint64_t, double, std::string> Value;
+
+std::string toString(const Value &value);
+
+Value parseValue(pbf data);
+Value parseValue(const rapidjson::Value&);
+
+namespace util {
+inline bool parseNumericString(const std::string &str, double &result) {
+ char *end = nullptr;
+ const char *begin = str.c_str();
+ result = std::strtod(begin, &end);
+ while (*end != '\0' && isspace(*end)) end++; // eat whitespace after the end
+ return errno == 0 && end - begin == long(str.size());
+}
+}
+
+template <typename T>
+T toNumber(const Value &value) {
+ if (value.is<std::string>()) {
+ double val;
+ return util::parseNumericString(value.get<std::string>(), val) ? val : 0;
+ }
+ else if (value.is<bool>()) return value.get<bool>();
+ else if (value.is<int64_t>()) return value.get<int64_t>();
+ else if (value.is<uint64_t>()) return value.get<uint64_t>();
+ else if (value.is<double>()) return value.get<double>();
+ else return 0;
+}
+
+}
+
+#endif
diff --git a/src/mbgl/style/value_comparison.hpp b/src/mbgl/style/value_comparison.hpp
new file mode 100644
index 0000000000..895c8a0869
--- /dev/null
+++ b/src/mbgl/style/value_comparison.hpp
@@ -0,0 +1,109 @@
+#ifndef MBGL_STYLE_VALUE_COMPARISON
+#define MBGL_STYLE_VALUE_COMPARISON
+
+#include <mbgl/style/value.hpp>
+#include <cstdlib>
+#include <cerrno>
+
+namespace mbgl {
+
+namespace util {
+
+namespace detail {
+
+template <typename Operator>
+struct relaxed_operator_visitor {
+ typedef bool result_type;
+
+ template <typename T0, typename T1>
+ inline bool operator()(T0, T1) const { return false; }
+
+ template <typename T>
+ inline bool operator()(T lhs, T rhs) const { return Operator()(lhs, rhs); }
+
+ inline bool operator()(int64_t lhs, uint64_t rhs) const {
+ return Operator()(double(lhs), double(rhs));
+ }
+
+ inline bool operator()(int64_t lhs, double rhs) const {
+ return Operator()(double(lhs), rhs);
+ }
+
+ inline bool operator()(uint64_t lhs, int64_t rhs) const {
+ return Operator()(double(lhs), double(rhs));
+ }
+
+ inline bool operator()(uint64_t lhs, double rhs) const {
+ return Operator()(double(lhs), rhs);
+ }
+
+ inline bool operator()(double lhs, uint64_t rhs) const {
+ return Operator()(lhs, double(rhs));
+ }
+
+ inline bool operator()(double lhs, int64_t rhs) const {
+ return Operator()(lhs, double(rhs));
+ }
+};
+
+struct relaxed_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs == rhs; }
+};
+
+struct relaxed_not_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs != rhs; }
+};
+
+struct relaxed_greater_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs > rhs; }
+};
+
+struct relaxed_greater_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs >= rhs; }
+};
+
+struct relaxed_less_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs < rhs; }
+};
+
+struct relaxed_less_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs <= rhs; }
+};
+
+} // end namespace detail
+
+inline bool relaxed_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_not_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_not_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_greater(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_less(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>(), lhs, rhs);
+}
+
+}
+
+}
+
+#endif
diff --git a/src/text/collision.cpp b/src/mbgl/text/collision.cpp
index 2e0ec6dce2..2e0ec6dce2 100644
--- a/src/text/collision.cpp
+++ b/src/mbgl/text/collision.cpp
diff --git a/src/mbgl/text/collision.hpp b/src/mbgl/text/collision.hpp
new file mode 100644
index 0000000000..3bf37a6a12
--- /dev/null
+++ b/src/mbgl/text/collision.hpp
@@ -0,0 +1,58 @@
+#ifndef MBGL_TEXT_COLLISION
+#define MBGL_TEXT_COLLISION
+
+#include <mbgl/text/types.hpp>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wshadow"
+#ifdef __clang__
+#pragma GCC diagnostic ignored "-Wdeprecated-register"
+#else
+#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+#include <boost/geometry.hpp>
+#include <boost/geometry/geometries/point.hpp>
+#include <boost/geometry/geometries/box.hpp>
+#include <boost/geometry/index/rtree.hpp>
+#pragma GCC diagnostic pop
+
+namespace mbgl {
+
+namespace bg = boost::geometry;
+namespace bgm = bg::model;
+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::linear<16,4>> Tree;
+
+class Collision {
+
+public:
+ Collision(float zoom, float tileExtent, float tileSize, float placementDepth = 1);
+
+ float getPlacementScale(const GlyphBoxes &glyphs, float minPlacementScale, bool avoidEdges);
+ PlacementRange getPlacementRange(const GlyphBoxes &glyphs, float placementScale,
+ bool horizontal);
+ void insert(const GlyphBoxes &glyphs, const CollisionAnchor &anchor, float placementScale,
+ const PlacementRange &placementRange, bool horizontal);
+
+private:
+ Tree hTree;
+ Tree cTree;
+ PlacementValue leftEdge;
+ PlacementValue topEdge;
+ PlacementValue rightEdge;
+ PlacementValue bottomEdge;
+
+public:
+ const float tilePixelRatio;
+ const float zoom;
+ const float maxPlacementScale;
+};
+}
+
+#endif
diff --git a/src/text/glyph.cpp b/src/mbgl/text/glyph.cpp
index f02c710db2..f02c710db2 100644
--- a/src/text/glyph.cpp
+++ b/src/mbgl/text/glyph.cpp
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
new file mode 100644
index 0000000000..4fbb75fc1e
--- /dev/null
+++ b/src/mbgl/text/glyph.hpp
@@ -0,0 +1,60 @@
+#ifndef MBGL_TEXT_GLYPH
+#define MBGL_TEXT_GLYPH
+
+#include <mbgl/util/rect.hpp>
+
+#include <cstdint>
+#include <vector>
+#include <map>
+
+namespace mbgl {
+
+typedef std::pair<uint16_t, uint16_t> GlyphRange;
+
+// Note: this only works for the BMP
+GlyphRange getGlyphRange(char32_t glyph);
+
+struct GlyphMetrics {
+ operator bool() const {
+ return !(width == 0 && height == 0 && advance == 0);
+ }
+
+ // Glyph metrics.
+ uint32_t width = 0;
+ uint32_t height = 0;
+ int32_t left = 0;
+ int32_t top = 0;
+ uint32_t advance = 0;
+
+};
+
+struct Glyph {
+ inline explicit Glyph() : rect(0, 0, 0, 0), metrics() {}
+ inline explicit Glyph(const Rect<uint16_t> &rect_,
+ const GlyphMetrics &metrics_)
+ : rect(rect_), metrics(metrics_) {}
+
+ operator bool() const {
+ return metrics || rect;
+ }
+
+ const Rect<uint16_t> rect;
+ const GlyphMetrics metrics;
+};
+
+typedef std::map<uint32_t, Glyph> GlyphPositions;
+
+class PositionedGlyph {
+public:
+ inline explicit PositionedGlyph(uint32_t glyph_, float x_, float y_)
+ : glyph(glyph_), x(x_), y(y_) {}
+
+ uint32_t glyph = 0;
+ float x = 0;
+ float y = 0;
+};
+
+typedef std::vector<PositionedGlyph> Shaping;
+}
+
+#endif
diff --git a/src/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp
index 8537ab5156..2f5db180fd 100644
--- a/src/text/glyph_store.cpp
+++ b/src/mbgl/text/glyph_store.cpp
@@ -143,7 +143,7 @@ GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, Gl
// Load the glyph set URL
std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
if (name == "fontstack") return util::percentEncode(fontStack);
- if (name == "range") return std::to_string(glyphRange.first) + "-" + std::to_string(glyphRange.second);
+ if (name == "range") return util::toString(glyphRange.first) + "-" + util::toString(glyphRange.second);
return "";
});
@@ -153,7 +153,7 @@ GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, Gl
request->onload([&, url](const Response &res) {
if (res.code != 200) {
// Something went wrong with loading the glyph pbf. Pass on the error to the future listeners.
- const std::string msg = util::sprintf<255>("[ERROR] failed to load glyphs (%d): %s\n", res.code, res.message.c_str());
+ const std::string msg = std::string { "[ERROR] failed to load glyphs (" } + util::toString(res.code) + "): " + res.message;
promise.set_exception(std::make_exception_ptr(std::runtime_error(msg)));
} else {
// Transfer the data to the GlyphSet and signal its availability.
diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp
new file mode 100644
index 0000000000..95ab92f307
--- /dev/null
+++ b/src/mbgl/text/glyph_store.hpp
@@ -0,0 +1,99 @@
+#ifndef MBGL_TEXT_GLYPH_STORE
+#define MBGL_TEXT_GLYPH_STORE
+
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/vec.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <cstdint>
+#include <vector>
+#include <future>
+#include <map>
+#include <set>
+#include <unordered_map>
+
+namespace mbgl {
+
+class FileSource;
+
+class SDFGlyph {
+public:
+ uint32_t id = 0;
+
+ // A signed distance field of the glyph with a border of 3 pixels.
+ std::string bitmap;
+
+ // Glyph metrics
+ GlyphMetrics metrics;
+};
+
+class FontStack {
+public:
+ void insert(uint32_t id, const SDFGlyph &glyph);
+ const std::map<uint32_t, GlyphMetrics> &getMetrics() const;
+ const std::map<uint32_t, SDFGlyph> &getSDFs() const;
+ const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight,
+ float horizontalAlign, float verticalAlign, float justify,
+ float spacing, const vec2<float> &translate) const;
+ void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign,
+ float verticalAlign, float justify) const;
+
+private:
+ std::map<uint32_t, std::string> bitmaps;
+ std::map<uint32_t, GlyphMetrics> metrics;
+ std::map<uint32_t, SDFGlyph> sdfs;
+ mutable std::mutex mtx;
+};
+
+class GlyphPBF {
+public:
+ GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, FileSource& fileSource);
+
+private:
+ GlyphPBF(const GlyphPBF &) = delete;
+ GlyphPBF(GlyphPBF &&) = delete;
+ GlyphPBF &operator=(const GlyphPBF &) = delete;
+ GlyphPBF &operator=(GlyphPBF &&) = delete;
+
+public:
+ void parse(FontStack &stack);
+
+ std::shared_future<GlyphPBF &> getFuture();
+
+private:
+ std::string data;
+ std::promise<GlyphPBF &> promise;
+ std::shared_future<GlyphPBF &> future;
+ std::mutex mtx;
+};
+
+// Manages Glyphrange PBF loading.
+class GlyphStore {
+public:
+ GlyphStore(FileSource& fileSource);
+
+ // Block until all specified GlyphRanges of the specified font stack are loaded.
+ void waitForGlyphRanges(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges);
+
+ FontStack &getFontStack(const std::string &fontStack);
+
+ void setURL(const std::string &url);
+
+private:
+ // Loads an individual glyph range from the font stack and adds it to rangeSets
+ std::shared_future<GlyphPBF &> loadGlyphRange(const std::string &fontStack, std::map<GlyphRange, std::unique_ptr<GlyphPBF>> &rangeSets, GlyphRange range);
+
+ FontStack &createFontStack(const std::string &fontStack);
+
+ std::string glyphURL;
+ FileSource& fileSource;
+ std::unordered_map<std::string, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>> ranges;
+ std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks;
+ std::mutex mtx;
+};
+
+
+}
+
+#endif
diff --git a/src/text/placement.cpp b/src/mbgl/text/placement.cpp
index 84d4e20b2f..84d4e20b2f 100644
--- a/src/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
new file mode 100644
index 0000000000..28eb8d5317
--- /dev/null
+++ b/src/mbgl/text/placement.hpp
@@ -0,0 +1,31 @@
+#ifndef MBGL_TEXT_PLACEMENT
+#define MBGL_TEXT_PLACEMENT
+
+#include <mbgl/text/types.hpp>
+#include <mbgl/text/glyph.hpp>
+
+#include <mbgl/util/vec.hpp>
+
+namespace mbgl {
+
+struct Anchor;
+class StyleBucketSymbol;
+
+class Placement {
+public:
+ static Placement getIcon(Anchor &anchor, const Rect<uint16_t> &image, float iconBoxScale,
+ const std::vector<Coordinate> &line, const StyleBucketSymbol &props);
+
+ static Placement getGlyphs(Anchor &anchor, const vec2<float> &origin, const Shaping &shaping,
+ const GlyphPositions &face, float boxScale, bool horizontal,
+ const std::vector<Coordinate> &line, const StyleBucketSymbol &props);
+
+ static const float globalMinScale;
+
+ GlyphBoxes boxes;
+ PlacedGlyphs shapes;
+ float minScale;
+};
+}
+
+#endif
diff --git a/src/text/rotation_range.cpp b/src/mbgl/text/rotation_range.cpp
index 664ea9c709..664ea9c709 100644
--- a/src/text/rotation_range.cpp
+++ b/src/mbgl/text/rotation_range.cpp
diff --git a/src/mbgl/text/rotation_range.hpp b/src/mbgl/text/rotation_range.hpp
new file mode 100644
index 0000000000..4968fda164
--- /dev/null
+++ b/src/mbgl/text/rotation_range.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_TEXT_ROTATION_RANGE
+#define MBGL_TEXT_ROTATION_RANGE
+
+#include <mbgl/util/math.hpp>
+#include <mbgl/text/types.hpp>
+
+#include <vector>
+#include <cassert>
+
+namespace mbgl {
+
+/*
+ * Combine an array of collision ranges to form a continuous
+ * range that includes 0. Collisions within the ignoreRange are ignored
+ */
+CollisionRange mergeCollisions(const CollisionList &collisions,
+ PlacementRange ignoreRange);
+
+/*
+ * Calculate collision ranges for two rotating boxes.e
+ */
+CollisionList rotatingRotatingCollisions(const CollisionRect &a,
+ const CollisionRect &b,
+ const CollisionAnchor &anchorToAnchor);
+
+/*
+ * Return the intersection points of a circle and a line segment;
+ */
+void circleEdgeCollisions(std::back_insert_iterator<CollisionAngles> angles,
+ const CollisionPoint &corner, float radius,
+ const CollisionPoint &p1, const CollisionPoint &p2);
+
+/*
+ * Calculate the ranges for which the corner,
+ * rotatated around the anchor, is within the box;
+ */
+void cornerBoxCollisions(std::back_insert_iterator<CollisionList> collisions,
+ const CollisionPoint &corner,
+ const CollisionCorners &boxCorners, bool flip = false);
+
+/*
+ * Calculate collision ranges for a rotating box and a fixed box;
+ */
+CollisionList rotatingFixedCollisions(const CollisionRect &rotating,
+ const CollisionRect &fixed);
+
+/*
+ * Calculate the range a box conflicts with a second box
+ */
+CollisionRange rotationRange(const GlyphBox &inserting,
+ const PlacementBox &blocker, float scale);
+}
+
+#endif
diff --git a/src/mbgl/text/types.hpp b/src/mbgl/text/types.hpp
new file mode 100644
index 0000000000..23f49aa748
--- /dev/null
+++ b/src/mbgl/text/types.hpp
@@ -0,0 +1,113 @@
+#ifndef MBGL_TEXT_TYPES
+#define MBGL_TEXT_TYPES
+
+#include <mbgl/util/vec.hpp>
+#include <mbgl/util/rect.hpp>
+#include <mbgl/util/optional.hpp>
+#include <array>
+#include <vector>
+
+namespace mbgl {
+
+typedef vec2<float> CollisionPoint;
+typedef vec2<float> CollisionAnchor;
+
+typedef std::array<float, 2> PlacementRange;
+typedef float CollisionAngle;
+typedef std::vector<CollisionAngle> CollisionAngles;
+typedef std::array<CollisionAngle, 2> CollisionRange;
+typedef std::vector<CollisionRange> CollisionList;
+typedef std::array<CollisionPoint, 4> CollisionCorners;
+
+struct CollisionRect {
+ CollisionPoint tl;
+ CollisionPoint br;
+ inline explicit CollisionRect() {}
+ inline explicit CollisionRect(CollisionPoint::Type ax,
+ CollisionPoint::Type ay,
+ CollisionPoint::Type bx,
+ CollisionPoint::Type by)
+ : tl(ax, ay), br(bx, by) {}
+ inline explicit CollisionRect(const CollisionPoint &tl_,
+ const CollisionPoint &br_)
+ : tl(tl_), br(br_) {}
+};
+
+// These are the glyph boxes that we want to have placed.
+struct GlyphBox {
+ explicit GlyphBox() {}
+ explicit GlyphBox(const CollisionRect &box_,
+ const CollisionAnchor &anchor_,
+ float minScale_,
+ float maxScale_,
+ float padding_)
+ : box(box_), anchor(anchor_), minScale(minScale_), maxScale(maxScale_), padding(padding_) {}
+ explicit GlyphBox(const CollisionRect &box_,
+ float minScale_,
+ float padding_)
+ : box(box_), minScale(minScale_), padding(padding_) {}
+
+ CollisionRect box;
+ CollisionAnchor anchor;
+ float minScale = 0.0f;
+ float maxScale = std::numeric_limits<float>::infinity();
+ float padding = 0.0f;
+ mapbox::util::optional<CollisionRect> hBox;
+};
+
+typedef std::vector<GlyphBox> GlyphBoxes;
+
+
+// TODO: Transform the vec2<float>s to vec2<int16_t> to save bytes
+struct PlacedGlyph {
+ explicit PlacedGlyph(const vec2<float> &tl_, const vec2<float> &tr_,
+ const vec2<float> &bl_, const vec2<float> &br_,
+ const Rect<uint16_t> &tex_, float angle_, const vec2<float> &anchor_,
+ float minScale_, float maxScale_)
+ : tl(tl_),
+ tr(tr_),
+ bl(bl_),
+ br(br_),
+ tex(tex_),
+ angle(angle_),
+ anchor(anchor_),
+ minScale(minScale_),
+ maxScale(maxScale_) {}
+
+ vec2<float> tl, tr, bl, br;
+ Rect<uint16_t> tex;
+ float angle;
+ vec2<float> anchor;
+ float minScale, maxScale;
+};
+
+typedef std::vector<PlacedGlyph> PlacedGlyphs;
+
+// These are the placed boxes contained in the rtree.
+struct PlacementBox {
+ CollisionAnchor anchor;
+ CollisionRect box;
+ mapbox::util::optional<CollisionRect> hBox;
+ PlacementRange placementRange = {{0.0f, 0.0f}};
+ float placementScale = 0.0f;
+ float maxScale = std::numeric_limits<float>::infinity();
+ float padding = 0.0f;
+};
+
+struct PlacementProperty {
+ explicit PlacementProperty() {}
+ explicit PlacementProperty(float zoom_, const PlacementRange &rotationRange_)
+ : zoom(zoom_), rotationRange(rotationRange_) {}
+
+ inline operator bool() const {
+ return !std::isnan(zoom) && zoom != std::numeric_limits<float>::infinity() &&
+ rotationRange[0] != rotationRange[1];
+ }
+
+ float zoom = std::numeric_limits<float>::infinity();
+ PlacementRange rotationRange = {{0.0f, 0.0f}};
+};
+
+}
+
+#endif
diff --git a/src/mbgl/util/box.hpp b/src/mbgl/util/box.hpp
new file mode 100644
index 0000000000..55a5d46fbc
--- /dev/null
+++ b/src/mbgl/util/box.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_UTIL_BOX
+#define MBGL_UTIL_BOX
+
+#include <mbgl/util/vec.hpp>
+
+namespace mbgl {
+
+struct box {
+ vec2<double> tl, tr, bl, br;
+ vec2<double> center;
+};
+
+}
+
+#endif
diff --git a/src/util/clip_ids.cpp b/src/mbgl/util/clip_ids.cpp
index 9c391c38ad..9c391c38ad 100644
--- a/src/util/clip_ids.cpp
+++ b/src/mbgl/util/clip_ids.cpp
diff --git a/src/mbgl/util/clip_ids.hpp b/src/mbgl/util/clip_ids.hpp
new file mode 100644
index 0000000000..5855b16af7
--- /dev/null
+++ b/src/mbgl/util/clip_ids.hpp
@@ -0,0 +1,38 @@
+#ifndef MBGL_UTIL_CLIP_IDS
+#define MBGL_UTIL_CLIP_IDS
+
+#include <mbgl/map/tile.hpp>
+#include <list>
+#include <set>
+#include <vector>
+#include <forward_list>
+#include <map>
+
+namespace mbgl {
+
+class ClipIDGenerator {
+private:
+ struct Leaf {
+ Leaf(Tile &tile);
+ void add(const Tile::ID &p);
+ bool operator==(const Leaf &other) const;
+
+ Tile &tile;
+ std::forward_list<Tile::ID> children;
+ };
+
+ typedef std::vector<Leaf> Pool;
+ std::forward_list<Pool> pools;
+ uint8_t bit_offset = 0;
+
+private:
+ bool reuseExisting(Leaf &leaf);
+
+public:
+ void update(std::forward_list<Tile *> tiles);
+};
+
+
+}
+
+#endif
diff --git a/src/util/compression.cpp b/src/mbgl/util/compression.cpp
index d6d6370546..d6d6370546 100644
--- a/src/util/compression.cpp
+++ b/src/mbgl/util/compression.cpp
diff --git a/src/mbgl/util/compression.hpp b/src/mbgl/util/compression.hpp
new file mode 100644
index 0000000000..a33b2476a7
--- /dev/null
+++ b/src/mbgl/util/compression.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_UTIL_COMPRESSION
+#define MBGL_UTIL_COMPRESSION
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+std::string compress(const std::string &raw);
+std::string decompress(const std::string &raw);
+
+}
+}
+
+#endif
diff --git a/src/mbgl/util/constants.cpp b/src/mbgl/util/constants.cpp
new file mode 100644
index 0000000000..3d1422e6c7
--- /dev/null
+++ b/src/mbgl/util/constants.cpp
@@ -0,0 +1,27 @@
+#include <mbgl/util/constants.hpp>
+
+const float mbgl::util::tileSize = 512.0f;
+
+#if defined(DEBUG)
+const bool mbgl::debug::tileParseWarnings = false;
+const bool mbgl::debug::styleParseWarnings = false;
+const bool mbgl::debug::spriteWarnings = false;
+const bool mbgl::debug::renderWarnings = false;
+const bool mbgl::debug::renderTree = false;
+const bool mbgl::debug::labelTextMissingWarning = true;
+const bool mbgl::debug::missingFontStackWarning = true;
+const bool mbgl::debug::missingFontFaceWarning = true;
+const bool mbgl::debug::glyphWarning = true;
+const bool mbgl::debug::shapingWarning = true;
+#else
+const bool mbgl::debug::tileParseWarnings = false;
+const bool mbgl::debug::styleParseWarnings = false;
+const bool mbgl::debug::spriteWarnings = false;
+const bool mbgl::debug::renderWarnings = false;
+const bool mbgl::debug::renderTree = false;
+const bool mbgl::debug::labelTextMissingWarning = false;
+const bool mbgl::debug::missingFontStackWarning = false;
+const bool mbgl::debug::missingFontFaceWarning = false;
+const bool mbgl::debug::glyphWarning = false;
+const bool mbgl::debug::shapingWarning = false;
+#endif
diff --git a/src/mbgl/util/constants.hpp b/src/mbgl/util/constants.hpp
new file mode 100644
index 0000000000..98365e0f32
--- /dev/null
+++ b/src/mbgl/util/constants.hpp
@@ -0,0 +1,31 @@
+#ifndef MBGL_UTIL_CONSTANTS
+#define MBGL_UTIL_CONSTANTS
+
+#include <cmath>
+
+namespace mbgl {
+
+namespace util {
+
+extern const float tileSize;
+
+}
+
+namespace debug {
+
+extern const bool tileParseWarnings;
+extern const bool styleParseWarnings;
+extern const bool spriteWarnings;
+extern const bool renderWarnings;
+extern const bool renderTree;
+extern const bool labelTextMissingWarning;
+extern const bool missingFontStackWarning;
+extern const bool missingFontFaceWarning;
+extern const bool glyphWarning;
+extern const bool shapingWarning;
+
+}
+
+}
+
+#endif
diff --git a/src/mbgl/util/error.hpp b/src/mbgl/util/error.hpp
new file mode 100644
index 0000000000..09fa8d3e21
--- /dev/null
+++ b/src/mbgl/util/error.hpp
@@ -0,0 +1,20 @@
+#ifndef MBGL_UTIL_ERROR
+#define MBGL_UTIL_ERROR
+
+#include <stdexcept>
+#include <string>
+
+namespace mbgl {
+namespace error {
+
+struct style_parse : std::exception {
+ inline style_parse(size_t offset_, const char *msg_) : offset(offset_), msg(msg_) {}
+ inline const char* what() const noexcept { return msg.c_str(); }
+ const size_t offset;
+ const std::string msg;
+};
+}
+
+}
+
+#endif \ No newline at end of file
diff --git a/src/mbgl/util/interpolate.hpp b/src/mbgl/util/interpolate.hpp
new file mode 100644
index 0000000000..c9232db4eb
--- /dev/null
+++ b/src/mbgl/util/interpolate.hpp
@@ -0,0 +1,27 @@
+#ifndef MBGL_UTIL_INTERPOLATE
+#define MBGL_UTIL_INTERPOLATE
+
+#include <array>
+
+namespace mbgl {
+namespace util {
+
+template <typename T>
+T interpolate(const T a, const T b, const double t) {
+ return a * (1.0 - t) + b * t;
+}
+
+template <typename T>
+inline std::array<T, 4> interpolate(const std::array<T, 4>& a, const std::array<T, 4>& b, const double t) {
+ return {{
+ interpolate(a[0], b[0], t),
+ interpolate(a[1], b[1], t),
+ interpolate(a[2], b[2], t),
+ interpolate(a[3], b[3], t)
+ }};
+}
+
+}
+}
+
+#endif
diff --git a/src/util/io.cpp b/src/mbgl/util/io.cpp
index 76f7c35ade..76f7c35ade 100644
--- a/src/util/io.cpp
+++ b/src/mbgl/util/io.cpp
diff --git a/src/mbgl/util/io.hpp b/src/mbgl/util/io.hpp
new file mode 100644
index 0000000000..e95fc16d9d
--- /dev/null
+++ b/src/mbgl/util/io.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_UTIL_IO
+#define MBGL_UTIL_IO
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+void write_file(const std::string &filename, const std::string &data);
+std::string read_file(const std::string &filename);
+
+}
+}
+
+#endif
diff --git a/src/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp
index 277b647f34..277b647f34 100644
--- a/src/util/mapbox.cpp
+++ b/src/mbgl/util/mapbox.cpp
diff --git a/src/mbgl/util/mapbox.hpp b/src/mbgl/util/mapbox.hpp
new file mode 100644
index 0000000000..0fbb9a91ed
--- /dev/null
+++ b/src/mbgl/util/mapbox.hpp
@@ -0,0 +1,17 @@
+#ifndef MBGL_UTIL_MAPBOX
+#define MBGL_UTIL_MAPBOX
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+namespace mapbox {
+
+std::string normalizeSourceURL(const std::string& url, const std::string& accessToken);
+std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken);
+
+}
+}
+}
+
+#endif
diff --git a/src/util/mat3.cpp b/src/mbgl/util/mat3.cpp
index 263768ee41..263768ee41 100644
--- a/src/util/mat3.cpp
+++ b/src/mbgl/util/mat3.cpp
diff --git a/src/mbgl/util/mat3.hpp b/src/mbgl/util/mat3.hpp
new file mode 100644
index 0000000000..fa40751764
--- /dev/null
+++ b/src/mbgl/util/mat3.hpp
@@ -0,0 +1,42 @@
+// This is an incomplete port of http://glmatrix.net/
+//
+// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the
+// use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not claim
+// that you wrote the original software. If you use this software in a
+// product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+
+#ifndef MBGL_UTIL_MAT3
+#define MBGL_UTIL_MAT3
+
+#include <array>
+
+namespace mbgl {
+
+typedef std::array<float, 9> mat3;
+
+namespace matrix {
+
+void identity(mat3& out);
+void translate(mat3& out, const mat3& a, float x, float y);
+void rotate(mat3& out, const mat3& a, float rad);
+void scale(mat3& out, const mat3& a, float x, float y);
+
+}
+}
+
+#endif
diff --git a/src/util/mat4.cpp b/src/mbgl/util/mat4.cpp
index 50270d9217..50270d9217 100644
--- a/src/util/mat4.cpp
+++ b/src/mbgl/util/mat4.cpp
diff --git a/src/util/math.cpp b/src/mbgl/util/math.cpp
index a7eab2d771..a7eab2d771 100644
--- a/src/util/math.cpp
+++ b/src/mbgl/util/math.cpp
diff --git a/src/mbgl/util/optional.hpp b/src/mbgl/util/optional.hpp
new file mode 100644
index 0000000000..8d46eae857
--- /dev/null
+++ b/src/mbgl/util/optional.hpp
@@ -0,0 +1,69 @@
+#ifndef MAPBOX_UTIL_OPTIONAL_HPP
+#define MAPBOX_UTIL_OPTIONAL_HPP
+
+#include <type_traits>
+
+#include <mbgl/util/variant.hpp>
+
+namespace mapbox
+{
+namespace util
+{
+
+template <typename T> class optional
+{
+ static_assert(!std::is_reference<T>::value, "optional doesn't support references");
+
+ struct none_type
+ {
+ };
+
+ variant<none_type, T> variant_;
+
+ public:
+ optional() = default;
+
+ optional(optional const &rhs)
+ {
+ if (this != &rhs)
+ { // protect against invalid self-assignment
+ variant_ = rhs.variant_;
+ }
+ }
+
+ optional(T const &v) { variant_ = v; }
+
+ explicit operator bool() const noexcept { return variant_.template is<T>(); }
+
+ T const &get() const { return variant_.template get<T>(); }
+ T &get() { return variant_.template get<T>(); }
+
+ T const &operator*() const { return this->get(); }
+ T operator*() { return this->get(); }
+
+ optional &operator=(T const &v)
+ {
+ variant_ = v;
+ return *this;
+ }
+
+ optional &operator=(optional const &rhs)
+ {
+ if (this != &rhs)
+ {
+ variant_ = rhs.variant_;
+ }
+ return *this;
+ }
+
+ template <typename... Args> void emplace(Args &&... args)
+ {
+ variant_ = T{std::forward<Args>(args)...};
+ }
+
+ void reset() { variant_ = none_type{}; }
+};
+}
+}
+
+#endif
diff --git a/src/util/parsedate.c b/src/mbgl/util/parsedate.c
index f888def853..f888def853 100644
--- a/src/util/parsedate.c
+++ b/src/mbgl/util/parsedate.c
diff --git a/src/mbgl/util/pbf.hpp b/src/mbgl/util/pbf.hpp
new file mode 100644
index 0000000000..d017219a52
--- /dev/null
+++ b/src/mbgl/util/pbf.hpp
@@ -0,0 +1,184 @@
+#ifndef MBGL_UTIL_PBF
+#define MBGL_UTIL_PBF
+
+/*
+ * Some parts are from upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2008-2011 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+#include <string>
+#include <cstring>
+
+namespace mbgl {
+
+struct pbf {
+ struct exception : std::exception { const char *what() const noexcept { return "pbf exception"; } };
+ struct unterminated_varint_exception : exception { const char *what() const noexcept { return "pbf unterminated varint exception"; } };
+ struct varint_too_long_exception : exception { const char *what() const noexcept { return "pbf varint too long exception"; } };
+ struct unknown_field_type_exception : exception { const char *what() const noexcept { return "pbf unknown field type exception"; } };
+ struct end_of_buffer_exception : exception { const char *what() const noexcept { return "pbf end of buffer exception"; } };
+
+ inline pbf(const unsigned char *data, size_t length);
+ inline pbf();
+
+ inline operator bool() const;
+
+ inline bool next();
+ inline bool next(uint32_t tag);
+ template <typename T = uint32_t> inline T varint();
+ template <typename T = uint32_t> inline T svarint();
+
+ template <typename T = uint32_t, int bytes = 4> inline T fixed();
+ inline float float32();
+ inline double float64();
+
+ inline std::string string();
+ inline bool boolean();
+
+ inline pbf message();
+
+ inline void skip();
+ inline void skipValue(uint32_t val);
+ inline void skipBytes(uint32_t bytes);
+
+ const uint8_t *data = nullptr;
+ const uint8_t *end = nullptr;
+ uint32_t value = 0;
+ uint32_t tag = 0;
+};
+
+pbf::pbf(const unsigned char *data_, size_t length)
+ : data(data_),
+ end(data_ + length),
+ value(0),
+ tag(0) {
+}
+
+pbf::pbf()
+ : data(nullptr),
+ end(nullptr),
+ value(0),
+ tag(0) {
+}
+
+
+pbf::operator bool() const {
+ return data < end;
+}
+
+bool pbf::next() {
+ if (data < end) {
+ value = static_cast<uint32_t>(varint());
+ tag = value >> 3;
+ return true;
+ }
+ return false;
+}
+
+bool pbf::next(uint32_t requested_tag) {
+ while (next()) {
+ if (tag == requested_tag) {
+ return true;
+ } else {
+ skip();
+ }
+ }
+ return false;
+}
+
+template <typename T>
+T pbf::varint() {
+ uint8_t byte = 0x80;
+ T result = 0;
+ int bitpos;
+ for (bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
+ if (data >= end) {
+ throw unterminated_varint_exception();
+ }
+ result |= ((T)(byte = *data) & 0x7F) << bitpos;
+
+ data++;
+ }
+ if (bitpos == 70 && (byte & 0x80)) {
+ throw varint_too_long_exception();
+ }
+
+ return result;
+}
+
+template <typename T>
+T pbf::svarint() {
+ T n = varint<T>();
+ return (n >> 1) ^ -(T)(n & 1);
+}
+
+template <typename T, int bytes>
+T pbf::fixed() {
+ skipBytes(bytes);
+ T result;
+ memcpy(&result, data - bytes, bytes);
+ return result;
+}
+
+float pbf::float32() {
+ return fixed<float, 4>();
+}
+
+double pbf::float64() {
+ return fixed<double, 8>();
+}
+
+std::string pbf::string() {
+ uint32_t bytes = static_cast<uint32_t>(varint());
+ const char *string_data = reinterpret_cast<const char*>(data);
+ skipBytes(bytes);
+ return std::string(string_data, bytes);
+}
+
+bool pbf::boolean() {
+ skipBytes(1);
+ return *(bool *)(data - 1);
+}
+
+pbf pbf::message() {
+ uint32_t bytes = static_cast<uint32_t>(varint());
+ const uint8_t *pos = data;
+ skipBytes(bytes);
+ return pbf(pos, bytes);
+}
+
+void pbf::skip() {
+ skipValue(value);
+}
+
+void pbf::skipValue(uint32_t val) {
+ switch (val & 0x7) {
+ case 0: // varint
+ varint();
+ break;
+ case 1: // 64 bit
+ skipBytes(8);
+ break;
+ case 2: // string/message
+ skipBytes(static_cast<uint32_t>(varint()));
+ break;
+ case 5: // 32 bit
+ skipBytes(4);
+ break;
+ default:
+ throw unknown_field_type_exception();
+ }
+}
+
+void pbf::skipBytes(uint32_t bytes) {
+ if (data + bytes > end) {
+ throw end_of_buffer_exception();
+ }
+ data += bytes;
+}
+
+} // end namespace mbgl
+
+#endif
diff --git a/src/mbgl/util/queue.h b/src/mbgl/util/queue.h
new file mode 100644
index 0000000000..fe02b454ea
--- /dev/null
+++ b/src/mbgl/util/queue.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+typedef void *QUEUE[2];
+
+/* Private macros. */
+#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
+#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
+#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
+#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
+
+/* Public macros. */
+#define QUEUE_DATA(ptr, type, field) \
+ ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
+
+#define QUEUE_FOREACH(q, h) \
+ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
+
+#define QUEUE_EMPTY(q) \
+ ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
+
+#define QUEUE_HEAD(q) \
+ (QUEUE_NEXT(q))
+
+#define QUEUE_INIT(q) \
+ do { \
+ QUEUE_NEXT(q) = (q); \
+ QUEUE_PREV(q) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_ADD(h, n) \
+ do { \
+ QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
+ QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV(h) = QUEUE_PREV(n); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ } \
+ while (0)
+
+#define QUEUE_SPLIT(h, q, n) \
+ do { \
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(n) = (n); \
+ QUEUE_NEXT(n) = (q); \
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ QUEUE_PREV(q) = (n); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_HEAD(h, q) \
+ do { \
+ QUEUE_NEXT(q) = QUEUE_NEXT(h); \
+ QUEUE_PREV(q) = (h); \
+ QUEUE_NEXT_PREV(q) = (q); \
+ QUEUE_NEXT(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_TAIL(h, q) \
+ do { \
+ QUEUE_NEXT(q) = (h); \
+ QUEUE_PREV(q) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(q) = (q); \
+ QUEUE_PREV(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_REMOVE(q) \
+ do { \
+ QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
+ QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
+ } \
+ while (0)
+
+#endif /* QUEUE_H_ */
diff --git a/src/util/raster.cpp b/src/mbgl/util/raster.cpp
index 56461aec5f..56461aec5f 100644
--- a/src/util/raster.cpp
+++ b/src/mbgl/util/raster.cpp
diff --git a/src/mbgl/util/raster.hpp b/src/mbgl/util/raster.hpp
new file mode 100644
index 0000000000..ff27f509f4
--- /dev/null
+++ b/src/mbgl/util/raster.hpp
@@ -0,0 +1,74 @@
+#ifndef MBGL_UTIL_RASTER
+#define MBGL_UTIL_RASTER
+
+#include <mbgl/util/transition.hpp>
+#include <mbgl/util/texture_pool.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/ptr.hpp>
+#include <mbgl/renderer/prerendered_texture.hpp>
+
+#include <string>
+#include <mutex>
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace mbgl {
+
+class Raster : public std::enable_shared_from_this<Raster> {
+
+public:
+ Raster(TexturePool&);
+ ~Raster();
+
+ // load image data
+ bool load(const std::string &img);
+
+ // bind current texture
+ void bind(bool linear = false);
+
+ // bind prerendered texture
+ void bind(const GLuint texture);
+
+ // loaded status
+ bool isLoaded() const;
+
+ // transitions
+ void beginFadeInTransition();
+ bool needsTransition() const;
+ void updateTransitions(timestamp now);
+
+public:
+ // loaded image dimensions
+ uint32_t width = 0, height = 0;
+
+ // has been uploaded to texture
+ bool textured = false;
+
+ // the uploaded texture
+ uint32_t texture = 0;
+
+ // texture opacity
+ double opacity = 0;
+
+private:
+ mutable std::mutex mtx;
+
+ // raw pixels have been loaded
+ bool loaded = false;
+
+ // shared texture pool
+ TexturePool& texturePool;
+
+ // min/mag filter
+ uint32_t filter = 0;
+
+ // the raw pixels
+ std::unique_ptr<util::Image> img;
+
+ // fade in transition
+ util::ptr<util::transition> fade_transition = nullptr;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/util/rect.hpp b/src/mbgl/util/rect.hpp
new file mode 100644
index 0000000000..f5c77f93d1
--- /dev/null
+++ b/src/mbgl/util/rect.hpp
@@ -0,0 +1,22 @@
+#ifndef MBGL_UTIL_RECT
+#define MBGL_UTIL_RECT
+
+namespace mbgl {
+
+template <typename T>
+struct Rect {
+ inline Rect() {}
+ inline Rect(T x_, T y_, T w_, T h_) : x(x_), y(y_), w(w_), h(h_) {}
+ T x = 0, y = 0;
+ T w = 0, h = 0;
+
+ template <typename Number>
+ Rect operator *(Number value) const {
+ return Rect(x * value, y * value, w * value, h * value);
+ }
+
+ operator bool() const { return w != 0 && h != 0; }
+};
+}
+
+#endif
diff --git a/src/util/sqlite3.cpp b/src/mbgl/util/sqlite3.cpp
index 787db83992..787db83992 100644
--- a/src/util/sqlite3.cpp
+++ b/src/mbgl/util/sqlite3.cpp
diff --git a/src/mbgl/util/sqlite3.hpp b/src/mbgl/util/sqlite3.hpp
new file mode 100644
index 0000000000..3e324f7ce1
--- /dev/null
+++ b/src/mbgl/util/sqlite3.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <string>
+#include <stdexcept>
+
+typedef struct sqlite3 sqlite3;
+typedef struct sqlite3_stmt sqlite3_stmt;
+
+namespace mapbox {
+namespace sqlite {
+
+enum OpenFlag : int {
+ ReadOnly = 0x00000001,
+ ReadWrite = 0x00000002,
+ Create = 0x00000004,
+ NoMutex = 0x00008000,
+ FullMutex = 0x00010000,
+ SharedCache = 0x00020000,
+ PrivateCache = 0x00040000,
+};
+
+struct Exception : std::runtime_error {
+ inline Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {}
+ const int code = 0;
+};
+
+class Statement;
+
+class Database {
+private:
+ Database(const Database &) = delete;
+ Database &operator=(const Database &) = delete;
+
+public:
+ Database(const std::string &filename, int flags = 0);
+ Database(Database &&);
+ ~Database();
+ Database &operator=(Database &&);
+
+ operator bool() const;
+
+ void exec(const std::string &sql);
+ Statement prepare(const char *query);
+
+private:
+ sqlite3 *db = nullptr;
+};
+
+class Statement {
+private:
+ Statement(const Statement &) = delete;
+ Statement &operator=(const Statement &) = delete;
+
+public:
+ Statement(sqlite3 *db, const char *sql);
+ Statement(Statement &&);
+ ~Statement();
+ Statement &operator=(Statement &&);
+
+ operator bool() const;
+
+ template <typename T> void bind(int offset, T value);
+ void bind(int offset, const std::string &value, bool retain = true);
+ template <typename T> T get(int offset);
+
+ bool run();
+ void reset();
+
+private:
+ sqlite3_stmt *stmt = nullptr;
+};
+
+}
+}
diff --git a/src/util/stopwatch.cpp b/src/mbgl/util/stopwatch.cpp
index c9b8756e3b..14b4f4018b 100644
--- a/src/util/stopwatch.cpp
+++ b/src/mbgl/util/stopwatch.cpp
@@ -1,6 +1,7 @@
#ifndef DISABLE_STOPWATCH
#include <mbgl/util/stopwatch.hpp>
#include <mbgl/util/time.hpp>
+#include <mbgl/util/string.hpp>
#include <mbgl/platform/log.hpp>
#include <iostream>
@@ -23,7 +24,7 @@ stopwatch::stopwatch(const std::string &name_, EventSeverity severity_, Event ev
void stopwatch::report(const std::string &name_) {
timestamp duration = now() - start;
- Log::Record(severity, event, name_ + ": " + std::to_string((double)(duration) / 1_millisecond) + "ms");
+ Log::Record(severity, event, name_ + ": " + util::toString(double(duration) / 1_millisecond) + "ms");
start += duration;
}
diff --git a/src/mbgl/util/stopwatch.hpp b/src/mbgl/util/stopwatch.hpp
new file mode 100644
index 0000000000..663bbb6fc7
--- /dev/null
+++ b/src/mbgl/util/stopwatch.hpp
@@ -0,0 +1,40 @@
+#ifndef MBGL_UTIL_STOPWATCH
+#define MBGL_UTIL_STOPWATCH
+
+#include <mbgl/platform/event.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+#ifndef DISABLE_STOPWATCH
+class stopwatch {
+public:
+ stopwatch(Event event = Event::General);
+ stopwatch(EventSeverity severity, Event event = Event::General);
+ stopwatch(const std::string &name, Event event = Event::General);
+ stopwatch(const std::string &name, EventSeverity severity, Event event = Event::General);
+ void report(const std::string &name);
+ ~stopwatch();
+
+private:
+ const std::string name;
+ EventSeverity severity = EventSeverity::Debug;
+ Event event = Event::General;
+ uint64_t start;
+};
+#else
+class stopwatch {
+ inline stopwatch(Event event = Event::General);
+ inline stopwatch(EventSeverity severity, Event event = Event::General);
+ inline stopwatch(const std::string &name, Event event = Event::General);
+ inline stopwatch(const std::string &name, EventSeverity severity, Event event = Event::General);
+ inline void report(const std::string &name) {}
+ inline ~stopwatch() {}
+};
+#endif
+}
+}
+
+#endif
diff --git a/src/util/texture_pool.cpp b/src/mbgl/util/texture_pool.cpp
index 9c8c24b085..9c8c24b085 100644
--- a/src/util/texture_pool.cpp
+++ b/src/mbgl/util/texture_pool.cpp
diff --git a/src/mbgl/util/texture_pool.hpp b/src/mbgl/util/texture_pool.hpp
new file mode 100644
index 0000000000..95d918c237
--- /dev/null
+++ b/src/mbgl/util/texture_pool.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_UTIL_TEXTUREPOOL
+#define MBGL_UTIL_TEXTUREPOOL
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/platform/gl.hpp>
+
+#include <set>
+#include <mutex>
+
+namespace mbgl {
+
+class TexturePool : private util::noncopyable {
+
+public:
+ GLuint getTextureID();
+ void removeTextureID(GLuint texture_id);
+ void clearTextureIDs();
+
+private:
+ std::set<GLuint> texture_ids;
+};
+
+}
+
+#endif
diff --git a/src/util/time.cpp b/src/mbgl/util/time.cpp
index 1953975b18..1953975b18 100644
--- a/src/util/time.cpp
+++ b/src/mbgl/util/time.cpp
diff --git a/src/mbgl/util/token.hpp b/src/mbgl/util/token.hpp
new file mode 100644
index 0000000000..64192a99f9
--- /dev/null
+++ b/src/mbgl/util/token.hpp
@@ -0,0 +1,50 @@
+#ifndef MBGL_UTIL_TOKEN
+#define MBGL_UTIL_TOKEN
+
+#include <map>
+#include <string>
+#include <algorithm>
+
+namespace mbgl {
+namespace util {
+
+// Replaces {tokens} in a string by calling the lookup function.
+template <typename Lookup>
+std::string replaceTokens(const std::string &source, const Lookup &lookup) {
+ std::string result;
+ result.reserve(source.size());
+
+ auto pos = source.begin();
+ const auto end = source.end();
+
+ while (pos != end) {
+ auto brace = std::find(pos, end, '{');
+ result.append(pos, brace);
+ pos = brace;
+ if (pos != end) {
+ for (brace++; brace != end && (std::isalnum(*brace) || *brace == '_'); brace++);
+ if (brace != end && *brace == '}') {
+ result.append(lookup({ pos + 1, brace }));
+ pos = brace + 1;
+ } else {
+ result.append(pos, brace);
+ pos = brace;
+ }
+ }
+ }
+
+ return result;
+}
+
+template <typename T>
+inline std::string replaceTokens(const std::string &source, const std::map<std::string, T> &properties) {
+ return replaceTokens(source, [&properties](const std::string &token) -> std::string {
+ const auto it_prop = properties.find(token);
+ return it_prop != properties.end() ? toString(it_prop->second) : "";
+ });
+}
+
+} // end namespace util
+} // end namespace mbgl
+
+#endif
diff --git a/src/util/transition.cpp b/src/mbgl/util/transition.cpp
index e63a5c311f..e63a5c311f 100644
--- a/src/util/transition.cpp
+++ b/src/mbgl/util/transition.cpp
diff --git a/src/mbgl/util/transition.hpp b/src/mbgl/util/transition.hpp
new file mode 100644
index 0000000000..d6bbc9eba0
--- /dev/null
+++ b/src/mbgl/util/transition.hpp
@@ -0,0 +1,77 @@
+#ifndef MBGL_UTIL_TRANSITION
+#define MBGL_UTIL_TRANSITION
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/time.hpp>
+
+namespace mbgl {
+namespace util {
+
+class transition : private noncopyable {
+public:
+ enum state {
+ running,
+ complete
+ };
+
+ inline transition(timestamp start_, timestamp duration_)
+ : start(start_),
+ duration(duration_) {}
+
+ inline float progress(timestamp now) const {
+ if (duration == 0) return 1;
+ if (start > now) return 0;
+
+ return (float)(now - start) / duration;
+ }
+
+ virtual state update(timestamp now) const = 0;
+ virtual ~transition();
+
+protected:
+ const timestamp start, duration;
+};
+
+template <typename T>
+class ease_transition : public transition {
+public:
+ ease_transition(T from_, T to_, T& value_, timestamp start_, timestamp duration_)
+ : transition(start_, duration_),
+ from(from_),
+ to(to_),
+ value(value_) {}
+
+ state update(timestamp now) const;
+
+private:
+ const T from, to;
+ T& value;
+
+};
+
+template <typename T>
+class timeout : public transition {
+public:
+ timeout(T final_value_, T& value_, timestamp start_, timestamp duration_)
+ : transition(start_, duration_),
+ final_value(final_value_),
+ value(value_) {}
+
+ state update(timestamp now) const {
+ if (progress(now) >= 1) {
+ value = final_value;
+ return complete;
+ } else {
+ return running;
+ }
+ }
+
+private:
+ const T final_value;
+ T& value;
+};
+
+}
+}
+
+#endif
diff --git a/src/mbgl/util/unitbezier.hpp b/src/mbgl/util/unitbezier.hpp
new file mode 100644
index 0000000000..095e15f809
--- /dev/null
+++ b/src/mbgl/util/unitbezier.hpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MBGL_UTIL_UNITBEZIER
+#define MBGL_UTIL_UNITBEZIER
+
+#include <cmath>
+
+namespace mbgl {
+namespace util {
+
+struct UnitBezier {
+ UnitBezier(double p1x, double p1y, double p2x, double p2y) {
+ // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
+ cx = 3.0 * p1x;
+ bx = 3.0 * (p2x - p1x) - cx;
+ ax = 1.0 - cx - bx;
+
+ cy = 3.0 * p1y;
+ by = 3.0 * (p2y - p1y) - cy;
+ ay = 1.0 - cy - by;
+ }
+
+ double sampleCurveX(double t) {
+ // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
+ return ((ax * t + bx) * t + cx) * t;
+ }
+
+ double sampleCurveY(double t) {
+ return ((ay * t + by) * t + cy) * t;
+ }
+
+ double sampleCurveDerivativeX(double t) {
+ return (3.0 * ax * t + 2.0 * bx) * t + cx;
+ }
+
+ // Given an x value, find a parametric value it came from.
+ double solveCurveX(double x, double epsilon) {
+ double t0;
+ double t1;
+ double t2;
+ double x2;
+ double d2;
+ int i;
+
+ // First try a few iterations of Newton's method -- normally very fast.
+ for (t2 = x, i = 0; i < 8; ++i) {
+ x2 = sampleCurveX(t2) - x;
+ if (fabs (x2) < epsilon)
+ return t2;
+ d2 = sampleCurveDerivativeX(t2);
+ if (fabs(d2) < 1e-6)
+ break;
+ t2 = t2 - x2 / d2;
+ }
+
+ // Fall back to the bisection method for reliability.
+ t0 = 0.0;
+ t1 = 1.0;
+ t2 = x;
+
+ if (t2 < t0)
+ return t0;
+ if (t2 > t1)
+ return t1;
+
+ while (t0 < t1) {
+ x2 = sampleCurveX(t2);
+ if (fabs(x2 - x) < epsilon)
+ return t2;
+ if (x > x2)
+ t0 = t2;
+ else
+ t1 = t2;
+ t2 = (t1 - t0) * .5 + t0;
+ }
+
+ // Failure.
+ return t2;
+ }
+
+ double solve(double x, double epsilon) {
+ return sampleCurveY(solveCurveX(x, epsilon));
+ }
+
+private:
+ double ax;
+ double bx;
+ double cx;
+
+ double ay;
+ double by;
+ double cy;
+};
+
+}
+}
+
+#endif
diff --git a/src/util/url.cpp b/src/mbgl/util/url.cpp
index e9b9672109..e9b9672109 100644
--- a/src/util/url.cpp
+++ b/src/mbgl/util/url.cpp
diff --git a/src/mbgl/util/url.hpp b/src/mbgl/util/url.hpp
new file mode 100644
index 0000000000..a7e5291ec5
--- /dev/null
+++ b/src/mbgl/util/url.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_UTIL_URL
+#define MBGL_UTIL_URL
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+std::string percentEncode(const std::string&);
+std::string percentDecode(const std::string&);
+
+}
+}
+
+#endif
diff --git a/src/mbgl/util/utf.hpp b/src/mbgl/util/utf.hpp
new file mode 100644
index 0000000000..d6ba2a1f2f
--- /dev/null
+++ b/src/mbgl/util/utf.hpp
@@ -0,0 +1,24 @@
+#ifndef MBGL_UTIL_UTF
+#define MBGL_UTIL_UTF
+
+#include <memory>
+
+#include <boost/regex/pending/unicode_iterator.hpp>
+
+namespace mbgl {
+
+namespace util {
+
+class utf8_to_utf32 {
+ public:
+ static std::u32string convert(std::string const& utf8)
+ {
+ boost::u8_to_u32_iterator<std::string::const_iterator> begin(utf8.begin());
+ boost::u8_to_u32_iterator<std::string::const_iterator> end(utf8.end());
+ return std::u32string(begin,end);
+ }
+};
+
+}}
+
+#endif
diff --git a/src/util/uv-channel.c b/src/mbgl/util/uv-channel.c
index 4e3b9fa5ff..4e3b9fa5ff 100644
--- a/src/util/uv-channel.c
+++ b/src/mbgl/util/uv-channel.c
diff --git a/src/mbgl/util/uv-channel.h b/src/mbgl/util/uv-channel.h
new file mode 100644
index 0000000000..ea5c279f65
--- /dev/null
+++ b/src/mbgl/util/uv-channel.h
@@ -0,0 +1,29 @@
+#ifndef MBGL_UTIL_UV_CHANNEL
+#define MBGL_UTIL_UV_CHANNEL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <uv.h>
+
+// Taken from http://navaneeth.github.io/blog/2013/08/02/channels-in-libuv/
+
+typedef struct uv_chan_s uv_chan_t;
+
+struct uv_chan_s {
+ uv_mutex_t mutex;
+ uv_cond_t cond;
+ void *q[2];
+};
+
+int uv_chan_init(uv_chan_t *chan);
+void uv_chan_send(uv_chan_t *chan, void *data);
+void *uv_chan_receive(uv_chan_t *chan);
+void uv_chan_destroy(uv_chan_t *chan);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/util/uv-messenger.c b/src/mbgl/util/uv-messenger.c
index 935b6f1c41..935b6f1c41 100644
--- a/src/util/uv-messenger.c
+++ b/src/mbgl/util/uv-messenger.c
diff --git a/src/util/uv-worker.c b/src/mbgl/util/uv-worker.c
index d2aa908019..d2aa908019 100644
--- a/src/util/uv-worker.c
+++ b/src/mbgl/util/uv-worker.c
diff --git a/src/mbgl/util/uv-worker.h b/src/mbgl/util/uv-worker.h
new file mode 100644
index 0000000000..cb2075d1c3
--- /dev/null
+++ b/src/mbgl/util/uv-worker.h
@@ -0,0 +1,41 @@
+#ifndef MBGL_UTIL_UV_WORKER
+#define MBGL_UTIL_UV_WORKER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <mbgl/util/uv-messenger.h>
+#include <mbgl/util/uv-channel.h>
+
+#include <stdlib.h>
+
+typedef struct uv_worker_s uv_worker_t;
+
+typedef void (*uv_worker_cb)(void *data);
+typedef void (*uv_worker_after_cb)(void *data);
+typedef void (*uv_worker_close_cb)(uv_worker_t *worker);
+
+struct uv_worker_s {
+#ifndef NDEBUG
+ unsigned long thread_id;
+#endif
+ uv_loop_t *loop;
+ uv_messenger_t *msgr;
+ uv_chan_t chan;
+ const char *name;
+ int count;
+ uv_worker_close_cb close_cb;
+ unsigned int active_items;
+};
+
+int uv_worker_init(uv_worker_t *worker, uv_loop_t *loop, int count, const char *name);
+void uv_worker_send(uv_worker_t *worker, void *data, uv_worker_cb work_cb,
+ uv_worker_after_cb after_work_cb);
+void uv_worker_close(uv_worker_t *worker, uv_worker_close_cb close_cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/util/uv.cpp b/src/mbgl/util/uv.cpp
index 7aa5bad0cf..7aa5bad0cf 100644
--- a/src/util/uv.cpp
+++ b/src/mbgl/util/uv.cpp
diff --git a/src/mbgl/util/uv_detail.hpp b/src/mbgl/util/uv_detail.hpp
new file mode 100644
index 0000000000..99f5edc145
--- /dev/null
+++ b/src/mbgl/util/uv_detail.hpp
@@ -0,0 +1,177 @@
+#ifndef MBGL_UTIL_UV_DETAIL
+#define MBGL_UTIL_UV_DETAIL
+
+#include <mbgl/util/uv-worker.h>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <uv.h>
+
+#include <functional>
+#include <cassert>
+#include <memory>
+#include <string>
+
+namespace uv {
+
+template <class T>
+void close(std::unique_ptr<T> ptr) {
+ uv_close(reinterpret_cast<uv_handle_t*>(ptr.release()), [](uv_handle_t* handle) {
+ delete reinterpret_cast<T*>(handle);
+ });
+}
+
+class loop : public mbgl::util::noncopyable {
+public:
+ inline loop() {
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
+ l = uv_loop_new();
+ if (l == nullptr) {
+#else
+ l = new uv_loop_t;
+ if (uv_loop_init(l) != 0) {
+#endif
+ throw std::runtime_error("failed to initialize loop");
+ }
+ }
+
+ inline ~loop() {
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
+ uv_loop_delete(l);
+#else
+ uv_loop_close(l);
+ delete l;
+#endif
+
+ }
+
+ inline uv_loop_t *operator*() { return l; }
+
+private:
+ uv_loop_t *l = nullptr;
+};
+
+class async : public mbgl::util::noncopyable {
+public:
+ inline async(uv_loop_t* loop, std::function<void ()> fn_)
+ : a(new uv_async_t)
+ , fn(fn_)
+ {
+ a->data = this;
+ if (uv_async_init(loop, a.get(), async_cb) != 0) {
+ throw std::runtime_error("failed to initialize async");
+ }
+ }
+
+ inline ~async() {
+ close(std::move(a));
+ }
+
+ inline void send() {
+ if (uv_async_send(a.get()) != 0) {
+ throw std::runtime_error("failed to async send");
+ }
+ }
+
+private:
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
+ static void async_cb(uv_async_t* a, int) {
+#else
+ static void async_cb(uv_async_t* a) {
+#endif
+ reinterpret_cast<async*>(a->data)->fn();
+ }
+
+ std::unique_ptr<uv_async_t> a;
+ std::function<void ()> fn;
+};
+
+class rwlock : public mbgl::util::noncopyable {
+public:
+ inline rwlock() {
+ if (uv_rwlock_init(&mtx) != 0) {
+ throw std::runtime_error("failed to initialize read-write lock");
+ }
+ }
+ inline ~rwlock() { uv_rwlock_destroy(&mtx); }
+ inline void rdlock() { uv_rwlock_rdlock(&mtx); }
+ inline void wrlock() { uv_rwlock_wrlock(&mtx); }
+ inline void rdunlock() { uv_rwlock_rdunlock(&mtx); }
+ inline void wrunlock() { uv_rwlock_wrunlock(&mtx); }
+
+private:
+ uv_rwlock_t mtx;
+};
+
+class readlock : public mbgl::util::noncopyable {
+public:
+ inline readlock(rwlock &mtx_) : mtx(mtx_) { mtx.rdlock(); }
+ inline readlock(const std::unique_ptr<rwlock> &mtx_) : mtx(*mtx_) { mtx.rdlock(); }
+ inline ~readlock() { mtx.rdunlock(); }
+
+private:
+ rwlock &mtx;
+};
+
+class writelock : public mbgl::util::noncopyable {
+public:
+ inline writelock(rwlock &mtx_) : mtx(mtx_) { mtx.wrlock(); }
+ inline writelock(const std::unique_ptr<rwlock> &mtx_) : mtx(*mtx_) { mtx.wrlock(); }
+ inline ~writelock() { mtx.wrunlock(); }
+
+private:
+ rwlock &mtx;
+};
+
+class worker : public mbgl::util::noncopyable {
+public:
+ inline worker(uv_loop_t *loop, unsigned int count, const char *name = nullptr) : w(new uv_worker_t) {
+ uv_worker_init(w, loop, count, name);
+ }
+ inline ~worker() {
+ uv_worker_close(w, [](uv_worker_t *worker_) {
+ delete worker_;
+ });
+ }
+ inline void add(void *data, uv_worker_cb work_cb, uv_worker_after_cb after_work_cb) {
+ uv_worker_send(w, data, work_cb, after_work_cb);
+ }
+
+private:
+ uv_worker_t *w;
+};
+
+template <typename T>
+class work : public mbgl::util::noncopyable {
+public:
+ typedef std::function<void (T&)> work_callback;
+ typedef std::function<void (T&)> after_work_callback;
+
+ template<typename... Args>
+ work(worker &worker, work_callback work_cb_, after_work_callback after_work_cb_, Args&&... args)
+ : data(std::forward<Args>(args)...),
+ work_cb(work_cb_),
+ after_work_cb(after_work_cb_) {
+ worker.add(this, do_work, after_work);
+ }
+
+private:
+ static void do_work(void *data) {
+ work<T> *w = reinterpret_cast<work<T> *>(data);
+ w->work_cb(w->data);
+ }
+
+ static void after_work(void *data) {
+ work<T> *w = reinterpret_cast<work<T> *>(data);
+ w->after_work_cb(w->data);
+ delete w;
+ }
+
+private:
+ T data;
+ work_callback work_cb;
+ after_work_callback after_work_cb;
+};
+
+}
+
+#endif
diff --git a/src/rapidjson/document.h b/src/rapidjson/document.h
new file mode 100755
index 0000000000..83d95a33d0
--- /dev/null
+++ b/src/rapidjson/document.h
@@ -0,0 +1,821 @@
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+#include "reader.h"
+#include "internal/strfunc.h"
+#include <new> // placement new
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+ A JSON value can be one of 7 types. This class is a variant type supporting
+ these types.
+
+ Use the Value if UTF8 and default allocator
+
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+*/
+#pragma pack (push, 4)
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+public:
+ //! Name-value pair in an object.
+ struct Member {
+ GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
+ GenericValue<Encoding, Allocator> value; //!< value of member.
+ };
+
+ typedef Encoding EncodingType; //!< Encoding type from template parameter.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef Member* MemberIterator; //!< Member iterator for iterating in object.
+ typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object.
+ typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
+ typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor creates a null value.
+ GenericValue() : flags_(kNullFlag) {}
+
+ //! Copy constructor is not permitted.
+private:
+ GenericValue(const GenericValue& rhs);
+
+public:
+
+ //! Constructor with JSON value type.
+ /*! This creates a Value of specified type with default content.
+ \param type Type of the value.
+ \note Default content for number is zero.
+ */
+ GenericValue(Type type) {
+ static const unsigned defaultFlags[7] = {
+ kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
+ kNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag
+ };
+ RAPIDJSON_ASSERT(type <= kNumberType);
+ flags_ = defaultFlags[type];
+ memset(&data_, 0, sizeof(data_));
+ }
+
+ //! Constructor for boolean value.
+ GenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {}
+
+ //! Constructor for int value.
+ GenericValue(int i) : flags_(kNumberIntFlag) {
+ data_.n.i64 = i;
+ if (i >= 0)
+ flags_ |= kUintFlag | kUint64Flag;
+ }
+
+ //! Constructor for unsigned value.
+ GenericValue(unsigned u) : flags_(kNumberUintFlag) {
+ data_.n.u64 = u;
+ if (!(u & 0x80000000))
+ flags_ |= kIntFlag | kInt64Flag;
+ }
+
+ //! Constructor for int64_t value.
+ GenericValue(int64_t i64) : flags_(kNumberInt64Flag) {
+ data_.n.i64 = i64;
+ if (i64 >= 0) {
+ flags_ |= kNumberUint64Flag;
+ if (!(i64 & 0xFFFFFFFF00000000LL))
+ flags_ |= kUintFlag;
+ if (!(i64 & 0xFFFFFFFF80000000LL))
+ flags_ |= kIntFlag;
+ }
+ else if (i64 >= -2147483648LL)
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for uint64_t value.
+ GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) {
+ data_.n.u64 = u64;
+ if (!(u64 & 0x8000000000000000ULL))
+ flags_ |= kInt64Flag;
+ if (!(u64 & 0xFFFFFFFF00000000ULL))
+ flags_ |= kUintFlag;
+ if (!(u64 & 0xFFFFFFFF80000000ULL))
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for double value.
+ GenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s, SizeType length) {
+ RAPIDJSON_ASSERT(s != NULL);
+ flags_ = kConstStringFlag;
+ data_.s.str = s;
+ data_.s.length = length;
+ }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); }
+
+ //! Destructor.
+ /*! Need to destruct elements of array, members of object, or copy-string.
+ */
+ ~GenericValue() {
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ switch(flags_) {
+ case kArrayFlag:
+ for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ v->~GenericValue();
+ Allocator::Free(data_.a.elements);
+ break;
+
+ case kObjectFlag:
+ for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
+ m->name.~GenericValue();
+ m->value.~GenericValue();
+ }
+ Allocator::Free(data_.o.members);
+ break;
+
+ case kCopyStringFlag:
+ Allocator::Free(const_cast<Ch*>(data_.s.str));
+ break;
+ }
+ }
+ }
+
+ //@}
+
+ //!@name Assignment operators
+ //@{
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. It will become a null value after assignment.
+ */
+ GenericValue& operator=(GenericValue& rhs) {
+ RAPIDJSON_ASSERT(this != &rhs);
+ this->~GenericValue();
+ memcpy(this, &rhs, sizeof(GenericValue));
+ rhs.flags_ = kNullFlag;
+ return *this;
+ }
+
+ //! Assignment with primitive types.
+ /*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch*
+ \param value The value to be assigned.
+ */
+ template <typename T>
+ GenericValue& operator=(T value) {
+ this->~GenericValue();
+ new (this) GenericValue(value);
+ return *this;
+ }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
+ bool IsNull() const { return flags_ == kNullFlag; }
+ bool IsFalse() const { return flags_ == kFalseFlag; }
+ bool IsTrue() const { return flags_ == kTrueFlag; }
+ bool IsBool() const { return (flags_ & kBoolFlag) != 0; }
+ bool IsObject() const { return flags_ == kObjectFlag; }
+ bool IsArray() const { return flags_ == kArrayFlag; }
+ bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
+ bool IsInt() const { return (flags_ & kIntFlag) != 0; }
+ bool IsUint() const { return (flags_ & kUintFlag) != 0; }
+ bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
+ bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
+ bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
+ bool IsString() const { return (flags_ & kStringFlag) != 0; }
+
+ //@}
+
+ //!@name Null
+ //@{
+
+ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+ //@}
+
+ //!@name Bool
+ //@{
+
+ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
+ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+ //@}
+
+ //!@name Object
+ //@{
+
+ //! Set this value as an empty object.
+ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+ //! Get the value associated with the object's name.
+ GenericValue& operator[](const Ch* name) {
+ if (Member* member = FindMember(name))
+ return member->value;
+ else {
+ static GenericValue NullValue;
+ return NullValue;
+ }
+ }
+ const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+ //! Member iterators.
+ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
+ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
+ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
+ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
+
+ //! Check whether a member exists in the object.
+ bool HasMember(const Ch* name) const { return FindMember(name) != 0; }
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory.
+ \return The value itself for fluent API.
+ \note The ownership of name and value will be transfered to this object if success.
+ */
+ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+ Object& o = data_.o;
+ if (o.size >= o.capacity) {
+ if (o.capacity == 0) {
+ o.capacity = kDefaultObjectCapacity;
+ o.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member));
+ }
+ else {
+ SizeType oldCapacity = o.capacity;
+ o.capacity *= 2;
+ o.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member));
+ }
+ }
+ o.members[o.size].name.RawAssign(name);
+ o.members[o.size].value.RawAssign(value);
+ o.size++;
+ return *this;
+ }
+
+ GenericValue& AddMember(const Ch* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name, internal::StrLen(name), nameAllocator);
+ return AddMember(n, value, allocator);
+ }
+
+ GenericValue& AddMember(const Ch* name, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name, internal::StrLen(name));
+ return AddMember(n, value, allocator);
+ }
+
+ template <typename T>
+ GenericValue& AddMember(const Ch* name, T value, Allocator& allocator) {
+ GenericValue n(name, internal::StrLen(name));
+ GenericValue v(value);
+ return AddMember(n, v, allocator);
+ }
+
+ //! Remove a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note Removing member is implemented by moving the last member. So the ordering of members is changed.
+ */
+ bool RemoveMember(const Ch* name) {
+ RAPIDJSON_ASSERT(IsObject());
+ if (Member* m = FindMember(name)) {
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(data_.o.members != 0);
+
+ Member* last = data_.o.members + (data_.o.size - 1);
+ if (data_.o.size > 1 && m != last) {
+ // Move the last one to this place
+ m->name = last->name;
+ m->value = last->value;
+ }
+ else {
+ // Only one left, just destroy
+ m->name.~GenericValue();
+ m->value.~GenericValue();
+ }
+ --data_.o.size;
+ return true;
+ }
+ return false;
+ }
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Set this value as an empty array.
+ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+ //! Get the number of elements in array.
+ SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+ //! Get the capacity of array.
+ SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+ //! Check whether the array is empty.
+ bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+ //! Remove all elements in the array.
+ /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+ */
+ void Clear() {
+ RAPIDJSON_ASSERT(IsArray());
+ for (SizeType i = 0; i < data_.a.size; ++i)
+ data_.a.elements[i].~GenericValue();
+ data_.a.size = 0;
+ }
+
+ //! Get an element from array by index.
+ /*! \param index Zero-based index of element.
+ \note
+\code
+Value a(kArrayType);
+a.PushBack(123);
+int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
+int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
+int z = a[0u].GetInt(); // This works too.
+\endcode
+ */
+ GenericValue& operator[](SizeType index) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(index < data_.a.size);
+ return data_.a.elements[index];
+ }
+ const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+ //! Element iterator
+ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
+ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
+ ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+ ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+ //! Request the array to have enough capacity to store elements.
+ /*! \param newCapacity The capacity that the array at least need to have.
+ \param allocator The allocator for allocating memory. It must be the same one use previously.
+ \return The value itself for fluent API.
+ */
+ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (newCapacity > data_.a.capacity) {
+ data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
+ data_.a.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Append a value at the end of the array.
+ /*! \param value The value to be appended.
+ \param allocator The allocator for allocating memory. It must be the same one use previously.
+ \return The value itself for fluent API.
+ \note The ownership of the value will be transfered to this object if success.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ */
+ GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (data_.a.size >= data_.a.capacity)
+ Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator);
+ data_.a.elements[data_.a.size++].RawAssign(value);
+ return *this;
+ }
+
+ template <typename T>
+ GenericValue& PushBack(T value, Allocator& allocator) {
+ GenericValue v(value);
+ return PushBack(v, allocator);
+ }
+
+ //! Remove the last element in the array.
+ GenericValue& PopBack() {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(!Empty());
+ data_.a.elements[--data_.a.size].~GenericValue();
+ return *this;
+ }
+ //@}
+
+ //!@name Number
+ //@{
+
+ int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; }
+ unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; }
+ int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
+ uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
+
+ double GetDouble() const {
+ RAPIDJSON_ASSERT(IsNumber());
+ if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
+ if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
+ if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
+ if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision)
+ }
+
+ GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
+ GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
+ GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
+ GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
+ GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
+
+ //! Get the length of string.
+ /*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+ */
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; }
+
+ //! Set this value as a string without copying source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string pointer.
+ \param length The length of source string, excluding the trailing null terminator.
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; }
+
+ //! Set this value as a string without copying source string.
+ /*! \param s source string pointer.
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); }
+
+ //! Set this value as a string by copying from source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string.
+ \param length The length of source string, excluding the trailing null terminator.
+ \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { SetString(s, internal::StrLen(s), allocator); return *this; }
+
+ //@}
+
+ //! Generate events of this value to a Handler.
+ /*! This function adopts the GoF visitor pattern.
+ Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+ It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+ \tparam Handler type of handler.
+ \param handler An object implementing concept Handler.
+ */
+ template <typename Handler>
+ const GenericValue& Accept(Handler& handler) const {
+ switch(GetType()) {
+ case kNullType: handler.Null(); break;
+ case kFalseType: handler.Bool(false); break;
+ case kTrueType: handler.Bool(true); break;
+
+ case kObjectType:
+ handler.StartObject();
+ for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
+ handler.String(m->name.data_.s.str, m->name.data_.s.length, false);
+ m->value.Accept(handler);
+ }
+ handler.EndObject(data_.o.size);
+ break;
+
+ case kArrayType:
+ handler.StartArray();
+ for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ v->Accept(handler);
+ handler.EndArray(data_.a.size);
+ break;
+
+ case kStringType:
+ handler.String(data_.s.str, data_.s.length, false);
+ break;
+
+ case kNumberType:
+ if (IsInt()) handler.Int(data_.n.i.i);
+ else if (IsUint()) handler.Uint(data_.n.u.u);
+ else if (IsInt64()) handler.Int64(data_.n.i64);
+ else if (IsUint64()) handler.Uint64(data_.n.u64);
+ else handler.Double(data_.n.d);
+ break;
+ }
+ return *this;
+ }
+
+private:
+ template <typename, typename>
+ friend class GenericDocument;
+
+ enum {
+ kBoolFlag = 0x100,
+ kNumberFlag = 0x200,
+ kIntFlag = 0x400,
+ kUintFlag = 0x800,
+ kInt64Flag = 0x1000,
+ kUint64Flag = 0x2000,
+ kDoubleFlag = 0x4000,
+ kStringFlag = 0x100000,
+ kCopyFlag = 0x200000,
+
+ // Initial flags of different types.
+ kNullFlag = kNullType,
+ kTrueFlag = kTrueType | kBoolFlag,
+ kFalseFlag = kFalseType | kBoolFlag,
+ kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+ kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+ kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+ kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+ kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+ kConstStringFlag = kStringType | kStringFlag,
+ kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+ kObjectFlag = kObjectType,
+ kArrayFlag = kArrayType,
+
+ kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
+ };
+
+ static const SizeType kDefaultArrayCapacity = 16;
+ static const SizeType kDefaultObjectCapacity = 16;
+
+ struct String {
+ const Ch* str;
+ SizeType length;
+ unsigned hashcode; //!< reserved
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // By using proper binary layout, retrieval of different integer types do not need conversions.
+ union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+ struct I {
+ int i;
+ char padding[4];
+ }i;
+ struct U {
+ unsigned u;
+ char padding2[4];
+ }u;
+#else
+ struct I {
+ char padding[4];
+ int i;
+ }i;
+ struct U {
+ char padding2[4];
+ unsigned u;
+ }u;
+#endif
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ }; // 8 bytes
+
+ struct Object {
+ Member* members;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ struct Array {
+ GenericValue<Encoding, Allocator>* elements;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ union Data {
+ String s;
+ Number n;
+ Object o;
+ Array a;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ //! Find member by name.
+ Member* FindMember(const Ch* name) {
+ RAPIDJSON_ASSERT(name);
+ RAPIDJSON_ASSERT(IsObject());
+
+ SizeType length = internal::StrLen(name);
+
+ Object& o = data_.o;
+ for (Member* member = o.members; member != data_.o.members + data_.o.size; ++member)
+ if (length == member->name.data_.s.length && memcmp(member->name.data_.s.str, name, length * sizeof(Ch)) == 0)
+ return member;
+
+ return 0;
+ }
+ const Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+ // Initialize this value as array with initial data, without calling destructor.
+ void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {
+ flags_ = kArrayFlag;
+ data_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue));
+ memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+ data_.a.size = data_.a.capacity = count;
+ }
+
+ //! Initialize this value as object with initial data, without calling destructor.
+ void SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) {
+ flags_ = kObjectFlag;
+ data_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member));
+ memcpy(data_.o.members, members, count * sizeof(Member));
+ data_.o.size = data_.o.capacity = count;
+ }
+
+ //! Initialize this value as constant string, without calling destructor.
+ void SetStringRaw(const Ch* s, SizeType length) {
+ RAPIDJSON_ASSERT(s != NULL);
+ flags_ = kConstStringFlag;
+ data_.s.str = s;
+ data_.s.length = length;
+ }
+
+ //! Initialize this value as copy string with initial data, without calling destructor.
+ void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) {
+ RAPIDJSON_ASSERT(s != NULL);
+ flags_ = kCopyStringFlag;
+ data_.s.str = (Ch *)allocator.Malloc((length + 1) * sizeof(Ch));
+ data_.s.length = length;
+ memcpy(const_cast<Ch*>(data_.s.str), s, length * sizeof(Ch));
+ const_cast<Ch*>(data_.s.str)[length] = '\0';
+ }
+
+ //! Assignment without calling destructor
+ void RawAssign(GenericValue& rhs) {
+ memcpy(this, &rhs, sizeof(GenericValue));
+ rhs.flags_ = kNullFlag;
+ }
+
+ Data data_;
+ unsigned flags_;
+};
+#pragma pack (pop)
+
+//! Value with UTF8 encoding.
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument
+
+//! A document for parsing JSON text as DOM.
+/*!
+ \implements Handler
+ \tparam Encoding encoding for both parsing and string storage.
+ \tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+
+ //! Constructor
+ /*! \param allocator Optional allocator for allocating stack memory.
+ \param stackCapacity Initial capacity of stack in bytes.
+ */
+ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
+
+ //! Parse JSON text from an input stream.
+ /*! \tparam parseFlags Combination of ParseFlag.
+ \param stream Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename Stream>
+ GenericDocument& ParseStream(Stream& stream) {
+ ValueType::SetNull(); // Remove existing root if exist
+ GenericReader<Encoding, Allocator> reader;
+ if (reader.template Parse<parseFlags>(stream, *this)) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
+ parseError_ = 0;
+ errorOffset_ = 0;
+ }
+ else {
+ parseError_ = reader.GetParseError();
+ errorOffset_ = reader.GetErrorOffset();
+ ClearStack();
+ }
+ return *this;
+ }
+
+ //! Parse JSON text from a mutable string.
+ /*! \tparam parseFlags Combination of ParseFlag.
+ \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& ParseInsitu(Ch* str) {
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag>(s);
+ }
+
+ //! Parse JSON text from a read-only string.
+ /*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ GenericStringStream<Encoding> s(str);
+ return ParseStream<parseFlags>(s);
+ }
+
+ //! Whether a parse error was occured in the last parsing.
+ bool HasParseError() const { return parseError_ != 0; }
+
+ //! Get the message of parsing error.
+ const char* GetParseError() const { return parseError_; }
+
+ //! Get the offset in character of the parsing error.
+ size_t GetErrorOffset() const { return errorOffset_; }
+
+ //! Get the allocator of this document.
+ Allocator& GetAllocator() { return stack_.GetAllocator(); }
+
+ //! Get the capacity of stack in bytes.
+ size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+ // Prohibit assignment
+ GenericDocument& operator=(const GenericDocument&);
+
+ friend class GenericReader<Encoding, Allocator>; // for Reader to call the following private handler functions
+
+ // Implementation of Handler
+ void Null() { new (stack_.template Push<ValueType>()) ValueType(); }
+ void Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); }
+ void Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); }
+
+ void String(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ }
+
+ void StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); }
+
+ void EndObject(SizeType memberCount) {
+ typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+ stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
+ }
+
+ void StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); }
+
+ void EndArray(SizeType elementCount) {
+ ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+ stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+ }
+
+ void ClearStack() {
+ if (Allocator::kNeedFree)
+ while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+ (stack_.template Pop<ValueType>(1))->~ValueType();
+ else
+ stack_.Clear();
+ }
+
+ static const size_t kDefaultStackCapacity = 1024;
+ internal::Stack<Allocator> stack_;
+ const char* parseError_;
+ size_t errorOffset_;
+};
+
+typedef GenericDocument<UTF8<> > Document;
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/src/rapidjson/filestream.h b/src/rapidjson/filestream.h
new file mode 100755
index 0000000000..885894963f
--- /dev/null
+++ b/src/rapidjson/filestream.h
@@ -0,0 +1,46 @@
+#ifndef RAPIDJSON_FILESTREAM_H_
+#define RAPIDJSON_FILESTREAM_H_
+
+#include <cstdio>
+
+namespace rapidjson {
+
+//! Wrapper of C file stream for input or output.
+/*!
+ This simple wrapper does not check the validity of the stream.
+ \implements Stream
+*/
+class FileStream {
+public:
+ typedef char Ch; //!< Character type. Only support char.
+
+ FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); }
+ char Peek() const { return current_; }
+ char Take() { char c = current_; Read(); return c; }
+ size_t Tell() const { return count_; }
+ void Put(char c) { fputc(c, fp_); }
+
+ // Not implemented
+ char* PutBegin() { return 0; }
+ size_t PutEnd(char*) { return 0; }
+
+private:
+ void Read() {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ int c = fgetc(fp_);
+ if (c != EOF) {
+ current_ = (char)c;
+ count_++;
+ }
+ else
+ current_ = '\0';
+ }
+
+ FILE* fp_;
+ char current_;
+ size_t count_;
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/src/rapidjson/internal/pow10.h b/src/rapidjson/internal/pow10.h
new file mode 100755
index 0000000000..bf3a9afb04
--- /dev/null
+++ b/src/rapidjson/internal/pow10.h
@@ -0,0 +1,54 @@
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+namespace rapidjson {
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+ \param n positive/negative exponent. Must <= 308.
+ \return 10.0^n
+*/
+inline double Pow10(int n) {
+ static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes
+ 1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,
+ 1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,
+ 1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,
+ 1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,
+ 1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,
+ 1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,
+ 1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,
+ 1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,
+ 1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,
+ 1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,
+ 1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,
+ 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80,
+ 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60,
+ 1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40,
+ 1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20,
+ 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0,
+ 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
+ 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+ 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+ 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+ 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+ 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+ 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+ 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+ 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+ 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+ 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+ 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+ 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+ 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+ 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+ };
+ RAPIDJSON_ASSERT(n <= 308);
+ return n < -308 ? 0.0 : e[n + 308];
+}
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_POW10_
diff --git a/src/rapidjson/internal/stack.h b/src/rapidjson/internal/stack.h
new file mode 100755
index 0000000000..966893b3fc
--- /dev/null
+++ b/src/rapidjson/internal/stack.h
@@ -0,0 +1,82 @@
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+namespace rapidjson {
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+ Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
+ RAPIDJSON_ASSERT(stack_capacity_ > 0);
+ if (!allocator_)
+ own_allocator_ = allocator_ = new Allocator();
+ stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
+ stack_end_ = stack_ + stack_capacity_;
+ }
+
+ ~Stack() {
+ Allocator::Free(stack_);
+ delete own_allocator_; // Only delete if it is owned by the stack
+ }
+
+ void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
+
+ template<typename T>
+ T* Push(size_t count = 1) {
+ // Expand the stack if needed
+ if (stack_top_ + sizeof(T) * count >= stack_end_) {
+ size_t new_capacity = stack_capacity_ * 2;
+ size_t size = GetSize();
+ size_t new_size = GetSize() + sizeof(T) * count;
+ if (new_capacity < new_size)
+ new_capacity = new_size;
+ stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
+ stack_capacity_ = new_capacity;
+ stack_top_ = stack_ + size;
+ stack_end_ = stack_ + stack_capacity_;
+ }
+ T* ret = (T*)stack_top_;
+ stack_top_ += sizeof(T) * count;
+ return ret;
+ }
+
+ template<typename T>
+ T* Pop(size_t count) {
+ RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+ stack_top_ -= count * sizeof(T);
+ return (T*)stack_top_;
+ }
+
+ template<typename T>
+ T* Top() {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return (T*)(stack_top_ - sizeof(T));
+ }
+
+ template<typename T>
+ T* Bottom() { return (T*)stack_; }
+
+ Allocator& GetAllocator() { return *allocator_; }
+ size_t GetSize() const { return stack_top_ - stack_; }
+ size_t GetCapacity() const { return stack_capacity_; }
+
+private:
+ Allocator* allocator_;
+ Allocator* own_allocator_;
+ char *stack_;
+ char *stack_top_;
+ char *stack_end_;
+ size_t stack_capacity_;
+};
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/src/rapidjson/internal/strfunc.h b/src/rapidjson/internal/strfunc.h
new file mode 100755
index 0000000000..bbf444fe6d
--- /dev/null
+++ b/src/rapidjson/internal/strfunc.h
@@ -0,0 +1,24 @@
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+namespace rapidjson {
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+ \param s Null-terminated input string.
+ \return Number of characters in the string.
+ \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+ const Ch* p = s;
+ while (*p != '\0')
+ ++p;
+ return SizeType(p - s);
+}
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/src/rapidjson/prettywriter.h b/src/rapidjson/prettywriter.h
new file mode 100755
index 0000000000..238ff5ff62
--- /dev/null
+++ b/src/rapidjson/prettywriter.h
@@ -0,0 +1,156 @@
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+namespace rapidjson {
+
+//! Writer with indentation and spacing.
+/*!
+ \tparam Stream Type of ouptut stream.
+ \tparam Encoding Encoding of both source strings and output.
+ \tparam Allocator Type of allocator for allocating memory of stack.
+*/
+template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
+class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
+public:
+ typedef Writer<Stream, Encoding, Allocator> Base;
+ typedef typename Base::Ch Ch;
+
+ //! Constructor
+ /*! \param stream Output stream.
+ \param allocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of
+ */
+ PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+ Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+ //! Set custom indentation.
+ /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
+ \param indentCharCount Number of indent characters for each indentation level.
+ \note The default indentation is 4 spaces.
+ */
+ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+ RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+ indentChar_ = indentChar;
+ indentCharCount_ = indentCharCount;
+ return *this;
+ }
+
+ //@name Implementation of Handler.
+ //@{
+
+ PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; }
+ PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; }
+ PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; }
+ PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; }
+ PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
+ PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
+ PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
+
+ PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ PrettyPrefix(kStringType);
+ Base::WriteString(str, length);
+ return *this;
+ }
+
+ PrettyWriter& StartObject() {
+ PrettyPrefix(kObjectType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+ Base::WriteStartObject();
+ return *this;
+ }
+
+ PrettyWriter& EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::stream_.Put('\n');
+ WriteIndent();
+ }
+ Base::WriteEndObject();
+ return *this;
+ }
+
+ PrettyWriter& StartArray() {
+ PrettyPrefix(kArrayType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+ Base::WriteStartArray();
+ return *this;
+ }
+
+ PrettyWriter& EndArray(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::stream_.Put('\n');
+ WriteIndent();
+ }
+ Base::WriteEndArray();
+ return *this;
+ }
+
+ //@}
+
+ //! Simpler but slower overload.
+ PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }
+
+protected:
+ void PrettyPrefix(Type type) {
+ (void)type;
+ if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+ typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+ if (level->inArray) {
+ if (level->valueCount > 0) {
+ Base::stream_.Put(','); // add comma if it is not the first element in array
+ Base::stream_.Put('\n');
+ }
+ else
+ Base::stream_.Put('\n');
+ WriteIndent();
+ }
+ else { // in object
+ if (level->valueCount > 0) {
+ if (level->valueCount % 2 == 0) {
+ Base::stream_.Put(',');
+ Base::stream_.Put('\n');
+ }
+ else {
+ Base::stream_.Put(':');
+ Base::stream_.Put(' ');
+ }
+ }
+ else
+ Base::stream_.Put('\n');
+
+ if (level->valueCount % 2 == 0)
+ WriteIndent();
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else
+ RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
+ }
+
+ void WriteIndent() {
+ size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+ PutN(Base::stream_, indentChar_, count);
+ }
+
+ Ch indentChar_;
+ unsigned indentCharCount_;
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/src/rapidjson/rapidjson.h b/src/rapidjson/rapidjson.h
new file mode 100755
index 0000000000..7acb2aa4fd
--- /dev/null
+++ b/src/rapidjson/rapidjson.h
@@ -0,0 +1,525 @@
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+// Copyright (c) 2011-2012 Milo Yip (miloyip@gmail.com)
+// Version 0.11
+
+#include <cstdlib> // malloc(), realloc(), free()
+#include <cstring> // memcpy()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+// Here defines int64_t and uint64_t types in global namespace.
+// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.
+#ifndef RAPIDJSON_NO_INT64DEFINE
+#ifdef _MSC_VER
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <inttypes.h>
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
+#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
+
+//! Endianness of the machine.
+/*! GCC provided macro for detecting endianness of the target machine. But other
+ compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+ RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN.
+*/
+#ifndef RAPIDJSON_ENDIAN
+#ifdef __BYTE_ORDER__
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#else
+#define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#endif // __BYTE_ORDER__
+#else
+#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN // Assumes little endian otherwise.
+#endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+
+// Enable SSE2 optimization.
+//#define RAPIDJSON_SSE2
+
+// Enable SSE4.2 optimization.
+//#define RAPIDJSON_SSE42
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+namespace rapidjson {
+//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
+/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+} // namespace rapidjson
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! By default, rapidjson uses C assert() for assertion.
+ User can override it by defining RAPIDJSON_ASSERT(x) macro.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+ \brief Concept for allocating, resizing and freeing memory block.
+
+ Note that Malloc() and Realloc() are non-static but Free() is static.
+
+ So if an allocator need to support Free(), it needs to put its pointer in
+ the header of memory block.
+
+\code
+concept Allocator {
+ static const bool kNeedFree; //!< Whether this allocator needs to call Free().
+
+ // Allocate a memory block.
+ // \param size of the memory block in bytes.
+ // \returns pointer to the memory block.
+ void* Malloc(size_t size);
+
+ // Resize a memory block.
+ // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+ // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+ // \param newSize the new size in bytes.
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // Free a memory block.
+ // \param pointer to the memory block. Null pointer is permitted.
+ static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+ \implements Allocator
+*/
+class CrtAllocator {
+public:
+ static const bool kNeedFree = true;
+ void* Malloc(size_t size) { return malloc(size); }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
+ static void Free(void *ptr) { free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks.
+
+ It does not free memory blocks. And Realloc() only allocate new memory.
+
+ The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+ User may also supply a buffer as the first chunk.
+
+ If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+ The user-buffer is not deallocated by this allocator.
+
+ \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+ \implements Allocator
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+ static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+ //! Constructor with chunkSize.
+ /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ if (!baseAllocator_)
+ ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
+ AddChunk(chunk_capacity_);
+ }
+
+ //! Constructor with user-supplied buffer.
+ /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+ The user buffer will not be deallocated when this allocator is destructed.
+
+ \param buffer User supplied buffer.
+ \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+ \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ RAPIDJSON_ASSERT(buffer != 0);
+ RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+ chunkHead_ = (ChunkHeader*)buffer;
+ chunkHead_->capacity = size - sizeof(ChunkHeader);
+ chunkHead_->size = 0;
+ chunkHead_->next = 0;
+ }
+
+ //! Destructor.
+ /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+ */
+ ~MemoryPoolAllocator() {
+ Clear();
+ delete ownBaseAllocator_;
+ }
+
+ //! Deallocates all memory chunks, excluding the user-supplied buffer.
+ void Clear() {
+ while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) {
+ ChunkHeader* next = chunkHead_->next;
+ baseAllocator_->Free(chunkHead_);
+ chunkHead_ = next;
+ }
+ }
+
+ //! Computes the total capacity of allocated memory chunks.
+ /*! \return total capacity in bytes.
+ */
+ size_t Capacity() {
+ size_t capacity = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ capacity += c->capacity;
+ return capacity;
+ }
+
+ //! Computes the memory blocks allocated.
+ /*! \return total used bytes.
+ */
+ size_t Size() {
+ size_t size = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ size += c->size;
+ return size;
+ }
+
+ //! Allocates a memory block. (concept Allocator)
+ void* Malloc(size_t size) {
+ size = (size + 3) & ~3; // Force aligning size to 4
+
+ if (chunkHead_->size + size > chunkHead_->capacity)
+ AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
+
+ char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size;
+ RAPIDJSON_ASSERT(((uintptr_t)buffer & 3) == 0); // returned buffer is aligned to 4
+ chunkHead_->size += size;
+
+ return buffer;
+ }
+
+ //! Resizes a memory block (concept Allocator)
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ if (originalPtr == 0)
+ return Malloc(newSize);
+
+ // Do not shrink if new size is smaller than original
+ if (originalSize >= newSize)
+ return originalPtr;
+
+ // Simply expand it if it is the last allocation and there is sufficient space
+ if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
+ size_t increment = newSize - originalSize;
+ increment = (increment + 3) & ~3; // Force aligning size to 4
+ if (chunkHead_->size + increment <= chunkHead_->capacity) {
+ chunkHead_->size += increment;
+ RAPIDJSON_ASSERT(((uintptr_t)originalPtr & 3) == 0); // returned buffer is aligned to 4
+ return originalPtr;
+ }
+ }
+
+ // Realloc process: allocate and copy memory, do not free original buffer.
+ void* newBuffer = Malloc(newSize);
+ RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
+ return memcpy(newBuffer, originalPtr, originalSize);
+ }
+
+ //! Frees a memory block (concept Allocator)
+ static void Free(void *) {} // Do nothing
+
+private:
+ //! Creates a new chunk.
+ /*! \param capacity Capacity of the chunk in bytes.
+ */
+ void AddChunk(size_t capacity) {
+ ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity);
+ chunk->capacity = capacity;
+ chunk->size = 0;
+ chunk->next = chunkHead_;
+ chunkHead_ = chunk;
+ }
+
+ static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
+ char *userBuffer_; //!< User supplied buffer.
+ BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
+ BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+ \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+ typename Ch; //! Type of character.
+
+ //! \brief Encode a Unicode codepoint to a buffer.
+ //! \param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character.
+ //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+ //! \returns the pointer to the next character after the encoded data.
+ static Ch* Encode(Ch *buffer, unsigned codepoint);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+ \tparam CharType Type for storing 8-bit UTF-8 data. Default is char.
+ \implements Encoding
+*/
+template<typename CharType = char>
+struct UTF8 {
+ typedef CharType Ch;
+
+ static Ch* Encode(Ch *buffer, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ *buffer++ = codepoint & 0xFF;
+ else if (codepoint <= 0x7FF) {
+ *buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF);
+ *buffer++ = 0x80 | ((codepoint & 0x3F));
+ }
+ else if (codepoint <= 0xFFFF) {
+ *buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF);
+ *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
+ *buffer++ = 0x80 | (codepoint & 0x3F);
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ *buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF);
+ *buffer++ = 0x80 | ((codepoint >> 12) & 0x3F);
+ *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
+ *buffer++ = 0x80 | (codepoint & 0x3F);
+ }
+ return buffer;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+ \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+ \implements Encoding
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+ typedef CharType Ch;
+
+ static Ch* Encode(Ch* buffer, unsigned codepoint) {
+ if (codepoint <= 0xFFFF) {
+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
+ *buffer++ = static_cast<Ch>(codepoint);
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ *buffer++ = static_cast<Ch>((v >> 10) + 0xD800);
+ *buffer++ = (v & 0x3FF) + 0xDC00;
+ }
+ return buffer;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-32
+ \tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+ \implements Encoding
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+ typedef CharType Ch;
+
+ static Ch *Encode(Ch* buffer, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ *buffer++ = codepoint;
+ return buffer;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Stream
+
+/*! \class rapidjson::Stream
+ \brief Concept for reading and writing characters.
+
+ For read-only stream, no need to implement PutBegin(), Put() and PutEnd().
+
+ For write-only stream, only need to implement Put().
+
+\code
+concept Stream {
+ typename Ch; //!< Character type of the stream.
+
+ //! Read the current character from stream without moving the read cursor.
+ Ch Peek() const;
+
+ //! Read the current character from stream and moving the read cursor to next character.
+ Ch Take();
+
+ //! Get the current read cursor.
+ //! \return Number of characters read from start.
+ size_t Tell();
+
+ //! Begin writing operation at the current read pointer.
+ //! \return The begin writer pointer.
+ Ch* PutBegin();
+
+ //! Write a character.
+ void Put(Ch c);
+
+ //! End the writing operation.
+ //! \param begin The begin write pointer returned by PutBegin().
+ //! \return Number of characters written.
+ size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+ for (size_t i = 0; i < n; i++)
+ stream.Put(c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \implements Stream
+*/
+template <typename Encoding>
+struct GenericStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return src_ - head_; }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+};
+
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+ \implements Stream
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+ // Read
+ Ch Peek() { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() { return src_ - head_; }
+
+ // Write
+ Ch* PutBegin() { return dst_ = src_; }
+ void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+ size_t PutEnd(Ch* begin) { return dst_ - begin; }
+
+ Ch* src_;
+ Ch* dst_;
+ Ch* head_;
+};
+
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+//! Type of JSON value
+enum Type {
+ kNullType = 0, //!< null
+ kFalseType = 1, //!< false
+ kTrueType = 2, //!< true
+ kObjectType = 3, //!< object
+ kArrayType = 4, //!< array
+ kStringType = 5, //!< string
+ kNumberType = 6, //!< number
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/src/rapidjson/reader.h b/src/rapidjson/reader.h
new file mode 100755
index 0000000000..16d672633b
--- /dev/null
+++ b/src/rapidjson/reader.h
@@ -0,0 +1,692 @@
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
+// Version 0.1
+
+#include "rapidjson.h"
+#include "internal/pow10.h"
+#include "internal/stack.h"
+#include <csetjmp>
+
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
+#endif
+
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(msg, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ parseError_ = msg; \
+ errorOffset_ = offset; \
+ longjmp(jmpbuf_, 1); \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+//! Combination of parseFlags
+enum ParseFlag {
+ kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
+ kParseInsituFlag = 1 //!< In-situ(destructive) parsing.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*! \class rapidjson::Handler
+ \brief Concept for receiving events from GenericReader upon parsing.
+\code
+concept Handler {
+ typename Ch;
+
+ void Null();
+ void Bool(bool b);
+ void Int(int i);
+ void Uint(unsigned i);
+ void Int64(int64_t i);
+ void Uint64(uint64_t i);
+ void Double(double d);
+ void String(const Ch* str, SizeType length, bool copy);
+ void StartObject();
+ void EndObject(SizeType memberCount);
+ void StartArray();
+ void EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+ \implements Handler
+*/
+template<typename Encoding = UTF8<> >
+struct BaseReaderHandler {
+ typedef typename Encoding::Ch Ch;
+
+ void Default() {}
+ void Null() { Default(); }
+ void Bool(bool) { Default(); }
+ void Int(int) { Default(); }
+ void Uint(unsigned) { Default(); }
+ void Int64(int64_t) { Default(); }
+ void Uint64(uint64_t) { Default(); }
+ void Double(double) { Default(); }
+ void String(const Ch*, SizeType, bool) { Default(); }
+ void StartObject() { Default(); }
+ void EndObject(SizeType) { Default(); }
+ void StartArray() { Default(); }
+ void EndArray(SizeType) { Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param stream A input stream for skipping white spaces.
+ \note This function has SSE2/SSE4.2 specialization.
+*/
+template<typename Stream>
+void SkipWhitespace(Stream& stream) {
+ Stream s = stream; // Use a local copy for optimization
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+ stream = s;
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ static const char whitespace[16] = " \n\r\t";
+ __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
+
+ for (;;) {
+ __m128i s = _mm_loadu_si128((const __m128i *)p);
+ unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
+ if (r == 0) // all 16 characters are whitespace
+ p += 16;
+ else { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ if (_BitScanForward(&offset, r))
+ return p + offset;
+#else
+ if (r != 0)
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ static const char whitespaces[4][17] = {
+ " ",
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
+ "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
+
+ __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
+ __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
+ __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
+ __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
+
+ for (;;) {
+ __m128i s = _mm_loadu_si128((const __m128i *)p);
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = ~_mm_movemask_epi8(x);
+ if (r == 0) // all 16 characters are whitespace
+ p += 16;
+ else { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ if (_BitScanForward(&offset, r))
+ return p + offset;
+#else
+ if (r != 0)
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template<> inline void SkipWhitespace(InsituStringStream& stream) {
+ stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
+}
+
+//! Template function specialization for StringStream
+template<> inline void SkipWhitespace(StringStream& stream) {
+ stream.src_ = SkipWhitespace_SIMD(stream.src_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
+ object implementing Handler concept.
+
+ It needs to allocate a stack for storing a single decoded string during
+ non-destructive parsing.
+
+ For in-situ parsing, the decoded string is directly written to the source
+ text string, no temporary buffer is required.
+
+ A GenericReader object can be reused for parsing multiple JSON text.
+
+ \tparam Encoding Encoding of both the stream and the parse output.
+ \tparam Allocator Allocator type for stack.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericReader {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ //! Constructor.
+ /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+ \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
+ */
+ GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
+
+ //! Parse JSON text.
+ /*! \tparam parseFlags Combination of ParseFlag.
+ \tparam Stream Type of input stream.
+ \tparam Handler Type of handler which must implement Handler concept.
+ \param stream Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <unsigned parseFlags, typename Stream, typename Handler>
+ bool Parse(Stream& stream, Handler& handler) {
+ parseError_ = 0;
+ errorOffset_ = 0;
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
+#endif
+ if (setjmp(jmpbuf_)) {
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ stack_.Clear();
+ return false;
+ }
+
+ SkipWhitespace(stream);
+
+ if (stream.Peek() == '\0')
+ RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell());
+ else {
+ switch (stream.Peek()) {
+ case '{': ParseObject<parseFlags>(stream, handler); break;
+ case '[': ParseArray<parseFlags>(stream, handler); break;
+ default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell());
+ }
+ SkipWhitespace(stream);
+
+ if (stream.Peek() != '\0')
+ RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell());
+ }
+
+ return true;
+ }
+
+ bool HasParseError() const { return parseError_ != 0; }
+ const char* GetParseError() const { return parseError_; }
+ size_t GetErrorOffset() const { return errorOffset_; }
+
+private:
+ // Parse object: { string : value, ... }
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseObject(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == '{');
+ stream.Take(); // Skip '{'
+ handler.StartObject();
+ SkipWhitespace(stream);
+
+ if (stream.Peek() == '}') {
+ stream.Take();
+ handler.EndObject(0); // empty object
+ return;
+ }
+
+ for (SizeType memberCount = 0;;) {
+ if (stream.Peek() != '"') {
+ RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell());
+ break;
+ }
+
+ ParseString<parseFlags>(stream, handler);
+ SkipWhitespace(stream);
+
+ if (stream.Take() != ':') {
+ RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell());
+ break;
+ }
+ SkipWhitespace(stream);
+
+ ParseValue<parseFlags>(stream, handler);
+ SkipWhitespace(stream);
+
+ ++memberCount;
+
+ switch(stream.Take()) {
+ case ',': SkipWhitespace(stream); break;
+ case '}': handler.EndObject(memberCount); return;
+ default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell());
+ }
+ }
+ }
+
+ // Parse array: [ value, ... ]
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseArray(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == '[');
+ stream.Take(); // Skip '['
+ handler.StartArray();
+ SkipWhitespace(stream);
+
+ if (stream.Peek() == ']') {
+ stream.Take();
+ handler.EndArray(0); // empty array
+ return;
+ }
+
+ for (SizeType elementCount = 0;;) {
+ ParseValue<parseFlags>(stream, handler);
+ ++elementCount;
+ SkipWhitespace(stream);
+
+ switch (stream.Take()) {
+ case ',': SkipWhitespace(stream); break;
+ case ']': handler.EndArray(elementCount); return;
+ default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell());
+ }
+ }
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseNull(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == 'n');
+ stream.Take();
+
+ if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l')
+ handler.Null();
+ else
+ RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseTrue(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == 't');
+ stream.Take();
+
+ if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e')
+ handler.Bool(true);
+ else
+ RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell());
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseFalse(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == 'f');
+ stream.Take();
+
+ if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e')
+ handler.Bool(false);
+ else
+ RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
+ }
+
+ // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ template<typename Stream>
+ unsigned ParseHex4(Stream& stream) {
+ Stream s = stream; // Use a local copy for optimization
+ unsigned codepoint = 0;
+ for (int i = 0; i < 4; i++) {
+ Ch c = s.Take();
+ codepoint <<= 4;
+ codepoint += c;
+ if (c >= '0' && c <= '9')
+ codepoint -= '0';
+ else if (c >= 'A' && c <= 'F')
+ codepoint -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ codepoint -= 'a' - 10;
+ else
+ RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1);
+ }
+ stream = s; // Restore stream
+ return codepoint;
+ }
+
+ // Parse string, handling the prefix and suffix double quotes and escaping.
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseString(Stream& stream, Handler& handler) {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ static const Ch escape[256] = {
+ Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+ Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
+ 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
+ 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
+ };
+#undef Z16
+
+ Stream s = stream; // Use a local copy for optimization
+ RAPIDJSON_ASSERT(s.Peek() == '\"');
+ s.Take(); // Skip '\"'
+ Ch *head;
+ SizeType len;
+ if (parseFlags & kParseInsituFlag)
+ head = s.PutBegin();
+ else
+ len = 0;
+
+#define RAPIDJSON_PUT(x) \
+ do { \
+ if (parseFlags & kParseInsituFlag) \
+ s.Put(x); \
+ else { \
+ *stack_.template Push<Ch>() = x; \
+ ++len; \
+ } \
+ } while(false)
+
+ for (;;) {
+ Ch c = s.Take();
+ if (c == '\\') { // Escape
+ Ch e = s.Take();
+ if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e])
+ RAPIDJSON_PUT(escape[(unsigned char)e]);
+ else if (e == 'u') { // Unicode
+ unsigned codepoint = ParseHex4(s);
+ if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair
+ if (s.Take() != '\\' || s.Take() != 'u') {
+ RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2);
+ return;
+ }
+ unsigned codepoint2 = ParseHex4(s);
+ if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) {
+ RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2);
+ return;
+ }
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+ }
+
+ Ch buffer[4];
+ SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]);
+
+ if (parseFlags & kParseInsituFlag)
+ for (SizeType i = 0; i < count; i++)
+ s.Put(buffer[i]);
+ else {
+ memcpy(stack_.template Push<Ch>(count), buffer, count * sizeof(Ch));
+ len += count;
+ }
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1);
+ return;
+ }
+ }
+ else if (c == '"') { // Closing double quote
+ if (parseFlags & kParseInsituFlag) {
+ size_t length = s.PutEnd(head);
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ RAPIDJSON_PUT('\0'); // null-terminate the string
+ handler.String(head, SizeType(length), false);
+ }
+ else {
+ RAPIDJSON_PUT('\0');
+ handler.String(stack_.template Pop<Ch>(len), len - 1, true);
+ }
+ stream = s; // restore stream
+ return;
+ }
+ else if (c == '\0') {
+ RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1);
+ return;
+ }
+ else if ((unsigned)c < 0x20) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1);
+ return;
+ }
+ else
+ RAPIDJSON_PUT(c); // Normal character, just copy
+ }
+#undef RAPIDJSON_PUT
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseNumber(Stream& stream, Handler& handler) {
+ Stream s = stream; // Local copy for optimization
+ // Parse minus
+ bool minus = false;
+ if (s.Peek() == '-') {
+ minus = true;
+ s.Take();
+ }
+
+ // Parse int: zero / ( digit1-9 *DIGIT )
+ unsigned i;
+ bool try64bit = false;
+ if (s.Peek() == '0') {
+ i = 0;
+ s.Take();
+ }
+ else if (s.Peek() >= '1' && s.Peek() <= '9') {
+ i = s.Take() - '0';
+
+ if (minus)
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i >= 214748364) { // 2^31 = 2147483648
+ if (i != 214748364 || s.Peek() > '8') {
+ try64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + (s.Take() - '0');
+ }
+ else
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i >= 429496729) { // 2^32 - 1 = 4294967295
+ if (i != 429496729 || s.Peek() > '5') {
+ try64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + (s.Take() - '0');
+ }
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell());
+ return;
+ }
+
+ // Parse 64bit int
+ uint64_t i64 = 0;
+ bool useDouble = false;
+ if (try64bit) {
+ i64 = i;
+ if (minus)
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808
+ if (i64 != 922337203685477580uLL || s.Peek() > '8') {
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + (s.Take() - '0');
+ }
+ else
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615
+ if (i64 != 1844674407370955161uLL || s.Peek() > '5') {
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + (s.Take() - '0');
+ }
+ }
+
+ // Force double for big integer
+ double d = 0.0;
+ if (useDouble) {
+ d = (double)i64;
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (d >= 1E307) {
+ RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
+ return;
+ }
+ d = d * 10 + (s.Take() - '0');
+ }
+ }
+
+ // Parse frac = decimal-point 1*DIGIT
+ int expFrac = 0;
+ if (s.Peek() == '.') {
+ if (!useDouble) {
+ d = try64bit ? (double)i64 : (double)i;
+ useDouble = true;
+ }
+ s.Take();
+
+ if (s.Peek() >= '0' && s.Peek() <= '9') {
+ d = d * 10 + (s.Take() - '0');
+ --expFrac;
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell());
+ return;
+ }
+
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (expFrac > -16) {
+ d = d * 10 + (s.Peek() - '0');
+ --expFrac;
+ }
+ s.Take();
+ }
+ }
+
+ // Parse exp = e [ minus / plus ] 1*DIGIT
+ int exp = 0;
+ if (s.Peek() == 'e' || s.Peek() == 'E') {
+ if (!useDouble) {
+ d = try64bit ? (double)i64 : (double)i;
+ useDouble = true;
+ }
+ s.Take();
+
+ bool expMinus = false;
+ if (s.Peek() == '+')
+ s.Take();
+ else if (s.Peek() == '-') {
+ s.Take();
+ expMinus = true;
+ }
+
+ if (s.Peek() >= '0' && s.Peek() <= '9') {
+ exp = s.Take() - '0';
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ exp = exp * 10 + (s.Take() - '0');
+ if (exp > 308) {
+ RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
+ return;
+ }
+ }
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell());
+ return;
+ }
+
+ if (expMinus)
+ exp = -exp;
+ }
+
+ // Finish parsing, call event according to the type of number.
+ if (useDouble) {
+ d *= internal::Pow10(exp + expFrac);
+ handler.Double(minus ? -d : d);
+ }
+ else {
+ if (try64bit) {
+ if (minus)
+ handler.Int64(-(int64_t)i64);
+ else
+ handler.Uint64(i64);
+ }
+ else {
+ if (minus)
+ handler.Int(-(int)i);
+ else
+ handler.Uint(i);
+ }
+ }
+
+ stream = s; // restore stream
+ }
+
+ // Parse any JSON value
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseValue(Stream& stream, Handler& handler) {
+ switch (stream.Peek()) {
+ case 'n': ParseNull <parseFlags>(stream, handler); break;
+ case 't': ParseTrue <parseFlags>(stream, handler); break;
+ case 'f': ParseFalse <parseFlags>(stream, handler); break;
+ case '"': ParseString<parseFlags>(stream, handler); break;
+ case '{': ParseObject<parseFlags>(stream, handler); break;
+ case '[': ParseArray <parseFlags>(stream, handler); break;
+ default : ParseNumber<parseFlags>(stream, handler);
+ }
+ }
+
+ static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
+ jmp_buf jmpbuf_; //!< setjmp buffer for fast exit from nested parsing function calls.
+ const char* parseError_;
+ size_t errorOffset_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<> > Reader;
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/src/rapidjson/stringbuffer.h b/src/rapidjson/stringbuffer.h
new file mode 100755
index 0000000000..269ae10761
--- /dev/null
+++ b/src/rapidjson/stringbuffer.h
@@ -0,0 +1,49 @@
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+
+namespace rapidjson {
+
+//! Represents an in-memory output stream.
+/*!
+ \tparam Encoding Encoding of the stream.
+ \tparam Allocator type for allocating memory buffer.
+ \implements Stream
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+struct GenericStringBuffer {
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+
+ void Clear() { stack_.Clear(); }
+
+ const char* GetString() const {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.template Pop<Ch>(1);
+
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t Size() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+ memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/src/rapidjson/writer.h b/src/rapidjson/writer.h
new file mode 100755
index 0000000000..d96f2081a9
--- /dev/null
+++ b/src/rapidjson/writer.h
@@ -0,0 +1,241 @@
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include <cstdio> // snprintf() or _sprintf_s()
+#include <new> // placement new
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+namespace rapidjson {
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+ It generates JSON text by events to an output stream.
+
+ User may programmatically calls the functions of a writer to generate JSON text.
+
+ On the other side, a writer can also be passed to objects that generates events,
+
+ for example Reader::Parse() and Document::Accept().
+
+ \tparam Stream Type of ouptut stream.
+ \tparam Encoding Encoding of both source strings and output.
+ \implements Handler
+*/
+template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
+class Writer {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {}
+
+ //@name Implementation of Handler
+ //@{
+ Writer& Null() { Prefix(kNullType); WriteNull(); return *this; }
+ Writer& Bool(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; }
+ Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; }
+ Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; }
+ Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; }
+ Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }
+ Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; }
+
+ Writer& String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ Prefix(kStringType);
+ WriteString(str, length);
+ return *this;
+ }
+
+ Writer& StartObject() {
+ Prefix(kObjectType);
+ new (level_stack_.template Push<Level>()) Level(false);
+ WriteStartObject();
+ return *this;
+ }
+
+ Writer& EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ WriteEndObject();
+ return *this;
+ }
+
+ Writer& StartArray() {
+ Prefix(kArrayType);
+ new (level_stack_.template Push<Level>()) Level(true);
+ WriteStartArray();
+ return *this;
+ }
+
+ Writer& EndArray(SizeType elementCount = 0) {
+ (void)elementCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ WriteEndArray();
+ return *this;
+ }
+ //@}
+
+ //! Simpler but slower overload.
+ Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
+
+protected:
+ //! Information for each nested level
+ struct Level {
+ Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
+ bool inArray; //!< true if in array, otherwise in object
+ size_t valueCount; //!< number of values in this level
+ };
+
+ static const size_t kDefaultLevelDepth = 32;
+
+ void WriteNull() {
+ stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');
+ }
+
+ void WriteBool(bool b) {
+ if (b) {
+ stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');
+ }
+ else {
+ stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');
+ }
+ }
+
+ void WriteInt(int i) {
+ if (i < 0) {
+ stream_.Put('-');
+ i = -i;
+ }
+ WriteUint((unsigned)i);
+ }
+
+ void WriteUint(unsigned u) {
+ char buffer[10];
+ char *p = buffer;
+ do {
+ *p++ = (u % 10) + '0';
+ u /= 10;
+ } while (u > 0);
+
+ do {
+ --p;
+ stream_.Put(*p);
+ } while (p != buffer);
+ }
+
+ void WriteInt64(int64_t i64) {
+ if (i64 < 0) {
+ stream_.Put('-');
+ i64 = -i64;
+ }
+ WriteUint64((uint64_t)i64);
+ }
+
+ void WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char *p = buffer;
+ do {
+ *p++ = char(u64 % 10) + '0';
+ u64 /= 10;
+ } while (u64 > 0);
+
+ do {
+ --p;
+ stream_.Put(*p);
+ } while (p != buffer);
+ }
+
+ //! \todo Optimization with custom double-to-string converter.
+ void WriteDouble(double d) {
+ char buffer[100];
+#if _MSC_VER
+ int ret = sprintf_s(buffer, sizeof(buffer), "%g", d);
+#else
+ int ret = snprintf(buffer, sizeof(buffer), "%g", d);
+#endif
+ RAPIDJSON_ASSERT(ret >= 1);
+ for (int i = 0; i < ret; i++)
+ stream_.Put(buffer[i]);
+ }
+
+ void WriteString(const Ch* str, SizeType length) {
+ static const char hexDigits[] = "0123456789ABCDEF";
+ static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+ 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
+ Z16, Z16, // 30~4F
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
+#undef Z16
+ };
+
+ stream_.Put('\"');
+ for (const Ch* p = str; p != str + length; ++p) {
+ if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p]) {
+ stream_.Put('\\');
+ stream_.Put(escape[(unsigned char)*p]);
+ if (escape[(unsigned char)*p] == 'u') {
+ stream_.Put('0');
+ stream_.Put('0');
+ stream_.Put(hexDigits[(*p) >> 4]);
+ stream_.Put(hexDigits[(*p) & 0xF]);
+ }
+ }
+ else
+ stream_.Put(*p);
+ }
+ stream_.Put('\"');
+ }
+
+ void WriteStartObject() { stream_.Put('{'); }
+ void WriteEndObject() { stream_.Put('}'); }
+ void WriteStartArray() { stream_.Put('['); }
+ void WriteEndArray() { stream_.Put(']'); }
+
+ void Prefix(Type type) {
+ (void)type;
+ if (level_stack_.GetSize() != 0) { // this value is not at root
+ Level* level = level_stack_.template Top<Level>();
+ if (level->valueCount > 0) {
+ if (level->inArray)
+ stream_.Put(','); // add comma if it is not the first element in array
+ else // in object
+ stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else
+ RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
+ }
+
+ Stream& stream_;
+ internal::Stack<Allocator> level_stack_;
+
+private:
+ // Prohibit assignment for VC C4512 warning
+ Writer& operator=(const Writer& w);
+};
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_