#include #include #include #include #include #include namespace mbgl { template <> optional parseProperty(const char* name, const JSValue& value) { if (!value.IsBool()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a boolean", name); return {}; } return value.GetBool(); } template <> optional parseProperty(const char* name, const JSValue& value) { if (!value.IsNumber()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", name); return {}; } return value.GetDouble(); } template <> optional parseProperty(const char* name, const JSValue& value) { if (std::string { "text-font" } == name) { if (!value.IsArray()) { Log::Warning(Event::ParseStyle, "value of '%s' must be an array of strings", name); return {}; } std::string result = ""; for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { const JSValue& stop = value[i]; if (stop.IsString()) { result += stop.GetString(); if (i < value.Size()-1) { result += ","; } } else { Log::Warning(Event::ParseStyle, "text-font members must be strings"); return {}; } } return result; } if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); return {}; } return std::string { value.GetString(), value.GetStringLength() }; } template <> optional parseProperty(const char* name, const JSValue& value) { if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); return {}; } CSSColorParser::Color css_color = CSSColorParser::parse({ value.GetString(), value.GetStringLength() }); // Premultiply the color. const float factor = css_color.a / 255; return Color{{(float)css_color.r * factor, (float)css_color.g * factor, (float)css_color.b * factor, css_color.a}}; } template <> optional parseProperty(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() }) }; } template <> optional parseProperty(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() }) }; } template <> optional parseProperty(const char* name, const JSValue& value) { if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); return {}; } return { CapTypeClass({ value.GetString(), value.GetStringLength() }) }; } template <> optional parseProperty(const char* name, const JSValue& value) { if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); return {}; } return { JoinTypeClass({ value.GetString(), value.GetStringLength() }) }; } template <> optional parseProperty(const char* name, const JSValue& value) { if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); return {}; } return { PlacementTypeClass({ value.GetString(), value.GetStringLength() }) }; } template <> optional parseProperty(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() }) }; } template <> optional parseProperty(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() }) }; } template <> optional parseProperty(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() }) }; } template <> optional parseProperty(const char* name, const JSValue& value) { if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name); return {}; } return { RotationAlignmentTypeClass({ value.GetString(), value.GetStringLength() }) }; } template <> optional> parseProperty(const char* name, const JSValue& value) { if (value.IsArray() && value.Size() == 2 && value[rapidjson::SizeType(0)].IsNumber() && value[rapidjson::SizeType(1)].IsNumber()) { float first = value[rapidjson::SizeType(0)].GetDouble(); float second = value[rapidjson::SizeType(1)].GetDouble(); return { {{ first, second }} }; } else { Log::Warning(Event::ParseStyle, "value of '%s' must be an array of two numbers", name); return {}; } } template <> optional> parseProperty(const char* name, const JSValue& value) { if (!value.IsArray()) { Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers", name); return {}; } std::vector result; for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { const JSValue& part = value[i]; if (!part.IsNumber()) { Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers", name); return {}; } result.push_back(part.GetDouble()); } return result; } template <> optional parseProperty(const char *, const JSValue& value) { PropertyTransition transition; if (value.IsObject()) { bool parsed = false; if (value.HasMember("duration") && value["duration"].IsNumber()) { transition.duration = std::chrono::milliseconds(value["duration"].GetUint()); parsed = true; } if (value.HasMember("delay") && value["delay"].IsNumber()) { transition.delay = std::chrono::milliseconds(value["delay"].GetUint()); parsed = true; } if (!parsed) { return {}; } } return transition; } // --- Function --- template optional>> parseStops(const char* name, const JSValue& value) { if (!value.IsArray()) { Log::Warning(Event::ParseStyle, "stops function must specify a stops array"); return {}; } std::vector> stops; for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { const JSValue& stop = value[i]; if (!stop.IsArray()) { Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); return {}; } if (stop.Size() != 2) { Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification"); return {}; } const JSValue& z = stop[rapidjson::SizeType(0)]; if (!z.IsNumber()) { Log::Warning(Event::ParseStyle, "zoom level in stop must be a number"); return {}; } optional v = parseProperty(name, stop[rapidjson::SizeType(1)]); if (!v) { return {}; } stops.emplace_back(z.GetDouble(), *v); } return stops; } template optional> parseFunction(const char* name, const JSValue& value) { if (!value.IsObject()) { auto constant = parseProperty(name, value); if (!constant) { return {}; } return { Function(*constant) }; } if (!value.HasMember("stops")) { Log::Warning(Event::ParseStyle, "function must specify a function type"); return {}; } float base = 1.0f; if (value.HasMember("base")) { const JSValue& value_base = value["base"]; if (!value_base.IsNumber()) { Log::Warning(Event::ParseStyle, "base must be numeric"); return {}; } base = value_base.GetDouble(); } auto stops = parseStops(name, value["stops"]); if (!stops) { return {}; } return { Function(*stops, base) }; } template <> optional>> parseProperty(const char* name, const JSValue& value) { return parseFunction>(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template <> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template<> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template<> optional> parseProperty(const char* name, const JSValue& value) { return parseFunction(name, value); } template optional>> parseFadedFunction(const JSValue& value) { if (!value.HasMember("stops")) { Log::Warning(Event::ParseStyle, "function must specify a function type"); return {}; } auto stops = parseStops("", value["stops"]); if (!stops) { return {}; } return Function>(*stops); } template <> optional>>> parseProperty(const char* name, const JSValue& value) { if (value.IsObject()) { return parseFadedFunction>(value); } auto constant = parseProperty>(name, value); if (!constant) { return {}; } return Function>>(*constant); } template <> optional>> parseProperty(const char* name, const JSValue& value) { if (value.IsObject()) { return parseFadedFunction(value); } auto constant = parseProperty(name, value); if (!constant) { return {}; } return Function>(*constant); } } // namespace mbgl