From 71d2b230a123997b1793dec03b2dec1c6611faaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 16 Jun 2014 11:49:11 +0200 Subject: [PATCH 1/6] separate bucket render properties and change naming --- include/llmr/renderer/fill_bucket.hpp | 4 +- include/llmr/renderer/icon_bucket.hpp | 4 +- include/llmr/renderer/line_bucket.hpp | 4 +- include/llmr/renderer/text_bucket.hpp | 4 +- include/llmr/style/bucket_description.hpp | 55 ++-- include/llmr/text/placement.hpp | 4 +- src/map/tile_parser.cpp | 45 ++- src/renderer/fill_bucket.cpp | 44 ++- src/renderer/icon_bucket.cpp | 10 +- src/renderer/line_bucket.cpp | 19 +- src/renderer/painter_icon.cpp | 2 +- src/renderer/painter_text.cpp | 8 +- src/renderer/text_bucket.cpp | 8 +- src/style/bucket_description.cpp | 4 - src/style/style_parser.cpp | 358 ++++++++++++++-------- src/text/placement.cpp | 25 +- 16 files changed, 362 insertions(+), 236 deletions(-) diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp index 2d1f61d6a..95d53ce75 100644 --- a/include/llmr/renderer/fill_bucket.hpp +++ b/include/llmr/renderer/fill_bucket.hpp @@ -41,7 +41,7 @@ public: FillBucket(FillVertexBuffer& vertexBuffer, TriangleElementsBuffer& triangleElementsBuffer, LineElementsBuffer& lineElementsBuffer, - const BucketDescription& bucket_desc); + const BucketFillDescription& properties); ~FillBucket(); virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); @@ -55,7 +55,7 @@ public: void drawVertices(OutlineShader& shader); public: - const BucketGeometryDescription geom_desc; + const BucketFillDescription &properties; private: TESSalloc *allocator; diff --git a/include/llmr/renderer/icon_bucket.hpp b/include/llmr/renderer/icon_bucket.hpp index 0878622ec..5d653a15f 100644 --- a/include/llmr/renderer/icon_bucket.hpp +++ b/include/llmr/renderer/icon_bucket.hpp @@ -26,7 +26,7 @@ class VectorTileFeature; class IconBucket : public Bucket { public: IconBucket(IconVertexBuffer& vertexBuffer, - const BucketDescription& bucket_desc); + const BucketIconDescription& properties); virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); virtual bool hasData() const; @@ -37,7 +37,7 @@ public: void drawIcons(DotShader& shader); public: - const BucketGeometryDescription geometry; + const BucketIconDescription &properties; private: diff --git a/include/llmr/renderer/line_bucket.hpp b/include/llmr/renderer/line_bucket.hpp index e28c85b7a..d7253ace9 100644 --- a/include/llmr/renderer/line_bucket.hpp +++ b/include/llmr/renderer/line_bucket.hpp @@ -25,7 +25,7 @@ public: LineBucket(LineVertexBuffer& vertexBuffer, TriangleElementsBuffer& triangleElementsBuffer, PointElementsBuffer& pointElementsBuffer, - const BucketDescription& bucket_desc); + const BucketLineDescription& properties); virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); virtual bool hasData() const; @@ -39,7 +39,7 @@ public: void drawPoints(LinejoinShader& shader); public: - const BucketGeometryDescription geometry; + const BucketLineDescription &properties; private: diff --git a/include/llmr/renderer/text_bucket.hpp b/include/llmr/renderer/text_bucket.hpp index 36c50ae7f..566ed459e 100644 --- a/include/llmr/renderer/text_bucket.hpp +++ b/include/llmr/renderer/text_bucket.hpp @@ -28,7 +28,7 @@ public: TextBucket( TextVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, - const BucketDescription &bucket_desc, Placement &placement); + const BucketTextDescription &properties, Placement &placement); virtual void render(Painter &painter, const std::string &layer_name, const Tile::ID &id); virtual bool hasData() const; @@ -43,7 +43,7 @@ public: void drawGlyphs(TextShader &shader); public: - const BucketGeometryDescription &geom_desc; + const BucketTextDescription &properties; private: TextVertexBuffer& vertexBuffer; diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index f77ff5170..a2386e436 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -82,31 +82,50 @@ inline float verticalAlignmentType(const std::string& alignment) { else return 0.5; }; +class BucketFillDescription { +public: +}; -class BucketGeometryDescription { +class BucketLineDescription { public: CapType cap = CapType::None; JoinType join = JoinType::None; - std::string font; - std::string field; - std::string icon; - float size = 0.0f; float miter_limit = 2.0f; float round_limit = 1.0f; - TextPathType path = TextPathType::Horizontal; - float alignment = 0.5; - float vertical_alignment = 0.5; - float line_height = 1.2 * 24; - float max_width = 15.0f * 24; - float letter_spacing = 0; - vec2 translate {0, 0}; - float padding = 2.0f; - float textMinDistance = 250.0f; - float rotate = 0.0f; // what is this? - float maxAngleDelta = M_PI; - bool alwaysVisible = false; }; +class BucketIconDescription { +public: + uint16_t size = 16; + vec2 translate {0, 0}; + std::string icon; +}; + +class BucketTextDescription { +public: + std::string field; + TextPathType path = TextPathType::Horizontal; + std::string font; + float max_size = 16.0f; + float max_width = 15.0f * 24; + float line_height = 1.2f * 24; + float letter_spacing = 0.0f; + float alignment = 0.5f; + float vertical_alignment = 0.5; + vec2 translate {0, 0}; + float max_angle_delta = M_PI; + float min_distance = 250.0f; + float rotate = 0.0f; // what is this? + float padding = 2.0f; + bool always_visible = false; +}; + +class BucketRasterDescription { +public: +}; + +typedef util::variant BucketRenderDescription; class BucketDescription { public: @@ -120,7 +139,7 @@ public: PropertyFilterExpression filter = std::true_type(); // Specifies how the geometry for this bucket should be created - BucketGeometryDescription geometry; + BucketRenderDescription render; }; std::ostream& operator<<(std::ostream&, const BucketDescription& bucket); diff --git a/include/llmr/text/placement.hpp b/include/llmr/text/placement.hpp index fb3ddaa66..ec7462aa9 100644 --- a/include/llmr/text/placement.hpp +++ b/include/llmr/text/placement.hpp @@ -10,14 +10,14 @@ namespace llmr { class TextBucket; -class BucketGeometryDescription; +class BucketTextDescription; class Placement { public: Placement(int8_t zoom); void addFeature(TextBucket &bucket, const std::vector &line, - const BucketGeometryDescription &info, + const BucketTextDescription &info, const GlyphPositions &face, const Shaping &shaping); diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 21d2bf1bf..1c1268c80 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -166,24 +166,38 @@ void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer, std::unique_ptr TileParser::createFillBucket(const VectorTileLayer &layer, const BucketDescription &bucket_desc) { + if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { + return nullptr; + } + std::unique_ptr bucket = std::make_unique( - tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, bucket_desc); + tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, + bucket_desc.render.get()); addBucketFeatures(bucket, layer, bucket_desc); return obsolete() ? nullptr : std::move(bucket); } std::unique_ptr TileParser::createLineBucket(const VectorTileLayer &layer, const BucketDescription &bucket_desc) { + if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { + return nullptr; + } + std::unique_ptr bucket = std::make_unique( - tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, bucket_desc); + tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, + bucket_desc.render.get()); addBucketFeatures(bucket, layer, bucket_desc); return obsolete() ? nullptr : std::move(bucket); } std::unique_ptr TileParser::createIconBucket(const VectorTileLayer &layer, const BucketDescription &bucket_desc) { - std::unique_ptr bucket = - std::make_unique(tile.iconVertexBuffer, bucket_desc); + if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { + return nullptr; + } + + std::unique_ptr bucket = std::make_unique( + tile.iconVertexBuffer, bucket_desc.render.get()); addBucketFeatures(bucket, layer, bucket_desc, *spriteAtlas); return obsolete() ? nullptr : std::move(bucket); } @@ -192,8 +206,15 @@ typedef std::pair GlyphRange; std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &layer, const BucketDescription &bucket_desc) { + + if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { + return nullptr; + } + + const BucketTextDescription &properties = bucket_desc.render.get(); + std::unique_ptr bucket = std::make_unique( - tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); + tile.textVertexBuffer, tile.triangleElementsBuffer, properties, placement); util::utf8_to_utf32 ucs4conv; @@ -210,7 +231,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye VectorTileFeature feature{feature_pbf, layer}; const std::u32string string = ucs4conv.convert( - util::replaceTokens(bucket_desc.geometry.field, feature.properties)); + util::replaceTokens(properties.field, feature.properties)); // Loop through all characters of this text and collect unique codepoints. for (uint32_t chr : string) { @@ -220,23 +241,23 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye labels.emplace_back(string, feature.geometry); } - glyphStore->waitForGlyphRanges(bucket_desc.geometry.font, ranges); + glyphStore->waitForGlyphRanges(properties.font, ranges); } // Create a copy! - const FontStack &fontStack = glyphStore->getFontStack(bucket_desc.geometry.font); + const FontStack &fontStack = glyphStore->getFontStack(properties.font); GlyphPositions face; // Shape and place all labels. for (const std::pair &label : labels) { // 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 Shaping shaping = fontStack.getShaping(label.first, properties.max_width, + properties.line_height, properties.alignment, + properties.vertical_alignment, properties.letter_spacing); // Place labels. - addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, label.first, fontStack, *glyphAtlas, + addGlyph(tile.id.to_uint64(), properties.font, label.first, fontStack, *glyphAtlas, face); bucket->addFeature(label.second, face, shaping); diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index 702156659..d7ba048a5 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -30,30 +30,26 @@ void FillBucket::free(void *, void *ptr) { ::free(ptr); } -FillBucket::FillBucket(FillVertexBuffer& vertexBuffer, - TriangleElementsBuffer& triangleElementsBuffer, - LineElementsBuffer& lineElementsBuffer, - const BucketDescription& bucket_desc) - : geom_desc(bucket_desc.geometry), - allocator(new TESSalloc { - &alloc, - &realloc, - &free, - nullptr, // userData - 64, // meshEdgeBucketSize - 64, // meshVertexBucketSize - 32, // meshFaceBucketSize - 64, // dictNodeBucketSize - 8, // regionBucketSize - 128, // extraVertices allocated for the priority queue. -}), -tesselator(tessNewTess(allocator)), -vertexBuffer(vertexBuffer), -triangleElementsBuffer(triangleElementsBuffer), -lineElementsBuffer(lineElementsBuffer), -vertex_start(vertexBuffer.index()), -triangle_elements_start(triangleElementsBuffer.index()), -line_elements_start(lineElementsBuffer.index()) { +FillBucket::FillBucket(FillVertexBuffer &vertexBuffer, + TriangleElementsBuffer &triangleElementsBuffer, + LineElementsBuffer &lineElementsBuffer, + const BucketFillDescription &properties) + : properties(properties), + allocator(new TESSalloc{&alloc, &realloc, &free, nullptr, // userData + 64, // meshEdgeBucketSize + 64, // meshVertexBucketSize + 32, // meshFaceBucketSize + 64, // dictNodeBucketSize + 8, // regionBucketSize + 128, // extraVertices allocated for the priority queue. + }), + tesselator(tessNewTess(allocator)), + vertexBuffer(vertexBuffer), + triangleElementsBuffer(triangleElementsBuffer), + lineElementsBuffer(lineElementsBuffer), + vertex_start(vertexBuffer.index()), + triangle_elements_start(triangleElementsBuffer.index()), + line_elements_start(lineElementsBuffer.index()) { assert(tesselator); } diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp index fd43f6951..b6c324d2a 100644 --- a/src/renderer/icon_bucket.cpp +++ b/src/renderer/icon_bucket.cpp @@ -19,8 +19,8 @@ struct geometry_too_long_exception : std::exception {}; using namespace llmr; IconBucket::IconBucket(IconVertexBuffer& vertexBuffer, - const BucketDescription& bucket_desc) - : geometry(bucket_desc.geometry), + const BucketIconDescription& properties) + : properties(properties), vertexBuffer(vertexBuffer), vertex_start(vertexBuffer.index()) { } @@ -28,15 +28,15 @@ IconBucket::IconBucket(IconVertexBuffer& vertexBuffer, void IconBucket::addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas) { std::string field; - if (geometry.field.size()) { - field = util::replaceTokens(geometry.field, feature.properties); + if (properties.icon.size()) { + field = util::replaceTokens(properties.icon, feature.properties); } if (!field.size()) { field = ""; } - const Rect rect = sprite_atlas.getIcon(geometry.size, field); + const Rect rect = sprite_atlas.getIcon(properties.size, field); const uint16_t tx = rect.x + rect.w / 2; const uint16_t ty = rect.y + rect.h / 2; diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index 58dde3f50..d6d3dcf77 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -20,8 +20,8 @@ using namespace llmr; LineBucket::LineBucket(LineVertexBuffer& vertexBuffer, TriangleElementsBuffer& triangleElementsBuffer, PointElementsBuffer& pointElementsBuffer, - const BucketDescription& bucket_desc) - : geometry(bucket_desc.geometry), + const BucketLineDescription& properties) + : properties(properties), vertexBuffer(vertexBuffer), triangleElementsBuffer(triangleElementsBuffer), pointElementsBuffer(pointElementsBuffer), @@ -60,9 +60,6 @@ struct TriangleElement { typedef uint16_t PointElement; void LineBucket::addGeometry(const std::vector& vertices) { - const JoinType join = geometry.join; - const CapType cap = geometry.cap; - const float miterLimit = geometry.miter_limit; // TODO: use roundLimit // const float roundLimit = geometry.round_limit; @@ -80,8 +77,8 @@ void LineBucket::addGeometry(const std::vector& vertices) { return; } - CapType beginCap = cap; - CapType endCap = closed ? CapType::Butt : cap; + CapType beginCap = properties.cap; + CapType endCap = closed ? CapType::Butt : properties.cap; JoinType currentJoin = JoinType::None; @@ -111,7 +108,7 @@ void LineBucket::addGeometry(const std::vector& vertices) { if (currentVertex) prevVertex = currentVertex; currentVertex = vertices[i]; - currentJoin = join; + currentJoin = properties.join; if (prevVertex) distance += util::dist(currentVertex, prevVertex); @@ -164,7 +161,7 @@ void LineBucket::addGeometry(const std::vector& vertices) { // Switch to miter joins if the angle is very low. if (currentJoin != JoinType::Miter) { - if (std::fabs(joinAngularity) < 0.5 && roundness < miterLimit) { + if (std::fabs(joinAngularity) < 0.5 && roundness < properties.miter_limit) { currentJoin = JoinType::Miter; } } @@ -213,14 +210,14 @@ void LineBucket::addGeometry(const std::vector& vertices) { // The two normals are almost parallel. joinNormal.x = -nextNormal.y; joinNormal.y = nextNormal.x; - } else if (roundness > miterLimit) { + } else if (roundness > properties.miter_limit) { // If the miter grows too large, flip the direction to make a // bevel join. joinNormal.x = (prevNormal.x - nextNormal.x) / joinAngularity; joinNormal.y = (prevNormal.y - nextNormal.y) / joinAngularity; } - if (roundness > miterLimit) { + if (roundness > properties.miter_limit) { flip = -flip; } diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 8ddf493d0..8c07349b2 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -41,7 +41,7 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons spriteAtlas.bind(map.getState().isChanging()); - const float iconSize = bucket.geometry.size * map.getState().getPixelRatio(); + const float iconSize = bucket.properties.size * map.getState().getPixelRatio(); iconShader->setSize(iconSize); #ifndef GL_ES_VERSION_2_0 glPointSize(iconSize); diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index 5307a12ac..baebe2669 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -20,7 +20,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons mat4 exMatrix; matrix::copy(exMatrix, projMatrix); - if (bucket.geom_desc.path == TextPathType::Curve) { + if (bucket.properties.path == TextPathType::Curve) { matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle()); } @@ -30,7 +30,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons } // If layerStyle.size > bucket.info.fontSize then labels may collide - float fontSize = std::fmin(properties.size, bucket.geom_desc.size); + float fontSize = std::fmin(properties.size, bucket.properties.max_size); matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f); const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); @@ -48,10 +48,10 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons float angle = std::round((map.getState().getAngle() + rotate) / M_PI * 128); // adjust min/max zooms for variable font sies - float zoomAdjust = log(fontSize / bucket.geom_desc.size) / log(2); + float zoomAdjust = log(fontSize / bucket.properties.max_size) / log(2); textShader->setAngle((int32_t)(angle + 256) % 256); - textShader->setFlip(bucket.geom_desc.path == TextPathType::Curve ? 1 : 0); + textShader->setFlip(bucket.properties.path == TextPathType::Curve ? 1 : 0); textShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) * 10); // current zoom level // Label fading diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index da6de3817..bd18f0576 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -22,8 +22,8 @@ using namespace llmr; TextBucket::TextBucket( TextVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, - const BucketDescription &bucket_desc, Placement &placement) - : geom_desc(bucket_desc.geometry), + const BucketTextDescription &properties, Placement &placement) + : properties(properties), vertexBuffer(vertexBuffer), triangleElementsBuffer(triangleElementsBuffer), placement(placement), @@ -113,14 +113,14 @@ void TextBucket::addFeature(const pbf &geom_pbf, while ((cmd = geometry.next(x, y)) != Geometry::end) { if (cmd == Geometry::move_to) { if (!line.empty()) { - placement.addFeature(*this, line, geom_desc, face, shaping); + placement.addFeature(*this, line, properties, face, shaping); line.clear(); } } line.emplace_back(x, y); } if (line.size()) { - placement.addFeature(*this, line, geom_desc, face, shaping); + placement.addFeature(*this, line, properties, face, shaping); } } diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp index b154c3a17..24d086f64 100644 --- a/src/style/bucket_description.cpp +++ b/src/style/bucket_description.cpp @@ -8,10 +8,6 @@ std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket os << " - type: " << (uint32_t)bucket.type << std::endl; os << " - source_name: " << bucket.source_name << std::endl; os << " - source_layer: " << bucket.source_layer << std::endl; - os << " - cap: " << (uint32_t)bucket.geometry.cap << std::endl; - os << " - join: " << (uint32_t)bucket.geometry.join << std::endl; - os << " - font: " << bucket.geometry.font << std::endl; - os << " - size: " << bucket.geometry.size << std::endl; return os; } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index b686c0ec5..edce8d2b6 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -73,134 +73,40 @@ PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) { BucketDescription StyleParser::parseBucket(JSVal value) { BucketDescription bucket; - rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); - for (; itr != value.MemberEnd(); ++itr) { - const std::string name(itr->name.GetString(), itr->name.GetStringLength()); - JSVal value = itr->value; - - if (name == "type") { - if (value.IsString()) { - bucket.type = bucketType({ value.GetString(), value.GetStringLength() }); - } else { - throw Style::exception("bucket type must be a string"); - } - } else if (name == "feature_type") { - if (value.IsString()) { - bucket.feature_type = bucketType({ value.GetString(), value.GetStringLength() }); - } else { - throw Style::exception("feature type must be a string"); - } - } else if (name == "source") { - if (value.IsString()) { - bucket.source_name = { value.GetString(), value.GetStringLength() }; - } else { - throw Style::exception("source name must be a string"); - } - } else if (name == "layer") { - if (value.IsString()) { - bucket.source_layer = { value.GetString(), value.GetStringLength() }; - } else { - throw Style::exception("layer name must be a string"); - } - } else if (name == "cap") { - if (value.IsString()) { - bucket.geometry.cap = capType({ value.GetString(), value.GetStringLength() }); - } else { - throw Style::exception("cap type must be a string"); - } - } else if (name == "join") { - if (value.IsString()) { - bucket.geometry.join = joinType({ value.GetString(), value.GetStringLength() }); - } else { - throw Style::exception("join type must be a string"); - } - } else if (name == "font") { - if (value.IsString()) { - bucket.geometry.font = { value.GetString(), value.GetStringLength() }; - } else { - throw Style::exception("font stack must be a string"); - } - } else if (name == "fontSize" || name == "size") { - if (value.IsNumber()) { - bucket.geometry.size = value.GetDouble(); - } else { - throw Style::exception("font size must be a number"); - } - } else if (name == "text_field" || name == "icon") { - if (value.IsString()) { - bucket.geometry.field = { value.GetString(), value.GetStringLength() }; - } else { - throw Style::exception("text field must be a string"); - } - } else if (name == "path") { - if (value.IsString()) { - bucket.geometry.path = textPathType({ value.GetString(), value.GetStringLength() }); - } else { - throw Style::exception("curve must be a string"); - } - } else if (name == "alignment") { - if (value.IsString()) { - bucket.geometry.alignment = alignmentType({ value.GetString(), value.GetStringLength() }); - } else { - throw Style::exception("alignment must be a string"); - } - } else if (name == "translate") { - if (value.IsArray()) { - bucket.geometry.translate.x = value[(rapidjson::SizeType)0].GetDouble() * 24; - bucket.geometry.translate.y = value[(rapidjson::SizeType)1].GetDouble() * -24; - } else { - throw Style::exception("translate must be a string"); - } - } else if (name == "verticalAlignment") { - if (value.IsString()) { - bucket.geometry.vertical_alignment = verticalAlignmentType({ value.GetString(), value.GetStringLength() }); - } else { - throw Style::exception("verticalAlignment must be a string"); - } - } else if (name == "lineHeight") { - if (value.IsNumber()) { - bucket.geometry.line_height = value.GetDouble() * 24; - } else { - throw Style::exception("line height must be a number"); - } - } else if (name == "maxWidth") { - if (value.IsNumber()) { - bucket.geometry.max_width = value.GetDouble() * 24; - } else { - throw Style::exception("max width must be a number"); - } - } else if (name == "letterSpacing") { - if (value.IsNumber()) { - bucket.geometry.letter_spacing = value.GetDouble() * 24; - } else { - throw Style::exception("letter spacing must be a number"); - } - } else if (name == "miterLimit") { - if (value.IsNumber()) { - bucket.geometry.miter_limit = value.GetDouble(); - } else { - throw Style::exception("miter limit must be a number"); - } - } else if (name == "roundLimit") { - if (value.IsNumber()) { - bucket.geometry.round_limit = value.GetDouble(); - } else { - throw Style::exception("round limit must be a number"); - } - } else if (name == "textMinDistance") { - if (value.IsNumber()) { - bucket.geometry.textMinDistance = value.GetDouble(); - } else { - throw Style::exception("text min distance must be a number"); - } - } else if (name == "maxAngleDelta") { - if (value.IsNumber()) { - bucket.geometry.maxAngleDelta = value.GetDouble(); - } else { - throw Style::exception("max angle delta must be a number"); - } + if (value.HasMember("type")) { + JSVal type = value["type"]; + if (type.IsString()) { + bucket.type = bucketType({ type.GetString(), type.GetStringLength() }); + } else { + throw Style::exception("bucket type must be a string"); } + } + if (value.HasMember("feature_type")) { + JSVal feature_type = value["feature_type"]; + if (feature_type.IsString()) { + bucket.feature_type = bucketType({ feature_type.GetString(), feature_type.GetStringLength() }); + } else { + throw Style::exception("feature type must be a string"); + } + } + + if (value.HasMember("source")) { + JSVal source = value["source"]; + if (source.IsString()) { + bucket.source_name = { source.GetString(), source.GetStringLength() }; + } else { + throw Style::exception("source name must be a string"); + } + } + + if (value.HasMember("layer")) { + JSVal source_layer = value["layer"]; + if (source_layer.IsString()) { + bucket.source_layer = { source_layer.GetString(), source_layer.GetStringLength() }; + } else { + throw Style::exception("layer name must be a string"); + } } if (value.HasMember("filter")) { @@ -214,6 +120,206 @@ BucketDescription StyleParser::parseBucket(JSVal value) { bucket.feature_type = bucket.type; } + switch (bucket.type) { + case BucketType::Fill: { + bucket.render = BucketFillDescription{}; + } break; + + case BucketType::Line: { + bucket.render = BucketLineDescription{}; + BucketLineDescription &render = bucket.render.get(); + + if (value.HasMember("cap")) { + JSVal property = value["cap"]; + if (property.IsString()) { + render.cap = capType({property.GetString(), property.GetStringLength()}); + } else { + throw Style::exception("cap type must be a string"); + } + } + if (value.HasMember("join")) { + JSVal property = value["join"]; + if (property.IsString()) { + render.join = joinType({property.GetString(), property.GetStringLength()}); + } else { + throw Style::exception("join type must be a string"); + } + } + if (value.HasMember("miterLimit")) { + JSVal property = value["miterLimit"]; + if (property.IsNumber()) { + render.miter_limit = property.GetDouble(); + } else { + throw Style::exception("miter limit must be a number"); + } + } + if (value.HasMember("roundLimit")) { + JSVal property = value["roundLimit"]; + if (property.IsNumber()) { + render.round_limit = property.GetDouble(); + } else { + throw Style::exception("round limit must be a number"); + } + } + } break; + + case BucketType::Icon: { + bucket.render = BucketIconDescription{}; + BucketIconDescription &render = bucket.render.get(); + + if (value.HasMember("size")) { + JSVal property = value["size"]; + if (property.IsNumber()) { + render.size = property.GetDouble(); + } else { + throw Style::exception("font size must be a number"); + } + } + + if (value.HasMember("icon")) { + JSVal property = value["icon"]; + if (property.IsString()) { + render.icon = {property.GetString(), property.GetStringLength()}; + } else { + throw Style::exception("text field must be a string"); + } + } + + if (value.HasMember("translate")) { + JSVal property = value["translate"]; + if (property.IsArray()) { + render.translate.x = property[(rapidjson::SizeType)0].GetDouble() * 24; + render.translate.y = property[(rapidjson::SizeType)1].GetDouble() * -24; + } else { + throw Style::exception("translate must be a string"); + } + } + } break; + + case BucketType::Text: { + bucket.render = BucketTextDescription{}; + BucketTextDescription &render = bucket.render.get(); + + if (value.HasMember("text_field")) { + JSVal property = value["text_field"]; + if (property.IsString()) { + render.field = {property.GetString(), property.GetStringLength()}; + } else { + throw Style::exception("text field must be a string"); + } + } + + if (value.HasMember("path")) { + JSVal property = value["path"]; + if (property.IsString()) { + render.path = textPathType({property.GetString(), property.GetStringLength()}); + } else { + throw Style::exception("curve must be a string"); + } + } + + if (value.HasMember("font")) { + JSVal property = value["font"]; + if (property.IsString()) { + render.font = {property.GetString(), property.GetStringLength()}; + } else { + throw Style::exception("font stack must be a string"); + } + } + + if (value.HasMember("fontSize")) { + JSVal property = value["fontSize"]; + if (property.IsNumber()) { + render.max_size = property.GetDouble(); + } else { + throw Style::exception("font size must be a number"); + } + } + + if (value.HasMember("maxWidth")) { + JSVal property = value["maxWidth"]; + if (property.IsNumber()) { + render.max_width = property.GetDouble() * 24; + } else { + throw Style::exception("max width must be a number"); + } + } + + if (value.HasMember("lineHeight")) { + JSVal property = value["lineHeight"]; + if (property.IsNumber()) { + render.line_height = property.GetDouble() * 24; + } else { + throw Style::exception("line height must be a number"); + } + } + + if (value.HasMember("letterSpacing")) { + JSVal property = value["letterSpacing"]; + if (property.IsNumber()) { + render.letter_spacing = property.GetDouble() * 24; + } else { + throw Style::exception("letter spacing must be a number"); + } + } + + if (value.HasMember("alignment")) { + JSVal property = value["alignment"]; + if (property.IsString()) { + render.alignment = + alignmentType({property.GetString(), property.GetStringLength()}); + } else { + throw Style::exception("alignment must be a string"); + } + } + + if (value.HasMember("verticalAlignment")) { + JSVal property = value["verticalAlignment"]; + if (property.IsString()) { + render.vertical_alignment = + verticalAlignmentType({property.GetString(), property.GetStringLength()}); + } else { + throw Style::exception("verticalAlignment must be a string"); + } + } + + if (value.HasMember("translate")) { + JSVal property = value["translate"]; + if (property.IsArray()) { + render.translate.x = property[(rapidjson::SizeType)0].GetDouble() * 24; + render.translate.y = property[(rapidjson::SizeType)1].GetDouble() * -24; + } else { + throw Style::exception("translate must be a string"); + } + } + + if (value.HasMember("maxAngleDelta")) { + JSVal property = value["maxAngleDelta"]; + if (property.IsNumber()) { + render.max_angle_delta = property.GetDouble(); + } else { + throw Style::exception("max angle delta must be a number"); + } + } + + if (value.HasMember("textMinDistance")) { + JSVal property = value["textMinDistance"]; + if (property.IsNumber()) { + render.min_distance = property.GetDouble(); + } else { + throw Style::exception("text min distance must be a number"); + } + } + } break; + + case BucketType::Raster: { + bucket.render = BucketRasterDescription{}; + } break; + + default: + break; + } + return bucket; } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index b15e32496..112f1d79c 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -244,19 +244,11 @@ void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes, } } -void Placement::addFeature(TextBucket& bucket, - const std::vector &line, - const BucketGeometryDescription &info, - const GlyphPositions &face, +void Placement::addFeature(TextBucket &bucket, const std::vector &line, + const BucketTextDescription &info, const GlyphPositions &face, const Shaping &shaping) { - const bool horizontal = info.path == TextPathType::Horizontal; - const float padding = info.padding; - const float maxAngleDelta = info.maxAngleDelta; - const float textMinDistance = info.textMinDistance; - const float rotate = info.rotate; - const float fontScale = - (tileExtent / util::tileSize) / (glyphSize / info.size); + const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.max_size); Anchors anchors; @@ -268,7 +260,7 @@ void Placement::addFeature(TextBucket& bucket, } else { // Line labels - anchors = interpolate(line, textMinDistance, minScale); + anchors = interpolate(line, info.min_distance, minScale); // Sort anchors by segment so that we can start placement with // the anchors that can be shown at the lowest zoom levels. @@ -279,11 +271,10 @@ void Placement::addFeature(TextBucket& bucket, PlacedGlyphs glyphs; GlyphBoxes boxes; - getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal, - line, maxAngleDelta, rotate); - PlacementProperty place = - collision.place(boxes, anchor, anchor.scale, maxPlacementScale, - padding, horizontal, info.alwaysVisible); + getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal, line, + info.max_angle_delta, info.rotate); + PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale, + info.padding, horizontal, info.always_visible); if (place) { bucket.addGlyphs(glyphs, place.zoom, place.rotationRange, zoom - zOffset); } From 4a41b02cefcba67d6c4cfa061e7bf2e19a7f49f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 16 Jun 2014 15:47:37 +0200 Subject: [PATCH 2/6] move to std::map for classes --- include/llmr/style/class_description.hpp | 32 +- include/llmr/style/properties.hpp | 190 ++++++--- include/llmr/style/style.hpp | 9 +- include/llmr/style/style_parser.hpp | 18 +- src/style/class_description.cpp | 9 + src/style/style.cpp | 507 +++++++++++++---------- src/style/style_parser.cpp | 157 +++---- 7 files changed, 537 insertions(+), 385 deletions(-) create mode 100644 src/style/class_description.cpp diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp index 216ddeb70..6bd2a03c1 100644 --- a/include/llmr/style/class_description.hpp +++ b/include/llmr/style/class_description.hpp @@ -2,21 +2,35 @@ #define LLMR_STYLE_CLASS_DESCRIPTION #include -#include -#include +#include #include "properties.hpp" namespace llmr { class ClassDescription { public: - BackgroundClass background; - std::map fill; - std::map line; - std::map icon; - std::map text; - std::map raster; - std::map composite; + inline const ClassProperties &operator[](const std::string &name) const { + auto it = styles.find(name); + if (it != styles.end()) { + return it->second; + } else { + return defaultProperties; + } + } + + void addClass(const std::string &name, ClassProperties &&properties); + + inline std::unordered_map::const_iterator begin() const { + return styles.begin(); + } + + inline std::unordered_map::const_iterator end() const { + return styles.end(); + } + +private: + std::unordered_map styles; + static const ClassProperties defaultProperties; }; diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 487f2d6c6..c31942f94 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -6,9 +6,12 @@ #include #include #include +#include #include +#include #include +#include namespace llmr { @@ -16,7 +19,10 @@ namespace llmr { typedef std::array Color; struct PropertyTransition { - inline PropertyTransition(uint16_t duration, uint16_t delay = 0) : duration(duration), delay(delay) {} + inline PropertyTransition(uint16_t duration, uint16_t delay = 0) + : duration(duration), delay(delay) {} + inline PropertyTransition(const PropertyTransition &transition) + : duration(transition.duration), delay(transition.delay) {} uint16_t duration = 0; uint16_t delay = 0; }; @@ -82,21 +88,124 @@ struct FunctionProperty { std::vector values; inline FunctionProperty() : function(&functions::null) {} + + inline FunctionProperty(const FunctionProperty &property) + : function(property.function), values(property.values) {} + inline FunctionProperty(FunctionProperty &&property) + : function(property.function), values(std::move(property.values)) {} + + + inline void operator=(const FunctionProperty &rhs) { + function = rhs.function; + values = rhs.values; + } + inline FunctionProperty(float value) : function(&functions::constant), values(1, value) {} template inline T evaluate(float z) const { return function(z, values); } }; -struct GenericClass { - boost::optional enabled; - boost::optional> translate; - boost::optional translate_transition; - boost::optional translateAnchor; - boost::optional opacity; - boost::optional opacity_transition; - boost::optional prerender; - boost::optional prerenderBuffer; - boost::optional prerenderSize; - boost::optional prerenderBlur; + +enum class RenderType { + Fill, + Line, + Icon, + Text, + Raster, + Composite, + Background +}; + +enum class ClassPropertyKey { + Enabled, + TranslateX, + TranslateY, + TranslateTransition, + TranslateAnchor, + Opacity, + OpacityTransition, + Prerender, + PrerenderBuffer, + PrerenderSize, + PrerenderBlur, + + FillWinding, + FillAntialias, + FillColor, + FillColorTransition, + FillStrokeColor, + FillStrokeColorTransition, + FillImage, + + LineWidth, + LineWidthTransition, + LineOffset, + LineOffsetTransition, + LineColor, + LineColorTransition, + LineDashLand, + LineDashGap, + LineDashTransition, + + IconSize, + IconColor, + IconColorTransition, + IconImage, + IconRadius, + IconRadiusTransition, + IconBlur, + IconBlurTransition, + + TextColor, + TextColorTransition, + TextHaloColor, + TextHaloColorTransition, + TextHaloRadius, + TextHaloRadiusTransition, + TextHaloBlur, + TextHaloBlurTransition, + TextSize, + TextRotate, + TextAlwaysVisible, + + BackgroundColor, + BackgroundColorTransition, +}; + +typedef util::variant< + FunctionProperty, + PropertyTransition, + TranslateAnchor, + Color, + Winding, + std::string, + bool +> ClassPropertyValue; + +class ClassProperties { +public: + inline ClassProperties(RenderType type) : type(type) {} + inline ClassProperties(ClassProperties &&properties) + : type(properties.type), properties(std::move(properties.properties)) {} + + template + inline const T *get(ClassPropertyKey key) const { + const auto it = properties.find(key); + if (it != properties.end() && it->second.is()) { + return ::std::addressof(it->second.get()); + } else { + return nullptr; + } + } + + template + inline void emplace(Args&& ...args) { + properties.emplace(::std::forward(args)...); + } + + const RenderType type; + +private: + std::map properties; }; struct PrerenderProperties { @@ -137,17 +246,6 @@ struct GenericProperties { } }; -struct IconClass : public GenericClass { - boost::optional size; - boost::optional color; - boost::optional color_transition; - boost::optional image; - boost::optional radius; - boost::optional radius_transition; - boost::optional blur; - boost::optional blur_transition; -}; - struct IconProperties : public GenericProperties { inline IconProperties() : GenericProperties() {} float size = 0; @@ -157,17 +255,6 @@ struct IconProperties : public GenericProperties { float blur = 0; }; -struct LineClass : public GenericClass { - boost::optional width; - boost::optional width_transition; - boost::optional offset; - boost::optional offset_transition; - boost::optional color; - boost::optional color_transition; - boost::optional> dash_array; - boost::optional dash_array_transition; -}; - struct LineProperties : public GenericProperties { inline LineProperties() : GenericProperties() {} float width = 0; @@ -176,16 +263,6 @@ struct LineProperties : public GenericProperties { std::array dash_array = {{ 1, -1 }}; }; -struct FillClass : public GenericClass { - boost::optional winding; - boost::optional antialias; - boost::optional fill_color; - boost::optional fill_color_transition; - boost::optional stroke_color; - boost::optional stroke_color_transition; - boost::optional image; -}; - struct FillProperties : public GenericProperties { inline FillProperties() : GenericProperties() {} Winding winding = Winding::NonZero; @@ -196,20 +273,6 @@ struct FillProperties : public GenericProperties { std::string image; }; -struct TextClass : public GenericClass { - boost::optional color; - boost::optional color_transition; - boost::optional halo; - boost::optional halo_transition; - boost::optional halo_radius; - boost::optional halo_radius_transition; - boost::optional halo_blur; - boost::optional halo_blur_transition; - boost::optional size; - boost::optional rotate; - boost::optional always_visible; -}; - struct TextProperties : public GenericProperties { inline TextProperties() : GenericProperties() {} Color color = {{ 0, 0, 0, 1 }}; @@ -221,26 +284,15 @@ struct TextProperties : public GenericProperties { bool always_visible = false; }; -struct BackgroundClass : public GenericClass { - boost::optional color; - boost::optional color_transition; -}; - struct BackgroundProperties : public GenericProperties { inline BackgroundProperties() : GenericProperties() {} Color color = {{ 1, 1, 1, 1 }}; }; -struct RasterClass : public GenericClass { -}; - struct RasterProperties : public GenericProperties { inline RasterProperties() : GenericProperties() {} }; -struct CompositeClass : public GenericClass { -}; - struct CompositeProperties : public GenericProperties { inline CompositeProperties() : GenericProperties() {} }; diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 58202393d..5dc19a11a 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -69,7 +69,14 @@ private: uint64_t transitionDuration(const std::string &layer_name, TransitionablePropertyKey key) const; uint64_t transitionDelay(const std::string &layer_name, TransitionablePropertyKey key) const; - void cascadeProperties(GenericProperties &properties, const GenericClass& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); private: // Last applied settings. diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 10f367475..0ef260890 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -30,14 +30,14 @@ private: const std::map &buckets, const std::map &layerBuckets); - void parseGenericClass(GenericClass &klass, JSVal value); - FillClass parseFillClass(JSVal value); - LineClass parseLineClass(JSVal value); - IconClass parseIconClass(JSVal value); - TextClass parseTextClass(JSVal value); - BackgroundClass parseBackgroundClass(JSVal value); - RasterClass parseRasterClass(JSVal value); - CompositeClass parseCompositeClass(JSVal value); + void parseGenericClass(ClassProperties &klass, JSVal value); + ClassProperties parseFillClass(JSVal value); + ClassProperties parseLineClass(JSVal value); + ClassProperties parseIconClass(JSVal value); + ClassProperties parseTextClass(JSVal value); + ClassProperties parseBackgroundClass(JSVal value); + ClassProperties parseRasterClass(JSVal value); + ClassProperties parseCompositeClass(JSVal value); PropertyFilterExpression parseFilterOrExpression(JSVal value); @@ -49,7 +49,7 @@ private: Value parseValue(JSVal value); FunctionProperty::fn parseFunctionType(JSVal type); FunctionProperty parseFunction(JSVal value); - boost::optional parseTransition(JSVal value, std::string property_name); + void parseTransition(ClassProperties &klass, ClassPropertyKey key, JSVal value, std::string property_name); private: std::map constants; diff --git a/src/style/class_description.cpp b/src/style/class_description.cpp new file mode 100644 index 000000000..48cf63930 --- /dev/null +++ b/src/style/class_description.cpp @@ -0,0 +1,9 @@ +#include + +namespace llmr { + +void ClassDescription::addClass(const std::string &name, ClassProperties &&properties) { + styles.emplace(name, std::move(properties)); +} + +} diff --git a/src/style/style.cpp b/src/style/style.cpp index a0c8a1e57..0b842772c 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -25,36 +25,272 @@ void Style::reset() { properties_to_transition.clear(); } -void Style::cascadeProperties(GenericProperties &properties, const GenericClass& klass, const std::string& layer_name, const std::string& class_name, float z) { - if (klass.enabled) { - properties.enabled = klass.enabled.get().evaluate(z); +void Style::cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + using Key = ClassPropertyKey; + + if (const FunctionProperty *enabled = klass.get(Key::Enabled)) { + properties.enabled = enabled->evaluate(z); } - if (klass.translate) { - properties.translate = {{ klass.translate.get()[0].evaluate(z), - klass.translate.get()[1].evaluate(z) }}; + if (const FunctionProperty *translateX = klass.get(Key::TranslateX)) { + properties.translate[0] = translateX->evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - if (klass.translate_transition && klass.translate_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Translate, klass.translate_transition.get()); + } + + if (const FunctionProperty *translateY = klass.get(Key::TranslateY)) { + properties.translate[1] = translateY->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + } + + if (const PropertyTransition *translateTransition = klass.get(Key::TranslateTransition)) { + if (translateTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Translate, *translateTransition); } } - if (klass.translateAnchor) { - properties.translateAnchor = klass.translateAnchor.get(); + if (const TranslateAnchor *translateAnchor = klass.get(Key::TranslateAnchor)) { + properties.translateAnchor = *translateAnchor; } - if (klass.opacity) { - properties.opacity = klass.opacity.get().evaluate(z); + if (const FunctionProperty *opacity = klass.get(Key::Opacity)) { + properties.opacity = opacity->evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (klass.opacity_transition && klass.opacity_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Opacity, klass.opacity_transition.get()); + } + + if (const PropertyTransition *opacityTransition = klass.get(Key::OpacityTransition)) { + if (opacityTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Opacity, *opacityTransition); } } - properties.prerender = klass.prerender; - properties.prerenderBuffer = klass.prerenderBuffer; - properties.prerenderSize = klass.prerenderSize; - properties.prerenderBlur = klass.prerenderBlur; + if (const FunctionProperty *prerender = klass.get(Key::Prerender)) { + properties.prerender = *prerender; + } + + if (const FunctionProperty *prerenderBuffer = klass.get(Key::PrerenderBuffer)) { + properties.prerenderBuffer = *prerenderBuffer; + } + + if (const FunctionProperty *prerenderSize = klass.get(Key::PrerenderSize)) { + properties.prerenderSize = *prerenderSize; + } + + if (const FunctionProperty *prerenderBlur = klass.get(Key::PrerenderBlur)) { + properties.prerenderBlur = *prerenderBlur; + } +} + +void Style::cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Winding *winding = klass.get(Key::FillWinding)) { + properties.winding = *winding; + } + + if (const FunctionProperty *antialias = klass.get(Key::FillAntialias)) { + properties.antialias = antialias->evaluate(z); + } + + if (const Color *fillColor = klass.get(Key::FillColor)) { + properties.fill_color = *fillColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; + } + + if (const PropertyTransition *fillColorTransition = klass.get(Key::FillColorTransition)) { + if (fillColorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, *fillColorTransition); + } + } + + if (const Color *fillStrokeColor = klass.get(Key::FillStrokeColor)) { + properties.stroke_color = *fillStrokeColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; + } + + if (const PropertyTransition *fillStrokeColorTransition = klass.get(Key::FillStrokeColorTransition)) { + if (fillStrokeColorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::StrokeColor, *fillStrokeColorTransition); + } + } + + if (const std::string *image = klass.get(Key::FillImage)) { + properties.image = *image; + } +} + +void Style::cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const FunctionProperty *width = klass.get(Key::LineWidth)) { + properties.width = width->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; + } + + if (const PropertyTransition *width_transition = klass.get(Key::LineWidthTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Width, *width_transition); + } + + if (const FunctionProperty *offset = klass.get(Key::LineOffset)) { + properties.offset = offset->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; + } + + if (const PropertyTransition *offset_transition = klass.get(Key::LineOffsetTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Offset, *offset_transition); + } + + if (const Color *color = klass.get(Key::LineColor)) { + properties.color = *color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *color_transition = klass.get(Key::LineColorTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *color_transition); + } + + if (const FunctionProperty *dash_array = klass.get(Key::LineDashLand)) { + properties.dash_array[0] = dash_array->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; + } + + if (const FunctionProperty *dash_array = klass.get(Key::LineDashGap)) { + properties.dash_array[1] = dash_array->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; + } + + if (const PropertyTransition *dash_array_transition = klass.get(Key::LineDashTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::DashArray, *dash_array_transition); + } +} + +void Style::cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Color *color = klass.get(Key::TextColor)) { + properties.color = *color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); + } + + if (const FunctionProperty *size = klass.get(Key::TextSize)) { + properties.size = size->evaluate(z); + } + + if (const Color *haloColor = klass.get(Key::TextHaloColor)) { + properties.halo = *haloColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; + } + + if (const PropertyTransition *haloColorTransition = klass.get(Key::TextHaloColorTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Halo, *haloColorTransition); + } + + if (const FunctionProperty *haloRadius = klass.get(Key::TextHaloRadius)) { + properties.halo_radius = haloRadius->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; + } + + if (const PropertyTransition *haloRadiusTransition = klass.get(Key::TextHaloRadiusTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloRadius, *haloRadiusTransition); + } + + if (const FunctionProperty *haloBlur = klass.get(Key::TextHaloBlur)) { + properties.halo_blur = haloBlur->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; + } + + if (const PropertyTransition *haloBlurTransition = klass.get(Key::TextHaloBlurTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloBlur, *haloBlurTransition); + } + + if (const FunctionProperty *rotate = klass.get(Key::TextRotate)) { + properties.rotate = rotate->evaluate(z); + } + + if (const FunctionProperty *alwaysVisible = klass.get(Key::TextAlwaysVisible)) { + properties.always_visible = alwaysVisible->evaluate(z); + } +} + +void Style::cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Color *color = klass.get(Key::IconColor)) { + properties.color = *color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *colorTransition = klass.get(Key::IconColorTransition)) { + if (colorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); + } + } + + if (const FunctionProperty *size = klass.get(Key::IconSize)) { + properties.size = size->evaluate(z); + } + + if (const std::string *image = klass.get(Key::IconImage)) { + properties.image = *image; + } + + if (const FunctionProperty *radius = klass.get(Key::IconRadius)) { + properties.radius = radius->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; + } + + if (const PropertyTransition *radiusTransition = klass.get(Key::IconRadiusTransition)) { + if (radiusTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Radius, *radiusTransition); + } + } + + if (const FunctionProperty *blur = klass.get(Key::IconBlur)) { + properties.blur = blur->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; + } + + if (const PropertyTransition *blurTransition = klass.get(Key::IconBlurTransition)) { + if (blurTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Blur, *blurTransition); + } + } +} + +void Style::cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +} + +void Style::cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +} + +void Style::cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Color *backgroundColor = klass.get(Key::BackgroundColor)) { + properties.color = *backgroundColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { + if (colorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); + } + } } @@ -85,217 +321,38 @@ void Style::cascade(float z) { const std::string& class_name = class_pair.first; const ClassDescription& sheetClass = class_pair.second; + using Key = ClassPropertyKey; + // Skip if not enabled. if (appliedClasses.find(class_name) == appliedClasses.end()) continue; - // Cascade fill classes. - for (const auto& fill_pair : sheetClass.fill) { - const std::string& layer_name = fill_pair.first; - const llmr::FillClass& layer = fill_pair.second; + for (const auto &pair : sheetClass) { + const std::string& layer_name = pair.first; + const ClassProperties& properties = pair.second; - llmr::FillProperties& fill = computed.fills[layer_name]; - - cascadeProperties(fill, layer, layer_name, class_name, z); - - if (layer.winding) { - fill.winding = layer.winding.get(); - } - - if (layer.antialias) { - fill.antialias = layer.antialias.get().evaluate(z); - } - - if (layer.fill_color) { - fill.fill_color = layer.fill_color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; - if (layer.fill_color_transition && layer.fill_color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, layer.fill_color_transition.get()); - } - } - - if (layer.stroke_color) { - fill.stroke_color = layer.stroke_color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; - if (layer.stroke_color_transition && layer.stroke_color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::StrokeColor, layer.stroke_color_transition.get()); - } - } - - if (layer.image) { - fill.image = layer.image.get(); - } - } - - // Cascade line classes. - for (const auto& line_pair : sheetClass.line) { - const std::string& layer_name = line_pair.first; - const llmr::LineClass& layer = line_pair.second; - - llmr::LineProperties& stroke = computed.lines[layer_name]; - - cascadeProperties(stroke, layer, layer_name, class_name, z); - - if (layer.width) { - stroke.width = layer.width.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; - if (layer.width_transition && layer.width_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Width, layer.width_transition.get()); - } - - } - - if (layer.offset) { - stroke.offset = layer.offset.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; - if (layer.offset_transition && layer.offset_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Offset, layer.offset_transition.get()); - } - } - - if (layer.color) { - stroke.color = layer.color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition && layer.color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, layer.color_transition.get()); - } - } - - if (layer.dash_array) { - stroke.dash_array = {{ layer.dash_array.get()[0].evaluate(z), - layer.dash_array.get()[1].evaluate(z) }}; - computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; - if (layer.dash_array_transition && layer.dash_array_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::DashArray, layer.dash_array_transition.get()); - } - } - } - - // Cascade icon classes. - for (const auto& icon_pair : sheetClass.icon) { - const std::string& layer_name = icon_pair.first; - const llmr::IconClass& layer = icon_pair.second; - - llmr::IconProperties& icon = computed.icons[layer_name]; - - cascadeProperties(icon, layer, layer_name, class_name, z); - - if (layer.color) { - icon.color = layer.color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition && layer.color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, layer.color_transition.get()); - } - } - - if (layer.size) { - icon.size = layer.size.get().evaluate(z); - } - - if (layer.image) { - icon.image = layer.image.get(); - } - - if (layer.radius) { - icon.radius = layer.radius.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; - if (layer.radius_transition && layer.radius_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Radius, layer.radius_transition.get()); - } - } - - if (layer.blur) { - icon.blur = layer.blur.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; - if (layer.blur_transition && layer.blur_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Blur, layer.blur_transition.get()); - } - } - } - - // Cascade text classes. - for (const auto& text_pair : sheetClass.text) { - const std::string& layer_name = text_pair.first; - const llmr::TextClass& layer = text_pair.second; - - llmr::TextProperties& text = computed.texts[layer_name]; - - cascadeProperties(text, layer, layer_name, class_name, z); - - if (layer.color) { - text.color = layer.color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition && layer.color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, layer.color_transition.get()); - } - } - - if (layer.size) { - text.size = layer.size.get().evaluate(z); - } - - if (layer.halo) { - text.halo = layer.halo.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; - if (layer.halo_transition && layer.halo_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Halo, layer.halo_transition.get()); - } - } - - if (layer.halo_radius) { - text.halo_radius = layer.halo_radius.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; - if (layer.halo_radius_transition && layer.halo_radius_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloRadius, layer.halo_radius_transition.get()); - } - } - - if (layer.halo_blur) { - text.halo_blur = layer.halo_blur.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; - if (layer.halo_blur_transition && layer.halo_blur_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloBlur, layer.halo_blur_transition.get()); - } - } - - if (layer.rotate) { - text.rotate = layer.rotate.get().evaluate(z); - } - - if (layer.always_visible) { - text.always_visible = layer.always_visible.get().evaluate(z); - } - } - - // Cascade raster classes. - for (const auto& raster_pair : sheetClass.raster) { - const std::string& layer_name = raster_pair.first; - const llmr::RasterClass& layer = raster_pair.second; - - llmr::RasterProperties& raster = computed.rasters[layer_name]; - - cascadeProperties(raster, layer, layer_name, class_name, z); - } - - // Cascade composite classes. - for (const auto& composite_pair : sheetClass.composite) { - const std::string& layer_name = composite_pair.first; - const llmr::CompositeClass& layer = composite_pair.second; - - llmr::CompositeProperties& composite = computed.composites[layer_name]; - - cascadeProperties(composite, layer, layer_name, class_name, z); - } - - // Cascade background. - { - cascadeProperties(computed.background, sheetClass.background, "background", class_name, z); - - if (sheetClass.background.color) { - computed.background.color = sheetClass.background.color.get(); - computed.effective_classes["background"][TransitionablePropertyKey::Color] = class_name; - if (sheetClass.background.color_transition && sheetClass.background.color_transition.get().duration) { - properties_to_transition["background"].emplace(TransitionablePropertyKey::Color, sheetClass.background.color_transition.get()); - } + // Find out what bucket this class is + switch (properties.type) { + case RenderType::Fill: + cascadeProperties(computed.fills[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Line: + cascadeProperties(computed.lines[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Icon: + cascadeProperties(computed.icons[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Text: + cascadeProperties(computed.texts[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Raster: + cascadeProperties(computed.rasters[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Composite: + cascadeProperties(computed.composites[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Background: + cascadeProperties(computed.background, properties, layer_name, class_name, z); + break; } } } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index edce8d2b6..941be502b 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -482,10 +483,10 @@ void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescript const std::string &bucket_name = layer_bucket_it->second; if (bucket_name == "background") { // background buckets are fake - class_desc.background = parseBackgroundClass(value); + class_desc.addClass("background", parseBackgroundClass(value)); } else if (bucket_name.length() == 0) { // no bucket name == composite bucket. - class_desc.composite.insert({ name, std::forward(parseCompositeClass(value)) }); + class_desc.addClass(name, parseCompositeClass(value)); } else { auto bucket_it = buckets.find(bucket_name); if (bucket_it == buckets.end()) { @@ -497,15 +498,15 @@ void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescript BucketType type = bucket_it->second.type; if (type == BucketType::Fill) { - class_desc.fill.insert({ name, std::forward(parseFillClass(value)) }); + class_desc.addClass(name, parseFillClass(value)); } else if (type == BucketType::Line) { - class_desc.line.insert({ name, std::forward(parseLineClass(value)) }); + class_desc.addClass(name, parseLineClass(value)); } else if (type == BucketType::Icon) { - class_desc.icon.insert({ name, std::forward(parseIconClass(value)) }); + class_desc.addClass(name, parseIconClass(value)); } else if (type == BucketType::Text) { - class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); + class_desc.addClass(name, parseTextClass(value)); } else if (type == BucketType::Raster) { - class_desc.raster.insert({ name, std::forward(parseRasterClass(value)) }); + class_desc.addClass(name, parseRasterClass(value)); } else { throw Style::exception("unknown class type name"); } @@ -663,7 +664,7 @@ FunctionProperty StyleParser::parseFunction(JSVal value) { return property; } -boost::optional StyleParser::parseTransition(JSVal value, std::string property_name) { +void StyleParser::parseTransition(ClassProperties &klass, ClassPropertyKey key, JSVal value, std::string property_name) { uint16_t duration = 0, delay = 0; std::string transition_property = std::string("transition-").append(property_name); if (value.HasMember(transition_property.c_str())) { @@ -679,200 +680,212 @@ boost::optional StyleParser::parseTransition(JSVal value, st } if (duration || delay) { - return boost::optional(PropertyTransition { duration, delay }); - } else { - return boost::optional(); + klass.emplace(key, PropertyTransition { duration, delay }); } } -void StyleParser::parseGenericClass(GenericClass &klass, JSVal value) { - if (value.HasMember("enabled")) { - klass.enabled = parseFunction(value["enabled"]); +void StyleParser::parseGenericClass(ClassProperties &klass, JSVal value) { + using Key = ClassPropertyKey; + + if (value.HasMember("enabled")) { + klass.emplace(Key::Enabled, parseFunction(value["enabled"])); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); - klass.translate = std::array {{ values[0], values[1] }}; - klass.translate_transition = parseTransition(value, "translate"); + klass.emplace(Key::TranslateX, std::move(values[0])); + klass.emplace(Key::TranslateY, std::move(values[1])); + parseTransition(klass, Key::TranslateTransition, value, "translate"); } if (value.HasMember("translate-anchor")) { - klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.emplace(Key::TranslateAnchor, parseTranslateAnchor(value["translate-anchor"])); } if (value.HasMember("opacity")) { - klass.opacity = parseFunction(value["opacity"]); - klass.opacity_transition = parseTransition(value, "opacity"); + klass.emplace(Key::Opacity, parseFunction(value["opacity"])); + parseTransition(klass, Key::OpacityTransition, value, "opacity"); } if (value.HasMember("prerender")) { - klass.prerender = parseFunction(value["prerender"]); + klass.emplace(Key::Prerender, parseFunction(value["prerender"])); } if (value.HasMember("prerender-buffer")) { - klass.prerenderBuffer = parseFunction(value["prerender-buffer"]); + klass.emplace(Key::PrerenderBuffer, parseFunction(value["prerender-buffer"])); } if (value.HasMember("prerender-size")) { - klass.prerenderSize = parseFunction(value["prerender-size"]); + klass.emplace(Key::PrerenderSize, parseFunction(value["prerender-size"])); } if (value.HasMember("prerender-blur")) { - klass.prerenderBlur = parseFunction(value["prerender-blur"]); + klass.emplace(Key::PrerenderBlur, parseFunction(value["prerender-blur"])); } } -FillClass StyleParser::parseFillClass(JSVal value) { - FillClass klass; +ClassProperties StyleParser::parseFillClass(JSVal value) { + ClassProperties klass(RenderType::Fill); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("winding")) { throw std::runtime_error("winding in stylesheets not yet supported"); } if (value.HasMember("color")) { - klass.fill_color = parseColor(value["color"]); - klass.fill_color_transition = parseTransition(value, "color"); + klass.emplace(Key::FillColor, parseColor(value["color"])); + parseTransition(klass, Key::FillColorTransition, value, "color"); } if (value.HasMember("stroke")) { - klass.stroke_color = parseColor(value["stroke"]); - klass.stroke_color_transition = parseTransition(value, "stroke"); - } else { - klass.stroke_color = klass.fill_color; + klass.emplace(Key::FillStrokeColor, parseColor(value["stroke"])); + parseTransition(klass, Key::FillStrokeColorTransition, value, "stroke"); + } else if (const Color *fillColor = klass.get(Key::FillColor)) { + klass.emplace(Key::FillStrokeColor, *fillColor); } if (value.HasMember("antialias")) { - klass.antialias = parseBoolean(value["antialias"]); + klass.emplace(Key::FillAntialias, parseBoolean(value["antialias"])); } if (value.HasMember("image")) { - klass.image = parseString(value["image"]); + klass.emplace(Key::FillImage, parseString(value["image"])); } return klass; } -LineClass StyleParser::parseLineClass(JSVal value) { - LineClass klass; +ClassProperties StyleParser::parseLineClass(JSVal value) { + ClassProperties klass(RenderType::Line); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::LineColor, parseColor(value["color"])); + parseTransition(klass, Key::LineColorTransition, value, "color"); } if (value.HasMember("width")) { - klass.width = parseFunction(value["width"]); - klass.width_transition = parseTransition(value, "width"); + klass.emplace(Key::LineWidth, parseFunction(value["width"])); + parseTransition(klass, Key::LineWidthTransition, value, "width"); } if (value.HasMember("dasharray")) { std::vector values = parseArray(value["dasharray"], 2); - klass.dash_array = std::array {{ values[0], values[1] }}; - klass.dash_array_transition = parseTransition(value, "dasharray"); + klass.emplace(Key::LineDashLand, std::move(values[0])); + klass.emplace(Key::LineDashGap, std::move(values[1])); + parseTransition(klass, Key::LineDashTransition, value, "dasharray"); } return klass; } -IconClass StyleParser::parseIconClass(JSVal value) { - IconClass klass; +ClassProperties StyleParser::parseIconClass(JSVal value) { + ClassProperties klass(RenderType::Icon); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::IconColor, parseColor(value["color"])); + parseTransition(klass, Key::IconColorTransition, value, "color"); } if (value.HasMember("image")) { - klass.image = parseString(value["image"]); + klass.emplace(Key::IconImage, parseString(value["image"])); } if (value.HasMember("size")) { - klass.size = parseFunction(value["size"]); + klass.emplace(Key::IconSize, parseFunction(value["size"])); } if (value.HasMember("radius")) { - klass.radius = parseFunction(value["radius"]); - klass.radius_transition = parseTransition(value, "radius"); + klass.emplace(Key::IconRadius, parseFunction(value["radius"])); + parseTransition(klass, Key::IconRadiusTransition, value, "radius"); } if (value.HasMember("blur")) { - klass.blur = parseFunction(value["blur"]); - klass.blur_transition = parseTransition(value, "blur"); + klass.emplace(Key::IconBlur, parseFunction(value["blur"])); + parseTransition(klass, Key::IconBlurTransition, value, "blur"); } return klass; } -TextClass StyleParser::parseTextClass(JSVal value) { - TextClass klass; +ClassProperties StyleParser::parseTextClass(JSVal value) { + ClassProperties klass(RenderType::Text); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::TextColor, parseColor(value["color"])); + parseTransition(klass, Key::TextColorTransition, value, "color"); } if (value.HasMember("stroke")) { - klass.halo = parseColor(value["stroke"]); - klass.halo_transition = parseTransition(value, "stroke"); + klass.emplace(Key::TextHaloColor, parseColor(value["stroke"])); + parseTransition(klass, Key::TextHaloColorTransition, value, "stroke"); } if (value.HasMember("strokeWidth")) { - klass.halo_radius = parseFunction(value["strokeWidth"]); - klass.halo_radius_transition = parseTransition(value, "strokeWidth"); + klass.emplace(Key::TextHaloRadius, parseFunction(value["strokeWidth"])); + parseTransition(klass, Key::TextHaloRadiusTransition, value, "strokeWidth"); } if (value.HasMember("strokeBlur")) { - klass.halo_blur = parseFunction(value["strokeBlur"]); - klass.halo_blur_transition = parseTransition(value, "strokeBlur"); + klass.emplace(Key::TextHaloBlur, parseFunction(value["strokeBlur"])); + parseTransition(klass, Key::TextHaloBlurTransition, value, "strokeBlur"); } if (value.HasMember("size")) { - klass.size = parseFunction(value["size"]); + klass.emplace(Key::TextSize, parseFunction(value["size"])); } if (value.HasMember("rotate")) { - klass.rotate = parseFunction(value["rotate"]); + klass.emplace(Key::TextRotate, parseFunction(value["rotate"])); } if (value.HasMember("alwaysVisible")) { - klass.always_visible = parseFunction(value["alwaysVisible"]); + klass.emplace(Key::TextAlwaysVisible, parseFunction(value["alwaysVisible"])); } return klass; } -RasterClass StyleParser::parseRasterClass(JSVal value) { - RasterClass klass; +ClassProperties StyleParser::parseRasterClass(JSVal value) { + ClassProperties klass(RenderType::Raster); parseGenericClass(klass, value); return klass; } -CompositeClass StyleParser::parseCompositeClass(JSVal value) { - CompositeClass klass; +ClassProperties StyleParser::parseCompositeClass(JSVal value) { + ClassProperties klass(RenderType::Composite); parseGenericClass(klass, value); return klass; } -BackgroundClass StyleParser::parseBackgroundClass(JSVal value) { - BackgroundClass klass; +ClassProperties StyleParser::parseBackgroundClass(JSVal value) { + ClassProperties klass(RenderType::Background); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::BackgroundColor, parseColor(value["color"])); + parseTransition(klass, Key::BackgroundColorTransition, value, "color"); } return klass; From e3b9e9abf65a9926d01e45a6717dedbd11f21561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 16 Jun 2014 16:48:21 +0200 Subject: [PATCH 3/6] make code more concise --- include/llmr/style/style_parser.hpp | 12 +- src/style/style.cpp | 11 +- src/style/style_parser.cpp | 250 ++++++++++------------------ 3 files changed, 106 insertions(+), 167 deletions(-) diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 0ef260890..71a69530c 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -44,12 +44,20 @@ private: bool parseBoolean(JSVal value); std::string parseString(JSVal value); JSVal replaceConstant(JSVal value); - std::vector parseArray(JSVal value, uint16_t expected_count); Color parseColor(JSVal value); Value parseValue(JSVal value); FunctionProperty::fn parseFunctionType(JSVal type); FunctionProperty parseFunction(JSVal value); - void parseTransition(ClassProperties &klass, ClassPropertyKey key, JSVal value, std::string property_name); + + + void parseTransition(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + void parseColor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + void parseFunction(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + void parseString(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + void parseBoolean(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + void parseTranslateAnchor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + void parseFunctionArray(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); + private: std::map constants; diff --git a/src/style/style.cpp b/src/style/style.cpp index 0b842772c..f5c4d8043 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -107,11 +107,14 @@ void Style::cascadeProperties(FillProperties &properties, const ClassProperties& if (const Color *fillStrokeColor = klass.get(Key::FillStrokeColor)) { properties.stroke_color = *fillStrokeColor; computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; - } + } else if (const Color *fillColor = klass.get(Key::FillColor)) { + properties.stroke_color = *fillColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; - if (const PropertyTransition *fillStrokeColorTransition = klass.get(Key::FillStrokeColorTransition)) { - if (fillStrokeColorTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::StrokeColor, *fillStrokeColorTransition); + if (const PropertyTransition *fillColorTransition = klass.get(Key::FillColorTransition)) { + if (fillColorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, *fillColorTransition); + } } } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 941be502b..803fe9968 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -541,23 +541,22 @@ JSVal StyleParser::replaceConstant(JSVal value) { return value; } -std::vector StyleParser::parseArray(JSVal value, uint16_t expected_count) { - JSVal rvalue = replaceConstant(value); - if (!rvalue.IsArray()) { - throw Style::exception("array value must be an array"); - } +void StyleParser::parseFunctionArray(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + JSVal rvalue = replaceConstant(value[property_name]); + if (!rvalue.IsArray()) { + throw Style::exception("array value must be an array"); + } - if (rvalue.IsArray() && rvalue.Size() != expected_count) { - throw Style::exception("array value has unexpected number of elements"); - } - std::vector values; - values.reserve(expected_count); - for (uint16_t i = 0; i < expected_count; i++) { - values.push_back(parseFunction(rvalue[(rapidjson::SizeType)i])); - } + if (rvalue.Size() != keys.size()) { + throw Style::exception("array value has unexpected number of elements"); + } - return values; + for (uint16_t i = 0; i < keys.size(); i++) { + klass.emplace(keys[i], parseFunction(rvalue[(rapidjson::SizeType)i])); + } + } } Color StyleParser::parseColor(JSVal value) { @@ -594,6 +593,36 @@ Color StyleParser::parseColor(JSVal value) { css_color.a}}; } +void StyleParser::parseColor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + klass.emplace(key, parseColor(value[property_name])); + } +} + +void StyleParser::parseFunction(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + klass.emplace(key, parseFunction(value[property_name])); + } +} + +void StyleParser::parseString(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + klass.emplace(key, parseString(value[property_name])); + } +} + +void StyleParser::parseBoolean(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + klass.emplace(key, parseBoolean(value[property_name])); + } +} + +void StyleParser::parseTranslateAnchor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + klass.emplace(key, ::parseTranslateAnchor(value[property_name])); + } +} + FunctionProperty::fn StyleParser::parseFunctionType(JSVal type) { if (type.IsString()) { std::string t { type.GetString(), type.GetStringLength() }; @@ -664,11 +693,10 @@ FunctionProperty StyleParser::parseFunction(JSVal value) { return property; } -void StyleParser::parseTransition(ClassProperties &klass, ClassPropertyKey key, JSVal value, std::string property_name) { +void StyleParser::parseTransition(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { uint16_t duration = 0, delay = 0; - std::string transition_property = std::string("transition-").append(property_name); - if (value.HasMember(transition_property.c_str())) { - JSVal elements = value[transition_property.c_str()]; + if (value.HasMember(property_name)) { + JSVal elements = value[property_name]; if (elements.IsObject()) { if (elements.HasMember("duration") && elements["duration"].IsNumber()) { duration = elements["duration"].GetUint(); @@ -686,183 +714,88 @@ void StyleParser::parseTransition(ClassProperties &klass, ClassPropertyKey key, void StyleParser::parseGenericClass(ClassProperties &klass, JSVal value) { using Key = ClassPropertyKey; - - if (value.HasMember("enabled")) { - klass.emplace(Key::Enabled, parseFunction(value["enabled"])); - } - - if (value.HasMember("translate")) { - std::vector values = parseArray(value["translate"], 2); - klass.emplace(Key::TranslateX, std::move(values[0])); - klass.emplace(Key::TranslateY, std::move(values[1])); - parseTransition(klass, Key::TranslateTransition, value, "translate"); - } - - if (value.HasMember("translate-anchor")) { - klass.emplace(Key::TranslateAnchor, parseTranslateAnchor(value["translate-anchor"])); - } - - if (value.HasMember("opacity")) { - klass.emplace(Key::Opacity, parseFunction(value["opacity"])); - parseTransition(klass, Key::OpacityTransition, value, "opacity"); - } - - if (value.HasMember("prerender")) { - klass.emplace(Key::Prerender, parseFunction(value["prerender"])); - } - - if (value.HasMember("prerender-buffer")) { - klass.emplace(Key::PrerenderBuffer, parseFunction(value["prerender-buffer"])); - } - - if (value.HasMember("prerender-size")) { - klass.emplace(Key::PrerenderSize, parseFunction(value["prerender-size"])); - } - - if (value.HasMember("prerender-blur")) { - klass.emplace(Key::PrerenderBlur, parseFunction(value["prerender-blur"])); - } + parseFunction("enabled", Key::Enabled, klass, value); + parseFunctionArray("translate", { Key::TranslateX, Key::TranslateY }, klass, value); + parseTransition("transition-translate", Key::TranslateTransition, klass, value); + parseTranslateAnchor("translate-anchor", Key::TranslateAnchor, klass, value); + parseFunction("opacity", Key::Opacity, klass, value); + parseTransition("transition-opacity", Key::OpacityTransition, klass, value); + parseFunction("prerender", Key::Prerender, klass, value); + parseFunction("prerender-buffer", Key::PrerenderBuffer, klass, value); + parseFunction("prerender-size", Key::PrerenderSize, klass, value); + parseFunction("prerender-blur", Key::PrerenderBlur, klass, value); } ClassProperties StyleParser::parseFillClass(JSVal value) { ClassProperties klass(RenderType::Fill); - parseGenericClass(klass, value); using Key = ClassPropertyKey; - - if (value.HasMember("winding")) { - throw std::runtime_error("winding in stylesheets not yet supported"); - } - - if (value.HasMember("color")) { - klass.emplace(Key::FillColor, parseColor(value["color"])); - parseTransition(klass, Key::FillColorTransition, value, "color"); - } - - if (value.HasMember("stroke")) { - klass.emplace(Key::FillStrokeColor, parseColor(value["stroke"])); - parseTransition(klass, Key::FillStrokeColorTransition, value, "stroke"); - } else if (const Color *fillColor = klass.get(Key::FillColor)) { - klass.emplace(Key::FillStrokeColor, *fillColor); - } - - if (value.HasMember("antialias")) { - klass.emplace(Key::FillAntialias, parseBoolean(value["antialias"])); - } - - if (value.HasMember("image")) { - klass.emplace(Key::FillImage, parseString(value["image"])); - } + parseColor("color", Key::FillColor, klass, value); + parseTransition("transition-color", Key::FillColorTransition, klass, value); + parseColor("stroke", Key::FillStrokeColor, klass, value); + parseTransition("transition-stroke", Key::FillStrokeColorTransition, klass, value); + parseBoolean("antialias", Key::FillAntialias, klass, value); + parseString("image", Key::FillImage, klass, value); return klass; } ClassProperties StyleParser::parseLineClass(JSVal value) { ClassProperties klass(RenderType::Line); - parseGenericClass(klass, value); using Key = ClassPropertyKey; - - if (value.HasMember("color")) { - klass.emplace(Key::LineColor, parseColor(value["color"])); - parseTransition(klass, Key::LineColorTransition, value, "color"); - } - - if (value.HasMember("width")) { - klass.emplace(Key::LineWidth, parseFunction(value["width"])); - parseTransition(klass, Key::LineWidthTransition, value, "width"); - } - - if (value.HasMember("dasharray")) { - std::vector values = parseArray(value["dasharray"], 2); - klass.emplace(Key::LineDashLand, std::move(values[0])); - klass.emplace(Key::LineDashGap, std::move(values[1])); - parseTransition(klass, Key::LineDashTransition, value, "dasharray"); - } + parseColor("color", Key::LineColor, klass, value); + parseTransition("transition-color", Key::LineColorTransition, klass, value); + parseFunction("width", Key::LineWidth, klass, value); + parseTransition("transition-width", Key::LineWidthTransition, klass, value); + parseFunctionArray("dasharray", { Key::LineDashLand, Key::LineDashGap }, klass, value); + parseTransition("transition-dasharray", Key::LineDashTransition, klass, value); return klass; } ClassProperties StyleParser::parseIconClass(JSVal value) { ClassProperties klass(RenderType::Icon); - parseGenericClass(klass, value); using Key = ClassPropertyKey; - - if (value.HasMember("color")) { - klass.emplace(Key::IconColor, parseColor(value["color"])); - parseTransition(klass, Key::IconColorTransition, value, "color"); - } - - if (value.HasMember("image")) { - klass.emplace(Key::IconImage, parseString(value["image"])); - } - - if (value.HasMember("size")) { - klass.emplace(Key::IconSize, parseFunction(value["size"])); - } - - if (value.HasMember("radius")) { - klass.emplace(Key::IconRadius, parseFunction(value["radius"])); - parseTransition(klass, Key::IconRadiusTransition, value, "radius"); - } - - if (value.HasMember("blur")) { - klass.emplace(Key::IconBlur, parseFunction(value["blur"])); - parseTransition(klass, Key::IconBlurTransition, value, "blur"); - } + parseColor("color", Key::IconColor, klass, value); + parseTransition("transition-color", Key::IconColorTransition, klass, value); + parseString("image", Key::IconImage, klass, value); + parseFunction("size", Key::IconSize, klass, value); + parseFunction("radius", Key::IconRadius, klass, value); + parseTransition("transition-radius", Key::IconRadiusTransition, klass, value); + parseFunction("blur", Key::IconBlur, klass, value); + parseTransition("transition-blur", Key::IconBlurTransition, klass, value); return klass; } ClassProperties StyleParser::parseTextClass(JSVal value) { ClassProperties klass(RenderType::Text); - parseGenericClass(klass, value); using Key = ClassPropertyKey; - if (value.HasMember("color")) { - klass.emplace(Key::TextColor, parseColor(value["color"])); - parseTransition(klass, Key::TextColorTransition, value, "color"); - } - - if (value.HasMember("stroke")) { - klass.emplace(Key::TextHaloColor, parseColor(value["stroke"])); - parseTransition(klass, Key::TextHaloColorTransition, value, "stroke"); - } - - if (value.HasMember("strokeWidth")) { - klass.emplace(Key::TextHaloRadius, parseFunction(value["strokeWidth"])); - parseTransition(klass, Key::TextHaloRadiusTransition, value, "strokeWidth"); - } - - if (value.HasMember("strokeBlur")) { - klass.emplace(Key::TextHaloBlur, parseFunction(value["strokeBlur"])); - parseTransition(klass, Key::TextHaloBlurTransition, value, "strokeBlur"); - } - - if (value.HasMember("size")) { - klass.emplace(Key::TextSize, parseFunction(value["size"])); - } - - if (value.HasMember("rotate")) { - klass.emplace(Key::TextRotate, parseFunction(value["rotate"])); - } - - if (value.HasMember("alwaysVisible")) { - klass.emplace(Key::TextAlwaysVisible, parseFunction(value["alwaysVisible"])); - } + parseColor("color", Key::TextColor, klass, value); + parseTransition("transition-color", Key::TextColorTransition, klass, value); + parseColor("stroke", Key::TextHaloColor, klass, value); + parseTransition("transition-stroke", Key::TextHaloColorTransition, klass, value); + parseFunction("strokeWidth", Key::TextHaloRadius, klass, value); + parseTransition("transition-strokeWidth", Key::TextHaloRadiusTransition, klass, value); + parseFunction("strokeBlur", Key::TextHaloBlur, klass, value); + parseTransition("transition-strokeBlur", Key::TextHaloBlurTransition, klass, value); + parseFunction("size", Key::TextSize, klass, value); + parseFunction("rotate", Key::TextRotate, klass, value); + parseFunction("alwaysVisible", Key::TextAlwaysVisible, klass, value); return klass; } ClassProperties StyleParser::parseRasterClass(JSVal value) { ClassProperties klass(RenderType::Raster); - parseGenericClass(klass, value); return klass; @@ -870,7 +803,6 @@ ClassProperties StyleParser::parseRasterClass(JSVal value) { ClassProperties StyleParser::parseCompositeClass(JSVal value) { ClassProperties klass(RenderType::Composite); - parseGenericClass(klass, value); return klass; @@ -878,15 +810,11 @@ ClassProperties StyleParser::parseCompositeClass(JSVal value) { ClassProperties StyleParser::parseBackgroundClass(JSVal value) { ClassProperties klass(RenderType::Background); - parseGenericClass(klass, value); using Key = ClassPropertyKey; - - if (value.HasMember("color")) { - klass.emplace(Key::BackgroundColor, parseColor(value["color"])); - parseTransition(klass, Key::BackgroundColorTransition, value, "color"); - } + parseColor("color", Key::BackgroundColor, klass, value); + parseTransition("transition-color", Key::BackgroundColorTransition, klass, value); return klass; } From 3cd1b8f07c3ce4820d2faefa5559324d9861ad92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 16 Jun 2014 17:00:25 +0200 Subject: [PATCH 4/6] template the parser --- include/llmr/style/style_parser.hpp | 19 ++-- src/style/style_parser.cpp | 130 +++++++++++----------------- 2 files changed, 59 insertions(+), 90 deletions(-) diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 71a69530c..0d254f33e 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -41,21 +41,20 @@ private: PropertyFilterExpression parseFilterOrExpression(JSVal value); - bool parseBoolean(JSVal value); - std::string parseString(JSVal value); JSVal replaceConstant(JSVal value); - Color parseColor(JSVal value); Value parseValue(JSVal value); - FunctionProperty::fn parseFunctionType(JSVal type); - FunctionProperty parseFunction(JSVal value); + template + T parse(JSVal value); + + template + inline void parse(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + klass.emplace(key, parse(value[property_name])); + } + } void parseTransition(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); - void parseColor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); - void parseFunction(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); - void parseString(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); - void parseBoolean(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); - void parseTranslateAnchor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); void parseFunctionArray(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 803fe9968..1454a40e7 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -382,7 +382,7 @@ void StyleParser::parseConstants(JSVal value) { } } -TranslateAnchor parseTranslateAnchor(JSVal anchor) { +template<> TranslateAnchor StyleParser::parse(JSVal anchor) { if (anchor.IsString()) { std::string a { anchor.GetString(), anchor.GetStringLength() }; if (a == "viewport") { @@ -513,7 +513,7 @@ void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescript } } -bool StyleParser::parseBoolean(JSVal value) { +template<> bool StyleParser::parse(JSVal value) { if (!value.IsBool()) { throw Style::exception("boolean value must be a boolean"); } @@ -521,7 +521,7 @@ bool StyleParser::parseBoolean(JSVal value) { return value.GetBool(); } -std::string StyleParser::parseString(JSVal value) { +template<> std::string StyleParser::parse(JSVal value) { if (!value.IsString()) { throw Style::exception("string value must be a string"); } @@ -541,25 +541,7 @@ JSVal StyleParser::replaceConstant(JSVal value) { return value; } -void StyleParser::parseFunctionArray(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value) { - if (value.HasMember(property_name)) { - JSVal rvalue = replaceConstant(value[property_name]); - if (!rvalue.IsArray()) { - throw Style::exception("array value must be an array"); - } - - - if (rvalue.Size() != keys.size()) { - throw Style::exception("array value has unexpected number of elements"); - } - - for (uint16_t i = 0; i < keys.size(); i++) { - klass.emplace(keys[i], parseFunction(rvalue[(rapidjson::SizeType)i])); - } - } -} - -Color StyleParser::parseColor(JSVal value) { +template<> Color StyleParser::parse(JSVal value) { JSVal rvalue = replaceConstant(value); if (rvalue.IsArray()) { // [ r, g, b, a] array @@ -593,37 +575,7 @@ Color StyleParser::parseColor(JSVal value) { css_color.a}}; } -void StyleParser::parseColor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { - if (value.HasMember(property_name)) { - klass.emplace(key, parseColor(value[property_name])); - } -} - -void StyleParser::parseFunction(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { - if (value.HasMember(property_name)) { - klass.emplace(key, parseFunction(value[property_name])); - } -} - -void StyleParser::parseString(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { - if (value.HasMember(property_name)) { - klass.emplace(key, parseString(value[property_name])); - } -} - -void StyleParser::parseBoolean(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { - if (value.HasMember(property_name)) { - klass.emplace(key, parseBoolean(value[property_name])); - } -} - -void StyleParser::parseTranslateAnchor(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { - if (value.HasMember(property_name)) { - klass.emplace(key, ::parseTranslateAnchor(value[property_name])); - } -} - -FunctionProperty::fn StyleParser::parseFunctionType(JSVal type) { +FunctionProperty::fn parseFunctionType(JSVal type) { if (type.IsString()) { std::string t { type.GetString(), type.GetStringLength() }; if (t == "constant") { @@ -646,7 +598,7 @@ FunctionProperty::fn StyleParser::parseFunctionType(JSVal type) { } } -FunctionProperty StyleParser::parseFunction(JSVal value) { +template<> FunctionProperty StyleParser::parse(JSVal value) { JSVal rvalue = replaceConstant(value); FunctionProperty property; @@ -693,6 +645,24 @@ FunctionProperty StyleParser::parseFunction(JSVal value) { return property; } +void StyleParser::parseFunctionArray(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value) { + if (value.HasMember(property_name)) { + JSVal rvalue = replaceConstant(value[property_name]); + if (!rvalue.IsArray()) { + throw Style::exception("array value must be an array"); + } + + + if (rvalue.Size() != keys.size()) { + throw Style::exception("array value has unexpected number of elements"); + } + + for (uint16_t i = 0; i < keys.size(); i++) { + klass.emplace(keys[i], parse(rvalue[(rapidjson::SizeType)i])); + } + } +} + void StyleParser::parseTransition(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { uint16_t duration = 0, delay = 0; if (value.HasMember(property_name)) { @@ -714,16 +684,16 @@ void StyleParser::parseTransition(const char *property_name, ClassPropertyKey ke void StyleParser::parseGenericClass(ClassProperties &klass, JSVal value) { using Key = ClassPropertyKey; - parseFunction("enabled", Key::Enabled, klass, value); + parse("enabled", Key::Enabled, klass, value); parseFunctionArray("translate", { Key::TranslateX, Key::TranslateY }, klass, value); parseTransition("transition-translate", Key::TranslateTransition, klass, value); - parseTranslateAnchor("translate-anchor", Key::TranslateAnchor, klass, value); - parseFunction("opacity", Key::Opacity, klass, value); + parse("translate-anchor", Key::TranslateAnchor, klass, value); + parse("opacity", Key::Opacity, klass, value); parseTransition("transition-opacity", Key::OpacityTransition, klass, value); - parseFunction("prerender", Key::Prerender, klass, value); - parseFunction("prerender-buffer", Key::PrerenderBuffer, klass, value); - parseFunction("prerender-size", Key::PrerenderSize, klass, value); - parseFunction("prerender-blur", Key::PrerenderBlur, klass, value); + parse("prerender", Key::Prerender, klass, value); + parse("prerender-buffer", Key::PrerenderBuffer, klass, value); + parse("prerender-size", Key::PrerenderSize, klass, value); + parse("prerender-blur", Key::PrerenderBlur, klass, value); } ClassProperties StyleParser::parseFillClass(JSVal value) { @@ -731,12 +701,12 @@ ClassProperties StyleParser::parseFillClass(JSVal value) { parseGenericClass(klass, value); using Key = ClassPropertyKey; - parseColor("color", Key::FillColor, klass, value); + parse("color", Key::FillColor, klass, value); parseTransition("transition-color", Key::FillColorTransition, klass, value); - parseColor("stroke", Key::FillStrokeColor, klass, value); + parse("stroke", Key::FillStrokeColor, klass, value); parseTransition("transition-stroke", Key::FillStrokeColorTransition, klass, value); - parseBoolean("antialias", Key::FillAntialias, klass, value); - parseString("image", Key::FillImage, klass, value); + parse("antialias", Key::FillAntialias, klass, value); + parse("image", Key::FillImage, klass, value); return klass; } @@ -746,9 +716,9 @@ ClassProperties StyleParser::parseLineClass(JSVal value) { parseGenericClass(klass, value); using Key = ClassPropertyKey; - parseColor("color", Key::LineColor, klass, value); + parse("color", Key::LineColor, klass, value); parseTransition("transition-color", Key::LineColorTransition, klass, value); - parseFunction("width", Key::LineWidth, klass, value); + parse("width", Key::LineWidth, klass, value); parseTransition("transition-width", Key::LineWidthTransition, klass, value); parseFunctionArray("dasharray", { Key::LineDashLand, Key::LineDashGap }, klass, value); parseTransition("transition-dasharray", Key::LineDashTransition, klass, value); @@ -761,13 +731,13 @@ ClassProperties StyleParser::parseIconClass(JSVal value) { parseGenericClass(klass, value); using Key = ClassPropertyKey; - parseColor("color", Key::IconColor, klass, value); + parse("color", Key::IconColor, klass, value); parseTransition("transition-color", Key::IconColorTransition, klass, value); - parseString("image", Key::IconImage, klass, value); - parseFunction("size", Key::IconSize, klass, value); - parseFunction("radius", Key::IconRadius, klass, value); + parse("image", Key::IconImage, klass, value); + parse("size", Key::IconSize, klass, value); + parse("radius", Key::IconRadius, klass, value); parseTransition("transition-radius", Key::IconRadiusTransition, klass, value); - parseFunction("blur", Key::IconBlur, klass, value); + parse("blur", Key::IconBlur, klass, value); parseTransition("transition-blur", Key::IconBlurTransition, klass, value); return klass; @@ -779,17 +749,17 @@ ClassProperties StyleParser::parseTextClass(JSVal value) { using Key = ClassPropertyKey; - parseColor("color", Key::TextColor, klass, value); + parse("color", Key::TextColor, klass, value); parseTransition("transition-color", Key::TextColorTransition, klass, value); - parseColor("stroke", Key::TextHaloColor, klass, value); + parse("stroke", Key::TextHaloColor, klass, value); parseTransition("transition-stroke", Key::TextHaloColorTransition, klass, value); - parseFunction("strokeWidth", Key::TextHaloRadius, klass, value); + parse("strokeWidth", Key::TextHaloRadius, klass, value); parseTransition("transition-strokeWidth", Key::TextHaloRadiusTransition, klass, value); - parseFunction("strokeBlur", Key::TextHaloBlur, klass, value); + parse("strokeBlur", Key::TextHaloBlur, klass, value); parseTransition("transition-strokeBlur", Key::TextHaloBlurTransition, klass, value); - parseFunction("size", Key::TextSize, klass, value); - parseFunction("rotate", Key::TextRotate, klass, value); - parseFunction("alwaysVisible", Key::TextAlwaysVisible, klass, value); + parse("size", Key::TextSize, klass, value); + parse("rotate", Key::TextRotate, klass, value); + parse("alwaysVisible", Key::TextAlwaysVisible, klass, value); return klass; } @@ -813,7 +783,7 @@ ClassProperties StyleParser::parseBackgroundClass(JSVal value) { parseGenericClass(klass, value); using Key = ClassPropertyKey; - parseColor("color", Key::BackgroundColor, klass, value); + parse("color", Key::BackgroundColor, klass, value); parseTransition("transition-color", Key::BackgroundColorTransition, klass, value); return klass; From c6fc235cf74d1c9d43096f6d6a5cf2032485b413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 16 Jun 2014 17:12:46 +0200 Subject: [PATCH 5/6] convert to json --- bin/style.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bin/style.js b/bin/style.js index ca42214ba..e80d76759 100644 --- a/bin/style.js +++ b/bin/style.js @@ -659,7 +659,7 @@ module.exports = { "fontSize": 24, "feature_type": "point", "type": "text", - "maxWidth": 5, + "maxWidth": 5 }, "country_label_line": { "source": "outdoors", @@ -735,7 +735,7 @@ module.exports = { "fontSize": 30, "maxWidth": 8, "letterSpacing": 0.4, - "lineHeight": 2, + "lineHeight": 2 }, "marine_label_point_2": { "source": "outdoors", @@ -750,7 +750,7 @@ module.exports = { "fontSize": 24, "maxWidth": 8, "letterSpacing": 0.2, - "lineHeight": 1.5, + "lineHeight": 1.5 }, "marine_label_point_3": { "source": "outdoors", @@ -765,7 +765,7 @@ module.exports = { "fontSize": 18, "maxWidth": 8, "letterSpacing": 0.1, - "lineHeight": 1.3, + "lineHeight": 1.3 }, "marine_label_point_other": { "source": "outdoors", @@ -780,7 +780,7 @@ module.exports = { "fontSize": 16, "maxWidth": 8, "letterSpacing": 0.1, - "lineHeight": 1.2, + "lineHeight": 1.2 }, "state_label": { "source": "outdoors", @@ -848,7 +848,7 @@ module.exports = { "fontSize": 18, "maxWidth": 6, "feature_type": "point", - "type": "text", + "type": "text" }, "road_label_1": { "source": "outdoors", @@ -961,7 +961,7 @@ module.exports = { "source": "outdoors", "layer": "poi_label", "icon": "{{maki}}", - "field": "scalerank", + "field": "scalerank", "value": 4, "size": 12, "type": "point" @@ -992,7 +992,7 @@ module.exports = { "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 12, "feature_type": "point", - "type": "text", + "type": "text" }, "poi_label_3": { "source": "outdoors", @@ -1008,7 +1008,7 @@ module.exports = { "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 11, "feature_type": "point", - "type": "text", + "type": "text" }, "poi_label_4_4": { "source": "outdoors", @@ -1027,7 +1027,7 @@ module.exports = { "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", - "type": "text", + "type": "text" }, "poi_label_4_16": { "source": "outdoors", @@ -1046,12 +1046,12 @@ module.exports = { "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", - "type": "text", + "type": "text" }, "poi_label_4_all": { "source": "outdoors", "layer": "poi_label", - "field": "scalerank", + "field": "scalerank", "value": 4, "text_field": "{{name_en}}", "path": "horizontal", @@ -1062,7 +1062,7 @@ module.exports = { "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", - "type": "text", + "type": "text" } }, "structure": [ @@ -2703,7 +2703,7 @@ module.exports = { "size": "poi_label_1-2_size", "stroke": "land", "strokeWidth": 0.3, - "strokeBlur": 1, + "strokeBlur": 1 }, "poi_label_3": { "color": "#444", @@ -2727,7 +2727,7 @@ module.exports = { ], "stroke": "land", "strokeWidth": 0.3, - "strokeBlur": 1, + "strokeBlur": 1 }, "poi_label_4_16": { "color": "#444", @@ -2739,7 +2739,7 @@ module.exports = { ], "stroke": "land", "strokeWidth": 0.3, - "strokeBlur": 1, + "strokeBlur": 1 }, "poi_label_4_all": { "color": "#444", @@ -2751,7 +2751,7 @@ module.exports = { ], "stroke": "land", "strokeWidth": 0.3, - "strokeBlur": 1, + "strokeBlur": 1 }, "poi_aerodrome": { "opacity": ["stops", @@ -3503,11 +3503,11 @@ module.exports = { }, "water_label": { "color": "text_water_night", - "stroke": "water_night", + "stroke": "water_night" }, "waterway_label": { "color": "text_water_night", - "stroke": "water_night", + "stroke": "water_night" }, "poi": { "color": "white", From 6b0f64dbfd62a907029fd1afe702b052e77324c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 16 Jun 2014 17:50:23 +0200 Subject: [PATCH 6/6] move to namespace to fix compile error on linux/gcc --- src/style/style_parser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 1454a40e7..172f0aeb3 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -3,7 +3,7 @@ #include #include -using namespace llmr; +namespace llmr { using JSVal = const rapidjson::Value&; @@ -814,3 +814,5 @@ Value StyleParser::parseValue(JSVal value) { throw Style::exception("unhandled value type in style"); return false; } + +}