KOSMIndoorMap

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

KDE's Doxygen guidelines are available online.