From 282e626ac112b1ca7a9bf9f9d4c0239db8fbd97a Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 10 Jun 2016 21:17:23 -0700 Subject: [PATCH 1/6] =?UTF-8?q?[core]=20Make=20enum=20=E2=86=94=20string?= =?UTF-8?q?=20conversion=20more=20generic-friendly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite enum.hpp in such a way that parseConstant can be defined generically for all enumerated types. While there, properly validated enumerated property values. --- include/mbgl/platform/event.hpp | 31 ---- include/mbgl/style/types.hpp | 10 +- include/mbgl/util/enum.hpp | 60 +++----- platform/darwin/src/log_nslog.mm | 3 +- platform/default/log_stderr.cpp | 3 +- platform/node/src/node_log.cpp | 6 +- src/mbgl/platform/event.cpp | 34 +++++ src/mbgl/platform/log.cpp | 3 +- src/mbgl/style/parser.cpp | 33 +++-- src/mbgl/style/property_parsing.cpp | 148 -------------------- src/mbgl/style/property_parsing.hpp | 28 ++-- src/mbgl/style/source.cpp | 4 +- src/mbgl/style/types.cpp | 80 +++++++++++ test/src/mbgl/test/fixture_log_observer.cpp | 4 +- test/style/style_parser.cpp | 5 +- 15 files changed, 194 insertions(+), 258 deletions(-) create mode 100644 src/mbgl/platform/event.cpp create mode 100644 src/mbgl/style/types.cpp diff --git a/include/mbgl/platform/event.hpp b/include/mbgl/platform/event.hpp index f082114946a..ee1ce6fa4e5 100644 --- a/include/mbgl/platform/event.hpp +++ b/include/mbgl/platform/event.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include namespace mbgl { @@ -13,14 +11,6 @@ enum class EventSeverity : uint8_t { Error, }; -MBGL_DEFINE_ENUM_CLASS(EventSeverityClass, EventSeverity, { - { EventSeverity::Debug, "DEBUG" }, - { EventSeverity::Info, "INFO" }, - { EventSeverity::Warning, "WARNING" }, - { EventSeverity::Error, "ERROR" }, - { EventSeverity(-1), "UNKNOWN" }, -}) - enum class Event : uint8_t { General, Setup, @@ -40,27 +30,6 @@ enum class Event : uint8_t { Glyph, }; -MBGL_DEFINE_ENUM_CLASS(EventClass, Event, { - { Event::General, "General" }, - { Event::Setup, "Setup" }, - { Event::Shader, "Shader" }, - { Event::ParseStyle, "ParseStyle" }, - { Event::ParseTile, "ParseTile" }, - { Event::Render, "Render" }, - { Event::Style, "Style" }, - { Event::Database, "Database" }, - { Event::HttpRequest, "HttpRequest" }, - { Event::Sprite, "Sprite" }, - { Event::Image, "Image" }, - { Event::OpenGL, "OpenGL" }, - { Event::JNI, "JNI" }, - { Event::Android, "Android" }, - { Event::Crash, "Crash" }, - { Event::Glyph, "Glyph" }, - { Event(-1), "Unknown" }, -}) - - struct EventPermutation { const EventSeverity severity; const Event event; diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp index ece56026df2..46c0cb3c394 100644 --- a/include/mbgl/style/types.hpp +++ b/include/mbgl/style/types.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace mbgl { @@ -13,14 +13,6 @@ enum class SourceType : uint8_t { Annotations }; -MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, { - { SourceType::Vector, "vector" }, - { SourceType::Raster, "raster" }, - { SourceType::GeoJSON, "geojson" }, - { SourceType::Video, "video" }, - { SourceType::Annotations, "annotations" }, -}) - namespace style { enum class VisibilityType : bool { diff --git a/include/mbgl/util/enum.hpp b/include/mbgl/util/enum.hpp index 3fbf313aedf..48ffda463eb 100644 --- a/include/mbgl/util/enum.hpp +++ b/include/mbgl/util/enum.hpp @@ -1,52 +1,36 @@ #pragma once -#include +#include + +#include +#include #include namespace mbgl { -template -struct EnumValue { - const Type value; - const char *name; -}; - -template *names, const size_t length> -struct Enum { - using Type = EnumName; - Type value; - static const constexpr size_t l = length; -private: - static constexpr inline bool compare(const char *a, const char *b) { - return *a == *b && (*a == '\0' || compare(a + 1, b + 1)); - } - static constexpr inline const char *lookup_type(Type e, EnumValue const * const list, size_t r) { - return r == 0 ? "" : list->value == e ? list->name : lookup_type(e, list + 1, r - 1); - } - static constexpr inline Type lookup_name(const char *n, EnumValue const * const list, size_t r) { - return r == 0 ? Type(-1) : compare(list->name, n) ? list->value : lookup_name(n, list + 1, r - 1); - } +template +class Enum { public: - inline constexpr Enum(const char *n) : value(lookup_name(n, names, length)) {} - inline constexpr Enum(const std::string &n) : value(lookup_name(n.c_str(), names, length)) {} - inline constexpr Enum(Type t) : value(t) {} - - inline void operator=(const char *n) { value = lookup_name(n, names, length); } - inline void operator=(const std::string &n) { *this = n.c_str(); } - inline void operator=(Type t) { value = t; } + using Value = std::pair; - inline constexpr bool valid() const { return value != Type(-1); } + static const char * toString(T t) { + auto it = std::find_if(begin, end, [&] (const auto& v) { return t == v.first; }); + assert(it != end); return it->second; + } - inline constexpr const char *c_str() const { return lookup_type(value, names, length); } - inline std::string str() const { return c_str(); } + static optional toEnum(const std::string& s) { + auto it = std::find_if(begin, end, [&] (const auto& v) { return s == v.second; }); + return it == end ? optional() : it->first; + } - inline constexpr operator Type() const { return value; } +private: + static const Value* begin; + static const Value* end; }; -#define MBGL_DEFINE_ENUM_CLASS(name, type, strings...) \ - const constexpr ::mbgl::EnumValue type##_names[] = strings; \ - using name = ::mbgl::Enum)>; \ - inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); } +#define MBGL_DEFINE_ENUM(type, strings...) \ +const constexpr Enum::Value type##_names[] = strings; \ +template <> const Enum::Value* Enum::begin = std::begin(type##_names); \ +template <> const Enum::Value* Enum::end = std::end(type##_names) } // namespace mbgl - diff --git a/platform/darwin/src/log_nslog.mm b/platform/darwin/src/log_nslog.mm index a2e31968ab1..49583ae3c45 100644 --- a/platform/darwin/src/log_nslog.mm +++ b/platform/darwin/src/log_nslog.mm @@ -1,4 +1,5 @@ #include +#include #import @@ -7,7 +8,7 @@ void Log::platformRecord(EventSeverity severity, const std::string &msg) { NSString *message = [[NSString alloc] initWithBytes:msg.data() length:msg.size() encoding:NSUTF8StringEncoding]; - NSLog(@"[%s] %@", EventSeverityClass(severity).c_str(), message); + NSLog(@"[%s] %@", Enum::toString(severity), message); } } diff --git a/platform/default/log_stderr.cpp b/platform/default/log_stderr.cpp index 536841617a7..145cdeda03d 100644 --- a/platform/default/log_stderr.cpp +++ b/platform/default/log_stderr.cpp @@ -1,11 +1,12 @@ #include +#include #include namespace mbgl { void Log::platformRecord(EventSeverity severity, const std::string &msg) { - std::cerr << "[" << severity << "] " << msg << std::endl; + std::cerr << "[" << Enum::toString(severity) << "] " << msg << std::endl; } } // namespace mbgl diff --git a/platform/node/src/node_log.cpp b/platform/node/src/node_log.cpp index a741109b27e..21eaa55bcad 100644 --- a/platform/node/src/node_log.cpp +++ b/platform/node/src/node_log.cpp @@ -1,6 +1,8 @@ #include "node_log.hpp" #include "util/async_queue.hpp" +#include + namespace node_mbgl { struct NodeLogObserver::LogMessage { @@ -23,10 +25,10 @@ NodeLogObserver::NodeLogObserver(v8::Local target) auto msg = Nan::New(); Nan::Set(msg, Nan::New("class").ToLocalChecked(), - Nan::New(mbgl::EventClass(message.event).c_str()).ToLocalChecked()); + Nan::New(mbgl::Enum::toString(message.event)).ToLocalChecked()); Nan::Set(msg, Nan::New("severity").ToLocalChecked(), - Nan::New(mbgl::EventSeverityClass(message.severity).c_str()).ToLocalChecked()); + Nan::New(mbgl::Enum::toString(message.severity)).ToLocalChecked()); if (message.code != -1) { Nan::Set(msg, Nan::New("code").ToLocalChecked(), diff --git a/src/mbgl/platform/event.cpp b/src/mbgl/platform/event.cpp new file mode 100644 index 00000000000..68d75a29417 --- /dev/null +++ b/src/mbgl/platform/event.cpp @@ -0,0 +1,34 @@ +#include +#include + +namespace mbgl { + +MBGL_DEFINE_ENUM(EventSeverity, { + { EventSeverity::Debug, "DEBUG" }, + { EventSeverity::Info, "INFO" }, + { EventSeverity::Warning, "WARNING" }, + { EventSeverity::Error, "ERROR" }, + { EventSeverity(-1), "UNKNOWN" }, +}); + +MBGL_DEFINE_ENUM(Event, { + { Event::General, "General" }, + { Event::Setup, "Setup" }, + { Event::Shader, "Shader" }, + { Event::ParseStyle, "ParseStyle" }, + { Event::ParseTile, "ParseTile" }, + { Event::Render, "Render" }, + { Event::Style, "Style" }, + { Event::Database, "Database" }, + { Event::HttpRequest, "HttpRequest" }, + { Event::Sprite, "Sprite" }, + { Event::Image, "Image" }, + { Event::OpenGL, "OpenGL" }, + { Event::JNI, "JNI" }, + { Event::Android, "Android" }, + { Event::Crash, "Crash" }, + { Event::Glyph, "Glyph" }, + { Event(-1), "Unknown" }, +}); + +} // namespace mbgl diff --git a/src/mbgl/platform/log.cpp b/src/mbgl/platform/log.cpp index 2118511592a..4b56435df0c 100644 --- a/src/mbgl/platform/log.cpp +++ b/src/mbgl/platform/log.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -54,7 +55,7 @@ void Log::record(EventSeverity severity, Event event, int64_t code, const std::s logStream << "{" << name << "}"; #endif - logStream << "[" << event << "]"; + logStream << "[" << Enum::toString(event) << "]"; if (code >= 0) { logStream << "(" << code << ")"; diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index 8e632ac6a0c..870fd6d71ee 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -161,11 +162,15 @@ void Parser::parseSources(const JSValue& value) { const JSValue& typeVal = sourceVal["type"]; if (!typeVal.IsString()) { - Log::Warning(Event::ParseStyle, "source type must have one of the enum values"); + Log::Warning(Event::ParseStyle, "source type must be a string"); continue; } - const auto type = SourceTypeClass({ typeVal.GetString(), typeVal.GetStringLength() }); + const auto type = Enum::toEnum({ typeVal.GetString(), typeVal.GetStringLength() }); + if (!type) { + Log::Warning(Event::ParseStyle, "source type must have one of the enum values"); + continue; + } // Sources can have URLs, either because they reference an external TileJSON file, or // because reference a GeoJSON file. They don't have to have one though when all source @@ -177,7 +182,7 @@ void Parser::parseSources(const JSValue& value) { std::unique_ptr tileset; std::unique_ptr geojsonvt; - switch (type) { + switch (*type) { case SourceType::Raster: if (sourceVal.HasMember("tileSize")) { const JSValue& tileSizeVal = sourceVal["tileSize"]; @@ -236,7 +241,7 @@ void Parser::parseSources(const JSValue& value) { } const std::string id { nameVal.GetString(), nameVal.GetStringLength() }; - std::unique_ptr source = std::make_unique(type, id, url, tileSize, std::move(tileset), std::move(geojsonvt)); + std::unique_ptr source = std::make_unique(*type, id, url, tileSize, std::move(tileset), std::move(geojsonvt)); sourcesMap.emplace(id, source.get()); sources.emplace_back(std::move(source)); @@ -481,21 +486,25 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique } } -MBGL_DEFINE_ENUM_CLASS(VisibilityTypeClass, VisibilityType, { - { VisibilityType::Visible, "visible" }, - { VisibilityType::None, "none" }, -}) - void Parser::parseVisibility(Layer& layer, const JSValue& value) { Layer::Impl& impl = *layer.baseImpl; + if (!value.HasMember("visibility")) { return; - } else if (!value["visibility"].IsString()) { + } + + if (!value["visibility"].IsString()) { Log::Warning(Event::ParseStyle, "value of 'visibility' must be a string"); - impl.visibility = VisibilityType::Visible; return; } - impl.visibility = VisibilityTypeClass({ value["visibility"].GetString(), value["visibility"].GetStringLength() }); + + const auto enumValue = Enum::toEnum({ value["visibility"].GetString(), value["visibility"].GetStringLength() }); + if (!enumValue) { + Log::Warning(Event::ParseStyle, "value of 'visibility' must be a valid enumeration value"); + return; + } + + impl.visibility = *enumValue; } Value parseFeatureType(const Value& value) { diff --git a/src/mbgl/style/property_parsing.cpp b/src/mbgl/style/property_parsing.cpp index 6e5174e9366..9985cc7f39c 100644 --- a/src/mbgl/style/property_parsing.cpp +++ b/src/mbgl/style/property_parsing.cpp @@ -55,154 +55,6 @@ optional parseConstant(const char* name, const JSValue& value) { css_color.a}}; } -MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, { - { TranslateAnchorType::Map, "map" }, - { TranslateAnchorType::Viewport, "viewport" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { TranslateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(RotateAnchorTypeClass, RotateAnchorType, { - { RotateAnchorType::Map, "map" }, - { RotateAnchorType::Viewport, "viewport" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(LineCapTypeClass, LineCapType, { - { LineCapType::Round, "round" }, - { LineCapType::Butt, "butt" }, - { LineCapType::Square, "square" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { LineCapTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(LineJoinTypeClass, LineJoinType, { - { LineJoinType::Miter, "miter" }, - { LineJoinType::Bevel, "bevel" }, - { LineJoinType::Round, "round" }, - { LineJoinType::FakeRound, "fakeround" }, - { LineJoinType::FlipBevel, "flipbevel" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { LineJoinTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(SymbolPlacementTypeClass, SymbolPlacementType, { - { SymbolPlacementType::Point, "point" }, - { SymbolPlacementType::Line, "line" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { SymbolPlacementTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(TextAnchorTypeClass, TextAnchorType, { - { TextAnchorType::Center, "center" }, - { TextAnchorType::Left, "left" }, - { TextAnchorType::Right, "right" }, - { TextAnchorType::Top, "top" }, - { TextAnchorType::Bottom, "bottom" }, - { TextAnchorType::TopLeft, "top-left" }, - { TextAnchorType::TopRight, "top-right" }, - { TextAnchorType::BottomLeft, "bottom-left" }, - { TextAnchorType::BottomRight, "bottom-right" } -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { TextAnchorTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, { - { TextJustifyType::Center, "center" }, - { TextJustifyType::Left, "left" }, - { TextJustifyType::Right, "right" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { TextJustifyTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, { - { TextTransformType::None, "none" }, - { TextTransformType::Uppercase, "uppercase" }, - { TextTransformType::Lowercase, "lowercase" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { TextTransformTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - -MBGL_DEFINE_ENUM_CLASS(AlignmentTypeClass, AlignmentType, { - { AlignmentType::Map, "map" }, - { AlignmentType::Viewport, "viewport" }, -}) - -template <> -optional parseConstant(const char* name, const JSValue& value) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); - return {}; - } - - return { AlignmentTypeClass({ value.GetString(), value.GetStringLength() }) }; -} - template <> optional> parseConstant(const char* name, const JSValue& value) { if (value.IsArray() && value.Size() == 2 && diff --git a/src/mbgl/style/property_parsing.hpp b/src/mbgl/style/property_parsing.hpp index d2d283fe179..d27a9e50313 100644 --- a/src/mbgl/style/property_parsing.hpp +++ b/src/mbgl/style/property_parsing.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -17,26 +18,33 @@ namespace mbgl { namespace style { -template +template ::value>> optional parseConstant(const char* name, const JSValue&); template <> optional parseConstant(const char*, const JSValue&); template <> optional parseConstant(const char*, const JSValue&); template <> optional parseConstant(const char*, const JSValue&); template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); -template <> optional parseConstant(const char*, const JSValue&); template <> optional> parseConstant(const char*, const JSValue&); template <> optional> parseConstant(const char*, const JSValue&); template <> optional> parseConstant(const char*, const JSValue&); +template +optional parseConstant(const char* name, const JSValue& value, + typename std::enable_if_t::value, void*> = nullptr) { + if (!value.IsString()) { + Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); + return {}; + } + + const auto result = Enum::toEnum({ value.GetString(), value.GetStringLength() }); + if (!result) { + Log::Warning(Event::ParseStyle, "value of '%s' must be a valid enumeration value", name); + } + + return result; +} + template PropertyValue parseProperty(const char* name, const JSValue& value) { if (!value.IsObject()) { diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp index 544d230a25d..bffb6a8fccf 100644 --- a/src/mbgl/style/source.cpp +++ b/src/mbgl/style/source.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -197,8 +198,7 @@ std::unique_ptr Source::createTile(const OverscaledTileID& overscaledTileI } else if (type == SourceType::GeoJSON) { return std::make_unique(overscaledTileID, id, parameters, geojsonvt.get()); } else { - Log::Warning(Event::Style, "Source type '%s' is not implemented", - SourceTypeClass(type).c_str()); + Log::Warning(Event::Style, "Source type '%s' is not implemented", Enum::toString(type)); return nullptr; } } diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp new file mode 100644 index 00000000000..d292d2d5b41 --- /dev/null +++ b/src/mbgl/style/types.cpp @@ -0,0 +1,80 @@ +#include +#include + +namespace mbgl { + +using namespace style; + +MBGL_DEFINE_ENUM(SourceType, { + { SourceType::Vector, "vector" }, + { SourceType::Raster, "raster" }, + { SourceType::GeoJSON, "geojson" }, + { SourceType::Video, "video" }, + { SourceType::Annotations, "annotations" }, +}); + +MBGL_DEFINE_ENUM(VisibilityType, { + { VisibilityType::Visible, "visible" }, + { VisibilityType::None, "none" }, +}); + +MBGL_DEFINE_ENUM(TranslateAnchorType, { + { TranslateAnchorType::Map, "map" }, + { TranslateAnchorType::Viewport, "viewport" }, +}); + +MBGL_DEFINE_ENUM(RotateAnchorType, { + { RotateAnchorType::Map, "map" }, + { RotateAnchorType::Viewport, "viewport" }, +}); + +MBGL_DEFINE_ENUM(LineCapType, { + { LineCapType::Round, "round" }, + { LineCapType::Butt, "butt" }, + { LineCapType::Square, "square" }, +}); + +MBGL_DEFINE_ENUM(LineJoinType, { + { LineJoinType::Miter, "miter" }, + { LineJoinType::Bevel, "bevel" }, + { LineJoinType::Round, "round" }, + { LineJoinType::FakeRound, "fakeround" }, + { LineJoinType::FlipBevel, "flipbevel" }, +}); + +MBGL_DEFINE_ENUM(SymbolPlacementType, { + { SymbolPlacementType::Point, "point" }, + { SymbolPlacementType::Line, "line" }, +}); + +MBGL_DEFINE_ENUM(TextAnchorType, { + { TextAnchorType::Center, "center" }, + { TextAnchorType::Left, "left" }, + { TextAnchorType::Right, "right" }, + { TextAnchorType::Top, "top" }, + { TextAnchorType::Bottom, "bottom" }, + { TextAnchorType::TopLeft, "top-left" }, + { TextAnchorType::TopRight, "top-right" }, + { TextAnchorType::BottomLeft, "bottom-left" }, + { TextAnchorType::BottomRight, "bottom-right" } +}); + +MBGL_DEFINE_ENUM(TextJustifyType, { + { TextJustifyType::Center, "center" }, + { TextJustifyType::Left, "left" }, + { TextJustifyType::Right, "right" }, +}); + +MBGL_DEFINE_ENUM(TextTransformType, { + { TextTransformType::None, "none" }, + { TextTransformType::Uppercase, "uppercase" }, + { TextTransformType::Lowercase, "lowercase" }, +}); + +MBGL_DEFINE_ENUM(AlignmentType, { + { AlignmentType::Map, "map" }, + { AlignmentType::Viewport, "viewport" }, + { AlignmentType::Undefined, "undefined" }, +}); + +} // namespace mbgl diff --git a/test/src/mbgl/test/fixture_log_observer.cpp b/test/src/mbgl/test/fixture_log_observer.cpp index 11587be15a2..fc0239bb1cc 100644 --- a/test/src/mbgl/test/fixture_log_observer.cpp +++ b/test/src/mbgl/test/fixture_log_observer.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace mbgl { @@ -96,7 +97,8 @@ ::std::ostream& operator<<(::std::ostream& os, const std::vector::toString(message.severity) << "\", \""; + os << Enum::toString(message.event) << "\""; os << ", " << message.code; os << ", \"" << message.msg << "\""; return os << "]" << std::endl; diff --git a/test/style/style_parser.cpp b/test/style/style_parser.cpp index 7590f32403c..aba5ec67bd1 100644 --- a/test/style/style_parser.cpp +++ b/test/style/style_parser.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -46,8 +47,8 @@ TEST_P(StyleParserTest, ParseStyle) { const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint(); const FixtureLogObserver::LogMessage message { - EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()), - EventClass(js_entry[rapidjson::SizeType(2)].GetString()), + *Enum::toEnum(js_entry[rapidjson::SizeType(1)].GetString()), + *Enum::toEnum(js_entry[rapidjson::SizeType(2)].GetString()), int64_t(-1), js_entry[rapidjson::SizeType(3)].GetString() }; From ee78b1b797bc8d46f7475612ae84f0ee548a0ed6 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 8 Jun 2016 16:39:31 -0700 Subject: [PATCH 2/6] [core] Eliminate some redundant NodeMap members --- platform/node/src/node_map.cpp | 26 +++++++++----------------- platform/node/src/node_map.hpp | 4 ---- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index 165e27b669d..e423a274c42 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -166,8 +166,7 @@ std::string StringifyStyle(v8::Local styleHandle) { */ NAN_METHOD(NodeMap::Load) { auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); - - if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); // Reset the flag as this could be the second time // we are calling this (being the previous successful). @@ -286,8 +285,7 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local obj) { */ NAN_METHOD(NodeMap::Render) { auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); - - if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); if (info.Length() <= 0 || !info[0]->IsObject()) { return Nan::ThrowTypeError("First argument must be an options object"); @@ -297,7 +295,7 @@ NAN_METHOD(NodeMap::Render) { return Nan::ThrowTypeError("Second argument must be a callback function"); } - if (!nodeMap->isLoaded()) { + if (!nodeMap->loaded) { return Nan::ThrowTypeError("Style is not loaded"); } @@ -417,8 +415,7 @@ void NodeMap::renderFinished() { */ NAN_METHOD(NodeMap::Release) { auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); - - if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); try { nodeMap->release(); @@ -430,21 +427,18 @@ NAN_METHOD(NodeMap::Release) { } void NodeMap::release() { - if (!isValid()) throw mbgl::util::Exception(releasedMessage()); - - valid = false; + if (!map) throw mbgl::util::Exception(releasedMessage()); uv_close(reinterpret_cast(async), [] (uv_handle_t *h) { delete reinterpret_cast(h); }); - map.reset(nullptr); + map.reset(); } NAN_METHOD(NodeMap::DumpDebugLogs) { auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); - - if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); nodeMap->map->dumpDebugLogs(); info.GetReturnValue().SetUndefined(); @@ -452,9 +446,7 @@ NAN_METHOD(NodeMap::DumpDebugLogs) { NAN_METHOD(NodeMap::QueryRenderedFeatures) { auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); - Nan::HandleScope scope; - - if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); if (info.Length() <= 0 || !info[0]->IsArray()) { return Nan::ThrowTypeError("First argument must be an array"); @@ -521,7 +513,7 @@ NodeMap::NodeMap(v8::Local options) : } NodeMap::~NodeMap() { - if (valid) release(); + if (map) release(); } std::unique_ptr NodeMap::request(const mbgl::Resource& resource, Callback callback_) { diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 6e28eb541eb..d3f7bd9e41e 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -34,9 +34,6 @@ class NodeMap : public Nan::ObjectWrap, void release(); - inline bool isLoaded() { return loaded; } - inline bool isValid() { return valid; } - static RenderOptions ParseOptions(v8::Local); static Nan::Persistent constructor; @@ -56,7 +53,6 @@ class NodeMap : public Nan::ObjectWrap, uv_async_t *async; bool loaded = false; - bool valid = true; }; } From 039b05ebb462762c43ce4fc750fd98ae0c9e0093 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 8 Jun 2016 17:18:06 -0700 Subject: [PATCH 3/6] [core] Extract code templates to individual .ejs files --- include/mbgl/style/layers/layer.hpp.ejs | 76 +++++ scripts/generate-style-code.js | 279 +----------------- src/mbgl/style/layers/layer.cpp.ejs | 92 ++++++ .../style/layers/layer_properties.cpp.ejs | 50 ++++ .../style/layers/layer_properties.hpp.ejs | 50 ++++ 5 files changed, 272 insertions(+), 275 deletions(-) create mode 100644 include/mbgl/style/layers/layer.hpp.ejs create mode 100644 src/mbgl/style/layers/layer.cpp.ejs create mode 100644 src/mbgl/style/layers/layer_properties.cpp.ejs create mode 100644 src/mbgl/style/layers/layer_properties.hpp.ejs diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs new file mode 100644 index 00000000000..fdf76208929 --- /dev/null +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -0,0 +1,76 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Do not edit. + +#pragma once + +#include +#include +#include + +#include + +<% if (type === 'line' || type === 'symbol') { -%> +#include + +<% } -%> +namespace mbgl { +namespace style { + +class <%- camelize(type) %>Layer : public Layer { +public: + <%- camelize(type) %>Layer(const std::string& layerID); + ~<%- camelize(type) %>Layer() final; + +<% if (type === 'raster') { -%> + // Source + + void setSource(const std::string& sourceID); + const std::string& getSourceID() const; + +<% } else if (type !== 'background') { -%> + // Source + + void setSource(const std::string& sourceID, const std::string& sourceLayer); + const std::string& getSourceID() const; + const std::string& getSourceLayer() const; + + void setFilter(const Filter&); + const Filter& getFilter() const; + +<% } -%> +<% if (layoutProperties.length) { -%> + // Layout properties + +<% for (const property of layoutProperties) { -%> + PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const; + void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>); + +<% } -%> +<% } -%> + // Paint properties + +<% for (const property of paintProperties) { -%> + PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const; + void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>); + +<% } -%> + // Private implementation + + class Impl; + Impl* const impl; + + <%- camelize(type) %>Layer(const Impl&); + <%- camelize(type) %>Layer(const <%- camelize(type) %>Layer&) = delete; +}; + +template <> +inline bool Layer::is<<%- camelize(type) %>Layer>() const { + return type == Type::<%- camelize(type) %>; +} + +} // namespace style +} // namespace mbgl diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 1796cda2123..21654117b8f 100644 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -76,281 +76,10 @@ global.defaultValue = function (property) { } } -const layerHpp = ejs.compile(`<% - const type = locals.type; - const layoutProperties = locals.layoutProperties; - const paintProperties = locals.paintProperties; --%> -// This file is generated. Do not edit. - -#pragma once - -#include -#include -#include - -#include - -<% if (type === 'line' || type === 'symbol') { -%> -#include - -<% } -%> -namespace mbgl { -namespace style { - -class <%- camelize(type) %>Layer : public Layer { -public: - <%- camelize(type) %>Layer(const std::string& layerID); - ~<%- camelize(type) %>Layer() final; - -<% if (type === 'raster') { -%> - // Source - - void setSource(const std::string& sourceID); - const std::string& getSourceID() const; - -<% } else if (type !== 'background') { -%> - // Source - - void setSource(const std::string& sourceID, const std::string& sourceLayer); - const std::string& getSourceID() const; - const std::string& getSourceLayer() const; - - void setFilter(const Filter&); - const Filter& getFilter() const; - -<% } -%> -<% if (layoutProperties.length) { -%> - // Layout properties - -<% for (const property of layoutProperties) { -%> - PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const; - void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>); - -<% } -%> -<% } -%> - // Paint properties - -<% for (const property of paintProperties) { -%> - PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const; - void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>); - -<% } -%> - // Private implementation - - class Impl; - Impl* const impl; - - <%- camelize(type) %>Layer(const Impl&); - <%- camelize(type) %>Layer(const <%- camelize(type) %>Layer&) = delete; -}; - -template <> -inline bool Layer::is<<%- camelize(type) %>Layer>() const { - return type == Type::<%- camelize(type) %>; -} - -} // namespace style -} // namespace mbgl -`, {strict: true}); - -const layerCpp = ejs.compile(`<% - const type = locals.type; - const layoutProperties = locals.layoutProperties; - const paintProperties = locals.paintProperties; --%> -// This file is generated. Edit scripts/generate-style-code.js, then run \`make style-code\`. - -#include _layer.hpp> -#include _layer_impl.hpp> - -namespace mbgl { -namespace style { - -<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID) - : Layer(Type::<%- camelize(type) %>, std::make_unique()) - , impl(static_cast(baseImpl.get())) { - impl->id = layerID; -} - -<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const Impl& other) - : Layer(Type::<%- camelize(type) %>, std::make_unique(other)) - , impl(static_cast(baseImpl.get())) { -} - -<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default; - -std::unique_ptr <%- camelize(type) %>Layer::Impl::clone() const { - return std::make_unique<<%- camelize(type) %>Layer>(*this); -} - -<% if (type === 'raster') { -%> -// Source - -void <%- camelize(type) %>Layer::setSource(const std::string& sourceID) { - impl->source = sourceID; -} - -const std::string& <%- camelize(type) %>Layer::getSourceID() const { - return impl->source; -} -<% } else if (type !== 'background') { -%> -// Source - -void <%- camelize(type) %>Layer::setSource(const std::string& sourceID, const std::string& sourceLayer) { - impl->source = sourceID; - impl->sourceLayer = sourceLayer; -} - -const std::string& <%- camelize(type) %>Layer::getSourceID() const { - return impl->source; -} - -const std::string& <%- camelize(type) %>Layer::getSourceLayer() const { - return impl->sourceLayer; -} - -// Filter - -void <%- camelize(type) %>Layer::setFilter(const Filter& filter) { - impl->filter = filter; -} - -const Filter& <%- camelize(type) %>Layer::getFilter() const { - return impl->filter; -} -<% } -%> - -// Layout properties - -<% for (const property of layoutProperties) { -%> -PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { - return impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.get(); -} - -void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) { - impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.set(value); -} -<% } -%> - -// Paint properties -<% for (const property of paintProperties) { %> -PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { - return impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.get(); -} - -void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) { - impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.set(value); -} -<% } -%> - -} // namespace style -} // namespace mbgl -`, {strict: true}); - -const propertiesHpp = ejs.compile(`<% - const type = locals.type; - const layoutProperties = locals.layoutProperties; - const paintProperties = locals.paintProperties; --%> -// This file is generated. Edit scripts/generate-style-code.js, then run \`make style-code\`. - -#pragma once - -#include -#include -#include - -namespace mbgl { -namespace style { - -class CascadeParameters; -class CalculationParameters; - -<% if (layoutProperties.length) { -%> -class <%- camelize(type) %>LayoutProperties { -public: - void parse(const JSValue&); - void recalculate(const CalculationParameters&); - -<% for (const property of layoutProperties) { -%> - LayoutProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; -<% } -%> -}; - -<% } -%> -class <%- camelize(type) %>PaintProperties { -public: - void parse(const JSValue&); - void cascade(const CascadeParameters&); - bool recalculate(const CalculationParameters&); - -<% for (const property of paintProperties) { -%> -<% if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') { -%> - PaintProperty<<%- propertyType(property) %>, CrossFadedPropertyEvaluator> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; -<% } else if (property.name === 'fill-outline-color') { -%> - PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { {{ 0, 0, 0, -1 }} }; -<% } else { -%> - PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; -<% } -%> -<% } -%> -}; - -} // namespace style -} // namespace mbgl -`, {strict: true}); - -const propertiesCpp = ejs.compile(`<% - const type = locals.type; - const layoutProperties = locals.layoutProperties; - const paintProperties = locals.paintProperties; --%> -// This file is generated. Edit scripts/generate-style-code.js, then run \`make style-code\`. - -#include _layer_properties.hpp> - -namespace mbgl { -namespace style { - -<% if (layoutProperties.length) { -%> -void <%- camelize(type) %>LayoutProperties::parse(const JSValue& value) { -<% for (const property of layoutProperties) { -%> - <%- camelizeWithLeadingLowercase(property.name) %>.parse(<%- JSON.stringify(property.name) %>, value); -<% } -%> -} - -void <%- camelize(type) %>LayoutProperties::recalculate(const CalculationParameters& parameters) { -<% for (const property of layoutProperties) { -%> - <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters); -<% } -%> -} - -<% } -%> -void <%- camelize(type) %>PaintProperties::parse(const JSValue& value) { -<% for (const property of paintProperties) { -%> - <%- camelizeWithLeadingLowercase(property.name) %>.parse(<%- JSON.stringify(property.name) %>, value); -<% } -%> -} - -void <%- camelize(type) %>PaintProperties::cascade(const CascadeParameters& parameters) { -<% for (const property of paintProperties) { -%> - <%- camelizeWithLeadingLowercase(property.name) %>.cascade(parameters); -<% } -%> -} - -bool <%- camelize(type) %>PaintProperties::recalculate(const CalculationParameters& parameters) { - bool hasTransitions = false; - -<% for (const property of paintProperties) { -%> - hasTransitions |= <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters); -<% } -%> - - return hasTransitions; -} - -} // namespace style -} // namespace mbgl -`, {strict: true}); +const layerHpp = ejs.compile(fs.readFileSync('include/mbgl/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); +const layerCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); +const propertiesHpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.hpp.ejs', 'utf8'), {strict: true}); +const propertiesCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.cpp.ejs', 'utf8'), {strict: true}); for (const type of spec.layer.type.values) { const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => { diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs new file mode 100644 index 00000000000..633d6738045 --- /dev/null +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -0,0 +1,92 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include _layer.hpp> +#include _layer_impl.hpp> + +namespace mbgl { +namespace style { + +<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID) + : Layer(Type::<%- camelize(type) %>, std::make_unique()) + , impl(static_cast(baseImpl.get())) { + impl->id = layerID; +} + +<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const Impl& other) + : Layer(Type::<%- camelize(type) %>, std::make_unique(other)) + , impl(static_cast(baseImpl.get())) { +} + +<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default; + +std::unique_ptr <%- camelize(type) %>Layer::Impl::clone() const { + return std::make_unique<<%- camelize(type) %>Layer>(*this); +} + +<% if (type === 'raster') { -%> +// Source + +void <%- camelize(type) %>Layer::setSource(const std::string& sourceID) { + impl->source = sourceID; +} + +const std::string& <%- camelize(type) %>Layer::getSourceID() const { + return impl->source; +} +<% } else if (type !== 'background') { -%> +// Source + +void <%- camelize(type) %>Layer::setSource(const std::string& sourceID, const std::string& sourceLayer) { + impl->source = sourceID; + impl->sourceLayer = sourceLayer; +} + +const std::string& <%- camelize(type) %>Layer::getSourceID() const { + return impl->source; +} + +const std::string& <%- camelize(type) %>Layer::getSourceLayer() const { + return impl->sourceLayer; +} + +// Filter + +void <%- camelize(type) %>Layer::setFilter(const Filter& filter) { + impl->filter = filter; +} + +const Filter& <%- camelize(type) %>Layer::getFilter() const { + return impl->filter; +} +<% } -%> + +// Layout properties + +<% for (const property of layoutProperties) { -%> +PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { + return impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.get(); +} + +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) { + impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.set(value); +} +<% } -%> + +// Paint properties +<% for (const property of paintProperties) { %> +PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { + return impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.get(); +} + +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) { + impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.set(value); +} +<% } -%> + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/layer_properties.cpp.ejs b/src/mbgl/style/layers/layer_properties.cpp.ejs new file mode 100644 index 00000000000..8fef8d29c40 --- /dev/null +++ b/src/mbgl/style/layers/layer_properties.cpp.ejs @@ -0,0 +1,50 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include _layer_properties.hpp> + +namespace mbgl { +namespace style { + +<% if (layoutProperties.length) { -%> +void <%- camelize(type) %>LayoutProperties::parse(const JSValue& value) { +<% for (const property of layoutProperties) { -%> + <%- camelizeWithLeadingLowercase(property.name) %>.parse(<%- JSON.stringify(property.name) %>, value); +<% } -%> +} + +void <%- camelize(type) %>LayoutProperties::recalculate(const CalculationParameters& parameters) { +<% for (const property of layoutProperties) { -%> + <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters); +<% } -%> +} + +<% } -%> +void <%- camelize(type) %>PaintProperties::parse(const JSValue& value) { +<% for (const property of paintProperties) { -%> + <%- camelizeWithLeadingLowercase(property.name) %>.parse(<%- JSON.stringify(property.name) %>, value); +<% } -%> +} + +void <%- camelize(type) %>PaintProperties::cascade(const CascadeParameters& parameters) { +<% for (const property of paintProperties) { -%> + <%- camelizeWithLeadingLowercase(property.name) %>.cascade(parameters); +<% } -%> +} + +bool <%- camelize(type) %>PaintProperties::recalculate(const CalculationParameters& parameters) { + bool hasTransitions = false; + +<% for (const property of paintProperties) { -%> + hasTransitions |= <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters); +<% } -%> + + return hasTransitions; +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs new file mode 100644 index 00000000000..55e07ad61bc --- /dev/null +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -0,0 +1,50 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#pragma once + +#include +#include +#include + +namespace mbgl { +namespace style { + +class CascadeParameters; +class CalculationParameters; + +<% if (layoutProperties.length) { -%> +class <%- camelize(type) %>LayoutProperties { +public: + void parse(const JSValue&); + void recalculate(const CalculationParameters&); + +<% for (const property of layoutProperties) { -%> + LayoutProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; +<% } -%> +}; + +<% } -%> +class <%- camelize(type) %>PaintProperties { +public: + void parse(const JSValue&); + void cascade(const CascadeParameters&); + bool recalculate(const CalculationParameters&); + +<% for (const property of paintProperties) { -%> +<% if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') { -%> + PaintProperty<<%- propertyType(property) %>, CrossFadedPropertyEvaluator> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; +<% } else if (property.name === 'fill-outline-color') { -%> + PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { {{ 0, 0, 0, -1 }} }; +<% } else { -%> + PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> }; +<% } -%> +<% } -%> +}; + +} // namespace style +} // namespace mbgl From 1529116ef6a3e2ece63adfa12e02f57a18efff27 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 8 Jun 2016 17:18:28 -0700 Subject: [PATCH 4/6] [core] Introduce Map::getLayer --- include/mbgl/map/map.hpp | 1 + src/mbgl/map/map.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index d50aac1c096..749c45c4c22 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -149,6 +149,7 @@ class Map : private util::noncopyable { AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&); + style::Layer* getLayer(const std::string& layerID); void addLayer(std::unique_ptr, const optional& beforeLayerID = {}); void removeLayer(const std::string& layerID); diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 2b39b3e8841..ae9330abae7 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -736,6 +736,10 @@ std::vector Map::queryRenderedFeatures(const ScreenBox& box, const opti #pragma mark - Style API +style::Layer* Map::getLayer(const std::string& layerID) { + return impl->style ? impl->style->getLayer(layerID) : nullptr; +} + void Map::addLayer(std::unique_ptr layer, const optional& before) { impl->view.activate(); From 6cc2f8a3a52d0c375458c7da4fe51e8160e38a88 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 10 Jun 2016 15:32:57 -0700 Subject: [PATCH 5/6] [core] Fix PropertyValue::set For runtime styling, it needs to overwrite any existing value. --- src/mbgl/style/paint_property.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index 7cb75781a36..67aa2244ec5 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -36,7 +36,7 @@ class PaintProperty { } void set(const PropertyValue& value_) { - values.emplace(ClassID::Default, value_); + values[ClassID::Default] = value_; } void parse(const char* name, const JSValue& layer) { From 3f5ea169f5d617455b21467fbd12a812c6aa2972 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 10 Jun 2016 21:17:58 -0700 Subject: [PATCH 6/6] [node] Partial implementation of runtime styling API for node bindings --- package.json | 2 +- platform/node/src/node_map.cpp | 76 +++++++++++ platform/node/src/node_map.hpp | 3 + platform/node/src/node_style.hpp | 126 ++++++++++++++++++ platform/node/src/node_style_properties.hpp | 120 +++++++++++++++++ .../node/src/node_style_properties.hpp.ejs | 35 +++++ platform/node/test/suite_implementation.js | 39 ++++-- scripts/generate-style-code.js | 17 ++- 8 files changed, 403 insertions(+), 15 deletions(-) create mode 100644 platform/node/src/node_style.hpp create mode 100644 platform/node/src/node_style_properties.hpp create mode 100644 platform/node/src/node_style_properties.hpp.ejs diff --git a/package.json b/package.json index 8bebceeb54c..ff341ffc7cd 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "express": "^4.11.1", "mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#09ee512cd59a8fb1a241c78833b7c8022bf4f263", "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#2461efc3d883f2f2e56a6c6b2bfd7d54bbfe9f86", - "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#e78f09dce98080a9a6fa436d11fdf6fc2f271d7a", + "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#ce8146c048487dab444d92ce06ef0b0ca8515c73", "node-gyp": "^3.3.1", "request": "^2.72.0", "tape": "^4.5.1" diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index e423a274c42..e629bb21498 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -1,9 +1,12 @@ #include "node_map.hpp" #include "node_request.hpp" #include "node_feature.hpp" +#include "node_style_properties.hpp" #include #include +#include +#include #include @@ -48,8 +51,13 @@ NAN_MODULE_INIT(NodeMap::Init) { tpl->SetClassName(Nan::New("Map").ToLocalChecked()); Nan::SetPrototypeMethod(tpl, "load", Load); + Nan::SetPrototypeMethod(tpl, "loaded", Loaded); Nan::SetPrototypeMethod(tpl, "render", Render); Nan::SetPrototypeMethod(tpl, "release", Release); + + Nan::SetPrototypeMethod(tpl, "addClass", AddClass); + Nan::SetPrototypeMethod(tpl, "setPaintProperty", SetPaintProperty); + Nan::SetPrototypeMethod(tpl, "dumpDebugLogs", DumpDebugLogs); Nan::SetPrototypeMethod(tpl, "queryRenderedFeatures", QueryRenderedFeatures); @@ -197,6 +205,21 @@ NAN_METHOD(NodeMap::Load) { info.GetReturnValue().SetUndefined(); } +NAN_METHOD(NodeMap::Loaded) { + auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); + + bool loaded = false; + + try { + loaded = nodeMap->map->isFullyLoaded(); + } catch (const std::exception &ex) { + return Nan::ThrowError(ex.what()); + } + + info.GetReturnValue().Set(Nan::New(loaded)); +} + NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local obj) { Nan::HandleScope scope; @@ -436,6 +459,59 @@ void NodeMap::release() { map.reset(); } +NAN_METHOD(NodeMap::AddClass) { + auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); + + if (info.Length() <= 0 || !info[0]->IsString()) { + return Nan::ThrowTypeError("First argument must be a string"); + } + + try { + nodeMap->map->addClass(*Nan::Utf8String(info[0])); + } catch (const std::exception &ex) { + return Nan::ThrowError(ex.what()); + } + + info.GetReturnValue().SetUndefined(); +} + +NAN_METHOD(NodeMap::SetPaintProperty) { + auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); + + if (info.Length() < 3) { + return Nan::ThrowTypeError("Three arguments required"); + } + + if (!info[0]->IsString()) { + return Nan::ThrowTypeError("First argument must be a string"); + } + + mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0])); + if (!layer) { + return Nan::ThrowTypeError("layer not found"); + } + + if (!info[1]->IsString()) { + return Nan::ThrowTypeError("Second argument must be a string"); + } + + static const PropertySetters setters = makePaintPropertySetters(); + + auto it = setters.find(*Nan::Utf8String(info[1])); + if (it == setters.end()) { + return Nan::ThrowTypeError("property not found"); + } + + if (!it->second(*layer, info[2])) { + return; + } + + nodeMap->map->update(mbgl::Update::RecalculateStyle); + info.GetReturnValue().SetUndefined(); +} + NAN_METHOD(NodeMap::DumpDebugLogs) { auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index d3f7bd9e41e..8dfb96eef87 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -24,8 +24,11 @@ class NodeMap : public Nan::ObjectWrap, static NAN_METHOD(New); static NAN_METHOD(Load); + static NAN_METHOD(Loaded); static NAN_METHOD(Render); static NAN_METHOD(Release); + static NAN_METHOD(AddClass); + static NAN_METHOD(SetPaintProperty); static NAN_METHOD(DumpDebugLogs); static NAN_METHOD(QueryRenderedFeatures); diff --git a/platform/node/src/node_style.hpp b/platform/node/src/node_style.hpp new file mode 100644 index 00000000000..b81d14c700f --- /dev/null +++ b/platform/node/src/node_style.hpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +namespace node_mbgl { + +template +struct ValueConverter {}; + +template <> +struct ValueConverter { + mbgl::optional> operator()(const v8::Local& value) const { + if (!value->IsBoolean()) { + Nan::ThrowTypeError("boolean required"); + return {}; + } + + return { value->BooleanValue() }; + } +}; + +template <> +struct ValueConverter { + mbgl::optional> operator()(const v8::Local& value) const { + if (!value->IsNumber()) { + Nan::ThrowTypeError("number required"); + return {}; + } + + return { value->NumberValue() }; + } +}; + +template <> +struct ValueConverter { + mbgl::optional> operator()(const v8::Local& value) const { + if (!value->IsString()) { + Nan::ThrowTypeError("string required"); + return {}; + } + + return { std::string(*Nan::Utf8String(value)) }; + } +}; + +template +struct ValueConverter::value>> { + mbgl::optional> operator()(const v8::Local& value) const { + if (!value->IsString()) { + Nan::ThrowTypeError("string required"); + return {}; + } + + mbgl::optional result = mbgl::Enum::toEnum(*Nan::Utf8String(value)); + if (!result) { + Nan::ThrowTypeError("invalid enumeration value"); + return {}; + } + + return { *result }; + } +}; + +template <> +struct ValueConverter { + mbgl::optional> operator()(const v8::Local& value) const { + (void)value; + return {}; + } +}; + +template <> +struct ValueConverter> { + mbgl::optional>> operator()(const v8::Local& value) const { + (void)value; + return {}; + } +}; + +template <> +struct ValueConverter> { + mbgl::optional>> operator()(const v8::Local& value) const { + (void)value; + return {}; + } +}; + +template <> +struct ValueConverter> { + mbgl::optional>> operator()(const v8::Local& value) const { + (void)value; + return {}; + } +}; + +using PropertySetter = std::function&)>; +using PropertySetters = std::unordered_map; + +template +PropertySetter makePropertySetter(void (L::*setter)(mbgl::style::PropertyValue)) { + return [setter] (mbgl::style::Layer& layer, const v8::Local& value) { + L* typedLayer = layer.as(); + if (!typedLayer) { + Nan::ThrowTypeError("layer doesn't support this property"); + return false; + } + + mbgl::optional> typedValue; + + if (value->IsNull() || value->IsUndefined()) { + typedValue = mbgl::style::PropertyValue(); + } else { + typedValue = ValueConverter()(value); + } + + if (!typedValue) { + return false; + } + + (typedLayer->*setter)(*typedValue); + return true; + }; +} + +} diff --git a/platform/node/src/node_style_properties.hpp b/platform/node/src/node_style_properties.hpp new file mode 100644 index 00000000000..4702918ae19 --- /dev/null +++ b/platform/node/src/node_style_properties.hpp @@ -0,0 +1,120 @@ +#include "node_style.hpp" + +#include +#include +#include +#include +#include +#include + +namespace node_mbgl { + +inline PropertySetters makeLayoutPropertySetters() { + using namespace mbgl::style; + PropertySetters result; + + + result["line-cap"] = makePropertySetter(&LineLayer::setLineCap); + result["line-join"] = makePropertySetter(&LineLayer::setLineJoin); + result["line-miter-limit"] = makePropertySetter(&LineLayer::setLineMiterLimit); + result["line-round-limit"] = makePropertySetter(&LineLayer::setLineRoundLimit); + + result["symbol-placement"] = makePropertySetter(&SymbolLayer::setSymbolPlacement); + result["symbol-spacing"] = makePropertySetter(&SymbolLayer::setSymbolSpacing); + result["symbol-avoid-edges"] = makePropertySetter(&SymbolLayer::setSymbolAvoidEdges); + result["icon-allow-overlap"] = makePropertySetter(&SymbolLayer::setIconAllowOverlap); + result["icon-ignore-placement"] = makePropertySetter(&SymbolLayer::setIconIgnorePlacement); + result["icon-optional"] = makePropertySetter(&SymbolLayer::setIconOptional); + result["icon-rotation-alignment"] = makePropertySetter(&SymbolLayer::setIconRotationAlignment); + result["icon-size"] = makePropertySetter(&SymbolLayer::setIconSize); + result["icon-image"] = makePropertySetter(&SymbolLayer::setIconImage); + result["icon-rotate"] = makePropertySetter(&SymbolLayer::setIconRotate); + result["icon-padding"] = makePropertySetter(&SymbolLayer::setIconPadding); + result["icon-keep-upright"] = makePropertySetter(&SymbolLayer::setIconKeepUpright); + result["icon-offset"] = makePropertySetter(&SymbolLayer::setIconOffset); + result["text-rotation-alignment"] = makePropertySetter(&SymbolLayer::setTextRotationAlignment); + result["text-field"] = makePropertySetter(&SymbolLayer::setTextField); + result["text-font"] = makePropertySetter(&SymbolLayer::setTextFont); + result["text-size"] = makePropertySetter(&SymbolLayer::setTextSize); + result["text-max-width"] = makePropertySetter(&SymbolLayer::setTextMaxWidth); + result["text-line-height"] = makePropertySetter(&SymbolLayer::setTextLineHeight); + result["text-letter-spacing"] = makePropertySetter(&SymbolLayer::setTextLetterSpacing); + result["text-justify"] = makePropertySetter(&SymbolLayer::setTextJustify); + result["text-anchor"] = makePropertySetter(&SymbolLayer::setTextAnchor); + result["text-max-angle"] = makePropertySetter(&SymbolLayer::setTextMaxAngle); + result["text-rotate"] = makePropertySetter(&SymbolLayer::setTextRotate); + result["text-padding"] = makePropertySetter(&SymbolLayer::setTextPadding); + result["text-keep-upright"] = makePropertySetter(&SymbolLayer::setTextKeepUpright); + result["text-transform"] = makePropertySetter(&SymbolLayer::setTextTransform); + result["text-offset"] = makePropertySetter(&SymbolLayer::setTextOffset); + result["text-allow-overlap"] = makePropertySetter(&SymbolLayer::setTextAllowOverlap); + result["text-ignore-placement"] = makePropertySetter(&SymbolLayer::setTextIgnorePlacement); + result["text-optional"] = makePropertySetter(&SymbolLayer::setTextOptional); + + + + + return result; +} + +inline PropertySetters makePaintPropertySetters() { + using namespace mbgl::style; + PropertySetters result; + + result["fill-antialias"] = makePropertySetter(&FillLayer::setFillAntialias); + result["fill-opacity"] = makePropertySetter(&FillLayer::setFillOpacity); + result["fill-color"] = makePropertySetter(&FillLayer::setFillColor); + result["fill-outline-color"] = makePropertySetter(&FillLayer::setFillOutlineColor); + result["fill-translate"] = makePropertySetter(&FillLayer::setFillTranslate); + result["fill-translate-anchor"] = makePropertySetter(&FillLayer::setFillTranslateAnchor); + result["fill-pattern"] = makePropertySetter(&FillLayer::setFillPattern); + + result["line-opacity"] = makePropertySetter(&LineLayer::setLineOpacity); + result["line-color"] = makePropertySetter(&LineLayer::setLineColor); + result["line-translate"] = makePropertySetter(&LineLayer::setLineTranslate); + result["line-translate-anchor"] = makePropertySetter(&LineLayer::setLineTranslateAnchor); + result["line-width"] = makePropertySetter(&LineLayer::setLineWidth); + result["line-gap-width"] = makePropertySetter(&LineLayer::setLineGapWidth); + result["line-offset"] = makePropertySetter(&LineLayer::setLineOffset); + result["line-blur"] = makePropertySetter(&LineLayer::setLineBlur); + result["line-dasharray"] = makePropertySetter(&LineLayer::setLineDasharray); + result["line-pattern"] = makePropertySetter(&LineLayer::setLinePattern); + + result["icon-opacity"] = makePropertySetter(&SymbolLayer::setIconOpacity); + result["icon-color"] = makePropertySetter(&SymbolLayer::setIconColor); + result["icon-halo-color"] = makePropertySetter(&SymbolLayer::setIconHaloColor); + result["icon-halo-width"] = makePropertySetter(&SymbolLayer::setIconHaloWidth); + result["icon-halo-blur"] = makePropertySetter(&SymbolLayer::setIconHaloBlur); + result["icon-translate"] = makePropertySetter(&SymbolLayer::setIconTranslate); + result["icon-translate-anchor"] = makePropertySetter(&SymbolLayer::setIconTranslateAnchor); + result["text-opacity"] = makePropertySetter(&SymbolLayer::setTextOpacity); + result["text-color"] = makePropertySetter(&SymbolLayer::setTextColor); + result["text-halo-color"] = makePropertySetter(&SymbolLayer::setTextHaloColor); + result["text-halo-width"] = makePropertySetter(&SymbolLayer::setTextHaloWidth); + result["text-halo-blur"] = makePropertySetter(&SymbolLayer::setTextHaloBlur); + result["text-translate"] = makePropertySetter(&SymbolLayer::setTextTranslate); + result["text-translate-anchor"] = makePropertySetter(&SymbolLayer::setTextTranslateAnchor); + + result["circle-radius"] = makePropertySetter(&CircleLayer::setCircleRadius); + result["circle-color"] = makePropertySetter(&CircleLayer::setCircleColor); + result["circle-blur"] = makePropertySetter(&CircleLayer::setCircleBlur); + result["circle-opacity"] = makePropertySetter(&CircleLayer::setCircleOpacity); + result["circle-translate"] = makePropertySetter(&CircleLayer::setCircleTranslate); + result["circle-translate-anchor"] = makePropertySetter(&CircleLayer::setCircleTranslateAnchor); + + result["raster-opacity"] = makePropertySetter(&RasterLayer::setRasterOpacity); + result["raster-hue-rotate"] = makePropertySetter(&RasterLayer::setRasterHueRotate); + result["raster-brightness-min"] = makePropertySetter(&RasterLayer::setRasterBrightnessMin); + result["raster-brightness-max"] = makePropertySetter(&RasterLayer::setRasterBrightnessMax); + result["raster-saturation"] = makePropertySetter(&RasterLayer::setRasterSaturation); + result["raster-contrast"] = makePropertySetter(&RasterLayer::setRasterContrast); + result["raster-fade-duration"] = makePropertySetter(&RasterLayer::setRasterFadeDuration); + + result["background-color"] = makePropertySetter(&BackgroundLayer::setBackgroundColor); + result["background-pattern"] = makePropertySetter(&BackgroundLayer::setBackgroundPattern); + result["background-opacity"] = makePropertySetter(&BackgroundLayer::setBackgroundOpacity); + + return result; +} + +} diff --git a/platform/node/src/node_style_properties.hpp.ejs b/platform/node/src/node_style_properties.hpp.ejs new file mode 100644 index 00000000000..1937421fa50 --- /dev/null +++ b/platform/node/src/node_style_properties.hpp.ejs @@ -0,0 +1,35 @@ +#include "node_style.hpp" + +<% for (const layer of locals.layers) { -%> +#include _layer.hpp> +<% } -%> + +namespace node_mbgl { + +inline PropertySetters makeLayoutPropertySetters() { + using namespace mbgl::style; + PropertySetters result; + +<% for (const layer of locals.layers) { -%> +<% for (const property of layer.layoutProperties) { -%> + result["<%- property.name %>"] = makePropertySetter(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>); +<% } -%> + +<% } -%> + return result; +} + +inline PropertySetters makePaintPropertySetters() { + using namespace mbgl::style; + PropertySetters result; + +<% for (const layer of locals.layers) { -%> +<% for (const property of layer.paintProperties) { -%> + result["<%- property.name %>"] = makePropertySetter(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>); +<% } -%> + +<% } -%> + return result; +} + +} diff --git a/platform/node/test/suite_implementation.js b/platform/node/test/suite_implementation.js index da226a68f48..4369c81ffce 100644 --- a/platform/node/test/suite_implementation.js +++ b/platform/node/test/suite_implementation.js @@ -41,16 +41,39 @@ module.exports = function (style, options, callback) { map.load(style); - map.render(options, function (err, pixels) { - var results = options.queryGeometry ? - map.queryRenderedFeatures(options.queryGeometry) : - []; - map.release(); - if (timedOut) return; - clearTimeout(watchdog); - callback(err, pixels, results.map(prepareFeatures)); + applyOperations(options.operations, function() { + map.render(options, function (err, pixels) { + var results = options.queryGeometry ? + map.queryRenderedFeatures(options.queryGeometry) : + []; + map.release(); + if (timedOut) return; + clearTimeout(watchdog); + callback(err, pixels, results.map(prepareFeatures)); + }); }); + function applyOperations(operations, callback) { + var operation = operations && operations[0]; + if (!operations || operations.length === 0) { + callback(); + + } else if (operation[0] === 'wait') { + var wait = function() { + if (map.loaded()) { + applyOperations(operations.slice(1), callback); + } else { + map.render(options, wait); + } + }; + wait(); + + } else { + map[operation[0]].apply(map, operation.slice(1)); + applyOperations(operations.slice(1), callback); + } + } + function prepareFeatures(r) { delete r.layer; return r; diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 21654117b8f..6469cf55fd1 100644 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -81,7 +81,7 @@ const layerCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer.cpp.ej const propertiesHpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.hpp.ejs', 'utf8'), {strict: true}); const propertiesCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.cpp.ejs', 'utf8'), {strict: true}); -for (const type of spec.layer.type.values) { +const layers = spec.layer.type.values.map((type) => { const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => { if (name !== 'visibility') { spec[`layout_${type}`][name].name = name; @@ -96,15 +96,20 @@ for (const type of spec.layer.type.values) { return memo; }, []); - const layer = { + return { type: type, layoutProperties: layoutProperties, paintProperties: paintProperties, }; +}); - fs.writeFileSync(`include/mbgl/style/layers/${type}_layer.hpp`, layerHpp(layer)); - fs.writeFileSync(`src/mbgl/style/layers/${type}_layer.cpp`, layerCpp(layer)); +for (const layer of layers) { + fs.writeFileSync(`include/mbgl/style/layers/${layer.type}_layer.hpp`, layerHpp(layer)); + fs.writeFileSync(`src/mbgl/style/layers/${layer.type}_layer.cpp`, layerCpp(layer)); - fs.writeFileSync(`src/mbgl/style/layers/${type}_layer_properties.hpp`, propertiesHpp(layer)); - fs.writeFileSync(`src/mbgl/style/layers/${type}_layer_properties.cpp`, propertiesCpp(layer)); + fs.writeFileSync(`src/mbgl/style/layers/${layer.type}_layer_properties.hpp`, propertiesHpp(layer)); + fs.writeFileSync(`src/mbgl/style/layers/${layer.type}_layer_properties.cpp`, propertiesCpp(layer)); } + +const nodeStyleCpp = ejs.compile(fs.readFileSync('platform/node/src/node_style_properties.hpp.ejs', 'utf8'), {strict: true}); +fs.writeFileSync('platform/node/src/node_style_properties.hpp', nodeStyleCpp({layers: layers}));