optional<Function<T>> parseFunction(const char* name, const JSVal& value) {
    if (!value.IsObject()) {
        auto constant = parseProperty<T>(name, value);
        if (!constant) {
            return {};
        }
        return { Function<T>(*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 JSVal& value_base = value["base"];

        if (!value_base.IsNumber()) {
            Log::Warning(Event::ParseStyle, "base must be numeric");
            return {};
        }

        base = value_base.GetDouble();
    }

    auto stops = parseStops<T>(name, value["stops"]);

    if (!stops) {
        return {};
    }

    return { Function<T>(*stops, base) };
}
optional<float> parseProperty(const char* name, const JSVal& value) {
    if (!value.IsNumber()) {
        Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", name);
        return {};
    }

    return value.GetDouble();
}
optional<RotateAnchorType> parseProperty<RotateAnchorType>(const char* name, const JSVal& value) {
    if (!value.IsString()) {
        Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
        return {};
    }

    return { RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
}
optional<bool> parseProperty(const char* name, const JSVal& value) {
    if (!value.IsBool()) {
        Log::Warning(Event::ParseStyle, "value of '%s' must be a boolean", name);
        return {};
    }

    return value.GetBool();
}
optional<std::array<float, 2>> parseProperty(const char* name, const JSVal& 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 {};
    }
}
void StyleParser::parseLayers(const JSVal& value) {
    std::vector<std::string> ids;

    if (!value.IsArray()) {
        Log::Warning(Event::ParseStyle, "layers must be an array");
        return;
    }

    for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
        const JSVal& layerValue = value[i];

        if (!layerValue.IsObject()) {
            Log::Warning(Event::ParseStyle, "layer must be an object");
            continue;
        }

        if (!layerValue.HasMember("id")) {
            Log::Warning(Event::ParseStyle, "layer must have an id");
            continue;
        }

        const JSVal& id = layerValue["id"];
        if (!id.IsString()) {
            Log::Warning(Event::ParseStyle, "layer id must be a string");
            continue;
        }

        const std::string layerID = { id.GetString(), id.GetStringLength() };
        if (layersMap.find(layerID) != layersMap.end()) {
            Log::Warning(Event::ParseStyle, "duplicate layer id %s", layerID.c_str());
            continue;
        }

        layersMap.emplace(layerID, std::pair<const JSVal&, util::ptr<StyleLayer>> { layerValue, nullptr });
        ids.push_back(layerID);
    }

    for (const auto& id : ids) {
        auto it = layersMap.find(id);

        parseLayer(it->first,
                   it->second.first,
                   it->second.second);

        if (it->second.second) {
            layers.emplace_back(it->second.second);
        }
    }
}
optional<Color> parseProperty(const char* name, const JSVal& 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}};
}
optional<PropertyTransition> parseProperty(const char *, const JSVal& 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;
}
void StyleParser::parseVisibility(StyleLayer& layer, const JSVal& value) {
    if (!value.HasMember("visibility")) {
        return;
    } else if (!value["visibility"].IsString()) {
        Log::Warning(Event::ParseStyle, "value of 'visibility' must be a string");
        layer.visibility = VisibilityType::Visible;
        return;
    }
    layer.visibility = VisibilityTypeClass({ value["visibility"].GetString(), value["visibility"].GetStringLength() });
}
optional<Function<Faded<std::string>>> parseProperty(const char* name, const JSVal& value) {
    if (value.IsObject()) {
        return parseFadedFunction<std::string>(value);
    }

    auto constant = parseProperty<std::string>(name, value);
    if (!constant) {
        return {};
    }
    return Function<Faded<std::string>>(*constant);
}
optional<std::vector<float>> parseProperty(const char* name, const JSVal& value) {
    if (!value.IsArray()) {
        Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers", name);
        return {};
    }

    std::vector<float> result;

    for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
        const JSVal& 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;
}
optional<std::string> parseProperty(const char* name, const JSVal& 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 JSVal& 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() };
}
optional<Function<Faded<T>>> parseFadedFunction(const JSVal& value) {
    if (!value.HasMember("stops")) {
        Log::Warning(Event::ParseStyle, "function must specify a function type");
        return {};
    }

    auto stops = parseStops<T>("", value["stops"]);

    if (!stops) {
        return {};
    }

    return Function<Faded<T>>(*stops);
}
optional<std::vector<std::pair<float, T>>> parseStops(const char* name, const JSVal& value) {
    if (!value.IsArray()) {
        Log::Warning(Event::ParseStyle, "stops function must specify a stops array");
        return {};
    }

    std::vector<std::pair<float, T>> stops;

    for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
        const JSVal& 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 JSVal& z = stop[rapidjson::SizeType(0)];
        if (!z.IsNumber()) {
            Log::Warning(Event::ParseStyle, "zoom level in stop must be a number");
            return {};
        }

        optional<T> v = parseProperty<T>(name, stop[rapidjson::SizeType(1)]);
        if (!v) {
            return {};
        }

        stops.emplace_back(z.GetDouble(), *v);
    }

    return stops;
}
示例#15
0
void StyleParser::parse(const JSVal& document) {
    if (document.HasMember("version")) {
        version = document["version"].GetInt();
        if (version != 8) {
            Log::Warning(Event::ParseStyle, "current renderer implementation only supports style spec version 8; using an outdated style will cause rendering errors");
        }
    }

    if (document.HasMember("sources")) {
        parseSources(document["sources"]);
    }

    if (document.HasMember("layers")) {
        parseLayers(document["layers"]);
    }

    if (document.HasMember("sprite")) {
        parseSprite(document["sprite"]);
    }

    if (document.HasMember("glyphs")) {
        parseGlyphURL(document["glyphs"]);
    }
}
示例#16
0
void StyleParser::parseSources(const JSVal& value) {
    if (!value.IsObject()) {
        Log::Warning(Event::ParseStyle, "sources must be an object");
        return;
    }

    rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
    for (; itr != value.MemberEnd(); ++itr) {
        const JSVal& nameVal = itr->name;
        const JSVal& sourceVal = itr->value;

        std::unique_ptr<Source> source = std::make_unique<Source>();

        source->info.source_id = { nameVal.GetString(), nameVal.GetStringLength() };

        if (!sourceVal.HasMember("type")) {
            Log::Warning(Event::ParseStyle, "source must have a type");
            continue;
        }

        const JSVal& typeVal = sourceVal["type"];
        if (!typeVal.IsString()) {
            Log::Warning(Event::ParseStyle, "source type must have one of the enum values");
            continue;
        }

        source->info.type = SourceTypeClass({ typeVal.GetString(), typeVal.GetStringLength() });

        if (sourceVal.HasMember("url")) {
            const JSVal& urlVal = sourceVal["url"];

            if (!urlVal.IsString()) {
                Log::Warning(Event::ParseStyle, "source url must be a string");
                continue;
            }

            source->info.url = { urlVal.GetString(), urlVal.GetStringLength() };
        }

        if (sourceVal.HasMember("tileSize")) {
            const JSVal& tileSizeVal = sourceVal["tileSize"];

            if (!tileSizeVal.IsUint()) {
                Log::Warning(Event::ParseStyle, "source tileSize must be an unsigned integer");
                continue;
            }

            unsigned int intValue = tileSizeVal.GetUint();
            if (intValue > std::numeric_limits<uint16_t>::max()) {
                Log::Warning(Event::ParseStyle, "values for tileSize that are larger than %d are not supported", std::numeric_limits<uint16_t>::max());
                continue;
            }

            source->info.tile_size = intValue;
        }

        source->info.parseTileJSONProperties(sourceVal);

        sourcesMap.emplace(source->info.source_id, source.get());
        sources.emplace_back(std::move(source));
    }
}
示例#17
0
void StyleParser::parseGlyphURL(const JSVal& value) {
    if (value.IsString()) {
        glyph_url = { value.GetString(), value.GetStringLength() };
    }
}
示例#18
0
void StyleParser::parseSprite(const JSVal& value) {
    if (value.IsString()) {
        sprite = { value.GetString(), value.GetStringLength() };
    }
}
示例#19
0
void StyleParser::parseLayer(const std::string& id, const JSVal& value, util::ptr<StyleLayer>& layer) {
    if (layer) {
        // Skip parsing this again. We already have a valid layer definition.
        return;
    }

    // Make sure we have not previously attempted to parse this layer.
    if (std::find(stack.begin(), stack.end(), id) != stack.end()) {
        Log::Warning(Event::ParseStyle, "layer reference of '%s' is circular", id.c_str());
        return;
    }

    if (value.HasMember("ref")) {
        // This layer is referencing another layer. Recursively parse that layer.
        const JSVal& refVal = value["ref"];
        if (!refVal.IsString()) {
            Log::Warning(Event::ParseStyle, "layer ref of '%s' must be a string", id.c_str());
            return;
        }

        const std::string ref { refVal.GetString(), refVal.GetStringLength() };
        auto it = layersMap.find(ref);
        if (it == layersMap.end()) {
            Log::Warning(Event::ParseStyle, "layer '%s' references unknown layer %s", id.c_str(), ref.c_str());
            return;
        }

        // Recursively parse the referenced layer.
        stack.push_front(id);
        parseLayer(it->first,
                   it->second.first,
                   it->second.second);
        stack.pop_front();

        util::ptr<StyleLayer> reference = it->second.second;
        if (!reference) {
            return;
        }

        layer = reference->clone();
        layer->id = id;
        layer->ref = ref;

    } else {
        // Otherwise, parse the source/source-layer/filter/render keys to form the bucket.
        if (!value.HasMember("type")) {
            Log::Warning(Event::ParseStyle, "layer '%s' is missing a type", id.c_str());
            return;
        }

        const JSVal& typeVal = value["type"];
        if (!typeVal.IsString()) {
            Log::Warning(Event::ParseStyle, "layer '%s' has an invalid type", id.c_str());
            return;
        }

        std::string type { typeVal.GetString(), typeVal.GetStringLength() };
        StyleLayerType typeClass = StyleLayerTypeClass(type);
        layer = StyleLayer::create(typeClass);

        if (!layer) {
            Log::Warning(Event::ParseStyle, "unknown type '%s' for layer '%s'", type.c_str(), id.c_str());
            return;
        }

        layer->id = id;
        layer->type = typeClass;

        if (value.HasMember("source")) {
            const JSVal& value_source = value["source"];
            if (value_source.IsString()) {
                layer->source = { value_source.GetString(), value_source.GetStringLength() };
                auto source_it = sourcesMap.find(layer->source);
                if (source_it == sourcesMap.end()) {
                    Log::Warning(Event::ParseStyle, "can't find source '%s' required for layer '%s'", layer->source.c_str(), layer->id.c_str());
                }
            } else {
                Log::Warning(Event::ParseStyle, "source of layer '%s' must be a string", layer->id.c_str());
            }
        }

        if (value.HasMember("source-layer")) {
            const JSVal& value_source_layer = value["source-layer"];
            if (value_source_layer.IsString()) {
                layer->sourceLayer = { value_source_layer.GetString(), value_source_layer.GetStringLength() };
            } else {
                Log::Warning(Event::ParseStyle, "source-layer of layer '%s' must be a string", layer->id.c_str());
            }
        }

        if (value.HasMember("filter")) {
            layer->filter = parseFilterExpression(value["filter"]);
        }

        if (value.HasMember("minzoom")) {
            const JSVal& min_zoom = value["minzoom"];
            if (min_zoom.IsNumber()) {
                layer->minZoom = min_zoom.GetDouble();
            } else {
                Log::Warning(Event::ParseStyle, "minzoom of layer %s must be numeric", layer->id.c_str());
            }
        }

        if (value.HasMember("maxzoom")) {
            const JSVal& max_zoom = value["maxzoom"];
            if (max_zoom.IsNumber()) {
                layer->maxZoom = max_zoom.GetDouble();
            } else {
                Log::Warning(Event::ParseStyle, "maxzoom of layer %s must be numeric", layer->id.c_str());
            }
        }

        if (value.HasMember("layout")) {
            parseVisibility(*layer, value["layout"]);
            layer->parseLayout(value["layout"]);
        }
    }

    layer->parsePaints(value);
}