KOSMIndoorMap

mapcssdeclaration.cpp
1/*
2 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "mapcssdeclaration_p.h"
8#include "logging.h"
9#include "mapcssproperty.h"
10
11#include <QDebug>
12#include <QIODevice>
13
14#include <cstring>
15
16using namespace KOSMIndoorMap;
17
18// keep this sorted by property name!
19struct {
20 const char* name;
21 MapCSSProperty property;
22 int flags;
23} static constexpr const property_types[] = {
24 // only those properties have their corresonding flag set that actually trigger emission of a scene graph item
25 // e.g. for a label we either need a text or an icon, the visual properties for those on their own would be a no-op
26 { "casing-color", MapCSSProperty::CasingColor, MapCSSDeclaration::NoFlag },
27 { "casing-dashes", MapCSSProperty::CasingDashes, MapCSSDeclaration::NoFlag },
28 { "casing-linecap", MapCSSProperty::CasingLineCap, MapCSSDeclaration::NoFlag },
29 { "casing-linejoin", MapCSSProperty::CasingLineJoin, MapCSSDeclaration::NoFlag },
30 { "casing-opacity", MapCSSProperty::CasingOpacity, MapCSSDeclaration::NoFlag },
31 { "casing-width", MapCSSProperty::CasingWidth, MapCSSDeclaration::NoFlag },
32 { "color", MapCSSProperty::Color, MapCSSDeclaration::LineProperty },
33 { "dashes", MapCSSProperty::Dashes, MapCSSDeclaration::NoFlag },
34 { "extrude", MapCSSProperty::Extrude, MapCSSDeclaration::ExtrudeProperty },
35 { "fill-color", MapCSSProperty::FillColor, MapCSSDeclaration::AreaProperty | MapCSSDeclaration::CanvasProperty }, // TODO this also applies to lines
36 { "fill-image", MapCSSProperty::FillImage, MapCSSDeclaration::AreaProperty | MapCSSDeclaration::CanvasProperty },
37 { "fill-opacity", MapCSSProperty::FillOpacity, MapCSSDeclaration::AreaProperty },
38 { "font-family", MapCSSProperty::FontFamily, MapCSSDeclaration::NoFlag },
39 { "font-size", MapCSSProperty::FontSize, MapCSSDeclaration::NoFlag },
40 { "font-style", MapCSSProperty::FontStyle, MapCSSDeclaration::NoFlag },
41 { "font-variant", MapCSSProperty::FontVariant, MapCSSDeclaration::NoFlag },
42 { "font-weight", MapCSSProperty::FontWeight, MapCSSDeclaration::NoFlag },
43 { "icon-allow-icon-overlap", MapCSSProperty::IconAllowIconOverlap, MapCSSDeclaration::NoFlag },
44 { "icon-allow-text-overlap", MapCSSProperty::IconAllowTextOverlap, MapCSSDeclaration::NoFlag },
45 { "icon-color", MapCSSProperty::IconColor, MapCSSDeclaration::NoFlag },
46 { "icon-height", MapCSSProperty::IconHeight, MapCSSDeclaration::NoFlag },
47 { "icon-image", MapCSSProperty::IconImage, MapCSSDeclaration::LabelProperty },
48 { "icon-opacity", MapCSSProperty::IconOpacity, MapCSSDeclaration::NoFlag },
49 { "icon-width", MapCSSProperty::IconWidth, MapCSSDeclaration::NoFlag },
50 { "image", MapCSSProperty::Image, MapCSSDeclaration::LineProperty },
51 { "linecap", MapCSSProperty::LineCap, MapCSSDeclaration::NoFlag },
52 { "linejoin", MapCSSProperty::LineJoin, MapCSSDeclaration::NoFlag },
53 { "max-width", MapCSSProperty::MaxWidth, MapCSSDeclaration::NoFlag },
54 { "opacity", MapCSSProperty::Opacity, MapCSSDeclaration::NoFlag },
55 { "shield-casing-color", MapCSSProperty::ShieldCasingColor, MapCSSDeclaration::LabelProperty },
56 { "shield-casing-width", MapCSSProperty::ShieldCasingWidth, MapCSSDeclaration::NoFlag },
57 { "shield-color", MapCSSProperty::ShieldColor, MapCSSDeclaration::LabelProperty },
58 { "shield-frame-color", MapCSSProperty::ShieldFrameColor, MapCSSDeclaration::LabelProperty },
59 { "shield-frame-width", MapCSSProperty::ShieldFrameWidth, MapCSSDeclaration::NoFlag },
60 { "shield-image", MapCSSProperty::ShieldImage, MapCSSDeclaration::LabelProperty },
61 { "shield-opacity", MapCSSProperty::ShieldOpacity, MapCSSDeclaration::NoFlag },
62 { "shield-shape", MapCSSProperty::ShieldShape, MapCSSDeclaration::NoFlag },
63 { "shield-text", MapCSSProperty::ShieldText, MapCSSDeclaration::LabelProperty },
64 { "text", MapCSSProperty::Text, MapCSSDeclaration::LabelProperty },
65 { "text-color", MapCSSProperty::TextColor, MapCSSDeclaration::CanvasProperty },
66 { "text-decoration", MapCSSProperty::TextDecoration, MapCSSDeclaration::NoFlag },
67 { "text-halo-color", MapCSSProperty::TextHaloColor, MapCSSDeclaration::NoFlag },
68 { "text-halo-radius", MapCSSProperty::TextHaloRadius, MapCSSDeclaration::NoFlag },
69 { "text-offset", MapCSSProperty::TextOffset, MapCSSDeclaration::NoFlag },
70 { "text-opacity", MapCSSProperty::TextOpacity, MapCSSDeclaration::NoFlag },
71 { "text-position", MapCSSProperty::TextPosition, MapCSSDeclaration::NoFlag },
72 { "text-transform", MapCSSProperty::TextTransform, MapCSSDeclaration::NoFlag },
73 { "width", MapCSSProperty::Width, MapCSSDeclaration::LineProperty },
74 { "z-index", MapCSSProperty::ZIndex, MapCSSDeclaration::NoFlag },
75};
76
77struct {
78 const char *name;
79 Qt::PenCapStyle capStyle;
80} static constexpr const capstyle_map[] = {
81 { "none", Qt::FlatCap },
82 { "round", Qt::RoundCap },
83 { "square", Qt::SquareCap },
84};
85
86struct {
87 const char *name;
88 Qt::PenJoinStyle joinStyle;
89} static constexpr const joinstyle_map[] = {
90 { "bevel", Qt::BevelJoin },
91 { "miter", Qt::MiterJoin },
92 { "round", Qt::RoundJoin },
93};
94
95struct {
96 const char *name;
97 QFont::Capitalization capitalizationStyle;
98} static constexpr const capitalizationstyle_map[] = {
99 { "capitalize", QFont::Capitalize },
100 { "lowercase", QFont::AllLowercase },
101 { "none", QFont::MixedCase },
102 { "normal", QFont::MixedCase },
103 { "small-caps", QFont::SmallCaps },
104 { "uppercase", QFont::AllUppercase },
105};
106
107struct {
108 const char *name;
109 MapCSSDeclaration::Unit unit;
110} static constexpr const unit_map[] = {
111 { "m", MapCSSDeclaration::Meters },
112 { "pt", MapCSSDeclaration::Point },
113 { "px", MapCSSDeclaration::Pixels },
114};
115
116struct {
117 const char *name;
118 MapCSSDeclaration::Position position;
119} static constexpr const position_map[] = {
120 { "center", MapCSSDeclaration::Position::Center },
121 { "line", MapCSSDeclaration::Position::Line },
122};
123
124MapCSSDeclaration::MapCSSDeclaration(Type type)
125 : m_type(type)
126{
127}
128
129MapCSSDeclaration::~MapCSSDeclaration() = default;
130
131bool MapCSSDeclaration::isValid() const
132{
133 switch (m_type) {
134 case PropertyDeclaration:
135 return property() != MapCSSProperty::Unknown;
136 case TagDeclaration:
137 return !m_identValue.isEmpty();
138 case ClassDeclaration:
139 return !m_class.isNull();
140 }
141
142 Q_UNREACHABLE();
143 return false;
144}
145
146MapCSSDeclaration::Type MapCSSDeclaration::type() const
147{
148 return m_type;
149}
150
151MapCSSProperty MapCSSDeclaration::property() const
152{
153 return m_property;
154}
155
156int MapCSSDeclaration::propertyFlags() const
157{
158 return m_flags;
159}
160
161int MapCSSDeclaration::intValue() const
162{
163 return m_doubleValue;
164}
165
166double MapCSSDeclaration::doubleValue() const
167{
168 return m_doubleValue;
169}
170
171bool MapCSSDeclaration::boolValue() const
172{
173 return m_boolValue;
174}
175
176QString MapCSSDeclaration::stringValue() const
177{
178 return m_stringValue;
179}
180
181QColor MapCSSDeclaration::colorValue() const
182{
183 if (!m_colorValue.isValid() && !m_stringValue.isEmpty()) {
184 return QColor(m_stringValue);
185 }
186 return m_colorValue;
187}
188
189QByteArray MapCSSDeclaration::keyValue() const
190{
191 return m_identValue;
192}
193
194QVector<double> MapCSSDeclaration::dashesValue() const
195{
196 return m_dashValue;
197}
198
199OSM::TagKey MapCSSDeclaration::tagKey() const
200{
201 return m_tagKey;
202}
203
204void MapCSSDeclaration::setDoubleValue(double val)
205{
206 m_doubleValue = val;
207}
208
209void MapCSSDeclaration::setBoolValue(bool val)
210{
211 m_boolValue = val;
212}
213
214void MapCSSDeclaration::setPropertyName(const char *name, std::size_t len)
215{
216 const auto it = std::lower_bound(std::begin(property_types), std::end(property_types), name, [len](const auto &lhs, const char *rhs) {
217 const auto lhsLen = std::strlen(lhs.name);
218 const auto cmp = std::strncmp(lhs.name, rhs, std::min(lhsLen, len));
219 return cmp < 0 || (cmp == 0 && lhsLen < len);
220 });
221 if (it == std::end(property_types) || std::strncmp((*it).name, name, std::max(len, std::strlen((*it).name))) != 0) {
222 qCWarning(Log) << "Unknown property declaration:" << QByteArray::fromRawData(name, len);
223 m_property = MapCSSProperty::Unknown;
224 return;
225 }
226 m_property = (*it).property;
227 m_flags = (*it).flags;
228}
229
230void MapCSSDeclaration::setIdentifierValue(const char *val, int len)
231{
232 m_identValue = QByteArray(val, len);
233}
234
235void MapCSSDeclaration::setStringValue(char *str)
236{
237 m_stringValue = QString::fromUtf8(str);
238 free(str);
239}
240
241void MapCSSDeclaration::setColorRgba(uint32_t argb)
242{
243 m_colorValue = QColor::fromRgba(argb);
244 //qDebug() << m_colorValue << argb;
245}
246
247void MapCSSDeclaration::setDashesValue(const QVector<double> &dashes)
248{
249 m_dashValue = dashes;
250}
251
252Qt::PenCapStyle MapCSSDeclaration::capStyle() const
253{
254 for (const auto &c : capstyle_map) {
255 if (std::strcmp(c.name, m_identValue.constData()) == 0) {
256 return c.capStyle;
257 }
258 }
259 qDebug() << "unknown line cap style:" << m_identValue;
260 return Qt::FlatCap;
261}
262
263Qt::PenJoinStyle MapCSSDeclaration::joinStyle() const
264{
265 for (const auto &j : joinstyle_map) {
266 if (std::strcmp(j.name, m_identValue.constData()) == 0) {
267 return j.joinStyle;
268 }
269 }
270 return Qt::RoundJoin;
271}
272
273QFont::Capitalization MapCSSDeclaration::capitalizationStyle() const
274{
275 for (const auto &c : capitalizationstyle_map) {
276 if (std::strcmp(c.name, m_identValue.constData()) == 0) {
277 return c.capitalizationStyle;
278 }
279 }
280 return QFont::MixedCase;
281}
282
283bool MapCSSDeclaration::isBoldStyle() const
284{
285 return m_identValue == "bold";
286}
287
288bool MapCSSDeclaration::isItalicStyle() const
289{
290 return m_identValue == "italic";
291}
292
293bool MapCSSDeclaration::isUnderlineStyle() const
294{
295 return m_identValue == "underline";
296}
297
298MapCSSDeclaration::Position MapCSSDeclaration::textPosition() const
299{
300 for (const auto &p : position_map) {
301 if (std::strcmp(p.name, m_identValue.constData()) == 0) {
302 return p.position;
303 }
304 }
305 return Position::NoPostion;
306}
307
308MapCSSDeclaration::Unit MapCSSDeclaration::unit() const
309{
310 return m_unit;
311}
312
313void MapCSSDeclaration::setUnit(const char *val, int len)
314{
315 for (const auto &u : unit_map) {
316 if (std::strncmp(u.name, val, std::max<std::size_t>(std::strlen(u.name), len)) == 0) {
317 m_unit = u.unit;
318 return;
319 }
320 }
321 qCWarning(Log) << "unknown unit:" << QByteArray(val, len);
322 m_unit = NoUnit;
323}
324
325ClassSelectorKey MapCSSDeclaration::classSelectorKey() const
326{
327 return m_class;
328}
329
330void MapCSSDeclaration::setClassSelectorKey(ClassSelectorKey key)
331{
332 m_class = key;
333}
334
335void MapCSSDeclaration::compile(const OSM::DataSet &dataSet)
336{
337 Q_UNUSED(dataSet);
338 // TODO resolve tag key if m_identValue is one
339 if (m_type == TagDeclaration) {
340 // TODO handle the case that the tag isn't actually available in dataSet
341 m_tagKey = dataSet.tagKey(m_identValue.constData());
342 }
343}
344
345void MapCSSDeclaration::write(QIODevice *out) const
346{
347 out->write(" ");
348
349 switch (m_type) {
350 case PropertyDeclaration:
351 for (const auto &p : property_types) {
352 if (p.property == m_property) {
353 out->write(p.name);
354 break;
355 }
356 }
357
358 out->write(": ");
359 if (!std::isnan(m_doubleValue)) {
360 out->write(QByteArray::number(m_doubleValue));
361 } else if (m_colorValue.isValid()) {
362 out->write(m_colorValue.name(QColor::HexArgb).toUtf8());
363 } else if (!m_dashValue.isEmpty()) {
364 for (const auto &d : m_dashValue) {
365 out->write(QByteArray::number(d));
366 out->write(", ");
367 }
368 } else if (!m_stringValue.isNull()) {
369 out->write("\"");
370 out->write(m_stringValue.toUtf8()); // this would need to be quoted...
371 out->write("\"");
372 } else if (!m_identValue.isEmpty()) {
373 out->write(m_identValue);
374 } else {
375 out->write(m_boolValue ? "true" : "false");
376 }
377
378 for (const auto &u : unit_map) {
379 if (u.unit == m_unit) {
380 out->write(u.name);
381 break;
382 }
383 }
384 break;
385 case TagDeclaration:
386 out->write("set ");
387 out->write(m_identValue);
388 if (!std::isnan(m_doubleValue)) {
389 out->write(" = ");
390 out->write(QByteArray::number(m_doubleValue));
391 } else if (!m_stringValue.isEmpty()) {
392 out->write(" = \"");
393 out->write(m_stringValue.toUtf8()); // this would need to be quoted...
394 out->write("\"");
395 }
396 break;
397 case ClassDeclaration:
398 out->write("set .");
399 out->write(m_class.name());
400 break;
401 }
402
403 out->write(";\n");
404}
A set of nodes, ways and relations.
Definition datatypes.h:340
TagKey tagKey(const char *keyName) const
Look up a tag key for the given tag name, if it exists.
Definition datatypes.cpp:27
A key of an OSM tag.
Definition datatypes.h:179
OSM-based multi-floor indoor maps for buildings.
MapCSSProperty
Known properties in MapCSS declarations.
QByteArray fromRawData(const char *data, qsizetype size)
QByteArray number(double n, char format, int precision)
QColor fromRgba(QRgb rgba)
Capitalization
qint64 write(const QByteArray &data)
QString fromUtf8(QByteArrayView str)
PenCapStyle
PenJoinStyle
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.