#include #include using namespace llmr; Style::Style() { appliedClasses.insert("default"); } void Style::reset() { computed.fills.clear(); computed.strokes.clear(); } void Style::load(const uint8_t *const data, uint32_t bytes) { pbf style(data, bytes); while (style.next()) { if (style.tag == 1) { // bucket buckets.insert(parseBucket(style.message())); } else if (style.tag == 2) { // structure layers.push_back(parseLayer(style.message())); } else if (style.tag == 3) { // class classes.insert(parseClass(style.message())); } else { style.skip(); } } } std::pair Style::parseBucket(pbf data) { BucketDescription bucket; std::string name; while (data.next()) { if (data.tag == 1) { // name name = data.string(); } else if (data.tag == 2) { // type bucket.type = (BucketType)data.varint(); } else if (data.tag == 3) { // source_name bucket.source_name = data.string(); } else if (data.tag == 4) { // source_layer bucket.source_layer = data.string(); } else if (data.tag == 5) { // source_field bucket.source_field = data.string(); } else if (data.tag == 6) { // source_value bucket.source_value.emplace_back(parseValue(data.message())); } else if (data.tag == 7) { // cap bucket.cap = (CapType)data.varint(); } else if (data.tag == 8) { // join bucket.join = (JoinType)data.varint(); } else if (data.tag == 9) { // font bucket.font = data.string(); } else if (data.tag == 10) { // font_size bucket.font_size = data.float32(); } else { data.skip(); } } return { name, bucket }; } LayerDescription Style::parseLayer(pbf data) { LayerDescription layer; while (data.next()) { if (data.tag == 1) { // name layer.name = data.string(); } else if (data.tag == 2) { // bucket_name layer.bucket_name = data.string(); } else if (data.tag == 3) { // child_layer layer.child_layer.emplace_back(parseLayer(data.message())); } else { data.skip(); } } return layer; } std::pair Style::parseClass(pbf data) { ClassDescription klass; std::string name; while (data.next()) { if (data.tag == 1) { // name name = data.string(); } else if (data.tag == 2) { // fill_style klass.fill.insert(parseFillClass(data.message())); } else if (data.tag == 3) { // stroke_style klass.stroke.insert(parseStrokeClass(data.message())); } else { data.skip(); } } return { name, klass }; } std::pair Style::parseFillClass(pbf data) { FillClass fill; std::string name; while (data.next()) { if (data.tag == 1) { // name name = data.string(); } else if (data.tag == 2) { // hidden fill.hidden = parseProperty(data.message()); } else if (data.tag == 3) { // winding fill.winding = (Winding)data.varint(); } else if (data.tag == 4) { // antialias fill.antialias = parseProperty(data.message()); } else if (data.tag == 5) { // fill_color fill.fill_color = parseColor(data); if (fill.stroke_color[3] == std::numeric_limits::infinity()) { fill.stroke_color = fill.fill_color; } } else if (data.tag == 6) { // stroke_color fill.stroke_color = parseColor(data); } else if (data.tag == 7) { // opacity fill.opacity = parseProperty(data.message()); } else { data.skip(); } } return { name, fill }; } std::pair Style::parseStrokeClass(pbf data) { StrokeClass stroke; std::string name; while (data.next()) { if (data.tag == 1) { // name name = data.string(); } else if (data.tag == 2) { // hidden stroke.hidden = parseProperty(data.message()); } else if (data.tag == 3) { // color stroke.color = parseColor(data); } else if (data.tag == 4) { // width stroke.width = parseProperty(data.message()); } else if (data.tag == 5) { // opacity stroke.offset = parseProperty(data.message()); } else { data.skip(); } } return { name, stroke }; } Color Style::parseColor(pbf& data) { uint32_t rgba = data.fixed(); return {{ (float)((rgba >> 24) & 0xFF) / 0xFF, (float)((rgba >> 16) & 0xFF) / 0xFF, (float)((rgba >> 8) & 0xFF) / 0xFF, (float)((rgba >> 0) & 0xFF) / 0xFF }}; } template FunctionProperty Style::parseProperty(pbf data) { FunctionProperty property; while (data.next()) { if (data.tag == 1) { // function switch((Property)data.varint()) { case Property::Null: property.function = &functions::null; break; case Property::Constant: property.function = &functions::constant; break; default: property.function = &functions::null; break; } } else if (data.tag == 2) { // value // read a packed float32 pbf floats = data.message(); while (floats) { property.values.push_back(floats.float32()); } } else { data.skip(); } } return property; } void Style::cascade(float z) { reset(); // Recalculate style // Basic cascading for (const auto& class_pair : classes) { const std::string& class_name = class_pair.first; const ClassDescription& sheetClass = class_pair.second; // Not enabled if (appliedClasses.find(class_name) == appliedClasses.end()) continue; // Cascade fill classes for (const auto& fill_pair : sheetClass.fill) { const std::string& layer_name = fill_pair.first; const llmr::FillClass& layer = fill_pair.second; llmr::FillProperties& fill = computed.fills[layer_name]; fill.hidden = layer.hidden(z); fill.winding = layer.winding; fill.antialias = layer.antialias(z); fill.fill_color = layer.fill_color; fill.stroke_color = layer.stroke_color; fill.opacity = layer.opacity(z); } // Cascade line classes for (const auto& stroke_pair : sheetClass.stroke) { const std::string& layer_name = stroke_pair.first; const llmr::StrokeClass& layer = stroke_pair.second; llmr::StrokeProperties& stroke = computed.strokes[layer_name]; stroke.hidden = layer.hidden(z); stroke.width = layer.width(z); stroke.offset = layer.offset(z); stroke.color = layer.color; } } }