7#include <QtCore/qmap.h>
13#include <qfontmetrics.h>
15#include <qimagereader.h>
16#include <qtextformat.h>
18#include <QtCore/q20algorithm.h>
20#ifndef QT_NO_CSSPARSER
24using namespace Qt::StringLiterals;
26QT_IMPL_METATYPE_EXTERN_TAGGED(QCss::BackgroundData, QCss__BackgroundData)
27QT_IMPL_METATYPE_EXTERN_TAGGED(QCss::LengthData, QCss__LengthData)
28QT_IMPL_METATYPE_EXTERN_TAGGED(QCss::BorderData, QCss__BorderData)
45 {
return std::string_view{lhs.name} < std::string_view{rhs.name}; }
47#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 1000
48# define NOT_OLD_GCCs(...) __VA_ARGS__
50# define NOT_OLD_GCCs(...)
52#define CHECK_ARRAY_IS_SORTED(array)
54 static_assert(q20::is_sorted(std::begin(array), std::end(array),
55 QCssKnownValue::ByName{}));
275 0, 46, 54, 47, 55, 56, 63, 38, 29, 83, 84, 28, 48, 7, 76, 52,
276 32, 68, 69, 30, 58, 74, 8, 12, 43, 65, 21, 15, 19, 20, 22, 24, 57, 27, 51, 80, 40, 4, 3, 45, 75, 18, 13,
277 66, 16, 35, 77, 36, 78, 64, 79, 37, 67, 23, 59, 42, 6, 60, 70, 82, 10, 31, 41, 14, 39, 71, 9, 11, 5, 81,
278 62, 25, 26, 33, 34, 2, 44, 72, 73, 53, 0, 17, 1, 61, 50, 49 };
280static_assert(std::size(indexOfId) == std::size(values) + 1);
285 return QLatin1StringView(values[indexOfId[variant.toInt()]].name);
287 return variant.toString();
292 {
"active", PseudoClass_Active },
293 {
"adjoins-item", PseudoClass_Item },
294 {
"alternate", PseudoClass_Alternate },
295 {
"bottom", PseudoClass_Bottom },
296 {
"checked", PseudoClass_Checked },
297 {
"closable", PseudoClass_Closable },
298 {
"closed", PseudoClass_Closed },
299 {
"default", PseudoClass_Default },
300 {
"disabled", PseudoClass_Disabled },
301 {
"edit-focus", PseudoClass_EditFocus },
302 {
"editable", PseudoClass_Editable },
303 {
"enabled", PseudoClass_Enabled },
304 {
"exclusive", PseudoClass_Exclusive },
305 {
"first", PseudoClass_First },
306 {
"flat", PseudoClass_Flat },
307 {
"floatable", PseudoClass_Floatable },
308 {
"focus", PseudoClass_Focus },
309 {
"has-children", PseudoClass_Children },
310 {
"has-siblings", PseudoClass_Sibling },
311 {
"horizontal", PseudoClass_Horizontal },
312 {
"hover", PseudoClass_Hover },
313 {
"indeterminate" , PseudoClass_Indeterminate },
314 {
"last", PseudoClass_Last },
315 {
"left", PseudoClass_Left },
316 {
"maximized", PseudoClass_Maximized },
317 {
"middle", PseudoClass_Middle },
318 {
"minimized", PseudoClass_Minimized },
319 {
"movable", PseudoClass_Movable },
320 {
"next-selected", PseudoClass_NextSelected },
321 {
"no-frame", PseudoClass_Frameless },
322 {
"non-exclusive", PseudoClass_NonExclusive },
323 {
"off", PseudoClass_Unchecked },
324 {
"on", PseudoClass_Checked },
325 {
"only-one", PseudoClass_OnlyOne },
326 {
"open", PseudoClass_Open },
327 {
"pressed", PseudoClass_Pressed },
328 {
"previous-selected", PseudoClass_PreviousSelected },
329 {
"read-only", PseudoClass_ReadOnly },
330 {
"right", PseudoClass_Right },
331 {
"selected", PseudoClass_Selected },
332 {
"top", PseudoClass_Top },
333 {
"unchecked" , PseudoClass_Unchecked },
334 {
"vertical", PseudoClass_Vertical },
335 {
"window", PseudoClass_Window }
385 return QString::compare(name, QLatin1StringView(prop.name), Qt::CaseInsensitive) < 0;
390 return QString::compare(QLatin1StringView(prop.name), name, Qt::CaseInsensitive) < 0;
393#undef CHECK_ARRAY_IS_SORTED
399 const QCssKnownValue *prop = std::lower_bound(std::begin(arr), std::end(arr), name);
400 if ((prop == std::end(arr)) || (name < *prop))
407 switch (propertyId) {
433ValueExtractor::ValueExtractor(
const QList<Declaration> &decls,
const QPalette &pal)
434: declarations(decls), adjustment(0), fontExtracted(
false), pal(pal)
438LengthData ValueExtractor::lengthValue(
const Value& v)
440 const QString str = v.variant.toString();
443 data.unit = LengthData::None;
444 if (s.endsWith(u"px", Qt::CaseInsensitive))
445 data.unit = LengthData::Px;
446 else if (s.endsWith(u"ex", Qt::CaseInsensitive))
447 data.unit = LengthData::Ex;
448 else if (s.endsWith(u"em", Qt::CaseInsensitive))
449 data.unit = LengthData::Em;
451 if (data.unit != LengthData::None)
453 else if (v.type == Value::Percentage)
454 data.unit = LengthData::Percent;
456 data.number = s.toDouble();
462 const int scale = (data.unit ==
LengthData::Ex ? QFontMetrics(f).xHeight()
465 return qRound(qBound(
double(INT_MIN) + 0.1, scale * data.number,
double(INT_MAX)));
468QTextLength ValueExtractor::textLength(
const Declaration &decl)
470 const LengthData data = lengthValue(decl.d->values.at(0));
471 if (data.unit == LengthData::Percent)
472 return QTextLength(QTextLength::PercentageLength, data.number);
474 return QTextLength(QTextLength::FixedLength, lengthValueFromData(data, f));
477int ValueExtractor::lengthValue(
const Declaration &decl)
479 if (decl.d->parsed.isValid())
480 return lengthValueFromData(qvariant_cast<LengthData>(decl.d->parsed), f);
481 if (decl.d->values.size() < 1)
483 LengthData data = lengthValue(decl.d->values.at(0));
484 decl.d->parsed = QVariant::fromValue<LengthData>(data);
485 return lengthValueFromData(data,f);
488void ValueExtractor::lengthValues(
const Declaration &decl,
int *m)
490 if (decl.d->parsed.isValid()) {
491 QList<QVariant> v = decl.d->parsed.toList();
492 Q_ASSERT(v.size() == 4);
493 for (
int i = 0; i < 4; i++)
494 m[i] = lengthValueFromData(qvariant_cast<LengthData>(v.at(i)), f);
500 for (i = 0; i < qMin(decl.d->values.size(), 4); i++)
501 datas[i] = lengthValue(decl.d->values[i]);
504 LengthData zero = {0.0, LengthData::None};
505 datas[0] = datas[1] = datas[2] = datas[3] = zero;
507 datas[3] = datas[2] = datas[1] = datas[0];
517 for (i = 0; i < 4; i++) {
518 v += QVariant::fromValue<LengthData>(datas[i]);
519 m[i] = lengthValueFromData(datas[i], f);
521 decl.d->parsed = std::move(v);
524bool ValueExtractor::extractGeometry(
int *w,
int *h,
int *minw,
int *minh,
int *maxw,
int *maxh)
528 for (
const Declaration &decl : std::as_const(declarations)) {
529 switch (decl.d->propertyId) {
530 case Width: *w = lengthValue(decl);
break;
531 case Height: *h = lengthValue(decl);
break;
532 case MinimumWidth: *minw = lengthValue(decl);
break;
533 case MinimumHeight: *minh = lengthValue(decl);
break;
534 case MaximumWidth: *maxw = lengthValue(decl);
break;
535 case MaximumHeight: *maxh = lengthValue(decl);
break;
544bool ValueExtractor::extractPosition(
int *left,
int *top,
int *right,
int *bottom, QCss::Origin *origin,
545 Qt::Alignment *position, QCss::PositionMode *mode, Qt::Alignment *textAlignment)
549 for (
const Declaration &decl : std::as_const(declarations)) {
550 switch (decl.d->propertyId) {
551 case Left: *left = lengthValue(decl);
break;
552 case Top: *top = lengthValue(decl);
break;
553 case Right: *right = lengthValue(decl);
break;
554 case Bottom: *bottom = lengthValue(decl);
break;
555 case QtOrigin: *origin = decl.originValue();
break;
556 case QtPosition: *position = decl.alignmentValue();
break;
557 case TextAlignment: *textAlignment = decl.alignmentValue();
break;
558 case Position: *mode = decl.positionValue();
break;
567bool ValueExtractor::extractBox(
int *margins,
int *paddings,
int *spacing)
571 for (
const Declaration &decl : std::as_const(declarations)) {
572 switch (decl.d->propertyId) {
573 case PaddingLeft: paddings[LeftEdge] = lengthValue(decl);
break;
574 case PaddingRight: paddings[RightEdge] = lengthValue(decl);
break;
575 case PaddingTop: paddings[TopEdge] = lengthValue(decl);
break;
576 case PaddingBottom: paddings[BottomEdge] = lengthValue(decl);
break;
577 case Padding: lengthValues(decl, paddings);
break;
579 case MarginLeft: margins[LeftEdge] = lengthValue(decl);
break;
580 case MarginRight: margins[RightEdge] = lengthValue(decl);
break;
581 case MarginTop: margins[TopEdge] = lengthValue(decl);
break;
582 case MarginBottom: margins[BottomEdge] = lengthValue(decl);
break;
583 case Margin: lengthValues(decl, margins);
break;
584 case QtSpacing:
if (spacing) *spacing = lengthValue(decl);
break;
594int ValueExtractor::extractStyleFeatures()
const
596 int features = StyleFeature_None;
597 for (
const Declaration &decl : declarations) {
598 if (decl.d->propertyId == QtStyleFeatures)
599 features = decl.styleFeaturesValue();
604QSize ValueExtractor::sizeValue(
const Declaration &decl)
606 if (decl.d->parsed.isValid()) {
607 QList<QVariant> v = decl.d->parsed.toList();
608 return QSize(lengthValueFromData(qvariant_cast<LengthData>(v.at(0)), f),
609 lengthValueFromData(qvariant_cast<LengthData>(v.at(1)), f));
612 LengthData x[2] = { {0, LengthData::None }, {0, LengthData::None} };
613 if (decl.d->values.size() > 0)
614 x[0] = lengthValue(decl.d->values.at(0));
615 if (decl.d->values.size() > 1)
616 x[1] = lengthValue(decl.d->values.at(1));
620 v << QVariant::fromValue<LengthData>(x[0]) << QVariant::fromValue<LengthData>(x[1]);
621 decl.d->parsed = std::move(v);
622 return QSize(lengthValueFromData(x[0], f), lengthValueFromData(x[1], f));
625void ValueExtractor::sizeValues(
const Declaration &decl, QSize *radii)
627 radii[0] = sizeValue(decl);
628 for (
int i = 1; i < 4; i++)
632bool ValueExtractor::extractBorder(
int *borders, QBrush *colors, BorderStyle *styles,
637 for (
const Declaration &decl : std::as_const(declarations)) {
638 switch (decl.d->propertyId) {
639 case BorderLeftWidth: borders[LeftEdge] = lengthValue(decl);
break;
640 case BorderRightWidth: borders[RightEdge] = lengthValue(decl);
break;
641 case BorderTopWidth: borders[TopEdge] = lengthValue(decl);
break;
642 case BorderBottomWidth: borders[BottomEdge] = lengthValue(decl);
break;
643 case BorderWidth: lengthValues(decl, borders);
break;
645 case BorderLeftColor: colors[LeftEdge] = decl.brushValue(pal);
break;
646 case BorderRightColor: colors[RightEdge] = decl.brushValue(pal);
break;
647 case BorderTopColor: colors[TopEdge] = decl.brushValue(pal);
break;
648 case BorderBottomColor: colors[BottomEdge] = decl.brushValue(pal);
break;
649 case BorderColor: decl.brushValues(colors, pal);
break;
651 case BorderTopStyle: styles[TopEdge] = decl.styleValue();
break;
652 case BorderBottomStyle: styles[BottomEdge] = decl.styleValue();
break;
653 case BorderLeftStyle: styles[LeftEdge] = decl.styleValue();
break;
654 case BorderRightStyle: styles[RightEdge] = decl.styleValue();
break;
655 case BorderStyles: decl.styleValues(styles);
break;
657 case BorderTopLeftRadius: radii[0] = sizeValue(decl);
break;
658 case BorderTopRightRadius: radii[1] = sizeValue(decl);
break;
659 case BorderBottomLeftRadius: radii[2] = sizeValue(decl);
break;
660 case BorderBottomRightRadius: radii[3] = sizeValue(decl);
break;
661 case BorderRadius: sizeValues(decl, radii);
break;
664 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
667 borderValue(decl, &borders[TopEdge], &styles[TopEdge], &colors[TopEdge]);
670 borderValue(decl, &borders[RightEdge], &styles[RightEdge], &colors[RightEdge]);
673 borderValue(decl, &borders[BottomEdge], &styles[BottomEdge], &colors[BottomEdge]);
676 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
677 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
678 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
679 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
690bool ValueExtractor::extractOutline(
int *borders, QBrush *colors, BorderStyle *styles,
691 QSize *radii,
int *offsets)
695 for (
const Declaration &decl : std::as_const(declarations)) {
696 switch (decl.d->propertyId) {
697 case OutlineWidth: lengthValues(decl, borders);
break;
698 case OutlineColor: decl.brushValues(colors, pal);
break;
699 case OutlineStyle: decl.styleValues(styles);
break;
701 case OutlineTopLeftRadius: radii[0] = sizeValue(decl);
break;
702 case OutlineTopRightRadius: radii[1] = sizeValue(decl);
break;
703 case OutlineBottomLeftRadius: radii[2] = sizeValue(decl);
break;
704 case OutlineBottomRightRadius: radii[3] = sizeValue(decl);
break;
705 case OutlineRadius: sizeValues(decl, radii);
break;
706 case OutlineOffset: lengthValues(decl, offsets);
break;
709 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
710 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
711 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
712 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
725 Qt::Alignment a[2] = { { }, { } };
726 for (
int i = 0; i < qMin(2, count); i++) {
729 switch (values[i].variant.toInt()) {
730 case Value_Left: a[i] = Qt::AlignLeft;
break;
731 case Value_Right: a[i] = Qt::AlignRight;
break;
732 case Value_Top: a[i] = Qt::AlignTop;
break;
733 case Value_Bottom: a[i] = Qt::AlignBottom;
break;
734 case Value_Center: a[i] = Qt::AlignCenter;
break;
739 if (a[0] == Qt::AlignCenter && a[1] != 0 && a[1] != Qt::AlignCenter)
740 a[0] = (a[1] == Qt::AlignLeft || a[1] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
741 if ((a[1] == 0 || a[1] == Qt::AlignCenter) && a[0] != Qt::AlignCenter)
742 a[1] = (a[0] == Qt::AlignLeft || a[0] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
749 v.variant.convert(QMetaType::fromType<QColor>());
754 return qvariant_cast<QColor>(v.variant);
756 if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent)
757 return QColor(Qt::transparent);
762 QStringList lst = v.variant.toStringList();
766 const QString &identifier = lst.at(0);
767 if ((identifier.compare(
"palette"_L1, Qt::CaseInsensitive)) == 0) {
768 static_assert((Value_LastColorRole - Value_FirstColorRole + 1) == QPalette::ColorRole::NColorRoles);
770 int role = findKnownValue(lst.at(1).trimmed(),
values);
771 if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
772 return (QPalette::ColorRole)(role-Value_FirstColorRole);
777 const bool rgb = identifier.startsWith(
"rgb"_L1);
778 const bool hsv = !rgb && identifier.startsWith(
"hsv"_L1);
779 const bool hsl = !rgb && !hsv && identifier.startsWith(
"hsl"_L1);
781 if (!rgb && !hsv && !hsl)
784 const bool hasAlpha = identifier.size() == 4 && identifier.at(3) == u'a';
785 if (identifier.size() > 3 && !hasAlpha)
792 QList<QCss::Value> colorDigits;
793 if (!p.parseExpr(&colorDigits))
795 const int tokenCount = colorDigits.size();
797 for (
int i = 0; i < qMin(tokenCount, 7); i += 2) {
799 const qreal maxRange = (rgb || i != 0) ? 255. : 359.;
800 colorDigits[i].variant = colorDigits.at(i).variant.toReal() * (maxRange / 100.);
811 if (hasAlpha && tokenCount != 7) {
812 qWarning(
"QCssParser::parseColorValue: Specified color with alpha value but no alpha given: '%s'", qPrintable(lst.join(u' ')));
815 if (!hasAlpha && tokenCount != 5) {
816 qWarning(
"QCssParser::parseColorValue: Specified color without alpha value but alpha given: '%s'", qPrintable(lst.join(u' ')));
820 int v1 = colorDigits.at(0).variant.toInt();
821 int v2 = colorDigits.at(2).variant.toInt();
822 int v3 = colorDigits.at(4).variant.toInt();
824 if (tokenCount == 7) {
825 int alphaValue = colorDigits.at(6).variant.toInt();
827 alpha = colorDigits.at(6).variant.toReal() * 255.;
833 return QColor::fromRgb(v1, v2, v3, alpha);
835 return QColor::fromHsv(v1, v2, v3, alpha);
836 return QColor::fromHsl(v1, v2, v3, alpha);
844 return pal.color(c.role);
853 return QBrush(c.color);
861 QStringList lst = v.variant.toStringList();
865 QStringList gradFuncs;
866 gradFuncs <<
"qlineargradient"_L1 <<
"qradialgradient"_L1 <<
"qconicalgradient"_L1 <<
"qgradient"_L1;
869 if ((gradType = gradFuncs.indexOf(lst.at(0).toLower())) == -1)
872 QHash<QString, qreal> vars;
873 QList<QGradientStop> stops;
877 spreads <<
"pad"_L1 <<
"reflect"_L1 <<
"repeat"_L1;
879 int coordinateMode = -1;
880 QStringList coordinateModes;
881 coordinateModes <<
"logical"_L1 <<
"stretchtodevice"_L1 <<
"objectbounding"_L1 <<
"object"_L1;
883 bool dependsOnThePalette =
false;
885 while (parser.hasNext()) {
887 if (!parser.test(IDENT))
889 QString attr = parser.lexem();
891 if (!parser.test(COLON))
894 if (attr.compare(
"stop"_L1, Qt::CaseInsensitive) == 0) {
903 dependsOnThePalette =
true;
904 stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal)));
908 (
void)parser.parseTerm(&value);
909 if (attr.compare(
"spread"_L1, Qt::CaseInsensitive) == 0)
910 spread = spreads.indexOf(value.variant.toString());
911 else if (attr.compare(
"coordinatemode"_L1, Qt::CaseInsensitive) == 0)
912 coordinateMode = coordinateModes.indexOf(value.variant.toString());
914 vars[attr] = value.variant.toReal();
917 (
void)parser.test(COMMA);
922 vars.value(
"x2"_L1), vars.value(
"y2"_L1));
923 lg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
926 lg.setSpread(QGradient::Spread(spread));
928 if (dependsOnThePalette)
935 vars.value(
"radius"_L1), vars.value(
"fx"_L1),
936 vars.value(
"fy"_L1));
937 rg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
940 rg.setSpread(QGradient::Spread(spread));
942 if (dependsOnThePalette)
948 QConicalGradient cg(vars.value(
"cx"_L1), vars.value(
"cy"_L1), vars.value(
"angle"_L1));
949 cg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
952 cg.setSpread(QGradient::Spread(spread));
954 if (dependsOnThePalette)
965 return pal.color(c.role);
974 switch (v.variant.toInt()) {
1007void ValueExtractor::borderValue(
const Declaration &decl,
int *width, QCss::BorderStyle *style, QBrush *color)
1009 if (decl.d->parsed.isValid()) {
1010 BorderData data = qvariant_cast<BorderData>(decl.d->parsed);
1011 *width = lengthValueFromData(data.width, f);
1012 *style = data.style;
1013 *color = data.color.type != BrushData::Invalid ? brushFromData(data.color, pal) : QBrush(QColor());
1018 *style = BorderStyle_None;
1021 if (decl.d->values.isEmpty())
1025 data.width.number = 0;
1026 data.width.unit = LengthData::None;
1027 data.style = BorderStyle_None;
1030 if (decl.d->values.at(i).type == Value::Length || decl.d->values.at(i).type == Value::Number) {
1031 data.width = lengthValue(decl.d->values.at(i));
1032 *width = lengthValueFromData(data.width, f);
1033 if (++i >= decl.d->values.size()) {
1034 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1039 data.style = parseStyleValue(decl.d->values.at(i));
1040 if (data.style != BorderStyle_Unknown) {
1041 *style = data.style;
1042 if (++i >= decl.d->values.size()) {
1043 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1047 data.style = BorderStyle_None;
1050 data.color = parseBrushValue(decl.d->values.at(i), pal);
1051 if (data.color.type != BrushData::Invalid) {
1052 *color = brushFromData(data.color, pal);
1053 if (data.color.type != BrushData::DependsOnThePalette)
1054 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1063 *alignment = Qt::AlignTop | Qt::AlignLeft;
1065 for (qsizetype i = 0; i < values.size(); ++i) {
1068 *image = v.variant.toString();
1074 *brush = QBrush(Qt::transparent);
1077 Repeat repeatAttempt =
static_cast<
Repeat>(findKnownValue(v.variant.toString(),
1080 *repeat = repeatAttempt;
1085 const int start = i;
1087 if (i < values.size() - 1
1092 Qt::Alignment a = parseAlignment(values.constData() + start, count);
1100 *brush = parseBrushValue(v, pal);
1104bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *repeat,
1105 Qt::Alignment *alignment, Origin *origin, Attachment *attachment,
1109 for (
const Declaration &decl : declarations) {
1110 if (decl.d->values.isEmpty())
1112 const QCss::Value &val = decl.d->values.at(0);
1113 switch (decl.d->propertyId) {
1114 case BackgroundColor:
1115 *brush = decl.brushValue();
1117 case BackgroundImage:
1118 if (val.type == Value::Uri)
1119 *image = val.variant.toString();
1121 case BackgroundRepeat:
1122 if (decl.d->parsed.isValid()) {
1123 *repeat =
static_cast<Repeat>(decl.d->parsed.toInt());
1125 *repeat =
static_cast<Repeat>(findKnownValue(val.variant.toString(),
1127 decl.d->parsed = *repeat;
1130 case BackgroundPosition:
1131 *alignment = decl.alignmentValue();
1133 case BackgroundOrigin:
1134 *origin = decl.originValue();
1136 case BackgroundClip:
1137 *clip = decl.originValue();
1140 if (decl.d->parsed.isValid()) {
1141 BackgroundData data = qvariant_cast<BackgroundData>(decl.d->parsed);
1142 *brush = brushFromData(data.brush, pal);
1143 *image = data.image;
1144 *repeat = data.repeat;
1145 *alignment = data.alignment;
1147 BrushData brushData;
1148 parseShorthandBackgroundProperty(decl.d->values, &brushData, image, repeat, alignment, pal);
1149 *brush = brushFromData(brushData, pal);
1150 if (brushData.type != BrushData::DependsOnThePalette) {
1151 BackgroundData data = { brushData, *image, *repeat, *alignment };
1152 decl.d->parsed = QVariant::fromValue<BackgroundData>(data);
1156 case BackgroundAttachment:
1157 *attachment = decl.attachmentValue();
1170 switch (value.variant.toInt()) {
1171 case Value_Small: *fontSizeAdjustment = -1;
break;
1176 default: valid =
false;
break;
1184 QString s = value.variant.toString();
1185 if (s.endsWith(
"pt"_L1, Qt::CaseInsensitive)) {
1187 value.variant = std::move(s);
1188 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1189 font->setPointSizeF(qBound(qreal(0), value.variant.toReal(), qreal(1 << 24) - 1));
1192 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1194 value.variant = std::move(s);
1195 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1196 font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
1207 switch (value.variant.toInt()) {
1208 case Value_Normal: font->setStyle(QFont::StyleNormal);
return true;
1209 case Value_Italic: font->setStyle(QFont::StyleItalic);
return true;
1210 case Value_Oblique: font->setStyle(QFont::StyleOblique);
return true;
1220 switch (value.variant.toInt()) {
1221 case Value_Normal: font->setKerning(
true);
return true;
1222 case Value_None: font->setKerning(
false);
return true;
1232 switch (value.variant.toInt()) {
1233 case Value_Normal: font->setWeight(QFont::Normal);
return true;
1234 case Value_Bold: font->setWeight(QFont::Bold);
return true;
1242 font->setWeight(QFont::Weight(qRound(qBound(0.0, value.variant.toDouble(), 1001.0))));
1247
1248
1249
1250
1254 QStringList families;
1255 bool shouldAddSpace =
false;
1256 for (qsizetype i = start; i < values.size(); ++i) {
1261 shouldAddSpace =
false;
1264 const QString str = v.variant.toString();
1270 shouldAddSpace =
true;
1272 if (!family.isEmpty())
1274 if (families.isEmpty())
1276 font->setFamilies(families);
1282 for (
const QCss::Value &value : values) {
1283 if (value.type != Value::KnownIdentifier)
1285 switch (value.variant.toInt()) {
1286 case Value_Underline: font->setUnderline(
true);
break;
1287 case Value_Overline: font->setOverline(
true);
break;
1288 case Value_LineThrough: font->setStrikeOut(
true);
break;
1290 font->setUnderline(
false);
1291 font->setOverline(
false);
1292 font->setStrikeOut(
false);
1301 QString s = value.variant.toString();
1304 if (s.endsWith(
"em"_L1, Qt::CaseInsensitive)) {
1306 val = s.toDouble(&ok);
1308 font->setLetterSpacing(QFont::PercentageSpacing, (val + 1.0) * 100);
1309 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1311 val = s.toDouble(&ok);
1313 font->setLetterSpacing(QFont::AbsoluteSpacing, val);
1319 QString s = value.variant.toString();
1320 if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1324 val = s.toDouble(&ok);
1326 font->setWordSpacing(val);
1332 font->setStyle(QFont::StyleNormal);
1333 font->setWeight(QFont::Normal);
1334 *fontSizeAdjustment = -255;
1337 while (i < values.size()) {
1338 if (setFontStyleFromValue(values.at(i), font)
1339 || setFontWeightFromValue(values.at(i), font))
1345 if (i < values.size()) {
1346 setFontSizeFromValue(values.at(i), font, fontSizeAdjustment);
1350 if (i < values.size()) {
1351 setFontFamilyFromValues(values, font, i);
1358 switch (value.variant.toInt()) {
1359 case Value_Normal: font->setCapitalization(QFont::MixedCase);
break;
1360 case Value_SmallCaps: font->setCapitalization(QFont::SmallCaps);
break;
1369 switch (value.variant.toInt()) {
1370 case Value_None: font->setCapitalization(QFont::MixedCase);
break;
1371 case Value_Uppercase: font->setCapitalization(QFont::AllUppercase);
break;
1372 case Value_Lowercase: font->setCapitalization(QFont::AllLowercase);
break;
1378bool ValueExtractor::extractFont(QFont *font,
int *fontSizeAdjustment)
1380 if (fontExtracted) {
1382 *fontSizeAdjustment = adjustment;
1383 return fontExtracted == 1;
1387 for (
const Declaration &decl : std::as_const(declarations)) {
1388 if (decl.d->values.isEmpty())
1390 const QCss::Value &val = decl.d->values.at(0);
1391 switch (decl.d->propertyId) {
1392 case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment);
break;
1393 case FontStyle: setFontStyleFromValue(val, font);
break;
1394 case FontWeight: setFontWeightFromValue(val, font);
break;
1395 case FontFamily: setFontFamilyFromValues(decl.d->values, font);
break;
1396 case FontKerning: setFontKerningFromValue(val, font);
break;
1397 case TextDecoration: setTextDecorationFromValues(decl.d->values, font);
break;
1398 case Font: parseShorthandFontProperty(decl.d->values, font, fontSizeAdjustment);
break;
1399 case FontVariant: setFontVariantFromValue(val, font);
break;
1400 case TextTransform: setTextTransformFromValue(val, font);
break;
1401 case LetterSpacing: setLetterSpacingFromValue(val, font);
break;
1402 case WordSpacing: setWordSpacingFromValue(val, font);
break;
1409 adjustment = *fontSizeAdjustment;
1410 fontExtracted = hit ? 1 : 2;
1414bool ValueExtractor::extractPalette(QBrush *foreground,
1415 QBrush *selectedForeground,
1416 QBrush *selectedBackground,
1417 QBrush *alternateBackground,
1418 QBrush *placeHolderTextForeground,
1419 QBrush *accent)
const
1422 for (
const Declaration &decl : declarations) {
1423 switch (decl.d->propertyId) {
1424 case Color: *foreground = decl.brushValue(pal);
break;
1425 case QtSelectionForeground: *selectedForeground = decl.brushValue(pal);
break;
1426 case QtSelectionBackground: *selectedBackground = decl.brushValue(pal);
break;
1427 case QtAlternateBackground: *alternateBackground = decl.brushValue(pal);
break;
1428 case QtPlaceHolderTextColor: *placeHolderTextForeground = decl.brushValue(pal);
break;
1429 case QtAccent: *accent = decl.brushValue(pal);
break;
1437void ValueExtractor::extractFont()
1442 extractFont(&f, &dummy);
1445bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size)
const
1448 for (
const Declaration &decl : declarations) {
1449 switch (decl.d->propertyId) {
1451 *icon = decl.iconValue();
1452 if (decl.d->values.size() > 0 && decl.d->values.at(0).type == Value::Uri) {
1454 QImageReader imageReader(decl.d->values.at(0).variant.toString());
1455 if ((*size = imageReader.size()).isNull()) {
1458 *size = imageReader.read().size();
1462 case QtImageAlignment: *a = decl.alignmentValue();
break;
1470bool ValueExtractor::extractIcon(QIcon *icon, QSize *size)
const
1473 const auto declaration = std::find_if(
1474 declarations.rbegin(), declarations.rend(),
1475 [](
const Declaration &decl) {
return decl.d->propertyId == QtIcon; });
1476 if (declaration == declarations.rend())
1479 *icon = declaration->iconValue();
1482 if (declaration->d->values.isEmpty())
1485 const auto &propertyValue = declaration->d->values.constFirst();
1486 if (propertyValue.type != Value::Uri)
1490 const QString url(propertyValue.variant.toString());
1491 QImageReader imageReader(url);
1492 *size = imageReader.size();
1493 if (!size->isNull())
1497 *size = imageReader.read().size();
1503QColor Declaration::colorValue(
const QPalette &pal)
const
1505 if (d->values.size() != 1)
1508 if (d->parsed.isValid()) {
1509 switch (d->parsed.typeId()) {
1510 case qMetaTypeId<QColor>():
1511 return qvariant_cast<QColor>(d->parsed);
1512 case qMetaTypeId<
int>():
1513 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1514 case qMetaTypeId<QList<QVariant>>():
1515 if (d->parsed.toList().size() == 1) {
1516 auto parsedList = d->parsed.toList();
1517 const auto &value = parsedList.at(0);
1518 return qvariant_cast<QColor>(value);
1524 ColorData color = parseColorValue(d->values.at(0));
1525 if (color.type == ColorData::Role) {
1526 d->parsed = QVariant::fromValue<
int>(color.role);
1527 return pal.color((QPalette::ColorRole)(color.role));
1529 d->parsed = QVariant::fromValue<QColor>(color.color);
1534QBrush Declaration::brushValue(
const QPalette &pal)
const
1536 if (d->values.size() != 1)
1539 if (d->parsed.isValid()) {
1540 if (d->parsed.userType() == QMetaType::QBrush)
1541 return qvariant_cast<QBrush>(d->parsed);
1542 if (d->parsed.userType() == QMetaType::Int)
1543 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1546 BrushData data = parseBrushValue(d->values.at(0), pal);
1548 if (data.type == BrushData::Role) {
1549 d->parsed = QVariant::fromValue<
int>(data.role);
1550 return pal.color((QPalette::ColorRole)(data.role));
1552 if (data.type != BrushData::DependsOnThePalette)
1553 d->parsed = QVariant::fromValue<QBrush>(data.brush);
1558void Declaration::brushValues(QBrush *c,
const QPalette &pal)
const
1560 int needParse = 0x1f;
1563 if (d->parsed.isValid()) {
1565 Q_ASSERT(d->parsed.metaType() == QMetaType::fromType<QList<QVariant>>());
1566 QList<QVariant> v = d->parsed.toList();
1567 for (i = 0; i < qMin(v.size(), 4); i++) {
1568 if (v.at(i).userType() == QMetaType::QBrush) {
1569 c[i] = qvariant_cast<QBrush>(v.at(i));
1570 }
else if (v.at(i).userType() == QMetaType::Int) {
1571 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1573 needParse |= (1<<i);
1577 if (needParse != 0) {
1579 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1580 if (!(needParse & (1<<i)))
1582 BrushData data = parseBrushValue(d->values.at(i), pal);
1583 if (data.type == BrushData::Role) {
1584 v += QVariant::fromValue<
int>(data.role);
1585 c[i] = pal.color((QPalette::ColorRole)(data.role));
1587 if (data.type != BrushData::DependsOnThePalette) {
1588 v += QVariant::fromValue<QBrush>(data.brush);
1595 if (needParse & 0x10)
1596 d->parsed = std::move(v);
1598 if (i == 0) c[0] = c[1] = c[2] = c[3] = QBrush();
1599 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1600 else if (i == 2) c[2] = c[0], c[3] = c[1];
1601 else if (i == 3) c[3] = c[1];
1604bool Declaration::realValue(qreal *real,
const char *unit)
const
1606 if (d->values.size() != 1)
1608 const Value &v = d->values.at(0);
1609 if (unit && v.type != Value::Length)
1611 const QString str = v.variant.toString();
1614 const QLatin1StringView unitStr(unit);
1615 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1617 s.chop(unitStr.size());
1620 qreal val = s.toDouble(&ok);
1630 const QString str = v.variant.toString();
1633 const QLatin1StringView unitStr(unit);
1634 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1636 s.chop(unitStr.size());
1639 int val = s.toInt(&ok);
1645bool Declaration::intValue(
int *i,
const char *unit)
const
1647 if (d->values.size() != 1)
1649 return intValueHelper(d->values.at(0), i, unit);
1652QSize Declaration::sizeValue()
const
1654 if (d->parsed.isValid())
1655 return qvariant_cast<QSize>(d->parsed);
1657 int x[2] = { 0, 0 };
1658 const qsizetype count = d->values.size();
1659 for (qsizetype i = 0; i < count; ++i) {
1661 qWarning(
"QCssParser::sizeValue: Too many values provided");
1664 const auto &value = d->values.at(i);
1665 const QString valueString = value.variant.toString();
1666 if (valueString.endsWith(u"pt", Qt::CaseInsensitive)) {
1667 intValueHelper(value, &x[i],
"pt");
1670 x[i] = (x[i] * 72) / 96;
1673 intValueHelper(value, &x[i],
"px");
1678 QSize size(x[0], x[1]);
1679 d->parsed = QVariant::fromValue<QSize>(size);
1683QRect Declaration::rectValue()
const
1685 if (d->values.size() != 1)
1688 if (d->parsed.isValid())
1689 return qvariant_cast<QRect>(d->parsed);
1691 const QCss::Value &v = d->values.at(0);
1692 if (v.type != Value::Function)
1694 const QStringList func = v.variant.toStringList();
1695 if (func.size() != 2 || func.at(0).compare(
"rect"_L1) != 0)
1697 const auto args = QStringView{func[1]}.split(u' ', Qt::SkipEmptyParts);
1698 if (args.size() != 4)
1700 QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
1701 d->parsed = QVariant::fromValue<QRect>(rect);
1705void Declaration::colorValues(QColor *c,
const QPalette &pal)
const
1708 if (d->parsed.isValid()) {
1709 QList<QVariant> v = d->parsed.toList();
1710 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1711 if (v.at(i).userType() == QMetaType::QColor) {
1712 c[i] = qvariant_cast<QColor>(v.at(i));
1714 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1719 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1720 ColorData color = parseColorValue(d->values.at(i));
1721 if (color.type == ColorData::Role) {
1722 v += QVariant::fromValue<
int>(color.role);
1723 c[i] = pal.color((QPalette::ColorRole)(color.role));
1725 v += QVariant::fromValue<QColor>(color.color);
1729 d->parsed = std::move(v);
1732 if (i == 0) c[0] = c[1] = c[2] = c[3] = QColor();
1733 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1734 else if (i == 2) c[2] = c[0], c[3] = c[1];
1735 else if (i == 3) c[3] = c[1];
1738BorderStyle Declaration::styleValue()
const
1740 if (d->values.size() != 1)
1741 return BorderStyle_None;
1742 return parseStyleValue(d->values.at(0));
1745void Declaration::styleValues(BorderStyle *s)
const
1748 for (i = 0; i < qMin(d->values.size(), 4); i++)
1749 s[i] = parseStyleValue(d->values.at(i));
1750 if (i == 0) s[0] = s[1] = s[2] = s[3] = BorderStyle_None;
1751 else if (i == 1) s[3] = s[2] = s[1] = s[0];
1752 else if (i == 2) s[2] = s[0], s[3] = s[1];
1753 else if (i == 3) s[3] = s[1];
1756Repeat Declaration::repeatValue()
const
1758 if (d->parsed.isValid())
1759 return static_cast<Repeat>(d->parsed.toInt());
1760 if (d->values.size() != 1)
1761 return Repeat_Unknown;
1762 int v = findKnownValue(d->values.at(0).variant.toString(),
1765 return static_cast<Repeat>(v);
1768Origin Declaration::originValue()
const
1770 if (d->parsed.isValid())
1771 return static_cast<Origin>(d->parsed.toInt());
1772 if (d->values.size() != 1)
1773 return Origin_Unknown;
1774 int v = findKnownValue(d->values.at(0).variant.toString(),
1777 return static_cast<Origin>(v);
1780PositionMode Declaration::positionValue()
const
1782 if (d->parsed.isValid())
1783 return static_cast<PositionMode>(d->parsed.toInt());
1784 if (d->values.size() != 1)
1785 return PositionMode_Unknown;
1786 int v = findKnownValue(d->values.at(0).variant.toString(),
1789 return static_cast<PositionMode>(v);
1792Attachment Declaration::attachmentValue()
const
1794 if (d->parsed.isValid())
1795 return static_cast<Attachment>(d->parsed.toInt());
1796 if (d->values.size() != 1)
1797 return Attachment_Unknown;
1798 int v = findKnownValue(d->values.at(0).variant.toString(),
1801 return static_cast<Attachment>(v);
1804int Declaration::styleFeaturesValue()
const
1806 Q_ASSERT(d->propertyId == QtStyleFeatures);
1807 if (d->parsed.isValid())
1808 return d->parsed.toInt();
1809 int features = StyleFeature_None;
1810 for (
const Value &value : std::as_const(d->values)) {
1811 features |=
static_cast<
int>(findKnownValue(value.variant.toString(),
1814 d->parsed = features;
1818QString Declaration::uriValue()
const
1820 if (d->values.isEmpty() || d->values.at(0).type != Value::Uri)
1822 return d->values.at(0).variant.toString();
1825Qt::Alignment Declaration::alignmentValue()
const
1827 if (d->parsed.isValid())
1828 return Qt::Alignment(d->parsed.toInt());
1829 if (d->values.isEmpty() || d->values.size() > 2)
1830 return Qt::AlignLeft | Qt::AlignTop;
1832 Qt::Alignment v = parseAlignment(d->values.constData(), d->values.size());
1837void Declaration::borderImageValue(QString *image,
int *cuts,
1838 TileMode *h, TileMode *v)
const
1840 const DeclarationData *d =
this->d.data();
1841 *image = uriValue();
1842 for (
int i = 0; i < 4; i++)
1844 *h = *v = TileMode_Stretch;
1846 if (d->values.size() < 2)
1849 if (d->values.at(1).type == Value::Number) {
1851 for (i = 0; i < qMin(d->values.size()-1, 4); i++) {
1852 const Value& v = d->values.at(i+1);
1853 if (v.type != Value::Number)
1855 cuts[i] = v.variant.toString().toInt();
1857 qWarning(
"Declaration::borderImageValue: Invalid cut value %d at position %d",
1859 cuts[0] = cuts[1] = cuts[2] = cuts[3] = -1;
1864 if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
1865 else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];
1866 else if (i == 2) cuts[2] = cuts[0], cuts[3] = cuts[1];
1867 else if (i == 3) cuts[3] = cuts[1];
1870 if (d->values.last().type == Value::Identifier) {
1871 *v =
static_cast<TileMode>(findKnownValue(d->values.last().variant.toString(),
1874 if (d->values[d->values.size() - 2].type == Value::Identifier) {
1875 *h =
static_cast<TileMode>
1876 (findKnownValue(d->values[d->values.size()-2].variant.toString(),
1882bool Declaration::borderCollapseValue()
const
1884 if (d->values.size() != 1)
1887 return d->values.at(0).toString() ==
"collapse"_L1;
1890QList<qreal> Declaration::dashArray()
const
1892 if (d->propertyId != Property::QtStrokeDashArray || d->values.empty())
1893 return QList<qreal>();
1895 bool isValid =
true;
1896 QList<qreal> dashes;
1897 for (qsizetype i = 0; i < d->values.size(); i++) {
1898 const Value &v = d->values[i];
1900 bool isValidSeparator = (i & 1) && v.type == Value::TermOperatorComma;
1901 bool isValidNumber = !(i & 1) && v.type == Value::Number;
1902 if (!isValidNumber && !isValidSeparator) {
1905 }
else if (isValidNumber) {
1907 dashes.append(v.variant.toReal(&ok));
1915 isValid &= !(dashes.size() & 1);
1916 return isValid ? dashes : QList<qreal>();
1919QIcon Declaration::iconValue()
const
1921 if (d->parsed.isValid())
1922 return qvariant_cast<QIcon>(d->parsed);
1925 for (qsizetype i = 0; i < d->values.size();) {
1926 const Value &value = d->values.at(i++);
1927 if (value.type != Value::Uri)
1929 QString uri = value.variant.toString();
1930 QIcon::Mode mode = QIcon::Normal;
1931 QIcon::State state = QIcon::Off;
1932 for (
int j = 0; j < 2; j++) {
1933 if (i != d->values.size() && d->values.at(i).type == Value::KnownIdentifier) {
1934 switch (d->values.at(i).variant.toInt()) {
1935 case Value_Disabled: mode = QIcon::Disabled;
break;
1936 case Value_Active: mode = QIcon::Active;
break;
1937 case Value_Selected: mode = QIcon::Selected;
break;
1938 case Value_Normal: mode = QIcon::Normal;
break;
1939 case Value_On: state = QIcon::On;
break;
1940 case Value_Off: state = QIcon::Off;
break;
1953 icon.addPixmap(uri, mode, state);
1955 if (i == d->values.size())
1958 if (d->values.at(i).type == Value::TermOperatorComma)
1962 d->parsed = QVariant::fromValue<QIcon>(icon);
1968int Selector::specificity()
const
1971 for (
const BasicSelector &sel : basicSelectors) {
1972 if (!sel.elementName.isEmpty())
1975 val += (sel.pseudos.size() + sel.attributeSelectors.size()) * 0x10;
1976 val += sel.ids.size() * 0x100;
1981QString Selector::pseudoElement()
const
1983 const BasicSelector& bs = basicSelectors.last();
1984 if (!bs.pseudos.isEmpty() && bs.pseudos.at(0).type == PseudoClass_Unknown)
1985 return bs.pseudos.at(0).name;
1989quint64 Selector::pseudoClass(quint64 *negated)
const
1991 const BasicSelector& bs = basicSelectors.last();
1992 if (bs.pseudos.isEmpty())
1993 return PseudoClass_Unspecified;
1994 quint64 pc = PseudoClass_Unknown;
1995 for (
int i = !pseudoElement().isEmpty(); i < bs.pseudos.size(); i++) {
1996 const Pseudo &pseudo = bs.pseudos.at(i);
1997 if (pseudo.type == PseudoClass_Unknown)
1998 return PseudoClass_Unknown;
1999 if (!pseudo.negated)
2002 *negated |= pseudo.type;
2011 QList<StyleRule> universals;
2012 for (qsizetype i = 0; i < styleRules.size(); ++i) {
2013 const StyleRule &rule = styleRules.at(i);
2014 QList<Selector> universalsSelectors;
2015 for (
const Selector &selector : rule.selectors) {
2017 if (selector.basicSelectors.isEmpty())
2020 if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
2021 if (selector.basicSelectors.size() != 1)
2023 }
else if (selector.basicSelectors.size() <= 1) {
2027 const BasicSelector &sel = selector.basicSelectors.at(selector.basicSelectors.size() - 1);
2029 if (!sel.ids.isEmpty()) {
2031 nr.selectors += selector;
2032 nr.declarations = rule.declarations;
2034 idIndex.insert(sel.ids.at(0), nr);
2035 }
else if (!sel.elementName.isEmpty()) {
2037 nr.selectors += selector;
2038 nr.declarations = rule.declarations;
2040 QString name = sel.elementName;
2041 if (nameCaseSensitivity == Qt::CaseInsensitive)
2042 name = std::move(name).toLower();
2043 nameIndex.insert(name, nr);
2045 universalsSelectors += selector;
2048 if (!universalsSelectors.isEmpty()) {
2050 nr.selectors = universalsSelectors;
2051 nr.declarations = rule.declarations;
2056 styleRules = universals;
2061StyleSelector::~StyleSelector()
2065bool StyleSelector::nodeNameEquals(NodePtr node,
const QString& nodeName)
const
2067 return nodeNames(node).contains(nodeName, nameCaseSensitivity);
2070QStringList StyleSelector::nodeIds(NodePtr node)
const
2072 return QStringList(attributeValue(node, QCss::AttributeSelector{
"id"_L1, {}, AttributeSelector::NoMatch}));
2075bool StyleSelector::selectorMatches(
const Selector &selector, NodePtr node)
const
2077 if (selector.basicSelectors.isEmpty())
2080 if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
2081 if (selector.basicSelectors.size() != 1)
2083 return basicSelectorMatches(selector.basicSelectors.at(0), node);
2085 if (selector.basicSelectors.size() <= 1)
2088 qsizetype i = selector.basicSelectors.size() - 1;
2089 node = duplicateNode(node);
2092 BasicSelector sel = selector.basicSelectors.at(i);
2094 match = basicSelectorMatches(sel, node);
2096 if (i == selector.basicSelectors.size() - 1)
2098 if (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2099 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent)
2103 if (match || (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2104 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent))
2110 sel = selector.basicSelectors.at(i);
2111 if (sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2112 || sel.relationToNext == BasicSelector::MatchNextSelectorIfParent) {
2114 NodePtr nextParent = parentNode(node);
2117 }
else if (sel.relationToNext == BasicSelector::MatchNextSelectorIfDirectAdjecent
2118 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent) {
2119 NodePtr previousSibling = previousSiblingNode(node);
2121 node = previousSibling;
2123 if (isNullNode(node)) {
2127 }
while (i >= 0 && (match || sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2128 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent));
2135bool StyleSelector::basicSelectorMatches(
const BasicSelector &sel, NodePtr node)
const
2137 if (!sel.attributeSelectors.isEmpty()) {
2138 if (!hasAttributes(node))
2141 for (
const QCss::AttributeSelector &a : sel.attributeSelectors) {
2143 const QString attrValue = attributeValue(node, a);
2144 if (attrValue.isNull())
2147 switch (a.valueMatchCriterium) {
2148 case QCss::AttributeSelector::NoMatch:
2150 case QCss::AttributeSelector::MatchEqual:
2151 if (attrValue != a.value)
2154 case QCss::AttributeSelector::MatchIncludes: {
2155 const auto lst = QStringView{attrValue}.tokenize(u' ');
2157 for (
auto s : lst) {
2167 case QCss::AttributeSelector::MatchDashMatch: {
2168 const QString dashPrefix = a.value + u'-';
2169 if (attrValue != a.value && !attrValue.startsWith(dashPrefix))
2173 case QCss::AttributeSelector::MatchBeginsWith:
2174 if (!attrValue.startsWith(a.value))
2177 case QCss::AttributeSelector::MatchEndsWith:
2178 if (!attrValue.endsWith(a.value))
2181 case QCss::AttributeSelector::MatchContains:
2182 if (!attrValue.contains(a.value))
2189 if (!sel.elementName.isEmpty()
2190 && !nodeNameEquals(node, sel.elementName))
2193 if (!sel.ids.isEmpty()
2194 && sel.ids != nodeIds(node))
2200void StyleSelector::matchRule(NodePtr node,
const StyleRule &rule, StyleSheetOrigin origin,
2201 int depth, std::multimap<uint64_t, StyleRule> *weightedRules)
const
2203 for (
const Selector &selector : rule.selectors) {
2204 if (selectorMatches(selector, node)) {
2205 if (uint32_t(rule.order) >= 0x100000ULL)
2206 qWarning(
"StyleSelector: rule order is to large - style sheet"
2207 "must not contain more than 0x100000 entries");
2208 if (uint32_t(selector.specificity()) >= 0x100000ULL)
2209 qWarning(
"StyleSelector: selector specifity is to large - "
2210 "style sheet must not contain more than 0x100000 selectors "
2212 const uint64_t weight = rule.order
2213 + selector.specificity() * 0x100000ULL
2214 + (uint(origin) + depth) * 0x10000000000ULL;
2215 StyleRule newRule = rule;
2216 if (rule.selectors.size() > 1)
2217 newRule.selectors.push_back(selector);
2220 weightedRules->emplace(weight, std::move(newRule));
2227QList<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
2229 QList<StyleRule> rules;
2230 if (styleSheets.isEmpty())
2233 std::multimap<uint64_t, StyleRule> weightedRules;
2236 for (
const StyleSheet &styleSheet : std::as_const(styleSheets)) {
2237 for (
const StyleRule &styleRule : styleSheet.styleRules)
2238 matchRule(node, styleRule, styleSheet.origin, styleSheet.depth, &weightedRules);
2240 if (!styleSheet.idIndex.isEmpty()) {
2241 const QStringList ids = nodeIds(node);
2242 for (
const QString &key : ids) {
2243 auto it = styleSheet.idIndex.constFind(key);
2244 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
2245 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2250 if (!styleSheet.nameIndex.isEmpty()) {
2251 const QStringList names = nodeNames(node);
2252 for (QString name : names) {
2253 if (nameCaseSensitivity == Qt::CaseInsensitive)
2254 name = std::move(name).toLower();
2255 auto it = styleSheet.nameIndex.constFind(name);
2256 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
2257 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2262 if (!medium.isEmpty()) {
2263 for (
const MediaRule &mediaRule : styleSheet.mediaRules) {
2264 if (mediaRule.media.contains(medium, Qt::CaseInsensitive)) {
2265 for (
const StyleRule &styleRule : mediaRule.styleRules) {
2266 matchRule(node, styleRule, styleSheet.origin,
2267 styleSheet.depth, &weightedRules);
2274 rules.reserve(weightedRules.size());
2275 for (
const auto &weigthedRule : weightedRules)
2276 rules.push_back(std::move(weigthedRule.second));
2283QList<Declaration> StyleSelector::declarationsForNode(NodePtr node,
const char *extraPseudo)
2285 QList<Declaration> decls;
2286 const QList<StyleRule> rules = styleRulesForNode(node);
2287 for (
const StyleRule &styleRule : rules) {
2288 const Selector &selector = styleRule.selectors.at(0);
2289 const QString pseudoElement = selector.pseudoElement();
2291 if (extraPseudo && pseudoElement == QLatin1StringView(extraPseudo)) {
2292 decls += styleRule.declarations;
2296 if (!pseudoElement.isEmpty())
2298 quint64 pseudoClass = selector.pseudoClass();
2299 if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
2300 decls += styleRule.declarations;
2307 return (c >=
'0' && c <=
'9')
2308 || (c >=
'a' && c <=
'f')
2309 || (c >=
'A' && c <=
'F')
2313QString Scanner::preprocess(
const QString &input,
bool *hasEscapeSequences)
2315 QString output = input;
2317 if (hasEscapeSequences)
2318 *hasEscapeSequences =
false;
2321 while (i < output.size()) {
2322 if (output.at(i) == u'\\') {
2327 const int hexStart = i;
2328 while (i < output.size()
2329 && isHexDigit(output.at(i).toLatin1())
2334 if (hexCount == 0) {
2335 if (hasEscapeSequences)
2336 *hasEscapeSequences =
true;
2340 hexCount = qMin(hexCount, 6);
2342 const char16_t code = QStringView{output}.mid(hexStart, hexCount).toUShort(&ok, 16);
2344 output.replace(hexStart - 1, hexCount + 1, code);
2356int QCssScanner_Generated::handleCommentStart()
2358 while (pos < input.size() - 1) {
2359 if (input.at(pos) == u'*' && input.at(pos + 1) == u'/') {
2368void Scanner::scan(
const QString &preprocessedInput, QList<Symbol> *symbols)
2370 QCssScanner_Generated scanner(preprocessedInput);
2372 int tok = scanner.lex();
2374 sym.token =
static_cast<QCss::TokenType>(tok);
2375 sym.text = scanner.input;
2376 sym.start = scanner.lexemStart;
2377 sym.len = scanner.lexemLength;
2378 symbols->append(sym);
2379 tok = scanner.lex();
2387 result.reserve(
len);
2388 for (
int i = 0; i <
len; ++i) {
2389 if (text.at(start + i) == u'\\' && i < len - 1)
2391 result += text.at(start + i);
2396Parser::Parser(
const QString &css,
bool isFile)
2405 hasEscapeSequences =
false;
2408void Parser::init(
const QString &css,
bool isFile)
2410 QString styleSheet = css;
2413 if (file.open(QFile::ReadOnly)) {
2414 sourcePath = QFileInfo(styleSheet).absolutePath() + u'/';
2415 QTextStream stream(&file);
2416 styleSheet = stream.readAll();
2418 qWarning() <<
"QCss::Parser - Failed to load file " << css;
2425 hasEscapeSequences =
false;
2428 Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
2433bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
2435 if (testTokenAndEndsWith(ATKEYWORD_SYM,
"charset"_L1)) {
2436 while (test(S) || test(CDO) || test(CDC)) {}
2437 if (!next(STRING))
return false;
2438 if (!next(SEMICOLON))
return false;
2441 while (test(S) || test(CDO) || test(CDC)) {}
2443 while (testImport()) {
2445 if (!parseImport(&rule))
return false;
2446 styleSheet->importRules.append(rule);
2447 while (test(S) || test(CDO) || test(CDC)) {}
2453 if (!parseMedia(&rule))
return false;
2454 styleSheet->mediaRules.append(rule);
2455 }
else if (testPage()) {
2457 if (!parsePage(&rule))
return false;
2458 styleSheet->pageRules.append(rule);
2459 }
else if (testAnimation()) {
2461 if (!parseAnimation(&rule))
return false;
2462 styleSheet->animationRules.append(rule);
2463 }
else if (testRuleset()) {
2465 if (!parseRuleset(&rule))
return false;
2466 styleSheet->styleRules.append(rule);
2467 }
else if (test(ATKEYWORD_SYM)) {
2468 if (!until(RBRACE))
return false;
2469 }
else if (hasNext()) {
2472 while (test(S) || test(CDO) || test(CDC)) {}
2473 }
while (hasNext());
2474 styleSheet->buildIndexes(nameCaseSensitivity);
2478Symbol Parser::errorSymbol()
2480 if (errorIndex == -1)
return Symbol();
2481 return symbols.at(errorIndex);
2486 if (!str->startsWith(u'\'') && !str->startsWith(u'\"'))
2492bool Parser::parseImport(ImportRule *importRule)
2497 importRule->href = lexem();
2499 if (!testAndParseUri(&importRule->href))
return false;
2501 removeOptionalQuotes(&importRule->href);
2506 if (!parseMedium(&importRule->media))
return false;
2508 while (test(COMMA)) {
2510 if (!parseNextMedium(&importRule->media))
return false;
2514 if (!next(SEMICOLON))
return false;
2520bool Parser::parseMedia(MediaRule *mediaRule)
2524 if (!parseNextMedium(&mediaRule->media))
return false;
2525 }
while (test(COMMA));
2527 if (!next(LBRACE))
return false;
2530 while (testRuleset()) {
2532 if (!parseRuleset(&rule))
return false;
2533 mediaRule->styleRules.append(rule);
2536 if (!next(RBRACE))
return false;
2541bool Parser::parseMedium(QStringList *media)
2543 media->append(lexem());
2548bool Parser::parsePage(PageRule *pageRule)
2552 if (testPseudoPage())
2553 if (!parsePseudoPage(&pageRule->selector))
return false;
2556 if (!next(LBRACE))
return false;
2561 if (!parseNextDeclaration(&decl))
return false;
2562 if (!decl.isEmpty())
2563 pageRule->declarations.append(decl);
2564 }
while (test(SEMICOLON));
2566 if (!next(RBRACE))
return false;
2571bool Parser::parsePseudoPage(QString *selector)
2573 if (!next(IDENT))
return false;
2574 *selector = lexem();
2578bool Parser::parseNextOperator(Value *value)
2580 if (!hasNext())
return true;
2582 case SLASH: value->type = Value::TermOperatorSlash; skipSpace();
break;
2583 case COMMA: value->type = Value::TermOperatorComma; skipSpace();
break;
2584 default: prev();
break;
2589bool Parser::parseAnimation(AnimationRule *animationRule)
2592 if (!test(IDENT))
return false;
2594 animationRule->animName = lexem();
2596 if (!next(LBRACE))
return false;
2599 while (test(PERCENTAGE) || test(IDENT)) {
2600 AnimationRule::AnimationRuleSet set;
2601 if (lookup() == PERCENTAGE) {
2602 QString name = lexem();
2604 float keyFrame = name.toFloat() / 100;
2605 set.keyFrame = keyFrame;
2606 }
else if (lookup() == IDENT) {
2608 if (parseElementName(&name)) {
2609 if (name == QStringLiteral(
"from"))
2611 else if (name == QStringLiteral(
"to"))
2617 if (!next(LBRACE))
return false;
2618 const int declarationStart = index;
2623 const int rewind = index;
2624 if (!parseNextDeclaration(&decl)) {
2626 const bool foundSemicolon = until(SEMICOLON);
2627 const int semicolonIndex = index;
2629 index = declarationStart;
2630 const bool foundRBrace = until(RBRACE);
2632 if (foundSemicolon && semicolonIndex < index) {
2633 decl = Declaration();
2634 index = semicolonIndex - 1;
2640 if (!decl.isEmpty()) {
2641 if (decl.d->property ==
"animation-timing-function"_L1)
2642 set.timingFunction = std::move(decl);
2644 set.declarations.push_back(std::move(decl));
2646 }
while (test(SEMICOLON));
2648 if (!next(RBRACE))
return false;
2650 animationRule->ruleSets.append(set);
2653 if (!next(RBRACE))
return false;
2659bool Parser::parseCombinator(BasicSelector::Relation *relation)
2661 *relation = BasicSelector::NoRelation;
2662 if (lookup() == S) {
2663 *relation = BasicSelector::MatchNextSelectorIfAncestor;
2669 *relation = BasicSelector::MatchNextSelectorIfDirectAdjecent;
2670 }
else if (test(GREATER)) {
2671 *relation = BasicSelector::MatchNextSelectorIfParent;
2672 }
else if (test(TILDE)) {
2673 *relation = BasicSelector::MatchNextSelectorIfIndirectAdjecent;
2679bool Parser::parseProperty(Declaration *decl)
2681 decl->d->property = lexem();
2682 decl->d->propertyId =
static_cast<Property>(findKnownValue(decl->d->property, properties));
2683 decl->d->inheritable = isInheritable(decl->d->propertyId);
2688bool Parser::parseRuleset(StyleRule *styleRule)
2691 if (!parseSelector(&sel))
return false;
2692 styleRule->selectors.append(sel);
2694 while (test(COMMA)) {
2697 if (!parseNextSelector(&sel))
return false;
2698 styleRule->selectors.append(sel);
2702 if (!next(LBRACE))
return false;
2703 const int declarationStart = index;
2708 const int rewind = index;
2709 if (!parseNextDeclaration(&decl)) {
2711 const bool foundSemicolon = until(SEMICOLON);
2712 const int semicolonIndex = index;
2714 index = declarationStart;
2715 const bool foundRBrace = until(RBRACE);
2717 if (foundSemicolon && semicolonIndex < index) {
2718 decl = Declaration();
2719 index = semicolonIndex - 1;
2725 if (!decl.isEmpty())
2726 styleRule->declarations.append(decl);
2727 }
while (test(SEMICOLON));
2729 if (!next(RBRACE))
return false;
2734bool Parser::parseSelector(Selector *sel)
2736 BasicSelector basicSel;
2737 if (!parseSimpleSelector(&basicSel))
return false;
2738 while (testCombinator()) {
2739 if (!parseCombinator(&basicSel.relationToNext))
return false;
2741 if (!testSimpleSelector())
break;
2742 sel->basicSelectors.append(basicSel);
2744 basicSel = BasicSelector();
2745 if (!parseSimpleSelector(&basicSel))
return false;
2747 sel->basicSelectors.append(basicSel);
2751bool Parser::parseSimpleSelector(BasicSelector *basicSel)
2754 if (lookupElementName()) {
2755 if (!parseElementName(&basicSel->elementName))
return false;
2765 QString theid = lexem();
2768 basicSel->ids.append(theid);
2770 }
else if (testClass()) {
2772 AttributeSelector a;
2773 a.name =
"class"_L1;
2774 a.valueMatchCriterium = AttributeSelector::MatchIncludes;
2775 if (!parseClass(&a.value))
return false;
2776 basicSel->attributeSelectors.append(a);
2777 }
else if (testAttrib()) {
2779 AttributeSelector a;
2780 if (!parseAttrib(&a))
return false;
2781 basicSel->attributeSelectors.append(a);
2782 }
else if (testPseudo()) {
2785 if (!parsePseudo(&ps))
return false;
2786 basicSel->pseudos.append(ps);
2788 if (onceMore) ++count;
2790 return count >= minCount;
2793bool Parser::parseClass(QString *name)
2795 if (!next(IDENT))
return false;
2800bool Parser::parseElementName(QString *name)
2803 case STAR: name->clear();
break;
2804 case IDENT: *name = lexem();
break;
2805 default:
return false;
2810bool Parser::parseAttrib(AttributeSelector *attr)
2813 if (!next(IDENT))
return false;
2814 attr->name = lexem();
2818 attr->valueMatchCriterium = AttributeSelector::MatchEqual;
2819 }
else if (test(INCLUDES)) {
2820 attr->valueMatchCriterium = AttributeSelector::MatchIncludes;
2821 }
else if (test(DASHMATCH)) {
2822 attr->valueMatchCriterium = AttributeSelector::MatchDashMatch;
2823 }
else if (test(BEGINSWITH)) {
2824 attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
2825 }
else if (test(ENDSWITH)) {
2826 attr->valueMatchCriterium = AttributeSelector::MatchEndsWith;
2827 }
else if (test(CONTAINS)) {
2828 attr->valueMatchCriterium = AttributeSelector::MatchContains;
2830 return next(RBRACKET);
2835 if (!test(IDENT) && !test(STRING))
return false;
2836 attr->value = unquotedLexem();
2839 return next(RBRACKET);
2842bool Parser::parsePseudo(Pseudo *pseudo)
2845 pseudo->negated = test(EXCLAMATION_SYM);
2847 pseudo->name = lexem();
2848 pseudo->type =
static_cast<quint64>(findKnownValue(pseudo->name, pseudos));
2851 if (!next(FUNCTION))
return false;
2852 pseudo->function = lexem();
2854 pseudo->function.chop(1);
2856 if (!test(IDENT))
return false;
2857 pseudo->name = lexem();
2859 return next(RPAREN);
2862bool Parser::parseNextDeclaration(Declaration *decl)
2864 if (!testProperty())
2866 if (!parseProperty(decl))
return false;
2867 if (!next(COLON))
return false;
2869 if (!parseNextExpr(&decl->d->values))
return false;
2871 if (!parsePrio(decl))
return false;
2875bool Parser::testPrio()
2877 const int rewind = index;
2878 if (!test(EXCLAMATION_SYM))
return false;
2884 if (lexem().compare(
"important"_L1, Qt::CaseInsensitive) != 0) {
2891bool Parser::parsePrio(Declaration *declaration)
2893 declaration->d->important =
true;
2898bool Parser::parseExpr(QList<Value> *values)
2901 if (!parseTerm(&val))
return false;
2902 values->append(val);
2907 if (!parseNextOperator(&val))
return false;
2908 if (val.type != QCss::Value::Unknown)
2909 values->append(val);
2913 if (!parseTerm(&val))
return false;
2914 values->append(val);
2920bool Parser::testTerm()
2922 return test(PLUS) || test(MINUS)
2932bool Parser::parseTerm(Value *value)
2934 QString str = lexem();
2935 bool haveUnary =
false;
2936 if (lookup() == PLUS || lookup() == MINUS) {
2938 if (!hasNext())
return false;
2943 value->variant = str;
2944 value->type = QCss::Value::String;
2947 value->type = Value::Number;
2948 value->variant.convert(QMetaType::fromType<
double>());
2951 value->type = Value::Percentage;
2953 value->variant = str;
2956 value->type = Value::Length;
2960 if (haveUnary)
return false;
2961 value->type = Value::String;
2964 value->variant = str;
2967 if (haveUnary)
return false;
2968 value->type = Value::Identifier;
2969 const int theid = findKnownValue(str, values);
2971 value->type = Value::KnownIdentifier;
2972 value->variant = theid;
2977 if (haveUnary)
return false;
2979 if (testHexColor()) {
2981 if (!parseHexColor(&col))
return false;
2982 value->type = Value::Color;
2983 value->variant = col;
2984 }
else if (testFunction()) {
2986 if (!parseFunction(&name, &args))
return false;
2987 if (name ==
"url"_L1) {
2988 value->type = Value::Uri;
2989 removeOptionalQuotes(&args);
2990 if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
2991 args.prepend(sourcePath);
2993 value->variant = std::move(args);
2995 value->type = Value::Function;
2996 value->variant = QStringList() << name << args;
2999 return recordError();
3008bool Parser::parseFunction(QString *name, QString *args)
3015 std::swap(start, index);
3016 if (!until(RPAREN))
return false;
3017 for (
int i = start; i < index - 1; ++i)
3018 args->append(symbols.at(i).lexem());
3020
3021
3022
3027bool Parser::parseHexColor(QColor *col)
3029 *col = QColor::fromString(lexem());
3030 if (!col->isValid()) {
3031 qWarning(
"QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
3038bool Parser::testAndParseUri(QString *uri)
3040 const int rewind = index;
3041 if (!testFunction())
return false;
3044 if (!parseFunction(&name, &args)) {
3048 if (name.compare(
"url"_L1, Qt::CaseInsensitive) != 0) {
3052 *uri = std::move(args);
3053 removeOptionalQuotes(uri);
3057bool Parser::testSimpleSelector()
3059 return testElementName()
3066bool Parser::next(QCss::TokenType t)
3068 if (hasNext() && next() == t)
3070 return recordError();
3073bool Parser::test(QCss::TokenType t)
3075 if (index >= symbols.size())
3077 if (symbols.at(index).token == t) {
3084QString Parser::unquotedLexem()
const
3086 QString s = lexem();
3087 if (lookup() == STRING) {
3094QString Parser::lexemUntil(QCss::TokenType t)
3097 while (hasNext() && next() != t)
3098 lexem += symbol().lexem();
3102bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
3108 switch(symbols.at(index-1).token) {
3109 case LBRACE: ++braceCount;
break;
3110 case LBRACKET: ++brackCount;
break;
3112 case LPAREN: ++parenCount;
break;
3116 while (index < symbols.size()) {
3117 QCss::TokenType t = symbols.at(index++).token;
3119 case LBRACE: ++braceCount;
break;
3120 case RBRACE: --braceCount;
break;
3121 case LBRACKET: ++brackCount;
break;
3122 case RBRACKET: --brackCount;
break;
3124 case LPAREN: ++parenCount;
break;
3125 case RPAREN: --parenCount;
break;
3128 if ((t == target || (target2 != NONE && t == target2))
3134 if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
3142bool Parser::testTokenAndEndsWith(QCss::TokenType t, QLatin1StringView str)
3144 if (!test(t))
return false;
3145 if (!lexem().endsWith(str, Qt::CaseInsensitive)) {
@ StyleFeature_BackgroundGradient
@ StyleFeature_BackgroundColor
@ OutlineBottomRightRadius
@ BorderBottomRightRadius
@ OutlineBottomLeftRadius
@ QtForegroundTextureCacheKey
Combined button and popup list for selecting options.
static void setTextDecorationFromValues(const QList< QCss::Value > &values, QFont *font)
static bool operator<(const QString &name, const QCssKnownValue &prop)
static constexpr QCssKnownValue positions[]
static void removeOptionalQuotes(QString *str)
static constexpr QCssKnownValue repeats[]
static bool setFontFamilyFromValues(const QList< QCss::Value > &values, QFont *font, int start=0)
static bool setFontWeightFromValue(const QCss::Value &value, QFont *font)
static int lengthValueFromData(const LengthData &data, const QFont &f)
static bool operator<(const QCssKnownValue &prop, const QString &name)
#define CHECK_ARRAY_IS_SORTED(array)
static void setTextTransformFromValue(const QCss::Value &value, QFont *font)
static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAdjustment)
static constexpr QCssKnownValue tileModes[]
static bool setFontStyleFromValue(const QCss::Value &value, QFont *font)
static ColorData parseColorValue(QCss::Value v)
static BorderStyle parseStyleValue(const QCss::Value &v)
static void setFontVariantFromValue(const QCss::Value &value, QFont *font)
static bool intValueHelper(const QCss::Value &v, int *i, const char *unit)
static Qt::Alignment parseAlignment(const QCss::Value *values, int count)
static constexpr QCssKnownValue styleFeatures[]
static constexpr QCssKnownValue properties[]
static void setLetterSpacingFromValue(const QCss::Value &value, QFont *font)
static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal)
static quint64 findKnownValue(const QString &name, const C &arr)
static bool isHexDigit(const char c)
static bool isInheritable(Property propertyId)
static constexpr uchar indexOfId[]
static constexpr QCssKnownValue pseudos[]
static bool setFontKerningFromValue(const QCss::Value &value, QFont *font)
static void parseShorthandBackgroundProperty(const QList< QCss::Value > &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal)
static constexpr QCssKnownValue attachments[]
static void parseShorthandFontProperty(const QList< QCss::Value > &values, QFont *font, int *fontSizeAdjustment)
static QBrush brushFromData(const BrushData &c, const QPalette &pal)
static void setWordSpacingFromValue(const QCss::Value &value, QFont *font)
static constexpr QCssKnownValue values[]
static constexpr QCssKnownValue origins[]
static QColor colorFromData(const ColorData &c, const QPalette &pal)
constexpr bool operator()(const QCssKnownValue &lhs, const QCssKnownValue &rhs) const noexcept
Q_GUI_EXPORT void buildIndexes(Qt::CaseSensitivity nameCaseSensitivity=Qt::CaseSensitive)