diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/clipper/clipper.cpp | 2 | ||||
-rwxr-xr-x | src/clipper/clipper.hpp | 398 | ||||
-rw-r--r-- | src/csscolorparser/csscolorparser.cpp | 2 | ||||
-rw-r--r-- | src/csscolorparser/csscolorparser.hpp | 44 | ||||
-rwxr-xr-x | src/libtess2/bucketalloc.c | 2 | ||||
-rwxr-xr-x | src/libtess2/bucketalloc.h | 2 | ||||
-rwxr-xr-x | src/libtess2/dict.c | 2 | ||||
-rwxr-xr-x | src/libtess2/mesh.h | 2 | ||||
-rwxr-xr-x | src/libtess2/priorityq.c | 2 | ||||
-rwxr-xr-x | src/libtess2/tess.h | 2 | ||||
-rwxr-xr-x | src/libtess2/tesselator.h | 209 | ||||
-rw-r--r-- | src/mbgl/geometry/anchor.hpp | 25 | ||||
-rw-r--r-- | src/mbgl/geometry/binpack.hpp | 100 | ||||
-rw-r--r-- | src/mbgl/geometry/buffer.hpp | 118 | ||||
-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.hpp | 17 | ||||
-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.hpp | 64 | ||||
-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.hpp | 21 | ||||
-rw-r--r-- | src/mbgl/geometry/geometry.hpp | 77 | ||||
-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.hpp | 54 | ||||
-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.hpp | 22 | ||||
-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.hpp | 39 | ||||
-rw-r--r-- | src/mbgl/geometry/resample.cpp (renamed from src/geometry/resample.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/geometry/resample.hpp | 13 | ||||
-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.hpp | 82 | ||||
-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.hpp | 26 | ||||
-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.hpp | 25 | ||||
-rw-r--r-- | src/mbgl/geometry/vao.cpp (renamed from src/geometry/vao.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/geometry/vao.hpp | 73 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp (renamed from src/map/map.cpp) | 33 | ||||
-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.hpp | 33 | ||||
-rw-r--r-- | src/mbgl/map/source.cpp (renamed from src/map/source.cpp) | 1 | ||||
-rw-r--r-- | src/mbgl/map/source.hpp | 86 | ||||
-rw-r--r-- | src/mbgl/map/sprite.cpp (renamed from src/map/sprite.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/map/sprite.hpp | 79 | ||||
-rw-r--r-- | src/mbgl/map/tile.cpp (renamed from src/map/tile.cpp) | 1 | ||||
-rw-r--r-- | src/mbgl/map/tile_data.cpp (renamed from src/map/tile_data.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/map/tile_data.hpp | 88 | ||||
-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.hpp | 77 | ||||
-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.hpp | 118 | ||||
-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.hpp | 74 | ||||
-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.hpp | 24 | ||||
-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.hpp | 35 | ||||
-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.hpp | 88 | ||||
-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.hpp | 40 | ||||
-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.hpp | 62 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.cpp (renamed from src/renderer/painter.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.hpp | 259 | ||||
-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) | 0 | ||||
-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.hpp | 37 | ||||
-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.hpp | 38 | ||||
-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.hpp | 114 | ||||
-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.hpp | 26 | ||||
-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.hpp | 25 | ||||
-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.hpp | 41 | ||||
-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.hpp | 32 | ||||
-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.hpp | 27 | ||||
-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.hpp | 33 | ||||
-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.hpp | 25 | ||||
-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.hpp | 29 | ||||
-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.hpp | 24 | ||||
-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.hpp | 31 | ||||
-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.hpp | 53 | ||||
-rw-r--r-- | src/mbgl/shader/shader.cpp (renamed from src/shader/shader.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/shader/shader.hpp | 28 | ||||
-rw-r--r-- | src/mbgl/shader/uniform.cpp (renamed from src/shader/uniform.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/shader/uniform.hpp | 53 | ||||
-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.hpp | 62 | ||||
-rw-r--r-- | src/mbgl/storage/caching_http_file_source.cpp | 115 | ||||
-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.hpp | 27 | ||||
-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.hpp | 36 | ||||
-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.hpp | 58 | ||||
-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.hpp | 49 | ||||
-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.hpp | 39 | ||||
-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.hpp | 37 | ||||
-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.hpp | 43 | ||||
-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.hpp | 125 | ||||
-rw-r--r-- | src/mbgl/style/filter_expression_private.hpp | 118 | ||||
-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.hpp | 55 | ||||
-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.hpp | 29 | ||||
-rw-r--r-- | src/mbgl/style/property_key.hpp | 70 | ||||
-rw-r--r-- | src/mbgl/style/property_transition.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/style/property_value.hpp | 21 | ||||
-rw-r--r-- | src/mbgl/style/style.cpp (renamed from src/style/style.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/style/style.hpp | 68 | ||||
-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.hpp | 112 | ||||
-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.hpp | 89 | ||||
-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.hpp | 23 | ||||
-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.hpp | 113 | ||||
-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.hpp | 114 | ||||
-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.hpp | 41 | ||||
-rw-r--r-- | src/mbgl/style/types.cpp (renamed from src/style/types.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/style/types.hpp | 196 | ||||
-rw-r--r-- | src/mbgl/style/value.cpp (renamed from src/style/value.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/style/value.hpp | 45 | ||||
-rw-r--r-- | src/mbgl/style/value_comparison.hpp | 109 | ||||
-rw-r--r-- | src/mbgl/text/collision.cpp (renamed from src/text/collision.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/text/collision.hpp | 58 | ||||
-rw-r--r-- | src/mbgl/text/glyph.cpp (renamed from src/text/glyph.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/text/glyph.hpp | 60 | ||||
-rw-r--r-- | src/mbgl/text/glyph_store.cpp (renamed from src/text/glyph_store.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/text/glyph_store.hpp | 99 | ||||
-rw-r--r-- | src/mbgl/text/placement.cpp (renamed from src/text/placement.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/text/placement.hpp | 31 | ||||
-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.hpp | 54 | ||||
-rw-r--r-- | src/mbgl/text/types.hpp | 113 | ||||
-rw-r--r-- | src/mbgl/util/box.hpp | 15 | ||||
-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.hpp | 38 | ||||
-rw-r--r-- | src/mbgl/util/compression.cpp (renamed from src/util/compression.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/compression.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/util/constants.cpp | 27 | ||||
-rw-r--r-- | src/mbgl/util/constants.hpp | 31 | ||||
-rw-r--r-- | src/mbgl/util/error.hpp | 20 | ||||
-rw-r--r-- | src/mbgl/util/interpolate.hpp | 27 | ||||
-rw-r--r-- | src/mbgl/util/io.cpp (renamed from src/util/io.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/io.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/util/mapbox.cpp (renamed from src/util/mapbox.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/mapbox.hpp | 17 | ||||
-rw-r--r-- | src/mbgl/util/mat3.cpp (renamed from src/util/mat3.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/mat3.hpp | 42 | ||||
-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.hpp | 69 | ||||
-rw-r--r-- | src/mbgl/util/parsedate.c (renamed from src/util/parsedate.c) | 0 | ||||
-rw-r--r-- | src/mbgl/util/pbf.hpp | 184 | ||||
-rw-r--r-- | src/mbgl/util/queue.h | 92 | ||||
-rw-r--r-- | src/mbgl/util/raster.cpp (renamed from src/util/raster.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/raster.hpp | 74 | ||||
-rw-r--r-- | src/mbgl/util/rect.hpp | 22 | ||||
-rw-r--r-- | src/mbgl/util/sqlite3.cpp (renamed from src/util/sqlite3.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/sqlite3.hpp | 74 | ||||
-rw-r--r-- | src/mbgl/util/stopwatch.cpp (renamed from src/util/stopwatch.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/stopwatch.hpp | 40 | ||||
-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.hpp | 25 | ||||
-rw-r--r-- | src/mbgl/util/time.cpp (renamed from src/util/time.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/token.hpp | 50 | ||||
-rw-r--r-- | src/mbgl/util/transition.cpp (renamed from src/util/transition.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/transition.hpp | 77 | ||||
-rw-r--r-- | src/mbgl/util/unitbezier.hpp | 121 | ||||
-rw-r--r-- | src/mbgl/util/url.cpp (renamed from src/util/url.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/url.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/util/utf.hpp | 24 | ||||
-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.h | 29 | ||||
-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.h | 41 | ||||
-rw-r--r-- | src/mbgl/util/uv.cpp (renamed from src/util/uv.cpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/uv_detail.hpp | 177 | ||||
-rw-r--r-- | src/mbgl/util/vec.hpp | 15 | ||||
-rwxr-xr-x | src/rapidjson/document.h | 821 | ||||
-rwxr-xr-x | src/rapidjson/filestream.h | 46 | ||||
-rwxr-xr-x | src/rapidjson/internal/pow10.h | 54 | ||||
-rwxr-xr-x | src/rapidjson/internal/stack.h | 82 | ||||
-rwxr-xr-x | src/rapidjson/internal/strfunc.h | 24 | ||||
-rwxr-xr-x | src/rapidjson/prettywriter.h | 156 | ||||
-rwxr-xr-x | src/rapidjson/rapidjson.h | 525 | ||||
-rwxr-xr-x | src/rapidjson/reader.h | 692 | ||||
-rwxr-xr-x | src/rapidjson/stringbuffer.h | 49 | ||||
-rwxr-xr-x | src/rapidjson/writer.h | 241 |
246 files changed, 9411 insertions, 26 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 66822ba5ce..66822ba5ce 100644 --- a/src/geometry/vao.cpp +++ b/src/mbgl/geometry/vao.cpp 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 822a98d63f..5be29d7543 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> @@ -15,6 +16,7 @@ #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> @@ -93,10 +95,10 @@ Map::Map(View& view_, FileSource& fileSource_) #endif transform(view_), fileSource(fileSource_), - glyphAtlas(1024, 1024), - spriteAtlas(512, 512), + glyphAtlas(util::make_unique<GlyphAtlas>(1024, 1024)), + 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. @@ -175,7 +177,8 @@ void Map::start() { }); asyncCleanup = util::make_unique<uv::async>(**loop, [this]() { - painter.cleanup(); + assert(painter); + painter->cleanup(); }); thread = std::thread([this]() { @@ -279,7 +282,8 @@ void Map::cleanup() { } void Map::terminate() { - painter.terminate(); + assert(painter); + painter->terminate(); } void Map::setReachability(bool reachable) { @@ -295,8 +299,9 @@ void Map::setReachability(bool reachable) { void Map::setup() { assert(std::this_thread::get_id() == mapThread); + assert(painter); view.make_active(); - painter.setup(); + painter->setup(); view.make_inactive(); } @@ -500,7 +505,8 @@ void Map::stopRotating() { void Map::setDebug(bool value) { debug = value; - painter.setDebug(debug); + assert(painter); + painter->setDebug(debug); update(); } @@ -583,8 +589,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(); }); } } @@ -627,8 +633,8 @@ 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(); } @@ -636,7 +642,8 @@ void Map::prepare() { void Map::render() { view.make_active(); - 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 f4f5a1b811..8e67ffb86c 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> 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 52f3538417..9f31048857 100644 --- a/src/map/tile.cpp +++ b/src/mbgl/map/tile.cpp @@ -1,6 +1,7 @@ #include <mbgl/map/tile.hpp> #include <mbgl/util/vec.hpp> #include <mbgl/util/string.hpp> +#include <mbgl/util/box.hpp> #include <cassert> diff --git a/src/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp index f89ff15baf..f89ff15baf 100644 --- a/src/map/tile_data.cpp +++ b/src/mbgl/map/tile_data.cpp 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 c0c3bb1c74..c0c3bb1c74 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 f350f2239b..f350f2239b 100644 --- a/src/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp 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 c4d273aa47..c4d273aa47 100644 --- a/src/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp 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 f38470530b..f38470530b 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 dd35f11372..dd35f11372 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..e4dc610418 --- /dev/null +++ b/src/mbgl/renderer/prerendered_texture.hpp @@ -0,0 +1,37 @@ +#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 previous_fbo = 0; + GLuint fbo = 0; + GLuint texture = 0; + GLuint fbo_depth_stencil = 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 84cb55eac4..84cb55eac4 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 5ce206996c..5ce206996c 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..2913c5eae5 --- /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 thread_id; + 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..70254b68da --- /dev/null +++ b/src/mbgl/storage/caching_http_file_source.cpp @@ -0,0 +1,115 @@ +#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/util/uv-messenger.h> +#include <mbgl/util/std.hpp> + +#include <uv.h> + +namespace mbgl { + +CachingHTTPFileSource::CachingHTTPFileSource(const std::string &path_) + : path(path_) {} + +CachingHTTPFileSource::~CachingHTTPFileSource() { + if (hasLoop()) { + assert(thread_id == std::this_thread::get_id()); + 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(); + } + } + } +} + +void CachingHTTPFileSource::setLoop(uv_loop_t* loop_) { + thread_id = 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::setBase(const std::string &value) { + assert(thread_id == std::this_thread::get_id()); + base = value; +} + +const std::string &CachingHTTPFileSource::getBase() const { + assert(thread_id == std::this_thread::get_id()); + return base; +} + +std::unique_ptr<Request> CachingHTTPFileSource::request(ResourceType type, const std::string &url) { + assert(thread_id == std::this_thread::get_id()); + + // Make URL absolute. + const std::string absoluteURL = [&]() -> std::string { + const size_t separator = url.find("://"); + if (separator == std::string::npos) { + // Relative URL. + return base + url; + } else { + return url; + } + }(); + + util::ptr<BaseRequest> req; + + // First, try to find an existing Request object. + auto it = pending.find(absoluteURL); + if (it != pending.end()) { + req = it->second.lock(); + } + + if (!req) { + if (absoluteURL.substr(0, 7) == "file://") { + req = std::make_shared<FileRequest>(absoluteURL.substr(7), loop); + } else { + req = std::make_shared<HTTPRequest>(type, absoluteURL, loop, store); + } + + pending.emplace(absoluteURL, req); + } + + return util::make_unique<Request>(req); +} + +void CachingHTTPFileSource::prepare(std::function<void()> fn) { + if (thread_id == std::this_thread::get_id()) { + fn(); + } else { + uv_messenger_send(queue, new std::function<void()>(std::move(fn))); + } +} + +void CachingHTTPFileSource::retryAllPending() { + assert(thread_id == std::this_thread::get_id()); + + 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 9f74c7b414..9f74c7b414 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..2f883728ff --- /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
\ No newline at end of file diff --git a/src/storage/file_request_baton.cpp b/src/mbgl/storage/file_request_baton.cpp index 0a9c5f6f55..0a9c5f6f55 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..897c88061d --- /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 thread_id; + 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 ebb9a84823..ebb9a84823 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..71d6e8814c --- /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 thread_id; + uv_loop_t *const loop; + CacheRequestBaton *cache_baton = nullptr; + util::ptr<HTTPRequestBaton> http_baton; + uv_timer_t *backoff_timer = nullptr; + util::ptr<SQLiteStore> store; + const ResourceType type; + uint8_t attempts = 0; + + friend struct HTTPRequestBaton; +}; + +} + +#endif
\ No newline at end of file diff --git a/src/storage/http_request_baton.cpp b/src/mbgl/storage/http_request_baton.cpp index 315708f4e0..315708f4e0 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 15ca4e14fb..15ca4e14fb 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 ae51ce3783..ae51ce3783 100644 --- a/src/style/value.cpp +++ b/src/mbgl/style/value.cpp 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 2f5db180fd..2f5db180fd 100644 --- a/src/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp 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 14b4f4018b..14b4f4018b 100644 --- a/src/util/stopwatch.cpp +++ b/src/mbgl/util/stopwatch.cpp 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/mbgl/util/vec.hpp b/src/mbgl/util/vec.hpp new file mode 100644 index 0000000000..60065b4fc3 --- /dev/null +++ b/src/mbgl/util/vec.hpp @@ -0,0 +1,15 @@ +#ifndef MBGL_UTIL_VEC +#define MBGL_UTIL_VEC + +#include <mbgl/util/vec.hpp> + +namespace mbgl { + +struct box { + vec2<double> tl, tr, bl, br; + vec2<double> center; +}; + +} + +#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_ |