Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsvgstyle.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
6#include "qsvgstyle_p.h"
7
8#include "qsvgfont_p.h"
9#include "qsvgnode_p.h"
10#include "private/qsvganimate_p.h"
11#include "qsvgdocument_p.h"
12
13#include "qpainter.h"
14#include "qcolor.h"
15#include "qdebug.h"
16
18
19QSvgRefCounted::~QSvgRefCounted()
20 = default;
21
22QSvgExtraStates::QSvgExtraStates()
23 : fillOpacity(1.0),
24 strokeOpacity(1.0),
25 svgFont(0),
26 textAnchor(Qt::AlignLeft),
27 fontWeight(QFont::Normal),
28 fillRule(Qt::WindingFill),
29 strokeDashOffset(0),
30 vectorEffect(false),
31 imageRendering(QSvgQualityStyle::ImageRenderingAuto)
32{
33}
34
35QSvgStyleProperty::~QSvgStyleProperty()
36 = default;
37
38QSvgQualityStyle::QSvgQualityStyle(int color)
39 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
40 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
41 , m_imageRenderingSet(0)
42{
43 Q_UNUSED(color);
44}
45
46QSvgQualityStyle::~QSvgQualityStyle()
47 = default;
48
49void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
50 m_imageRendering = hint;
51 m_imageRenderingSet = 1;
52}
53
54void QSvgQualityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &states)
55{
56 m_oldImageRendering = states.imageRendering;
57 if (m_imageRenderingSet) {
58 states.imageRendering = m_imageRendering;
59 }
60 if (m_imageRenderingSet) {
61 bool smooth = false;
62 if (m_imageRendering == ImageRenderingAuto)
63 // auto (the spec says to prefer quality)
64 smooth = true;
65 else
66 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
67 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
68 }
69}
70
71void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
72{
73 if (m_imageRenderingSet) {
74 states.imageRendering = m_oldImageRendering;
75 bool smooth = false;
76 if (m_oldImageRendering == ImageRenderingAuto)
77 smooth = true;
78 else
79 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
80 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
81 }
82}
83
84QSvgFillStyle::QSvgFillStyle()
85 : m_fillRuleSet(0)
86 , m_fillOpacitySet(0)
87 , m_fillSet(0)
88{
89}
90
91QSvgFillStyle::~QSvgFillStyle()
92 = default;
93
94void QSvgFillStyle::setFillRule(Qt::FillRule f)
95{
96 m_fillRuleSet = 1;
97 m_fillRule = f;
98}
99
100void QSvgFillStyle::setFillOpacity(qreal opacity)
101{
102 m_fillOpacitySet = 1;
103 m_fillOpacity = opacity;
104}
105
106void QSvgFillStyle::setPaintServer(QSvgPaintServerSharedPtr paintServer)
107{
108 m_paintServer = std::move(paintServer);
109 m_fillSet = 1;
110}
111
112void QSvgFillStyle::setBrush(QBrush brush)
113{
114 m_fill = std::move(brush);
115 m_paintServer.reset();
116 m_fillSet = 1;
117}
118
119void QSvgFillStyle::apply(QPainter *p, const QSvgNode *n, QSvgExtraStates &states)
120{
121 m_oldFill = p->brush();
122 m_oldFillRule = states.fillRule;
123 m_oldFillOpacity = states.fillOpacity;
124
125 if (m_fillRuleSet)
126 states.fillRule = m_fillRule;
127 if (m_fillSet) {
128 if (m_paintServer)
129 p->setBrush(m_paintServer->brush(p, n, states));
130 else
131 p->setBrush(m_fill);
132 }
133 if (m_fillOpacitySet)
134 states.fillOpacity = m_fillOpacity;
135}
136
137void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
138{
139 if (m_fillOpacitySet)
140 states.fillOpacity = m_oldFillOpacity;
141 if (m_fillSet)
142 p->setBrush(m_oldFill);
143 if (m_fillRuleSet)
144 states.fillRule = m_oldFillRule;
145}
146
147QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush)
148 : m_viewportFill(brush)
149{
150}
151
152QSvgViewportFillStyle::~QSvgViewportFillStyle()
153 = default;
154
155void QSvgViewportFillStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
156{
157 m_oldFill = p->brush();
158 p->setBrush(m_viewportFill);
159}
160
161void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
162{
163 p->setBrush(m_oldFill);
164}
165
166const int QSvgFontStyle::LIGHTER;
167const int QSvgFontStyle::BOLDER;
168
169QSvgFontStyle::QSvgFontStyle(QSvgFont *font)
170 : m_svgFont(font)
171 , m_familySet(0)
172 , m_sizeSet(0)
173 , m_styleSet(0)
174 , m_variantSet(0)
175 , m_weightSet(0)
176 , m_textAnchorSet(0)
177{
178}
179
180QSvgFontStyle::QSvgFontStyle()
181 : m_svgFont(0)
182 , m_familySet(0)
183 , m_sizeSet(0)
184 , m_styleSet(0)
185 , m_variantSet(0)
186 , m_weightSet(0)
187 , m_textAnchorSet(0)
188{
189}
190
191QSvgFontStyle::~QSvgFontStyle()
192 = default;
193
194void QSvgFontStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &states)
195{
196 m_oldQFont = p->font();
197 m_oldSvgFont = states.svgFont;
198 m_oldTextAnchor = states.textAnchor;
199 m_oldWeight = states.fontWeight;
200
201 if (m_textAnchorSet)
202 states.textAnchor = m_textAnchor;
203
204 QFont font = m_oldQFont;
205 if (m_familySet) {
206 states.svgFont = m_svgFont;
207 font.setFamilies(m_qfont.families());
208 }
209
210 if (m_sizeSet)
211 font.setPointSizeF(m_qfont.pointSizeF());
212
213 if (m_styleSet)
214 font.setStyle(m_qfont.style());
215
216 if (m_variantSet)
217 font.setCapitalization(m_qfont.capitalization());
218
219 if (m_weightSet) {
220 if (m_weight == BOLDER) {
221 states.fontWeight = qMin(states.fontWeight, QFont::Weight::Black - 100) + 100;
222 } else if (m_weight == LIGHTER) {
223 states.fontWeight = qMax(states.fontWeight, QFont::Weight::Thin + 100) - 100;
224 } else {
225 states.fontWeight = m_weight;
226 }
227 font.setWeight(QFont::Weight(qBound(static_cast<int>(QFont::Weight::Thin),
228 states.fontWeight,
229 static_cast<int>(QFont::Weight::Black))));
230 }
231
232 p->setFont(font);
233}
234
235void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
236{
237 p->setFont(m_oldQFont);
238 states.svgFont = m_oldSvgFont;
239 states.textAnchor = m_oldTextAnchor;
240 states.fontWeight = m_oldWeight;
241}
242
243QSvgStrokeStyle::QSvgStrokeStyle()
244 : m_vectorEffect(0)
245 , m_oldVectorEffect(0)
246 , m_strokeSet(0)
247 , m_strokeDashArraySet(0)
248 , m_strokeDashOffsetSet(0)
249 , m_strokeLineCapSet(0)
250 , m_strokeLineJoinSet(0)
251 , m_strokeMiterLimitSet(0)
252 , m_strokeOpacitySet(0)
253 , m_strokeWidthSet(0)
254 , m_vectorEffectSet(0)
255{
256}
257
258QSvgStrokeStyle::~QSvgStrokeStyle()
259 = default;
260
261void QSvgStrokeStyle::apply(QPainter *p, const QSvgNode *n, QSvgExtraStates &states)
262{
263 m_oldStroke = p->pen();
264 m_oldStrokeOpacity = states.strokeOpacity;
265 m_oldStrokeDashOffset = states.strokeDashOffset;
266 m_oldVectorEffect = states.vectorEffect;
267
268 QPen pen = p->pen();
269
270 qreal oldWidth = pen.widthF();
271 qreal width = m_stroke.widthF();
272 if (oldWidth == 0)
273 oldWidth = 1;
274 if (width == 0)
275 width = 1;
276 qreal scale = oldWidth / width;
277
278 if (m_strokeOpacitySet)
279 states.strokeOpacity = m_strokeOpacity;
280
281 if (m_vectorEffectSet)
282 states.vectorEffect = m_vectorEffect;
283
284 if (m_strokeSet) {
285 if (m_paintServer)
286 pen.setBrush(m_paintServer->brush(p, n, states));
287 else
288 pen.setBrush(m_stroke.brush());
289 }
290
291 if (m_strokeWidthSet)
292 pen.setWidthF(m_stroke.widthF());
293
294 bool setDashOffsetNeeded = false;
295
296 if (m_strokeDashOffsetSet) {
297 states.strokeDashOffset = m_strokeDashOffset;
298 setDashOffsetNeeded = true;
299 }
300
301 if (m_strokeDashArraySet) {
302 if (m_stroke.style() == Qt::SolidLine) {
303 pen.setStyle(Qt::SolidLine);
304 } else if (m_strokeWidthSet || oldWidth == 1) {
305 // If both width and dash array was set, the dash array is already scaled correctly.
306 pen.setDashPattern(m_stroke.dashPattern());
307 setDashOffsetNeeded = true;
308 } else {
309 // If dash array was set, but not the width, the dash array has to be scaled with respect to the old width.
310 QList<qreal> dashes = m_stroke.dashPattern();
311 for (int i = 0; i < dashes.size(); ++i)
312 dashes[i] /= oldWidth;
313 pen.setDashPattern(dashes);
314 setDashOffsetNeeded = true;
315 }
316 } else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
317 // If the width was set, but not the dash array, the old dash array must be scaled with respect to the new width.
318 QList<qreal> dashes = pen.dashPattern();
319 for (int i = 0; i < dashes.size(); ++i)
320 dashes[i] *= scale;
321 pen.setDashPattern(dashes);
322 setDashOffsetNeeded = true;
323 }
324
325 if (m_strokeLineCapSet)
326 pen.setCapStyle(m_stroke.capStyle());
327 if (m_strokeLineJoinSet)
328 pen.setJoinStyle(m_stroke.joinStyle());
329 if (m_strokeMiterLimitSet)
330 pen.setMiterLimit(m_stroke.miterLimit());
331
332 // You can have dash offset on solid strokes in SVG files, but not in Qt.
333 // QPen::setDashOffset() will set the pen style to Qt::CustomDashLine,
334 // so don't call the method if the pen is solid.
335 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
336 qreal currentWidth = pen.widthF();
337 if (currentWidth == 0)
338 currentWidth = 1;
339 pen.setDashOffset(states.strokeDashOffset / currentWidth);
340 }
341
342 pen.setCosmetic(states.vectorEffect);
343
344 p->setPen(pen);
345}
346
347void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
348{
349 p->setPen(m_oldStroke);
350 states.strokeOpacity = m_oldStrokeOpacity;
351 states.strokeDashOffset = m_oldStrokeDashOffset;
352 states.vectorEffect = m_oldVectorEffect;
353}
354
355void QSvgStrokeStyle::setDashArray(const QList<qreal> &dashes)
356{
357 if (m_strokeWidthSet) {
358 QList<qreal> d = dashes;
359 qreal w = m_stroke.widthF();
360 if (w != 0 && w != 1) {
361 for (int i = 0; i < d.size(); ++i)
362 d[i] /= w;
363 }
364 m_stroke.setDashPattern(d);
365 } else {
366 m_stroke.setDashPattern(dashes);
367 }
368 m_strokeDashArraySet = 1;
369}
370
371QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans)
372 : m_transform(trans)
373{
374}
375
376QSvgTransformStyle::~QSvgTransformStyle()
377 = default;
378
379void QSvgTransformStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
380{
381 m_oldWorldTransform.push(p->worldTransform());
382 p->setWorldTransform(m_transform, true);
383}
384
385void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
386{
387 p->setWorldTransform(m_oldWorldTransform.pop(), false /* don't combine */);
388}
389
390QSvgStyleProperty::Type QSvgQualityStyle::type() const
391{
392 return Quality;
393}
394
395QSvgStyleProperty::Type QSvgFillStyle::type() const
396{
397 return Fill;
398}
399
400QSvgStyleProperty::Type QSvgViewportFillStyle::type() const
401{
402 return ViewportFill;
403}
404
405QSvgStyleProperty::Type QSvgFontStyle::type() const
406{
407 return Font;
408}
409
410QSvgStyleProperty::Type QSvgStrokeStyle::type() const
411{
412 return Stroke;
413}
414
415QSvgStyleProperty::Type QSvgTransformStyle::type() const
416{
417 return Transform;
418}
419
420
421QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
422 : m_mode(mode)
423{
424
425}
426
427QSvgCompOpStyle::~QSvgCompOpStyle()
428 = default;
429
430void QSvgCompOpStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
431{
432 m_oldMode = p->compositionMode();
433 p->setCompositionMode(m_mode);
434}
435
436void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
437{
438 p->setCompositionMode(m_oldMode);
439}
440
441QSvgStyleProperty::Type QSvgCompOpStyle::type() const
442{
443 return CompOp;
444}
445
446QSvgOffsetStyle::~QSvgOffsetStyle()
447 = default;
448
449void QSvgOffsetStyle::apply(QPainter *, const QSvgNode *, QSvgExtraStates &)
450{
451}
452
453void QSvgOffsetStyle::revert(QPainter *, QSvgExtraStates &)
454{
455}
456
457QSvgStyleProperty::Type QSvgOffsetStyle::type() const
458{
459 return Offset;
460}
461
462QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
463 : m_opacity(opacity), m_oldOpacity(0)
464{
465
466}
467
468QSvgOpacityStyle::~QSvgOpacityStyle()
469 = default;
470
471void QSvgOpacityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
472{
473 m_oldOpacity = p->opacity();
474 p->setOpacity(m_opacity * m_oldOpacity);
475}
476
477void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
478{
479 p->setOpacity(m_oldOpacity);
480}
481
482QSvgStyleProperty::Type QSvgOpacityStyle::type() const
483{
484 return Opacity;
485}
486
487QSvgStaticStyle::QSvgStaticStyle()
488 = default;
489QSvgStaticStyle::~QSvgStaticStyle()
490 = default;
491
492void QSvgStaticStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
493{
494 for (auto &prop : m_properties) {
495 if (prop)
496 prop->apply(p, node, states);
497 }
498}
499
500void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
501{
502 for (auto &prop : m_properties) {
503 if (prop)
504 prop->revert(p, states);
505 }
506}
507
508namespace {
509
510QColor sumValue(const QColor &c1, const QColor &c2)
511{
512 QRgb rgb1 = c1.rgba();
513 QRgb rgb2 = c2.rgba();
514 int sumRed = qRed(rgb1) + qRed(rgb2);
515 int sumGreen = qGreen(rgb1) + qGreen(rgb2);
516 int sumBlue = qBlue(rgb1) + qBlue(rgb2);
517
518 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
519 qBound(0, sumGreen, 255),
520 qBound(0, sumBlue, 255),
521 255);
522
523 return QColor(sumRgb);
524}
525
526qreal sumValue(qreal value1, qreal value2)
527{
528 qreal sumValue = value1 + value2;
529 return qBound(0.0, sumValue, 1.0);
530}
531
532}
533
534QSvgAnimatedStyle::QSvgAnimatedStyle()
535{
536}
537
538QSvgAnimatedStyle::~QSvgAnimatedStyle()
539{
540}
541
542void QSvgAnimatedStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
543{
544 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
545 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
546
547 savePaintingState(p, node, states);
548 if (nodeAnims.isEmpty())
549 return;
550
551 QSvgStyleState currentStyle = m_static;
552 for (const QSvgAbstractAnimation *anim : std::as_const(nodeAnims)) {
553 if (!anim->isActive())
554 continue;
555
556 fetchStyleState(anim, currentStyle);
557 }
558
559 applyStyle(p, states, currentStyle);
560}
561
562void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
563{
564 p->setWorldTransform(m_worldTransform);
565 p->setBrush(m_static.fill);
566 p->setPen(m_static.stroke);
567 p->setOpacity(m_static.opacity);
568 states.fillOpacity = m_static.fillOpacity;
569 states.strokeOpacity = m_static.strokeOpacity;
570}
571
572void QSvgAnimatedStyle::savePaintingState(const QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
573{
574 m_worldTransform = p->worldTransform();
575 if (auto prop = node->style().property(QSvgStyleProperty::Transform))
576 m_static.transform = (static_cast<QSvgTransformStyle*>(prop))->qtransform();
577
578 if (auto prop = node->style().property(QSvgStyleProperty::Offset)) {
579 QSvgOffsetStyle *offset = static_cast<QSvgOffsetStyle*>(prop);
580 m_static.offsetPath = offset->path();
581 m_static.offsetRotateType = offset->rotateType();
582 m_static.offsetRotate = offset->rotateAngle();
583 }
584
585 m_static.fill = p->brush();
586 m_static.stroke = p->pen();
587 m_static.fillOpacity = states.fillOpacity;
588 m_static.strokeOpacity = states.strokeOpacity;
589 m_static.opacity = p->opacity();
590 m_transformToNode = m_static.transform.inverted() * m_worldTransform;
591}
592
593void QSvgAnimatedStyle::fetchStyleState(const QSvgAbstractAnimation *animation, QSvgStyleState &currentStyle)
594{
595 bool replace = animation->animationType() == QSvgAbstractAnimation::CSS ? true :
596 (static_cast<const QSvgAnimateNode *>(animation))->additiveType() == QSvgAnimateNode::Replace;
597
598 QList<QSvgAbstractAnimatedProperty *> properties = animation->properties();
599 for (const QSvgAbstractAnimatedProperty *property : std::as_const(properties)) {
600 if (property->propertyName() == QStringLiteral("fill")) {
601 QBrush brush = currentStyle.fill;
602 QColor brushColor = brush.color();
603 QColor animatedColor = property->interpolatedValue().value<QColor>();
604 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(brushColor, animatedColor);
605 brush.setColor(sumOrReplaceColor);
606 currentStyle.fill = brush;
607 } else if (property->propertyName() == QStringLiteral("stroke")) {
608 QPen &pen = currentStyle.stroke;
609 QBrush penBrush = pen.brush();
610 QColor penColor = penBrush.color();
611 QColor animatedColor = property->interpolatedValue().value<QColor>();
612 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(penColor, animatedColor);
613 penBrush.setColor(sumOrReplaceColor);
614 penBrush.setStyle(Qt::SolidPattern);
615 pen.setBrush(penBrush);
616 } else if (property->propertyName() == QStringLiteral("transform")) {
617 QTransform animatedTransform = property->interpolatedValue().value<QTransform>();
618 QTransform sumOrReplaceTransform = replace ? animatedTransform : animatedTransform * currentStyle.transform;
619 currentStyle.transform = sumOrReplaceTransform;
620 } else if (property->propertyName() == QStringLiteral("fill-opacity")) {
621 qreal animatedFillOpacity = property->interpolatedValue().value<qreal>();
622 qreal sumOrReplaceOpacity = replace ? animatedFillOpacity : sumValue(currentStyle.fillOpacity, animatedFillOpacity);
623 currentStyle.fillOpacity = sumOrReplaceOpacity;
624 } else if (property->propertyName() == QStringLiteral("stroke-opacity")) {
625 qreal animatedStrokeOpacity = property->interpolatedValue().value<qreal>();
626 qreal sumOrReplaceOpacity = replace ? animatedStrokeOpacity : sumValue(currentStyle.strokeOpacity, animatedStrokeOpacity);
627 currentStyle.strokeOpacity = sumOrReplaceOpacity;
628 } else if (property->propertyName() == QStringLiteral("opacity")) {
629 qreal animatedOpacity = property->interpolatedValue().value<qreal>();
630 qreal sumOrReplaceOpacity = replace ? animatedOpacity : sumValue(currentStyle.opacity, animatedOpacity);
631 currentStyle.opacity = sumOrReplaceOpacity;
632 } else if (property->propertyName() == QStringLiteral("offset-distance")) {
633 qreal offsetDistance = property->interpolatedValue().value<qreal>();
634 currentStyle.offsetDistance = offsetDistance;
635 }
636 }
637}
638
639void QSvgAnimatedStyle::applyStyle(QPainter *p, QSvgExtraStates &states, const QSvgStyleState &currentStyle)
640{
641 p->setBrush(currentStyle.fill);
642 states.fillOpacity = currentStyle.fillOpacity;
643 p->setPen(currentStyle.stroke);
644 states.strokeOpacity = currentStyle.strokeOpacity;
645 p->setOpacity(currentStyle.opacity);
646
647 QTransform transform = currentStyle.transform;
648 QTransform offset;
649 if (m_static.offsetPath) {
650 qreal offsetDistance = currentStyle.offsetDistance;
651 qreal angle = m_static.offsetPath.value().angleAtPercent(offsetDistance);
652 QPointF position = m_static.offsetPath.value().pointAtPercent(offsetDistance);
653 offset.translate(position.x(), position.y());
654
655 switch (m_static.offsetRotateType) {
656 case QtSvg::OffsetRotateType::Auto:
657 offset.rotate(-angle);
658 break;
659 case QtSvg::OffsetRotateType::Angle:
660 offset.rotate(m_static.offsetRotate);
661 break;
662 case QtSvg::OffsetRotateType::AutoAngle:
663 offset.rotate(m_static.offsetRotate - angle);
664 break;
665 case QtSvg::OffsetRotateType::Reverse:
666 offset.rotate(180 - angle);
667 break;
668 case QtSvg::OffsetRotateType::ReverseAngle:
669 offset.rotate(180 + m_static.offsetRotate - angle);
670 break;
671 }
672 }
673
674 QTransform combinedTransform = transform * offset * m_transformToNode;
675 p->setWorldTransform(combinedTransform);
676}
677
678QT_END_NAMESPACE
Combined button and popup list for selecting options.
#define QStringLiteral(str)
Definition qstring.h:1825