From 8edf4a77969e64e73d6468fa7e10ad73c1b63fb8 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 30 May 2014 11:54:28 -0700 Subject: [PATCH 1/5] [build] debug back to -O0 to ensure fullest symbol visibility --- common.gypi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common.gypi b/common.gypi index ba2347090..a9567d4d3 100644 --- a/common.gypi +++ b/common.gypi @@ -14,10 +14,10 @@ 'cflags_cc': ['-std=c++11', '-Wall', '-Wextra'], 'configurations': { 'Debug': { - 'cflags_cc': [ '-g', '-O1', '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ], + 'cflags_cc': [ '-g', '-O0', '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ], 'defines': [ 'DEBUG' ], 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '1', + 'GCC_OPTIMIZATION_LEVEL': '0', 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES', 'DEAD_CODE_STRIPPING': 'NO', 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'NO', From 71245802940ced5d0858624fd8fb5a7df79c3c22 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 30 May 2014 12:13:26 -0700 Subject: [PATCH 2/5] fix function signature --- include/llmr/text/glyph_store.hpp | 2 +- src/text/glyph_store.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index 56aa63f2e..e44b94fe0 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -36,7 +36,7 @@ public: const float &alignment, const float &verticalAlignment, const float &letterSpacing) const; - Shaping lineWrap(Shaping &shaping, + void lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth, const float &alignment, diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index d9f0fedff..e93d9e995 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -67,7 +67,7 @@ void alignHorizontally(Shaping &shaping, const std::map } } -Shaping FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth, +void FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth, const float &alignment, const float &verticalAlignment) const { uint32_t lastSafeBreak = 0; From da29a16370addf244371afa7255d127c246b5983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 17:51:46 +0200 Subject: [PATCH 3/5] skip second loop --- src/map/tile_parser.cpp | 42 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 7bf66cd08..b7667503b 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -183,6 +183,8 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye util::utf8_to_utf32 ucs4conv; + std::vector> labels; + // Determine and load glyph ranges { std::set ranges; @@ -210,6 +212,8 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye for (uint32_t chr : string) { ranges.insert(getGlyphRange(chr)); } + + labels.emplace_back(string, feature.geometry); } glyphStore->waitForGlyphRanges(bucket_desc.geometry.font, ranges); @@ -220,38 +224,18 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye GlyphPositions face; // Shape and place all labels. - { - FilteredVectorTileLayer filtered_layer(layer, bucket_desc); - for (const pbf &feature_pbf : filtered_layer) { - if (obsolete()) - return nullptr; - VectorTileFeature feature{feature_pbf, layer}; + for (const std::pair &label : labels) { - auto it_prop = feature.properties.find(bucket_desc.geometry.field); - if (it_prop == feature.properties.end()) { - // feature does not have the correct property - if (debug::labelTextMissingWarning) { - fprintf(stderr, - "[WARNING] feature doesn't have property '%s' required for labelling\n", - bucket_desc.geometry.field.c_str()); - } - continue; - } + // Shape labels. + const Shaping shaping = fontStack.getShaping(label.first, bucket_desc.geometry.max_width, + bucket_desc.geometry.line_height, bucket_desc.geometry.alignment, + bucket_desc.geometry.vertical_alignment, bucket_desc.geometry.letter_spacing); - const std::string source_string = toString(it_prop->second); - const std::u32string string = ucs4conv.convert(source_string); + // Place labels. + addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, label.first, fontStack, *glyphAtlas, + face); - // Shape labels. - const Shaping shaping = fontStack.getShaping(string, bucket_desc.geometry.max_width, - bucket_desc.geometry.line_height, bucket_desc.geometry.alignment, - bucket_desc.geometry.vertical_alignment, bucket_desc.geometry.letter_spacing); - - // Place labels. - addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, string, fontStack, *glyphAtlas, - face); - - bucket->addFeature(feature.geometry, face, shaping); - } + bucket->addFeature(label.second, face, shaping); } return std::move(bucket); From c5fd7a0cddbf6825e3947bfbff418730b288b7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 21:05:25 +0200 Subject: [PATCH 4/5] add token replacement system fixes #212 --- bin/style.js | 38 +++++++++++++++++++------------------- src/map/tile_parser.cpp | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/bin/style.js b/bin/style.js index 3d24d6e79..3088e5e52 100644 --- a/bin/style.js +++ b/bin/style.js @@ -266,7 +266,7 @@ module.exports = { "field": "index", "value": 10, "path": "curve", - "text_field": "ele", + "text_field": "{{ele}}m", "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 10, "feature_type": "line", @@ -647,7 +647,7 @@ module.exports = { "country_label": { "source": "outdoors", "layer": "country_label", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "font": "Open Sans Bold, Arial Unicode MS Bold", "fontSize": 24, @@ -664,7 +664,7 @@ module.exports = { "layer": "marine_label", "feature_type": "line", "type": "text", - "text_field": "name", + "text_field": "{{name}}", "path": "curve", "font": "Open Sans Italic, Arial Unicode MS Regular", "fontSize": 16 @@ -674,7 +674,7 @@ module.exports = { "layer": "marine_label", "feature_type": "point", "type": "text", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "field": "labelrank", "value": 1, @@ -686,7 +686,7 @@ module.exports = { "layer": "marine_label", "feature_type": "point", "type": "text", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "field": "labelrank", "value": 2, @@ -698,7 +698,7 @@ module.exports = { "layer": "marine_label", "feature_type": "point", "type": "text", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "field": "labelrank", "value": [3,4,5,6], @@ -708,7 +708,7 @@ module.exports = { "state_label": { "source": "outdoors", "layer": "state_label", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 16, @@ -721,7 +721,7 @@ module.exports = { "layer": "place_label", "field": "type", "value": "city", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 20, @@ -733,7 +733,7 @@ module.exports = { "layer": "place_label", "field": "type", "value": "town", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 24, @@ -745,7 +745,7 @@ module.exports = { "layer": "place_label", "field": "type", "value": "village", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 22, @@ -761,7 +761,7 @@ module.exports = { "suburb", "neighbourhood" ], - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, @@ -774,7 +774,7 @@ module.exports = { "layer": "road_label", "field": "class", "value": ["motorway","main"], - "text_field": "name", + "text_field": "{{name}}", "path": "curve", "padding": 2, "font": "Open Sans Regular, Arial Unicode MS Regular", @@ -788,7 +788,7 @@ module.exports = { "layer": "road_label", "field": "class", "value": ["street","street_limited"], - "text_field": "name", + "text_field": "{{name}}", "path": "curve", "padding": 2, "font": "Open Sans Regular, Arial Unicode MS Regular", @@ -802,7 +802,7 @@ module.exports = { "layer": "road_label", "field": "class", "value": ["service","driveway","path"], - "text_field": "name", + "text_field": "{{name}}", "path": "curve", "padding": 2, "font": "Open Sans Regular, Arial Unicode MS Regular", @@ -814,7 +814,7 @@ module.exports = { "water_label": { "source": "outdoors", "layer": "water_label", - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", "fontSize": 12, @@ -824,7 +824,7 @@ module.exports = { "waterway_label": { "source": "outdoors", "layer": "waterway_label", - "text_field": "name", + "text_field": "{{name}}", "path": "curve", "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", "fontSize": 12, @@ -876,7 +876,7 @@ module.exports = { 1, 2 ], - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "padding": 2, "maxWidth": 8, @@ -892,7 +892,7 @@ module.exports = { "layer": "poi_label", "field": "scalerank", "value": 3, - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "padding": 2, "maxWidth": 8, @@ -908,7 +908,7 @@ module.exports = { "layer": "poi_label", "field": "scalerank", "value": 4, - "text_field": "name", + "text_field": "{{name}}", "path": "horizontal", "padding": 2, "maxWidth": 8, diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index b7667503b..ecd15adbb 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -16,6 +16,8 @@ #include #include +#include + using namespace llmr; TileParser::TileParser(const std::string &data, VectorTileData &tile, @@ -182,6 +184,9 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); util::utf8_to_utf32 ucs4conv; + std::regex token_regex("\\{\\{(\\w+)\\}\\}"); + const auto tokens_end = std::sregex_token_iterator(); + std::vector> labels; @@ -195,18 +200,34 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye return nullptr; VectorTileFeature feature{feature_pbf, layer}; - auto it_prop = feature.properties.find(bucket_desc.geometry.field); - if (it_prop == feature.properties.end()) { - // feature does not have the correct property - if (debug::labelTextMissingWarning) { - fprintf(stderr, - "[WARNING] feature doesn't have property '%s' required for labelling\n", - bucket_desc.geometry.field.c_str()); + const std::string &field = bucket_desc.geometry.field; + std::string source_string; + source_string.reserve(field.size()); + + bool token = false; + for (auto token_it = std::sregex_token_iterator(field.begin(), field.end(), token_regex, {-1, 1}); token_it != tokens_end; ++token_it, token = !token) { + if (!token_it->matched) { + continue; + } + + if (token) { + auto it_prop = feature.properties.find(token_it->str()); + if (it_prop == feature.properties.end()) { + // feature does not have the correct property + if (debug::labelTextMissingWarning) { + fprintf(stderr, + "[WARNING] feature doesn't have property '%s' required for labelling\n", + token_it->str().c_str()); + } + continue; + } + source_string += toString(it_prop->second); + } else { + source_string += token_it->str(); } - continue; } - const std::u32string string = ucs4conv.convert(toString(it_prop->second)); + const std::u32string string = ucs4conv.convert(source_string); // Loop through all characters of this text and collect unique codepoints. for (uint32_t chr : string) { From 552b9a0f1bc86b617fd6d8163c5164eceeb01641 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 30 May 2014 12:35:49 -0700 Subject: [PATCH 5/5] fix potential crash in line wrapping: - shaping.size() == 0 would result in unsigned overflow because uint32_t(0) - 1 == huge number --- src/text/glyph_store.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index e93d9e995..5e94a35f4 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -38,8 +38,7 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m Shaping shaping; // Loop through all characters of this label and shape. for (uint32_t chr : string) { - GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); - shaping.push_back(glyph); + shaping.emplace_back(0, chr, x, 0); i++; x += metrics.find(chr)->second.advance + letterSpacing; } @@ -58,18 +57,24 @@ void alignVertically(Shaping &shaping, const uint32_t &lines, const float &lineH void alignHorizontally(Shaping &shaping, const std::map &metrics, const uint32_t &start, const uint32_t &end, const float &alignment) { - - uint32_t lastAdvance = metrics.find(shaping[end].glyph)->second.advance; - int32_t lineIndent = (shaping[end].x + lastAdvance) * alignment; - - for (uint32_t j = start; j <= end; j++) { - shaping[j].x -= lineIndent; + auto & shape = shaping.at(end); + auto metric = metrics.find(shape.glyph); + if (metric != metrics.end()) { + uint32_t lastAdvance = metric->second.advance; + int32_t lineIndent = (shape.x + lastAdvance) * alignment; + for (uint32_t j = start; j <= end; j++) { + shaping[j].x -= lineIndent; + } } } void FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth, const float &alignment, const float &verticalAlignment) const { + std::size_t num_shapes = shaping.size(); + if (!num_shapes) { + return; + } uint32_t lastSafeBreak = 0; uint32_t lengthBeforeCurrentLine = 0; uint32_t lineStartIndex = 0; @@ -77,11 +82,10 @@ void FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float for (uint32_t i = 0; i < shaping.size(); i++) { GlyphPlacement &shape = shaping[i]; - shape.x -= lengthBeforeCurrentLine; shape.y += lineHeight * line; - if (shape.x > maxWidth && lastSafeBreak != 0) { + if (shape.x > maxWidth && lastSafeBreak > 0) { uint32_t lineLength = shaping[lastSafeBreak + 1].x; @@ -103,7 +107,6 @@ void FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float lastSafeBreak = i; } } - alignHorizontally(shaping, metrics, lineStartIndex, shaping.size() - 1, alignment); alignVertically(shaping, line + 1, lineHeight, verticalAlignment); }