add constants and move style parser to its own class
This commit is contained in:
@@ -89,6 +89,9 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
"sprite": "img/maki-sprite",
|
||||
"constants": {
|
||||
"park": "#c8df9f",
|
||||
},
|
||||
"structure": [
|
||||
{ "name": "park", "bucket": "park" },
|
||||
{ "name": "wood", "bucket": "wood" },
|
||||
@@ -113,7 +116,7 @@ module.exports = {
|
||||
},
|
||||
"park": {
|
||||
"type": "fill",
|
||||
"color": "#c8df9f",
|
||||
"color": "park",
|
||||
"antialias": true,
|
||||
"image": "park"
|
||||
},
|
||||
|
||||
42
include/llmr/style/style_parser.hpp
Normal file
42
include/llmr/style/style_parser.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef LLMR_STYLE_STYLE_PARSER
|
||||
#define LLMR_STYLE_STYLE_PARSER
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <llmr/style/style.hpp>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
class StyleParser {
|
||||
public:
|
||||
using JSVal = const rapidjson::Value&;
|
||||
|
||||
void parseBuckets(JSVal value, std::map<std::string, BucketDescription>& buckets);
|
||||
void parseLayers(JSVal value, std::vector<LayerDescription>& layers);
|
||||
void parseConstants(JSVal value);
|
||||
void parseClasses(JSVal value, std::map<std::string, ClassDescription>& classes);
|
||||
|
||||
private:
|
||||
LayerDescription parseLayer(JSVal value);
|
||||
BucketDescription parseBucket(JSVal value);
|
||||
std::pair<std::string, ClassDescription> parseClassDescription(JSVal value);
|
||||
void parseClass(const std::string& name, JSVal value, ClassDescription& class_desc);
|
||||
FillClass parseFillClass(JSVal value);
|
||||
LineClass parseLineClass(JSVal value);
|
||||
PointClass parsePointClass(JSVal value);
|
||||
BackgroundClass parseBackgroundClass(JSVal value);
|
||||
|
||||
bool parseBoolean(JSVal value);
|
||||
std::string parseString(JSVal value);
|
||||
Color parseColor(JSVal value);
|
||||
Value parseValue(JSVal value);
|
||||
template <typename T> typename FunctionProperty<T>::fn parseFunctionType(JSVal type);
|
||||
FunctionProperty<float> parseFloatFunction(JSVal value);
|
||||
FunctionProperty<bool> parseBoolFunction(JSVal value);
|
||||
|
||||
private:
|
||||
std::map<std::string, const rapidjson::Value *> constants;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,5 +3,5 @@
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
const unsigned char resources::style[] = R"JSON({"buckets":{"water":{"source":"streets","layer":"water","type":"fill"},"road_large":{"source":"streets","layer":"road","field":"class","value":["motorway","main"],"type":"line","cap":"round","join":"round"},"road_regular":{"source":"streets","layer":"road","field":"class","value":"street","type":"line","cap":"round","join":"round"},"road_limited":{"source":"streets","layer":"road","field":"class","value":"street_limited","type":"line","cap":"round","join":"round"},"park":{"source":"streets","layer":"landuse","field":"class","value":"park","type":"fill"},"wood":{"source":"streets","layer":"landuse","field":"class","value":"wood","type":"fill"},"school":{"source":"streets","layer":"landuse","field":"class","value":"school","type":"fill"},"cemetery":{"source":"streets","layer":"landuse","field":"class","value":"cemetery","type":"fill"},"industrial":{"source":"streets","layer":"landuse","field":"class","value":"industrial","type":"fill"},"building":{"source":"streets","layer":"building","type":"fill"},"alcohol_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Alcohol"],"type":"point"},"cafe_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Cafe"],"type":"point"},"embassy_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Embassy"],"type":"point"},"park_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Park"],"type":"point"},"restaurant_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Restaurant"],"type":"point"}},"sprite":"img/maki-sprite","structure":[{"name":"park","bucket":"park"},{"name":"wood","bucket":"wood"},{"name":"water","bucket":"water"},{"name":"building","bucket":"building"},{"name":"road_limited","bucket":"road_limited"},{"name":"road_regular","bucket":"road_regular"},{"name":"road_large","bucket":"road_large"},{"name":"alcohol_poi","bucket":"alcohol_poi"},{"name":"cafe_poi","bucket":"cafe_poi"},{"name":"embassy_poi","bucket":"embassy_poi"},{"name":"park_poi","bucket":"park_poi"},{"name":"restaurant_poi","bucket":"restaurant_poi"}],"classes":[{"name":"default","layers":{"background":{"type":"background","color":"#FFFFFF"},"park":{"type":"fill","color":"#c8df9f","antialias":true,"image":"park"},"wood":{"type":"fill","color":"#33AA66","antialias":true,"opacity":0.1},"water":{"type":"fill","color":"#bae0e9","stroke":"#73b6e6","antialias":true,"image":"water_etsy"},"building":{"type":"fill","color":"#000000","antialias":true,"opacity":["linear",13,0,0.1,0,0.1]},"road_limited":{"type":"line","color":"#BBBBBB","width":["stops",{"z":0,"val":1},{"z":30,"val":1}]},"road_regular":{"type":"line","color":"#999999","width":["stops",{"z":0,"val":0.5},{"z":13,"val":0.5},{"z":16,"val":2},{"z":20,"val":32},{"z":30,"val":32}]},"road_large":{"type":"line","color":"#666666","width":["stops",{"z":0,"val":0.5},{"z":11,"val":0.5},{"z":13,"val":1},{"z":16,"val":4},{"z":20,"val":64},{"z":30,"val":64}]},"alcohol_poi":{"type":"point","color":"#cccccc","size":18,"image":"alcohol-shop","opacity":["linear",15,0,1,0,0.75]},"cafe_poi":{"type":"point","color":"#cccccc","size":18,"image":"cafe","opacity":["linear",15,0,1,0,0.75]},"embassy_poi":{"type":"point","color":"#cccccc","size":18,"image":"embassy","opacity":["linear",15,0,1,0,0.75]},"park_poi":{"type":"point","color":"#cccccc","size":18,"image":"park","opacity":["linear",15,0,1,0,0.75]},"restaurant_poi":{"type":"point","color":"#cccccc","size":18,"image":"restaurant","opacity":["linear",15,0,1,0,0.75]}}}]})JSON";
|
||||
const unsigned char resources::style[] = R"JSON({"buckets":{"water":{"source":"streets","layer":"water","type":"fill"},"road_large":{"source":"streets","layer":"road","field":"class","value":["motorway","main"],"type":"line","cap":"round","join":"round"},"road_regular":{"source":"streets","layer":"road","field":"class","value":"street","type":"line","cap":"round","join":"round"},"road_limited":{"source":"streets","layer":"road","field":"class","value":"street_limited","type":"line","cap":"round","join":"round"},"park":{"source":"streets","layer":"landuse","field":"class","value":"park","type":"fill"},"wood":{"source":"streets","layer":"landuse","field":"class","value":"wood","type":"fill"},"school":{"source":"streets","layer":"landuse","field":"class","value":"school","type":"fill"},"cemetery":{"source":"streets","layer":"landuse","field":"class","value":"cemetery","type":"fill"},"industrial":{"source":"streets","layer":"landuse","field":"class","value":"industrial","type":"fill"},"building":{"source":"streets","layer":"building","type":"fill"},"alcohol_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Alcohol"],"type":"point"},"cafe_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Cafe"],"type":"point"},"embassy_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Embassy"],"type":"point"},"park_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Park"],"type":"point"},"restaurant_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Restaurant"],"type":"point"}},"sprite":"img/maki-sprite","constants":{"park":"#c8df9f"},"structure":[{"name":"park","bucket":"park"},{"name":"wood","bucket":"wood"},{"name":"water","bucket":"water"},{"name":"building","bucket":"building"},{"name":"road_limited","bucket":"road_limited"},{"name":"road_regular","bucket":"road_regular"},{"name":"road_large","bucket":"road_large"},{"name":"alcohol_poi","bucket":"alcohol_poi"},{"name":"cafe_poi","bucket":"cafe_poi"},{"name":"embassy_poi","bucket":"embassy_poi"},{"name":"park_poi","bucket":"park_poi"},{"name":"restaurant_poi","bucket":"restaurant_poi"}],"classes":[{"name":"default","layers":{"background":{"type":"background","color":"#FFFFFF"},"park":{"type":"fill","color":"park","antialias":true,"image":"park"},"wood":{"type":"fill","color":"#33AA66","antialias":true,"opacity":0.1},"water":{"type":"fill","color":"#bae0e9","stroke":"#73b6e6","antialias":true,"image":"water_etsy"},"building":{"type":"fill","color":"#000000","antialias":true,"opacity":["linear",13,0,0.1,0,0.1]},"road_limited":{"type":"line","color":"#BBBBBB","width":["stops",{"z":0,"val":1},{"z":30,"val":1}]},"road_regular":{"type":"line","color":"#999999","width":["stops",{"z":0,"val":0.5},{"z":13,"val":0.5},{"z":16,"val":2},{"z":20,"val":32},{"z":30,"val":32}]},"road_large":{"type":"line","color":"#666666","width":["stops",{"z":0,"val":0.5},{"z":11,"val":0.5},{"z":13,"val":1},{"z":16,"val":4},{"z":20,"val":64},{"z":30,"val":64}]},"alcohol_poi":{"type":"point","color":"#cccccc","size":18,"image":"alcohol-shop","opacity":["linear",15,0,1,0,0.75]},"cafe_poi":{"type":"point","color":"#cccccc","size":18,"image":"cafe","opacity":["linear",15,0,1,0,0.75]},"embassy_poi":{"type":"point","color":"#cccccc","size":18,"image":"embassy","opacity":["linear",15,0,1,0,0.75]},"park_poi":{"type":"point","color":"#cccccc","size":18,"image":"park","opacity":["linear",15,0,1,0,0.75]},"restaurant_poi":{"type":"point","color":"#cccccc","size":18,"image":"restaurant","opacity":["linear",15,0,1,0,0.75]}}}]})JSON";
|
||||
const unsigned long resources::style_size = sizeof(resources::style);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <llmr/style/style.hpp>
|
||||
#include <csscolorparser/csscolorparser.hpp>
|
||||
#include <llmr/style/style_parser.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
@@ -80,23 +80,8 @@ void Style::cascade(float z) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loadBucketsJSON(const rapidjson::Value& value, std::map<std::string, BucketDescription>& buckets);
|
||||
BucketDescription loadBucketJSON(const rapidjson::Value& value);
|
||||
void loadLayersJSON(const rapidjson::Value& value, std::vector<LayerDescription>& layers);
|
||||
LayerDescription loadLayerJSON(const rapidjson::Value& value);
|
||||
void loadClassesJSON(const rapidjson::Value& value, std::map<std::string, ClassDescription>& classes);
|
||||
std::pair<std::string, ClassDescription> loadClassDescriptionJSON(const rapidjson::Value& value);
|
||||
void loadClassJSON(const std::string& name, const rapidjson::Value& value, ClassDescription& class_desc);
|
||||
FillClass loadFillClassJSON(const rapidjson::Value& value);
|
||||
LineClass loadLineClassJSON(const rapidjson::Value& value);
|
||||
PointClass loadPointClassJSON(const rapidjson::Value& value);
|
||||
BackgroundClass loadBackgroundClassJSON(const rapidjson::Value& value);
|
||||
Value loadValueJSON(const rapidjson::Value& value);
|
||||
|
||||
void Style::loadJSON(const uint8_t *const data, size_t bytes) {
|
||||
rapidjson::Document document;
|
||||
rapidjson::Document doc;
|
||||
|
||||
if (bytes <= 0) {
|
||||
return;
|
||||
@@ -106,491 +91,34 @@ void Style::loadJSON(const uint8_t *const data, size_t bytes) {
|
||||
throw exception("style JSON string is not 0-terminated");
|
||||
}
|
||||
|
||||
document.Parse<0>((const char *const)data);
|
||||
doc.Parse<0>((const char *const)data);
|
||||
|
||||
const rapidjson::Document& document = doc;
|
||||
|
||||
buckets.clear();
|
||||
layers.clear();
|
||||
classes.clear();
|
||||
|
||||
StyleParser parser;
|
||||
|
||||
if (document.IsObject()) {
|
||||
if (document.HasMember("buckets")) {
|
||||
loadBucketsJSON(document["buckets"], buckets);
|
||||
parser.parseBuckets(document["buckets"], buckets);
|
||||
}
|
||||
|
||||
if (document.HasMember("structure")) {
|
||||
loadLayersJSON(document["structure"], layers);
|
||||
parser.parseLayers(document["structure"], layers);
|
||||
}
|
||||
|
||||
if (document.HasMember("constants")) {
|
||||
parser.parseConstants(document["constants"]);
|
||||
}
|
||||
|
||||
if (document.HasMember("classes")) {
|
||||
loadClassesJSON(document["classes"], classes);
|
||||
parser.parseClasses(document["classes"], classes);
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("stylesheet root must be an object");
|
||||
}
|
||||
}
|
||||
|
||||
void loadBucketsJSON(const rapidjson::Value& value, std::map<std::string, BucketDescription>& buckets) {
|
||||
if (value.IsObject()) {
|
||||
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
|
||||
for (; itr != value.MemberEnd(); ++itr) {
|
||||
buckets.emplace(itr->name.GetString(), std::forward<BucketDescription>(loadBucketJSON(itr->value)));
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("buckets must be an object");
|
||||
}
|
||||
}
|
||||
|
||||
BucketDescription loadBucketJSON(const rapidjson::Value& value) {
|
||||
BucketDescription bucket;
|
||||
|
||||
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
|
||||
for (; itr != value.MemberEnd(); ++itr) {
|
||||
const std::string name(itr->name.GetString(), itr->name.GetStringLength());
|
||||
const rapidjson::Value& 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 == "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 == "field") {
|
||||
if (value.IsString()) {
|
||||
bucket.source_field = { value.GetString(), value.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("field name must be a string");
|
||||
}
|
||||
} else if (name == "value") {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
bucket.source_value.push_back(loadValueJSON(value[i]));
|
||||
}
|
||||
} else {
|
||||
bucket.source_value.push_back(loadValueJSON(value));
|
||||
}
|
||||
} 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") {
|
||||
if (value.IsNumber()) {
|
||||
bucket.geometry.font_size = value.GetDouble();
|
||||
} else {
|
||||
throw Style::exception("font size 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
void loadLayersJSON(const rapidjson::Value& value, std::vector<LayerDescription>& layers) {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
layers.push_back(loadLayerJSON(value[i]));
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("structure must be an array");
|
||||
}
|
||||
}
|
||||
|
||||
LayerDescription loadLayerJSON(const rapidjson::Value& value) {
|
||||
LayerDescription layer;
|
||||
|
||||
if (value.IsObject()) {
|
||||
if (value.HasMember("name")) {
|
||||
const rapidjson::Value& name = value["name"];
|
||||
if (name.IsString()) {
|
||||
layer.name = { name.GetString(), name.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("structure element name must be a string");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("structure element must have a name");
|
||||
}
|
||||
|
||||
if (value.HasMember("bucket")) {
|
||||
const rapidjson::Value& bucket = value["bucket"];
|
||||
if (bucket.IsString()) {
|
||||
layer.bucket_name = { bucket.GetString(), bucket.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("structure element bucket must be a string");
|
||||
}
|
||||
} else if (value.HasMember("layers")) {
|
||||
loadLayersJSON(value["layers"], layer.child_layer);
|
||||
} else {
|
||||
throw Style::exception("structure element must have either a bucket name or child layers");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("structure element must be an object");
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
void loadClassesJSON(const rapidjson::Value& value, std::map<std::string, ClassDescription>& classes) {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
classes.insert(std::forward<std::pair<std::string, ClassDescription>>(loadClassDescriptionJSON(value[i])));
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("classes must be an array");
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::string, ClassDescription> loadClassDescriptionJSON(const rapidjson::Value& value) {
|
||||
ClassDescription klass;
|
||||
std::string klass_name;
|
||||
|
||||
if (value.IsObject()) {
|
||||
if (value.HasMember("name")) {
|
||||
const rapidjson::Value& name = value["name"];
|
||||
if (name.IsString()) {
|
||||
klass_name = { name.GetString(), name.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("class name must be a string");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("class must have a name");
|
||||
}
|
||||
|
||||
if (value.HasMember("layers")) {
|
||||
const rapidjson::Value& layers = value["layers"];
|
||||
|
||||
if (layers.IsObject()) {
|
||||
rapidjson::Value::ConstMemberIterator itr = layers.MemberBegin();
|
||||
for (; itr != layers.MemberEnd(); ++itr) {
|
||||
const std::string name {
|
||||
itr->name.GetString(), itr->name.GetStringLength()
|
||||
};
|
||||
loadClassJSON(name, itr->value, klass);
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("class layer styles must be an object");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("class must have layer styles");
|
||||
}
|
||||
}
|
||||
|
||||
return { klass_name, std::forward<ClassDescription>(klass) };
|
||||
}
|
||||
|
||||
void loadClassJSON(const std::string& name, const rapidjson::Value& value, ClassDescription& class_desc) {
|
||||
if (value.IsObject()) {
|
||||
if (value.HasMember("type")) {
|
||||
const rapidjson::Value& type = value["type"];
|
||||
if (type.IsString()) {
|
||||
std::string type_name = { type.GetString(), type.GetStringLength() };
|
||||
if (type_name == "fill") {
|
||||
class_desc.fill.insert({ name, std::forward<FillClass>(loadFillClassJSON(value)) });
|
||||
} else if (type_name == "line") {
|
||||
class_desc.line.insert({ name, std::forward<LineClass>(loadLineClassJSON(value)) });
|
||||
} else if (type_name == "point") {
|
||||
class_desc.point.insert({ name, std::forward<PointClass>(loadPointClassJSON(value)) });
|
||||
} else if (type_name == "background") {
|
||||
class_desc.background = loadBackgroundClassJSON(value);
|
||||
} else {
|
||||
throw Style::exception("unkonwn class type name");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("style class type must be a string");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("style class must specify a type");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("style class must be an object");
|
||||
}
|
||||
}
|
||||
|
||||
bool parseBoolean(const rapidjson::Value& value) {
|
||||
if (!value.IsBool()) {
|
||||
throw Style::exception("boolean value must be a boolean");
|
||||
}
|
||||
|
||||
return value.GetBool();
|
||||
}
|
||||
|
||||
std::string parseString(const rapidjson::Value& value) {
|
||||
if (!value.IsString()) {
|
||||
throw Style::exception("string value must be a string");
|
||||
}
|
||||
|
||||
return { value.GetString(), value.GetStringLength() };
|
||||
}
|
||||
|
||||
Color parseColor(const rapidjson::Value& value) {
|
||||
if (!value.IsString()) {
|
||||
throw Style::exception("color value must be a string");
|
||||
}
|
||||
|
||||
CSSColorParser::Color css_color = CSSColorParser::parse({
|
||||
value.GetString(),
|
||||
value.GetStringLength()
|
||||
});
|
||||
|
||||
return {{
|
||||
(float)css_color.r / 255,
|
||||
(float)css_color.g / 255,
|
||||
(float)css_color.b / 255,
|
||||
css_color.a
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename FunctionProperty<T>::fn parseFunctionType(const rapidjson::Value& type) {
|
||||
if (type.IsString()) {
|
||||
std::string t { type.GetString(), type.GetStringLength() };
|
||||
if (t == "constant") {
|
||||
return &functions::constant;
|
||||
} else if (t == "linear") {
|
||||
return &functions::linear;
|
||||
} else if (t == "stops") {
|
||||
return &functions::stops;
|
||||
} else {
|
||||
throw Style::exception("unknown function type");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("function type must be a string");
|
||||
}
|
||||
}
|
||||
|
||||
FunctionProperty<float> parseFloatFunction(const rapidjson::Value& value) {
|
||||
FunctionProperty<float> property;
|
||||
|
||||
if (value.IsArray()) {
|
||||
if (value.Size() < 1) {
|
||||
throw Style::exception("value function does not have arguments");
|
||||
}
|
||||
|
||||
property.function = parseFunctionType<float>(value[(rapidjson::SizeType)0]);
|
||||
for (rapidjson::SizeType i = 1; i < value.Size(); ++i) {
|
||||
const rapidjson::Value& stop = value[i];
|
||||
if (stop.IsObject()) {
|
||||
if (!stop.HasMember("z")) {
|
||||
throw Style::exception("stop must have zoom level specification");
|
||||
}
|
||||
const rapidjson::Value& z = stop["z"];
|
||||
if (!z.IsNumber()) {
|
||||
throw Style::exception("zoom level in stops must be a number");
|
||||
}
|
||||
property.values.push_back(z.GetDouble());
|
||||
|
||||
if (!stop.HasMember("val")) {
|
||||
throw Style::exception("stop must have value specification");
|
||||
}
|
||||
const rapidjson::Value& val = stop["val"];
|
||||
if (!val.IsNumber()) {
|
||||
throw Style::exception("value in stops must be a number");
|
||||
}
|
||||
property.values.push_back(val.GetDouble());
|
||||
} else if (stop.IsNumber()) {
|
||||
property.values.push_back(stop.GetDouble());
|
||||
} else {
|
||||
throw Style::exception("stop must be a number");
|
||||
}
|
||||
}
|
||||
} else if (value.IsNumber()) {
|
||||
property.function = &functions::constant;
|
||||
property.values.push_back(value.GetDouble());
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
FunctionProperty<bool> parseBoolFunction(const rapidjson::Value& value) {
|
||||
FunctionProperty<bool> property;
|
||||
|
||||
if (value.IsArray()) {
|
||||
if (value.Size() < 1) {
|
||||
throw Style::exception("value function does not have arguments");
|
||||
}
|
||||
|
||||
property.function = parseFunctionType<bool>(value[(rapidjson::SizeType)0]);
|
||||
for (rapidjson::SizeType i = 1; i < value.Size(); ++i) {
|
||||
const rapidjson::Value& stop = value[i];
|
||||
if (stop.IsObject()) {
|
||||
if (!stop.HasMember("z")) {
|
||||
throw Style::exception("stop must have zoom level specification");
|
||||
}
|
||||
const rapidjson::Value& z = stop["z"];
|
||||
if (!z.IsBool()) {
|
||||
throw Style::exception("zoom level in stops must be a number");
|
||||
}
|
||||
property.values.push_back(z.GetBool());
|
||||
|
||||
if (!stop.HasMember("val")) {
|
||||
throw Style::exception("stop must have value specification");
|
||||
}
|
||||
const rapidjson::Value& val = stop["val"];
|
||||
if (!val.IsBool()) {
|
||||
throw Style::exception("value in stops must be a number");
|
||||
}
|
||||
property.values.push_back(val.GetBool());
|
||||
} else if (stop.IsBool()) {
|
||||
property.values.push_back(stop.GetBool());
|
||||
} else {
|
||||
throw Style::exception("stop must be a number");
|
||||
}
|
||||
}
|
||||
} else if (value.IsBool()) {
|
||||
property.function = &functions::constant;
|
||||
property.values.push_back(value.GetBool());
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
FillClass loadFillClassJSON(const rapidjson::Value& value) {
|
||||
FillClass klass;
|
||||
|
||||
if (value.HasMember("hidden")) {
|
||||
klass.hidden = parseBoolFunction(value["hidden"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.fill_color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("stroke")) {
|
||||
klass.stroke_color = parseColor(value["stroke"]);
|
||||
} else {
|
||||
klass.stroke_color = klass.fill_color;
|
||||
}
|
||||
|
||||
if (value.HasMember("antialias")) {
|
||||
klass.antialias = parseBoolean(value["antialias"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("image")) {
|
||||
klass.image = parseString(value["image"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFloatFunction(value["opacity"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
LineClass loadLineClassJSON(const rapidjson::Value& value) {
|
||||
LineClass klass;
|
||||
|
||||
if (value.HasMember("hidden")) {
|
||||
klass.hidden = parseBoolFunction(value["hidden"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("width")) {
|
||||
klass.width = parseFloatFunction(value["width"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFloatFunction(value["opacity"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
PointClass loadPointClassJSON(const rapidjson::Value& value) {
|
||||
PointClass klass;
|
||||
|
||||
if (value.HasMember("hidden")) {
|
||||
klass.hidden = parseBoolFunction(value["hidden"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFloatFunction(value["opacity"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("image")) {
|
||||
klass.image = parseString(value["image"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("size")) {
|
||||
klass.size = parseFloatFunction(value["size"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
BackgroundClass loadBackgroundClassJSON(const rapidjson::Value& value) {
|
||||
BackgroundClass klass;
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
Value loadValueJSON(const rapidjson::Value& value) {
|
||||
switch (value.GetType()) {
|
||||
case rapidjson::kNullType:
|
||||
case rapidjson::kFalseType:
|
||||
return false;
|
||||
|
||||
case rapidjson::kTrueType:
|
||||
return true;
|
||||
|
||||
case rapidjson::kStringType:
|
||||
return std::string { value.GetString(), value.GetStringLength() };
|
||||
|
||||
case rapidjson::kNumberType:
|
||||
if (value.IsUint64()) return value.GetUint64();
|
||||
if (value.IsInt64()) return value.GetInt64();
|
||||
return value.GetDouble();
|
||||
|
||||
case rapidjson::kObjectType:
|
||||
case rapidjson::kArrayType:
|
||||
throw Style::exception("value cannot be an object or array");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
490
src/style/style_parser.cpp
Normal file
490
src/style/style_parser.cpp
Normal file
@@ -0,0 +1,490 @@
|
||||
#include <llmr/style/style_parser.hpp>
|
||||
#include <csscolorparser/csscolorparser.hpp>
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
void StyleParser::parseBuckets(JSVal value, std::map<std::string, BucketDescription>& buckets) {
|
||||
if (value.IsObject()) {
|
||||
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
|
||||
for (; itr != value.MemberEnd(); ++itr) {
|
||||
buckets.emplace(
|
||||
std::forward<std::string>({ itr->name.GetString(), itr->name.GetStringLength() }),
|
||||
std::forward<BucketDescription>(parseBucket(itr->value))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("buckets must be an object");
|
||||
}
|
||||
}
|
||||
|
||||
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 == "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 == "field") {
|
||||
if (value.IsString()) {
|
||||
bucket.source_field = { value.GetString(), value.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("field name must be a string");
|
||||
}
|
||||
} else if (name == "value") {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
bucket.source_value.push_back(parseValue(value[i]));
|
||||
}
|
||||
} else {
|
||||
bucket.source_value.push_back(parseValue(value));
|
||||
}
|
||||
} 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") {
|
||||
if (value.IsNumber()) {
|
||||
bucket.geometry.font_size = value.GetDouble();
|
||||
} else {
|
||||
throw Style::exception("font size 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
void StyleParser::parseLayers(JSVal value, std::vector<LayerDescription>& layers) {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
layers.push_back(parseLayer(value[i]));
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("structure must be an array");
|
||||
}
|
||||
}
|
||||
|
||||
LayerDescription StyleParser::parseLayer(JSVal value) {
|
||||
LayerDescription layer;
|
||||
|
||||
if (value.IsObject()) {
|
||||
if (value.HasMember("name")) {
|
||||
JSVal name = value["name"];
|
||||
if (name.IsString()) {
|
||||
layer.name = { name.GetString(), name.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("structure element name must be a string");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("structure element must have a name");
|
||||
}
|
||||
|
||||
if (value.HasMember("bucket")) {
|
||||
JSVal bucket = value["bucket"];
|
||||
if (bucket.IsString()) {
|
||||
layer.bucket_name = { bucket.GetString(), bucket.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("structure element bucket must be a string");
|
||||
}
|
||||
} else if (value.HasMember("layers")) {
|
||||
parseLayers(value["layers"], layer.child_layer);
|
||||
} else {
|
||||
throw Style::exception("structure element must have either a bucket name or child layers");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("structure element must be an object");
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
void StyleParser::parseConstants(JSVal value) {
|
||||
if (value.IsObject()) {
|
||||
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
|
||||
for (; itr != value.MemberEnd(); ++itr) {
|
||||
constants.emplace(
|
||||
std::forward<std::string>({ itr->name.GetString(), itr->name.GetStringLength() }),
|
||||
&itr->value
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("constants must be an object");
|
||||
}
|
||||
}
|
||||
|
||||
void StyleParser::parseClasses(JSVal value, std::map<std::string, ClassDescription>& classes) {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
classes.insert(std::forward<std::pair<std::string, ClassDescription>>(parseClassDescription(value[i])));
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("classes must be an array");
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::string, ClassDescription> StyleParser::parseClassDescription(JSVal value) {
|
||||
ClassDescription klass;
|
||||
std::string klass_name;
|
||||
|
||||
if (value.IsObject()) {
|
||||
if (value.HasMember("name")) {
|
||||
JSVal name = value["name"];
|
||||
if (name.IsString()) {
|
||||
klass_name = { name.GetString(), name.GetStringLength() };
|
||||
} else {
|
||||
throw Style::exception("class name must be a string");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("class must have a name");
|
||||
}
|
||||
|
||||
if (value.HasMember("layers")) {
|
||||
JSVal layers = value["layers"];
|
||||
|
||||
if (layers.IsObject()) {
|
||||
rapidjson::Value::ConstMemberIterator itr = layers.MemberBegin();
|
||||
for (; itr != layers.MemberEnd(); ++itr) {
|
||||
const std::string name {
|
||||
itr->name.GetString(), itr->name.GetStringLength()
|
||||
};
|
||||
parseClass(name, itr->value, klass);
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("class layer styles must be an object");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("class must have layer styles");
|
||||
}
|
||||
}
|
||||
|
||||
return { klass_name, std::forward<ClassDescription>(klass) };
|
||||
}
|
||||
|
||||
void StyleParser::parseClass(const std::string& name, JSVal value, ClassDescription& class_desc) {
|
||||
if (value.IsObject()) {
|
||||
if (value.HasMember("type")) {
|
||||
JSVal type = value["type"];
|
||||
if (type.IsString()) {
|
||||
std::string type_name = { type.GetString(), type.GetStringLength() };
|
||||
if (type_name == "fill") {
|
||||
class_desc.fill.insert({ name, std::forward<FillClass>(parseFillClass(value)) });
|
||||
} else if (type_name == "line") {
|
||||
class_desc.line.insert({ name, std::forward<LineClass>(parseLineClass(value)) });
|
||||
} else if (type_name == "point") {
|
||||
class_desc.point.insert({ name, std::forward<PointClass>(parsePointClass(value)) });
|
||||
} else if (type_name == "background") {
|
||||
class_desc.background = parseBackgroundClass(value);
|
||||
} else {
|
||||
throw Style::exception("unkonwn class type name");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("style class type must be a string");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("style class must specify a type");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("style class must be an object");
|
||||
}
|
||||
}
|
||||
|
||||
bool StyleParser::parseBoolean(JSVal value) {
|
||||
if (!value.IsBool()) {
|
||||
throw Style::exception("boolean value must be a boolean");
|
||||
}
|
||||
|
||||
return value.GetBool();
|
||||
}
|
||||
|
||||
std::string StyleParser::parseString(JSVal value) {
|
||||
if (!value.IsString()) {
|
||||
throw Style::exception("string value must be a string");
|
||||
}
|
||||
|
||||
return { value.GetString(), value.GetStringLength() };
|
||||
}
|
||||
|
||||
Color StyleParser::parseColor(JSVal value) {
|
||||
if (!value.IsString()) {
|
||||
throw Style::exception("color value must be a string");
|
||||
}
|
||||
|
||||
const std::string str { value.GetString(), value.GetStringLength() };
|
||||
|
||||
auto it = constants.find(str);
|
||||
if (it != constants.end()) {
|
||||
return parseColor(*it->second);
|
||||
} else {
|
||||
CSSColorParser::Color css_color = CSSColorParser::parse(str);
|
||||
return {{
|
||||
(float)css_color.r / 255,
|
||||
(float)css_color.g / 255,
|
||||
(float)css_color.b / 255,
|
||||
css_color.a
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename FunctionProperty<T>::fn StyleParser::parseFunctionType(JSVal type) {
|
||||
if (type.IsString()) {
|
||||
std::string t { type.GetString(), type.GetStringLength() };
|
||||
if (t == "constant") {
|
||||
return &functions::constant;
|
||||
} else if (t == "linear") {
|
||||
return &functions::linear;
|
||||
} else if (t == "stops") {
|
||||
return &functions::stops;
|
||||
} else {
|
||||
throw Style::exception("unknown function type");
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("function type must be a string");
|
||||
}
|
||||
}
|
||||
|
||||
FunctionProperty<float> StyleParser::parseFloatFunction(JSVal value) {
|
||||
FunctionProperty<float> property;
|
||||
|
||||
if (value.IsArray()) {
|
||||
if (value.Size() < 1) {
|
||||
throw Style::exception("value function does not have arguments");
|
||||
}
|
||||
|
||||
property.function = parseFunctionType<float>(value[(rapidjson::SizeType)0]);
|
||||
for (rapidjson::SizeType i = 1; i < value.Size(); ++i) {
|
||||
JSVal stop = value[i];
|
||||
if (stop.IsObject()) {
|
||||
if (!stop.HasMember("z")) {
|
||||
throw Style::exception("stop must have zoom level specification");
|
||||
}
|
||||
JSVal z = stop["z"];
|
||||
if (!z.IsNumber()) {
|
||||
throw Style::exception("zoom level in stops must be a number");
|
||||
}
|
||||
property.values.push_back(z.GetDouble());
|
||||
|
||||
if (!stop.HasMember("val")) {
|
||||
throw Style::exception("stop must have value specification");
|
||||
}
|
||||
JSVal val = stop["val"];
|
||||
if (!val.IsNumber()) {
|
||||
throw Style::exception("value in stops must be a number");
|
||||
}
|
||||
property.values.push_back(val.GetDouble());
|
||||
} else if (stop.IsNumber()) {
|
||||
property.values.push_back(stop.GetDouble());
|
||||
} else {
|
||||
throw Style::exception("stop must be a number");
|
||||
}
|
||||
}
|
||||
} else if (value.IsNumber()) {
|
||||
property.function = &functions::constant;
|
||||
property.values.push_back(value.GetDouble());
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
FunctionProperty<bool> StyleParser::parseBoolFunction(JSVal value) {
|
||||
FunctionProperty<bool> property;
|
||||
|
||||
if (value.IsArray()) {
|
||||
if (value.Size() < 1) {
|
||||
throw Style::exception("value function does not have arguments");
|
||||
}
|
||||
|
||||
property.function = parseFunctionType<bool>(value[(rapidjson::SizeType)0]);
|
||||
for (rapidjson::SizeType i = 1; i < value.Size(); ++i) {
|
||||
JSVal stop = value[i];
|
||||
if (stop.IsObject()) {
|
||||
if (!stop.HasMember("z")) {
|
||||
throw Style::exception("stop must have zoom level specification");
|
||||
}
|
||||
JSVal z = stop["z"];
|
||||
if (!z.IsBool()) {
|
||||
throw Style::exception("zoom level in stops must be a number");
|
||||
}
|
||||
property.values.push_back(z.GetBool());
|
||||
|
||||
if (!stop.HasMember("val")) {
|
||||
throw Style::exception("stop must have value specification");
|
||||
}
|
||||
JSVal val = stop["val"];
|
||||
if (!val.IsBool()) {
|
||||
throw Style::exception("value in stops must be a number");
|
||||
}
|
||||
property.values.push_back(val.GetBool());
|
||||
} else if (stop.IsBool()) {
|
||||
property.values.push_back(stop.GetBool());
|
||||
} else {
|
||||
throw Style::exception("stop must be a number");
|
||||
}
|
||||
}
|
||||
} else if (value.IsBool()) {
|
||||
property.function = &functions::constant;
|
||||
property.values.push_back(value.GetBool());
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
FillClass StyleParser::parseFillClass(JSVal value) {
|
||||
FillClass klass;
|
||||
|
||||
if (value.HasMember("hidden")) {
|
||||
klass.hidden = parseBoolFunction(value["hidden"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.fill_color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("stroke")) {
|
||||
klass.stroke_color = parseColor(value["stroke"]);
|
||||
} else {
|
||||
klass.stroke_color = klass.fill_color;
|
||||
}
|
||||
|
||||
if (value.HasMember("antialias")) {
|
||||
klass.antialias = parseBoolean(value["antialias"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("image")) {
|
||||
klass.image = parseString(value["image"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFloatFunction(value["opacity"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
LineClass StyleParser::parseLineClass(JSVal value) {
|
||||
LineClass klass;
|
||||
|
||||
if (value.HasMember("hidden")) {
|
||||
klass.hidden = parseBoolFunction(value["hidden"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("width")) {
|
||||
klass.width = parseFloatFunction(value["width"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFloatFunction(value["opacity"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
PointClass StyleParser::parsePointClass(JSVal value) {
|
||||
PointClass klass;
|
||||
|
||||
if (value.HasMember("hidden")) {
|
||||
klass.hidden = parseBoolFunction(value["hidden"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFloatFunction(value["opacity"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("image")) {
|
||||
klass.image = parseString(value["image"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("size")) {
|
||||
klass.size = parseFloatFunction(value["size"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
BackgroundClass StyleParser::parseBackgroundClass(JSVal value) {
|
||||
BackgroundClass klass;
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
Value StyleParser::parseValue(JSVal value) {
|
||||
switch (value.GetType()) {
|
||||
case rapidjson::kNullType:
|
||||
case rapidjson::kFalseType:
|
||||
return false;
|
||||
|
||||
case rapidjson::kTrueType:
|
||||
return true;
|
||||
|
||||
case rapidjson::kStringType:
|
||||
return std::string { value.GetString(), value.GetStringLength() };
|
||||
|
||||
case rapidjson::kNumberType:
|
||||
if (value.IsUint64()) return value.GetUint64();
|
||||
if (value.IsInt64()) return value.GetInt64();
|
||||
return value.GetDouble();
|
||||
|
||||
case rapidjson::kObjectType:
|
||||
case rapidjson::kArrayType:
|
||||
throw Style::exception("value cannot be an object or array");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user