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, Num)
53 static_assert(std::size(array) == Num);
55 static_assert(q20::is_sorted(std::begin(array), std::end(array),
56 QCssKnownValue::ByName{}));
276 0, 46, 54, 47, 55, 56, 63, 38, 29, 83, 84, 28, 48, 7, 76, 52,
277 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,
278 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,
279 62, 25, 26, 33, 34, 2, 44, 72, 73, 53, 0, 17, 1, 61, 50, 49 };
281static_assert(std::size(indexOfId) == size_t(NumKnownValues));
286 return QLatin1StringView(values[indexOfId[variant.toInt()]].name);
288 return variant.toString();
293 {
"active", PseudoClass_Active },
294 {
"adjoins-item", PseudoClass_Item },
295 {
"alternate", PseudoClass_Alternate },
296 {
"bottom", PseudoClass_Bottom },
297 {
"checked", PseudoClass_Checked },
298 {
"closable", PseudoClass_Closable },
299 {
"closed", PseudoClass_Closed },
300 {
"default", PseudoClass_Default },
301 {
"disabled", PseudoClass_Disabled },
302 {
"edit-focus", PseudoClass_EditFocus },
303 {
"editable", PseudoClass_Editable },
304 {
"enabled", PseudoClass_Enabled },
305 {
"exclusive", PseudoClass_Exclusive },
306 {
"first", PseudoClass_First },
307 {
"flat", PseudoClass_Flat },
308 {
"floatable", PseudoClass_Floatable },
309 {
"focus", PseudoClass_Focus },
310 {
"has-children", PseudoClass_Children },
311 {
"has-siblings", PseudoClass_Sibling },
312 {
"horizontal", PseudoClass_Horizontal },
313 {
"hover", PseudoClass_Hover },
314 {
"indeterminate" , PseudoClass_Indeterminate },
315 {
"last", PseudoClass_Last },
316 {
"left", PseudoClass_Left },
317 {
"maximized", PseudoClass_Maximized },
318 {
"middle", PseudoClass_Middle },
319 {
"minimized", PseudoClass_Minimized },
320 {
"movable", PseudoClass_Movable },
321 {
"next-selected", PseudoClass_NextSelected },
322 {
"no-frame", PseudoClass_Frameless },
323 {
"non-exclusive", PseudoClass_NonExclusive },
324 {
"off", PseudoClass_Unchecked },
325 {
"on", PseudoClass_Checked },
326 {
"only-one", PseudoClass_OnlyOne },
327 {
"open", PseudoClass_Open },
328 {
"pressed", PseudoClass_Pressed },
329 {
"previous-selected", PseudoClass_PreviousSelected },
330 {
"read-only", PseudoClass_ReadOnly },
331 {
"right", PseudoClass_Right },
332 {
"selected", PseudoClass_Selected },
333 {
"top", PseudoClass_Top },
334 {
"unchecked" , PseudoClass_Unchecked },
335 {
"vertical", PseudoClass_Vertical },
336 {
"window", PseudoClass_Window }
386 return QString::compare(name, QLatin1StringView(prop.name), Qt::CaseInsensitive) < 0;
391 return QString::compare(QLatin1StringView(prop.name), name, Qt::CaseInsensitive) < 0;
394#undef CHECK_ARRAY_IS_SORTED
401 if ((prop == end) || (name
< *prop))
408 switch (propertyId) {
434ValueExtractor::ValueExtractor(
const QList<Declaration> &decls,
const QPalette &pal)
435: declarations(decls), adjustment(0), fontExtracted(
false), pal(pal)
439LengthData ValueExtractor::lengthValue(
const Value& v)
441 const QString str = v.variant.toString();
444 data.unit = LengthData::None;
445 if (s.endsWith(u"px", Qt::CaseInsensitive))
446 data.unit = LengthData::Px;
447 else if (s.endsWith(u"ex", Qt::CaseInsensitive))
448 data.unit = LengthData::Ex;
449 else if (s.endsWith(u"em", Qt::CaseInsensitive))
450 data.unit = LengthData::Em;
452 if (data.unit != LengthData::None)
454 else if (v.type == Value::Percentage)
455 data.unit = LengthData::Percent;
457 data.number = s.toDouble();
463 const int scale = (data.unit ==
LengthData::Ex ? QFontMetrics(f).xHeight()
466 return qRound(qBound(
double(INT_MIN) + 0.1, scale * data.number,
double(INT_MAX)));
469QTextLength ValueExtractor::textLength(
const Declaration &decl)
471 const LengthData data = lengthValue(decl.d->values.at(0));
472 if (data.unit == LengthData::Percent)
473 return QTextLength(QTextLength::PercentageLength, data.number);
475 return QTextLength(QTextLength::FixedLength, lengthValueFromData(data, f));
478int ValueExtractor::lengthValue(
const Declaration &decl)
480 if (decl.d->parsed.isValid())
481 return lengthValueFromData(qvariant_cast<LengthData>(decl.d->parsed), f);
482 if (decl.d->values.size() < 1)
484 LengthData data = lengthValue(decl.d->values.at(0));
485 decl.d->parsed = QVariant::fromValue<LengthData>(data);
486 return lengthValueFromData(data,f);
489void ValueExtractor::lengthValues(
const Declaration &decl,
int *m)
491 if (decl.d->parsed.isValid()) {
492 QList<QVariant> v = decl.d->parsed.toList();
493 Q_ASSERT(v.size() == 4);
494 for (
int i = 0; i < 4; i++)
495 m[i] = lengthValueFromData(qvariant_cast<LengthData>(v.at(i)), f);
501 for (i = 0; i < qMin(decl.d->values.size(), 4); i++)
502 datas[i] = lengthValue(decl.d->values[i]);
505 LengthData zero = {0.0, LengthData::None};
506 datas[0] = datas[1] = datas[2] = datas[3] = zero;
508 datas[3] = datas[2] = datas[1] = datas[0];
518 for (i = 0; i < 4; i++) {
519 v += QVariant::fromValue<LengthData>(datas[i]);
520 m[i] = lengthValueFromData(datas[i], f);
525bool ValueExtractor::extractGeometry(
int *w,
int *h,
int *minw,
int *minh,
int *maxw,
int *maxh)
529 for (
const Declaration &decl : std::as_const(declarations)) {
530 switch (decl.d->propertyId) {
531 case Width: *w = lengthValue(decl);
break;
532 case Height: *h = lengthValue(decl);
break;
533 case MinimumWidth: *minw = lengthValue(decl);
break;
534 case MinimumHeight: *minh = lengthValue(decl);
break;
535 case MaximumWidth: *maxw = lengthValue(decl);
break;
536 case MaximumHeight: *maxh = lengthValue(decl);
break;
545bool ValueExtractor::extractPosition(
int *left,
int *top,
int *right,
int *bottom, QCss::Origin *origin,
546 Qt::Alignment *position, QCss::PositionMode *mode, Qt::Alignment *textAlignment)
550 for (
const Declaration &decl : std::as_const(declarations)) {
551 switch (decl.d->propertyId) {
552 case Left: *left = lengthValue(decl);
break;
553 case Top: *top = lengthValue(decl);
break;
554 case Right: *right = lengthValue(decl);
break;
555 case Bottom: *bottom = lengthValue(decl);
break;
556 case QtOrigin: *origin = decl.originValue();
break;
557 case QtPosition: *position = decl.alignmentValue();
break;
558 case TextAlignment: *textAlignment = decl.alignmentValue();
break;
559 case Position: *mode = decl.positionValue();
break;
568bool ValueExtractor::extractBox(
int *margins,
int *paddings,
int *spacing)
572 for (
const Declaration &decl : std::as_const(declarations)) {
573 switch (decl.d->propertyId) {
574 case PaddingLeft: paddings[LeftEdge] = lengthValue(decl);
break;
575 case PaddingRight: paddings[RightEdge] = lengthValue(decl);
break;
576 case PaddingTop: paddings[TopEdge] = lengthValue(decl);
break;
577 case PaddingBottom: paddings[BottomEdge] = lengthValue(decl);
break;
578 case Padding: lengthValues(decl, paddings);
break;
580 case MarginLeft: margins[LeftEdge] = lengthValue(decl);
break;
581 case MarginRight: margins[RightEdge] = lengthValue(decl);
break;
582 case MarginTop: margins[TopEdge] = lengthValue(decl);
break;
583 case MarginBottom: margins[BottomEdge] = lengthValue(decl);
break;
584 case Margin: lengthValues(decl, margins);
break;
585 case QtSpacing:
if (spacing) *spacing = lengthValue(decl);
break;
595int ValueExtractor::extractStyleFeatures()
const
597 int features = StyleFeature_None;
598 for (
const Declaration &decl : declarations) {
599 if (decl.d->propertyId == QtStyleFeatures)
600 features = decl.styleFeaturesValue();
605QSize ValueExtractor::sizeValue(
const Declaration &decl)
607 if (decl.d->parsed.isValid()) {
608 QList<QVariant> v = decl.d->parsed.toList();
609 return QSize(lengthValueFromData(qvariant_cast<LengthData>(v.at(0)), f),
610 lengthValueFromData(qvariant_cast<LengthData>(v.at(1)), f));
613 LengthData x[2] = { {0, LengthData::None }, {0, LengthData::None} };
614 if (decl.d->values.size() > 0)
615 x[0] = lengthValue(decl.d->values.at(0));
616 if (decl.d->values.size() > 1)
617 x[1] = lengthValue(decl.d->values.at(1));
621 v << QVariant::fromValue<LengthData>(x[0]) << QVariant::fromValue<LengthData>(x[1]);
623 return QSize(lengthValueFromData(x[0], f), lengthValueFromData(x[1], f));
626void ValueExtractor::sizeValues(
const Declaration &decl, QSize *radii)
628 radii[0] = sizeValue(decl);
629 for (
int i = 1; i < 4; i++)
633bool ValueExtractor::extractBorder(
int *borders, QBrush *colors, BorderStyle *styles,
638 for (
const Declaration &decl : std::as_const(declarations)) {
639 switch (decl.d->propertyId) {
640 case BorderLeftWidth: borders[LeftEdge] = lengthValue(decl);
break;
641 case BorderRightWidth: borders[RightEdge] = lengthValue(decl);
break;
642 case BorderTopWidth: borders[TopEdge] = lengthValue(decl);
break;
643 case BorderBottomWidth: borders[BottomEdge] = lengthValue(decl);
break;
644 case BorderWidth: lengthValues(decl, borders);
break;
646 case BorderLeftColor: colors[LeftEdge] = decl.brushValue(pal);
break;
647 case BorderRightColor: colors[RightEdge] = decl.brushValue(pal);
break;
648 case BorderTopColor: colors[TopEdge] = decl.brushValue(pal);
break;
649 case BorderBottomColor: colors[BottomEdge] = decl.brushValue(pal);
break;
650 case BorderColor: decl.brushValues(colors, pal);
break;
652 case BorderTopStyle: styles[TopEdge] = decl.styleValue();
break;
653 case BorderBottomStyle: styles[BottomEdge] = decl.styleValue();
break;
654 case BorderLeftStyle: styles[LeftEdge] = decl.styleValue();
break;
655 case BorderRightStyle: styles[RightEdge] = decl.styleValue();
break;
656 case BorderStyles: decl.styleValues(styles);
break;
658 case BorderTopLeftRadius: radii[0] = sizeValue(decl);
break;
659 case BorderTopRightRadius: radii[1] = sizeValue(decl);
break;
660 case BorderBottomLeftRadius: radii[2] = sizeValue(decl);
break;
661 case BorderBottomRightRadius: radii[3] = sizeValue(decl);
break;
662 case BorderRadius: sizeValues(decl, radii);
break;
665 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
668 borderValue(decl, &borders[TopEdge], &styles[TopEdge], &colors[TopEdge]);
671 borderValue(decl, &borders[RightEdge], &styles[RightEdge], &colors[RightEdge]);
674 borderValue(decl, &borders[BottomEdge], &styles[BottomEdge], &colors[BottomEdge]);
677 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
678 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
679 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
680 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
691bool ValueExtractor::extractOutline(
int *borders, QBrush *colors, BorderStyle *styles,
692 QSize *radii,
int *offsets)
696 for (
const Declaration &decl : std::as_const(declarations)) {
697 switch (decl.d->propertyId) {
698 case OutlineWidth: lengthValues(decl, borders);
break;
699 case OutlineColor: decl.brushValues(colors, pal);
break;
700 case OutlineStyle: decl.styleValues(styles);
break;
702 case OutlineTopLeftRadius: radii[0] = sizeValue(decl);
break;
703 case OutlineTopRightRadius: radii[1] = sizeValue(decl);
break;
704 case OutlineBottomLeftRadius: radii[2] = sizeValue(decl);
break;
705 case OutlineBottomRightRadius: radii[3] = sizeValue(decl);
break;
706 case OutlineRadius: sizeValues(decl, radii);
break;
707 case OutlineOffset: lengthValues(decl, offsets);
break;
710 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
711 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
712 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
713 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
726 Qt::Alignment a[2] = { { }, { } };
727 for (
int i = 0; i < qMin(2, count); i++) {
730 switch (values[i].variant.toInt()) {
731 case Value_Left: a[i] = Qt::AlignLeft;
break;
732 case Value_Right: a[i] = Qt::AlignRight;
break;
733 case Value_Top: a[i] = Qt::AlignTop;
break;
734 case Value_Bottom: a[i] = Qt::AlignBottom;
break;
735 case Value_Center: a[i] = Qt::AlignCenter;
break;
740 if (a[0] == Qt::AlignCenter && a[1] != 0 && a[1] != Qt::AlignCenter)
741 a[0] = (a[1] == Qt::AlignLeft || a[1] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
742 if ((a[1] == 0 || a[1] == Qt::AlignCenter) && a[0] != Qt::AlignCenter)
743 a[1] = (a[0] == Qt::AlignLeft || a[0] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
750 v.variant.convert(QMetaType::fromType<QColor>());
755 return qvariant_cast<QColor>(v.variant);
757 if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent)
758 return QColor(Qt::transparent);
763 QStringList lst = v.variant.toStringList();
767 const QString &identifier = lst.at(0);
768 if ((identifier.compare(
"palette"_L1, Qt::CaseInsensitive)) == 0) {
769 static_assert((Value_LastColorRole - Value_FirstColorRole + 1) == QPalette::ColorRole::NColorRoles);
771 int role = findKnownValue(lst.at(1).trimmed(), values, NumKnownValues);
772 if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
773 return (QPalette::ColorRole)(role-Value_FirstColorRole);
778 const bool rgb = identifier.startsWith(
"rgb"_L1);
779 const bool hsv = !rgb && identifier.startsWith(
"hsv"_L1);
780 const bool hsl = !rgb && !hsv && identifier.startsWith(
"hsl"_L1);
782 if (!rgb && !hsv && !hsl)
785 const bool hasAlpha = identifier.size() == 4 && identifier.at(3) == u'a';
786 if (identifier.size() > 3 && !hasAlpha)
793 QList<QCss::Value> colorDigits;
794 if (!p.parseExpr(&colorDigits))
796 const int tokenCount = colorDigits.size();
798 for (
int i = 0; i < qMin(tokenCount, 7); i += 2) {
800 const qreal maxRange = (rgb || i != 0) ? 255. : 359.;
801 colorDigits[i].variant = colorDigits.at(i).variant.toReal() * (maxRange / 100.);
812 if (hasAlpha && tokenCount != 7) {
813 qWarning(
"QCssParser::parseColorValue: Specified color with alpha value but no alpha given: '%s'", qPrintable(lst.join(u' ')));
816 if (!hasAlpha && tokenCount != 5) {
817 qWarning(
"QCssParser::parseColorValue: Specified color without alpha value but alpha given: '%s'", qPrintable(lst.join(u' ')));
821 int v1 = colorDigits.at(0).variant.toInt();
822 int v2 = colorDigits.at(2).variant.toInt();
823 int v3 = colorDigits.at(4).variant.toInt();
825 if (tokenCount == 7) {
826 int alphaValue = colorDigits.at(6).variant.toInt();
828 alpha = colorDigits.at(6).variant.toReal() * 255.;
834 return QColor::fromRgb(v1, v2, v3, alpha);
836 return QColor::fromHsv(v1, v2, v3, alpha);
837 return QColor::fromHsl(v1, v2, v3, alpha);
845 return pal.color(c.role);
854 return QBrush(c.color);
862 QStringList lst = v.variant.toStringList();
866 QStringList gradFuncs;
867 gradFuncs <<
"qlineargradient"_L1 <<
"qradialgradient"_L1 <<
"qconicalgradient"_L1 <<
"qgradient"_L1;
870 if ((gradType = gradFuncs.indexOf(lst.at(0).toLower())) == -1)
873 QHash<QString, qreal> vars;
874 QList<QGradientStop> stops;
878 spreads <<
"pad"_L1 <<
"reflect"_L1 <<
"repeat"_L1;
880 int coordinateMode = -1;
881 QStringList coordinateModes;
882 coordinateModes <<
"logical"_L1 <<
"stretchtodevice"_L1 <<
"objectbounding"_L1 <<
"object"_L1;
884 bool dependsOnThePalette =
false;
886 while (parser.hasNext()) {
888 if (!parser.test(IDENT))
890 QString attr = parser.lexem();
892 if (!parser.test(COLON))
895 if (attr.compare(
"stop"_L1, Qt::CaseInsensitive) == 0) {
904 dependsOnThePalette =
true;
905 stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal)));
909 (
void)parser.parseTerm(&value);
910 if (attr.compare(
"spread"_L1, Qt::CaseInsensitive) == 0)
911 spread = spreads.indexOf(value.variant.toString());
912 else if (attr.compare(
"coordinatemode"_L1, Qt::CaseInsensitive) == 0)
913 coordinateMode = coordinateModes.indexOf(value.variant.toString());
915 vars[attr] = value.variant.toReal();
918 (
void)parser.test(COMMA);
923 vars.value(
"x2"_L1), vars.value(
"y2"_L1));
924 lg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
927 lg.setSpread(QGradient::Spread(spread));
929 if (dependsOnThePalette)
936 vars.value(
"radius"_L1), vars.value(
"fx"_L1),
937 vars.value(
"fy"_L1));
938 rg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
941 rg.setSpread(QGradient::Spread(spread));
943 if (dependsOnThePalette)
949 QConicalGradient cg(vars.value(
"cx"_L1), vars.value(
"cy"_L1), vars.value(
"angle"_L1));
950 cg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
953 cg.setSpread(QGradient::Spread(spread));
955 if (dependsOnThePalette)
966 return pal.color(c.role);
975 switch (v.variant.toInt()) {
1008void ValueExtractor::borderValue(
const Declaration &decl,
int *width, QCss::BorderStyle *style, QBrush *color)
1010 if (decl.d->parsed.isValid()) {
1011 BorderData data = qvariant_cast<BorderData>(decl.d->parsed);
1012 *width = lengthValueFromData(data.width, f);
1013 *style = data.style;
1014 *color = data.color.type != BrushData::Invalid ? brushFromData(data.color, pal) : QBrush(QColor());
1019 *style = BorderStyle_None;
1022 if (decl.d->values.isEmpty())
1026 data.width.number = 0;
1027 data.width.unit = LengthData::None;
1028 data.style = BorderStyle_None;
1031 if (decl.d->values.at(i).type == Value::Length || decl.d->values.at(i).type == Value::Number) {
1032 data.width = lengthValue(decl.d->values.at(i));
1033 *width = lengthValueFromData(data.width, f);
1034 if (++i >= decl.d->values.size()) {
1035 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1040 data.style = parseStyleValue(decl.d->values.at(i));
1041 if (data.style != BorderStyle_Unknown) {
1042 *style = data.style;
1043 if (++i >= decl.d->values.size()) {
1044 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1048 data.style = BorderStyle_None;
1051 data.color = parseBrushValue(decl.d->values.at(i), pal);
1052 if (data.color.type != BrushData::Invalid) {
1053 *color = brushFromData(data.color, pal);
1054 if (data.color.type != BrushData::DependsOnThePalette)
1055 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1064 *alignment = Qt::AlignTop | Qt::AlignLeft;
1066 for (qsizetype i = 0; i < values.size(); ++i) {
1069 *image = v.variant.toString();
1075 *brush = QBrush(Qt::transparent);
1078 Repeat repeatAttempt =
static_cast<Repeat>(findKnownValue(v.variant.toString(),
1079 repeats, NumKnownRepeats));
1081 *repeat = repeatAttempt;
1086 const int start = i;
1088 if (i < values.size() - 1
1093 Qt::Alignment a = parseAlignment(values.constData() + start, count);
1101 *brush = parseBrushValue(v, pal);
1105bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *repeat,
1106 Qt::Alignment *alignment, Origin *origin, Attachment *attachment,
1110 for (
const Declaration &decl : declarations) {
1111 if (decl.d->values.isEmpty())
1113 const QCss::Value &val = decl.d->values.at(0);
1114 switch (decl.d->propertyId) {
1115 case BackgroundColor:
1116 *brush = decl.brushValue();
1118 case BackgroundImage:
1119 if (val.type == Value::Uri)
1120 *image = val.variant.toString();
1122 case BackgroundRepeat:
1123 if (decl.d->parsed.isValid()) {
1124 *repeat =
static_cast<Repeat>(decl.d->parsed.toInt());
1126 *repeat =
static_cast<Repeat>(findKnownValue(val.variant.toString(),
1127 repeats, NumKnownRepeats));
1128 decl.d->parsed = *repeat;
1131 case BackgroundPosition:
1132 *alignment = decl.alignmentValue();
1134 case BackgroundOrigin:
1135 *origin = decl.originValue();
1137 case BackgroundClip:
1138 *clip = decl.originValue();
1141 if (decl.d->parsed.isValid()) {
1142 BackgroundData data = qvariant_cast<BackgroundData>(decl.d->parsed);
1143 *brush = brushFromData(data.brush, pal);
1144 *image = data.image;
1145 *repeat = data.repeat;
1146 *alignment = data.alignment;
1148 BrushData brushData;
1149 parseShorthandBackgroundProperty(decl.d->values, &brushData, image, repeat, alignment, pal);
1150 *brush = brushFromData(brushData, pal);
1151 if (brushData.type != BrushData::DependsOnThePalette) {
1152 BackgroundData data = { brushData, *image, *repeat, *alignment };
1153 decl.d->parsed = QVariant::fromValue<BackgroundData>(data);
1157 case BackgroundAttachment:
1158 *attachment = decl.attachmentValue();
1171 switch (value.variant.toInt()) {
1172 case Value_Small: *fontSizeAdjustment = -1;
break;
1177 default: valid =
false;
break;
1185 QString s = value.variant.toString();
1186 if (s.endsWith(
"pt"_L1, Qt::CaseInsensitive)) {
1189 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1190 font->setPointSizeF(qBound(qreal(0), value.variant.toReal(), qreal(1 << 24) - 1));
1193 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1196 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1197 font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
1208 switch (value.variant.toInt()) {
1209 case Value_Normal: font->setStyle(QFont::StyleNormal);
return true;
1210 case Value_Italic: font->setStyle(QFont::StyleItalic);
return true;
1211 case Value_Oblique: font->setStyle(QFont::StyleOblique);
return true;
1221 switch (value.variant.toInt()) {
1222 case Value_Normal: font->setKerning(
true);
return true;
1223 case Value_None: font->setKerning(
false);
return true;
1233 switch (value.variant.toInt()) {
1234 case Value_Normal: font->setWeight(QFont::Normal);
return true;
1235 case Value_Bold: font->setWeight(QFont::Bold);
return true;
1243 font->setWeight(QFont::Weight(qRound(qBound(0.0, value.variant.toDouble(), 1001.0))));
1248
1249
1250
1251
1255 QStringList families;
1256 bool shouldAddSpace =
false;
1257 for (qsizetype i = start; i < values.size(); ++i) {
1262 shouldAddSpace =
false;
1265 const QString str = v.variant.toString();
1271 shouldAddSpace =
true;
1273 if (!family.isEmpty())
1275 if (families.isEmpty())
1277 font->setFamilies(families);
1283 for (
const QCss::Value &value : values) {
1284 if (value.type != Value::KnownIdentifier)
1286 switch (value.variant.toInt()) {
1287 case Value_Underline: font->setUnderline(
true);
break;
1288 case Value_Overline: font->setOverline(
true);
break;
1289 case Value_LineThrough: font->setStrikeOut(
true);
break;
1291 font->setUnderline(
false);
1292 font->setOverline(
false);
1293 font->setStrikeOut(
false);
1302 QString s = value.variant.toString();
1305 if (s.endsWith(
"em"_L1, Qt::CaseInsensitive)) {
1307 val = s.toDouble(&ok);
1309 font->setLetterSpacing(QFont::PercentageSpacing, (val + 1.0) * 100);
1310 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1312 val = s.toDouble(&ok);
1314 font->setLetterSpacing(QFont::AbsoluteSpacing, val);
1320 QString s = value.variant.toString();
1321 if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1325 val = s.toDouble(&ok);
1327 font->setWordSpacing(val);
1333 font->setStyle(QFont::StyleNormal);
1334 font->setWeight(QFont::Normal);
1335 *fontSizeAdjustment = -255;
1338 while (i < values.size()) {
1339 if (setFontStyleFromValue(values.at(i), font)
1340 || setFontWeightFromValue(values.at(i), font))
1346 if (i < values.size()) {
1347 setFontSizeFromValue(values.at(i), font, fontSizeAdjustment);
1351 if (i < values.size()) {
1352 setFontFamilyFromValues(values, font, i);
1359 switch (value.variant.toInt()) {
1360 case Value_Normal: font->setCapitalization(QFont::MixedCase);
break;
1361 case Value_SmallCaps: font->setCapitalization(QFont::SmallCaps);
break;
1370 switch (value.variant.toInt()) {
1371 case Value_None: font->setCapitalization(QFont::MixedCase);
break;
1372 case Value_Uppercase: font->setCapitalization(QFont::AllUppercase);
break;
1373 case Value_Lowercase: font->setCapitalization(QFont::AllLowercase);
break;
1379bool ValueExtractor::extractFont(QFont *font,
int *fontSizeAdjustment)
1381 if (fontExtracted) {
1383 *fontSizeAdjustment = adjustment;
1384 return fontExtracted == 1;
1388 for (
const Declaration &decl : std::as_const(declarations)) {
1389 if (decl.d->values.isEmpty())
1391 const QCss::Value &val = decl.d->values.at(0);
1392 switch (decl.d->propertyId) {
1393 case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment);
break;
1394 case FontStyle: setFontStyleFromValue(val, font);
break;
1395 case FontWeight: setFontWeightFromValue(val, font);
break;
1396 case FontFamily: setFontFamilyFromValues(decl.d->values, font);
break;
1397 case FontKerning: setFontKerningFromValue(val, font);
break;
1398 case TextDecoration: setTextDecorationFromValues(decl.d->values, font);
break;
1399 case Font: parseShorthandFontProperty(decl.d->values, font, fontSizeAdjustment);
break;
1400 case FontVariant: setFontVariantFromValue(val, font);
break;
1401 case TextTransform: setTextTransformFromValue(val, font);
break;
1402 case LetterSpacing: setLetterSpacingFromValue(val, font);
break;
1403 case WordSpacing: setWordSpacingFromValue(val, font);
break;
1410 adjustment = *fontSizeAdjustment;
1411 fontExtracted = hit ? 1 : 2;
1415bool ValueExtractor::extractPalette(QBrush *foreground,
1416 QBrush *selectedForeground,
1417 QBrush *selectedBackground,
1418 QBrush *alternateBackground,
1419 QBrush *placeHolderTextForeground,
1420 QBrush *accent)
const
1423 for (
const Declaration &decl : declarations) {
1424 switch (decl.d->propertyId) {
1425 case Color: *foreground = decl.brushValue(pal);
break;
1426 case QtSelectionForeground: *selectedForeground = decl.brushValue(pal);
break;
1427 case QtSelectionBackground: *selectedBackground = decl.brushValue(pal);
break;
1428 case QtAlternateBackground: *alternateBackground = decl.brushValue(pal);
break;
1429 case QtPlaceHolderTextColor: *placeHolderTextForeground = decl.brushValue(pal);
break;
1430 case QtAccent: *accent = decl.brushValue(pal);
break;
1438void ValueExtractor::extractFont()
1443 extractFont(&f, &dummy);
1446bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size)
const
1449 for (
const Declaration &decl : declarations) {
1450 switch (decl.d->propertyId) {
1452 *icon = decl.iconValue();
1453 if (decl.d->values.size() > 0 && decl.d->values.at(0).type == Value::Uri) {
1455 QImageReader imageReader(decl.d->values.at(0).variant.toString());
1456 if ((*size = imageReader.size()).isNull()) {
1459 *size = imageReader.read().size();
1463 case QtImageAlignment: *a = decl.alignmentValue();
break;
1471bool ValueExtractor::extractIcon(QIcon *icon, QSize *size)
const
1474 const auto declaration = std::find_if(
1475 declarations.rbegin(), declarations.rend(),
1476 [](
const Declaration &decl) {
return decl.d->propertyId == QtIcon; });
1477 if (declaration == declarations.rend())
1480 *icon = declaration->iconValue();
1483 if (declaration->d->values.isEmpty())
1486 const auto &propertyValue = declaration->d->values.constFirst();
1487 if (propertyValue.type != Value::Uri)
1491 const QString url(propertyValue.variant.toString());
1492 QImageReader imageReader(url);
1493 *size = imageReader.size();
1494 if (!size->isNull())
1498 *size = imageReader.read().size();
1504QColor Declaration::colorValue(
const QPalette &pal)
const
1506 if (d->values.size() != 1)
1509 if (d->parsed.isValid()) {
1510 switch (d->parsed.typeId()) {
1511 case qMetaTypeId<QColor>():
1512 return qvariant_cast<QColor>(d->parsed);
1513 case qMetaTypeId<
int>():
1514 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1515 case qMetaTypeId<QList<QVariant>>():
1516 if (d->parsed.toList().size() == 1) {
1517 auto parsedList = d->parsed.toList();
1518 const auto &value = parsedList.at(0);
1519 return qvariant_cast<QColor>(value);
1525 ColorData color = parseColorValue(d->values.at(0));
1526 if (color.type == ColorData::Role) {
1527 d->parsed = QVariant::fromValue<
int>(color.role);
1528 return pal.color((QPalette::ColorRole)(color.role));
1530 d->parsed = QVariant::fromValue<QColor>(color.color);
1535QBrush Declaration::brushValue(
const QPalette &pal)
const
1537 if (d->values.size() != 1)
1540 if (d->parsed.isValid()) {
1541 if (d->parsed.userType() == QMetaType::QBrush)
1542 return qvariant_cast<QBrush>(d->parsed);
1543 if (d->parsed.userType() == QMetaType::Int)
1544 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1547 BrushData data = parseBrushValue(d->values.at(0), pal);
1549 if (data.type == BrushData::Role) {
1550 d->parsed = QVariant::fromValue<
int>(data.role);
1551 return pal.color((QPalette::ColorRole)(data.role));
1553 if (data.type != BrushData::DependsOnThePalette)
1554 d->parsed = QVariant::fromValue<QBrush>(data.brush);
1559void Declaration::brushValues(QBrush *c,
const QPalette &pal)
const
1561 int needParse = 0x1f;
1564 if (d->parsed.isValid()) {
1566 Q_ASSERT(d->parsed.metaType() == QMetaType::fromType<QList<QVariant>>());
1567 QList<QVariant> v = d->parsed.toList();
1568 for (i = 0; i < qMin(v.size(), 4); i++) {
1569 if (v.at(i).userType() == QMetaType::QBrush) {
1570 c[i] = qvariant_cast<QBrush>(v.at(i));
1571 }
else if (v.at(i).userType() == QMetaType::Int) {
1572 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1574 needParse |= (1<<i);
1578 if (needParse != 0) {
1580 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1581 if (!(needParse & (1<<i)))
1583 BrushData data = parseBrushValue(d->values.at(i), pal);
1584 if (data.type == BrushData::Role) {
1585 v += QVariant::fromValue<
int>(data.role);
1586 c[i] = pal.color((QPalette::ColorRole)(data.role));
1588 if (data.type != BrushData::DependsOnThePalette) {
1589 v += QVariant::fromValue<QBrush>(data.brush);
1596 if (needParse & 0x10)
1599 if (i == 0) c[0] = c[1] = c[2] = c[3] = QBrush();
1600 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1601 else if (i == 2) c[2] = c[0], c[3] = c[1];
1602 else if (i == 3) c[3] = c[1];
1605bool Declaration::realValue(qreal *real,
const char *unit)
const
1607 if (d->values.size() != 1)
1609 const Value &v = d->values.at(0);
1610 if (unit && v.type != Value::Length)
1612 const QString str = v.variant.toString();
1615 const QLatin1StringView unitStr(unit);
1616 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1618 s.chop(unitStr.size());
1621 qreal val = s.toDouble(&ok);
1631 const QString str = v.variant.toString();
1634 const QLatin1StringView unitStr(unit);
1635 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1637 s.chop(unitStr.size());
1640 int val = s.toInt(&ok);
1646bool Declaration::intValue(
int *i,
const char *unit)
const
1648 if (d->values.size() != 1)
1650 return intValueHelper(d->values.at(0), i, unit);
1653QSize Declaration::sizeValue()
const
1655 if (d->parsed.isValid())
1656 return qvariant_cast<QSize>(d->parsed);
1658 int x[2] = { 0, 0 };
1659 const qsizetype count = d->values.size();
1660 for (qsizetype i = 0; i < count; ++i) {
1662 qWarning(
"QCssParser::sizeValue: Too many values provided");
1665 const auto &value = d->values.at(i);
1666 const QString valueString = value.variant.toString();
1667 if (valueString.endsWith(u"pt", Qt::CaseInsensitive)) {
1668 intValueHelper(value, &x[i],
"pt");
1671 x[i] = (x[i] * 72) / 96;
1674 intValueHelper(value, &x[i],
"px");
1679 QSize size(x[0], x[1]);
1680 d->parsed = QVariant::fromValue<QSize>(size);
1684QRect Declaration::rectValue()
const
1686 if (d->values.size() != 1)
1689 if (d->parsed.isValid())
1690 return qvariant_cast<QRect>(d->parsed);
1692 const QCss::Value &v = d->values.at(0);
1693 if (v.type != Value::Function)
1695 const QStringList func = v.variant.toStringList();
1696 if (func.size() != 2 || func.at(0).compare(
"rect"_L1) != 0)
1698 const auto args = QStringView{func[1]}.split(u' ', Qt::SkipEmptyParts);
1699 if (args.size() != 4)
1701 QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
1702 d->parsed = QVariant::fromValue<QRect>(rect);
1706void Declaration::colorValues(QColor *c,
const QPalette &pal)
const
1709 if (d->parsed.isValid()) {
1710 QList<QVariant> v = d->parsed.toList();
1711 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1712 if (v.at(i).userType() == QMetaType::QColor) {
1713 c[i] = qvariant_cast<QColor>(v.at(i));
1715 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1720 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1721 ColorData color = parseColorValue(d->values.at(i));
1722 if (color.type == ColorData::Role) {
1723 v += QVariant::fromValue<
int>(color.role);
1724 c[i] = pal.color((QPalette::ColorRole)(color.role));
1726 v += QVariant::fromValue<QColor>(color.color);
1733 if (i == 0) c[0] = c[1] = c[2] = c[3] = QColor();
1734 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1735 else if (i == 2) c[2] = c[0], c[3] = c[1];
1736 else if (i == 3) c[3] = c[1];
1739BorderStyle Declaration::styleValue()
const
1741 if (d->values.size() != 1)
1742 return BorderStyle_None;
1743 return parseStyleValue(d->values.at(0));
1746void Declaration::styleValues(BorderStyle *s)
const
1749 for (i = 0; i < qMin(d->values.size(), 4); i++)
1750 s[i] = parseStyleValue(d->values.at(i));
1751 if (i == 0) s[0] = s[1] = s[2] = s[3] = BorderStyle_None;
1752 else if (i == 1) s[3] = s[2] = s[1] = s[0];
1753 else if (i == 2) s[2] = s[0], s[3] = s[1];
1754 else if (i == 3) s[3] = s[1];
1757Repeat Declaration::repeatValue()
const
1759 if (d->parsed.isValid())
1760 return static_cast<Repeat>(d->parsed.toInt());
1761 if (d->values.size() != 1)
1762 return Repeat_Unknown;
1763 int v = findKnownValue(d->values.at(0).variant.toString(),
1764 repeats, NumKnownRepeats);
1766 return static_cast<Repeat>(v);
1769Origin Declaration::originValue()
const
1771 if (d->parsed.isValid())
1772 return static_cast<Origin>(d->parsed.toInt());
1773 if (d->values.size() != 1)
1774 return Origin_Unknown;
1775 int v = findKnownValue(d->values.at(0).variant.toString(),
1776 origins, NumKnownOrigins);
1778 return static_cast<Origin>(v);
1781PositionMode Declaration::positionValue()
const
1783 if (d->parsed.isValid())
1784 return static_cast<PositionMode>(d->parsed.toInt());
1785 if (d->values.size() != 1)
1786 return PositionMode_Unknown;
1787 int v = findKnownValue(d->values.at(0).variant.toString(),
1788 positions, NumKnownPositionModes);
1790 return static_cast<PositionMode>(v);
1793Attachment Declaration::attachmentValue()
const
1795 if (d->parsed.isValid())
1796 return static_cast<Attachment>(d->parsed.toInt());
1797 if (d->values.size() != 1)
1798 return Attachment_Unknown;
1799 int v = findKnownValue(d->values.at(0).variant.toString(),
1800 attachments, NumKnownAttachments);
1802 return static_cast<Attachment>(v);
1805int Declaration::styleFeaturesValue()
const
1807 Q_ASSERT(d->propertyId == QtStyleFeatures);
1808 if (d->parsed.isValid())
1809 return d->parsed.toInt();
1810 int features = StyleFeature_None;
1811 for (
const Value &value : std::as_const(d->values)) {
1812 features |=
static_cast<
int>(findKnownValue(value.variant.toString(),
1813 styleFeatures, NumKnownStyleFeatures));
1815 d->parsed = features;
1819QString Declaration::uriValue()
const
1821 if (d->values.isEmpty() || d->values.at(0).type != Value::Uri)
1823 return d->values.at(0).variant.toString();
1826Qt::Alignment Declaration::alignmentValue()
const
1828 if (d->parsed.isValid())
1829 return Qt::Alignment(d->parsed.toInt());
1830 if (d->values.isEmpty() || d->values.size() > 2)
1831 return Qt::AlignLeft | Qt::AlignTop;
1833 Qt::Alignment v = parseAlignment(d->values.constData(), d->values.size());
1838void Declaration::borderImageValue(QString *image,
int *cuts,
1839 TileMode *h, TileMode *v)
const
1841 const DeclarationData *d =
this->d.data();
1842 *image = uriValue();
1843 for (
int i = 0; i < 4; i++)
1845 *h = *v = TileMode_Stretch;
1847 if (d->values.size() < 2)
1850 if (d->values.at(1).type == Value::Number) {
1852 for (i = 0; i < qMin(d->values.size()-1, 4); i++) {
1853 const Value& v = d->values.at(i+1);
1854 if (v.type != Value::Number)
1856 cuts[i] = v.variant.toString().toInt();
1858 qWarning(
"Declaration::borderImageValue: Invalid cut value %d at position %d",
1860 cuts[0] = cuts[1] = cuts[2] = cuts[3] = -1;
1865 if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
1866 else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];
1867 else if (i == 2) cuts[2] = cuts[0], cuts[3] = cuts[1];
1868 else if (i == 3) cuts[3] = cuts[1];
1871 if (d->values.last().type == Value::Identifier) {
1872 *v =
static_cast<TileMode>(findKnownValue(d->values.last().variant.toString(),
1873 tileModes, NumKnownTileModes));
1875 if (d->values[d->values.size() - 2].type == Value::Identifier) {
1876 *h =
static_cast<TileMode>
1877 (findKnownValue(d->values[d->values.size()-2].variant.toString(),
1878 tileModes, NumKnownTileModes));
1883bool Declaration::borderCollapseValue()
const
1885 if (d->values.size() != 1)
1888 return d->values.at(0).toString() ==
"collapse"_L1;
1891QList<qreal> Declaration::dashArray()
const
1893 if (d->propertyId != Property::QtStrokeDashArray || d->values.empty())
1894 return QList<qreal>();
1896 bool isValid =
true;
1897 QList<qreal> dashes;
1898 for (qsizetype i = 0; i < d->values.size(); i++) {
1899 const Value &v = d->values[i];
1901 bool isValidSeparator = (i & 1) && v.type == Value::TermOperatorComma;
1902 bool isValidNumber = !(i & 1) && v.type == Value::Number;
1903 if (!isValidNumber && !isValidSeparator) {
1906 }
else if (isValidNumber) {
1908 dashes.append(v.variant.toReal(&ok));
1916 isValid &= !(dashes.size() & 1);
1917 return isValid ? dashes : QList<qreal>();
1920QIcon Declaration::iconValue()
const
1922 if (d->parsed.isValid())
1923 return qvariant_cast<QIcon>(d->parsed);
1926 for (qsizetype i = 0; i < d->values.size();) {
1927 const Value &value = d->values.at(i++);
1928 if (value.type != Value::Uri)
1930 QString uri = value.variant.toString();
1931 QIcon::Mode mode = QIcon::Normal;
1932 QIcon::State state = QIcon::Off;
1933 for (
int j = 0; j < 2; j++) {
1934 if (i != d->values.size() && d->values.at(i).type == Value::KnownIdentifier) {
1935 switch (d->values.at(i).variant.toInt()) {
1936 case Value_Disabled: mode = QIcon::Disabled;
break;
1937 case Value_Active: mode = QIcon::Active;
break;
1938 case Value_Selected: mode = QIcon::Selected;
break;
1939 case Value_Normal: mode = QIcon::Normal;
break;
1940 case Value_On: state = QIcon::On;
break;
1941 case Value_Off: state = QIcon::Off;
break;
1954 icon.addPixmap(uri, mode, state);
1956 if (i == d->values.size())
1959 if (d->values.at(i).type == Value::TermOperatorComma)
1963 d->parsed = QVariant::fromValue<QIcon>(icon);
1969int Selector::specificity()
const
1972 for (
const BasicSelector &sel : basicSelectors) {
1973 if (!sel.elementName.isEmpty())
1976 val += (sel.pseudos.size() + sel.attributeSelectors.size()) * 0x10;
1977 val += sel.ids.size() * 0x100;
1982QString Selector::pseudoElement()
const
1984 const BasicSelector& bs = basicSelectors.last();
1985 if (!bs.pseudos.isEmpty() && bs.pseudos.at(0).type == PseudoClass_Unknown)
1986 return bs.pseudos.at(0).name;
1990quint64 Selector::pseudoClass(quint64 *negated)
const
1992 const BasicSelector& bs = basicSelectors.last();
1993 if (bs.pseudos.isEmpty())
1994 return PseudoClass_Unspecified;
1995 quint64 pc = PseudoClass_Unknown;
1996 for (
int i = !pseudoElement().isEmpty(); i < bs.pseudos.size(); i++) {
1997 const Pseudo &pseudo = bs.pseudos.at(i);
1998 if (pseudo.type == PseudoClass_Unknown)
1999 return PseudoClass_Unknown;
2000 if (!pseudo.negated)
2003 *negated |= pseudo.type;
2012 QList<StyleRule> universals;
2013 for (qsizetype i = 0; i < styleRules.size(); ++i) {
2014 const StyleRule &rule = styleRules.at(i);
2015 QList<Selector> universalsSelectors;
2016 for (
const Selector &selector : rule.selectors) {
2018 if (selector.basicSelectors.isEmpty())
2021 if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
2022 if (selector.basicSelectors.size() != 1)
2024 }
else if (selector.basicSelectors.size() <= 1) {
2028 const BasicSelector &sel = selector.basicSelectors.at(selector.basicSelectors.size() - 1);
2030 if (!sel.ids.isEmpty()) {
2032 nr.selectors += selector;
2033 nr.declarations = rule.declarations;
2035 idIndex.insert(sel.ids.at(0), nr);
2036 }
else if (!sel.elementName.isEmpty()) {
2038 nr.selectors += selector;
2039 nr.declarations = rule.declarations;
2041 QString name = sel.elementName;
2042 if (nameCaseSensitivity == Qt::CaseInsensitive)
2043 name = std::move(name).toLower();
2044 nameIndex.insert(name, nr);
2046 universalsSelectors += selector;
2049 if (!universalsSelectors.isEmpty()) {
2051 nr.selectors = universalsSelectors;
2052 nr.declarations = rule.declarations;
2057 styleRules = universals;
2062StyleSelector::~StyleSelector()
2066bool StyleSelector::nodeNameEquals(NodePtr node,
const QString& nodeName)
const
2068 return nodeNames(node).contains(nodeName, nameCaseSensitivity);
2071QStringList StyleSelector::nodeIds(NodePtr node)
const
2073 return QStringList(attributeValue(node, QCss::AttributeSelector{
"id"_L1, {}, AttributeSelector::NoMatch}));
2076bool StyleSelector::selectorMatches(
const Selector &selector, NodePtr node)
const
2078 if (selector.basicSelectors.isEmpty())
2081 if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
2082 if (selector.basicSelectors.size() != 1)
2084 return basicSelectorMatches(selector.basicSelectors.at(0), node);
2086 if (selector.basicSelectors.size() <= 1)
2089 qsizetype i = selector.basicSelectors.size() - 1;
2090 node = duplicateNode(node);
2093 BasicSelector sel = selector.basicSelectors.at(i);
2095 match = basicSelectorMatches(sel, node);
2097 if (i == selector.basicSelectors.size() - 1)
2099 if (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2100 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent)
2104 if (match || (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2105 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent))
2111 sel = selector.basicSelectors.at(i);
2112 if (sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2113 || sel.relationToNext == BasicSelector::MatchNextSelectorIfParent) {
2115 NodePtr nextParent = parentNode(node);
2118 }
else if (sel.relationToNext == BasicSelector::MatchNextSelectorIfDirectAdjecent
2119 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent) {
2120 NodePtr previousSibling = previousSiblingNode(node);
2122 node = previousSibling;
2124 if (isNullNode(node)) {
2128 }
while (i >= 0 && (match || sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2129 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent));
2136bool StyleSelector::basicSelectorMatches(
const BasicSelector &sel, NodePtr node)
const
2138 if (!sel.attributeSelectors.isEmpty()) {
2139 if (!hasAttributes(node))
2142 for (
const QCss::AttributeSelector &a : sel.attributeSelectors) {
2144 const QString attrValue = attributeValue(node, a);
2145 if (attrValue.isNull())
2148 switch (a.valueMatchCriterium) {
2149 case QCss::AttributeSelector::NoMatch:
2151 case QCss::AttributeSelector::MatchEqual:
2152 if (attrValue != a.value)
2155 case QCss::AttributeSelector::MatchIncludes: {
2156 const auto lst = QStringView{attrValue}.tokenize(u' ');
2158 for (
auto s : lst) {
2168 case QCss::AttributeSelector::MatchDashMatch: {
2169 const QString dashPrefix = a.value + u'-';
2170 if (attrValue != a.value && !attrValue.startsWith(dashPrefix))
2174 case QCss::AttributeSelector::MatchBeginsWith:
2175 if (!attrValue.startsWith(a.value))
2178 case QCss::AttributeSelector::MatchEndsWith:
2179 if (!attrValue.endsWith(a.value))
2182 case QCss::AttributeSelector::MatchContains:
2183 if (!attrValue.contains(a.value))
2190 if (!sel.elementName.isEmpty()
2191 && !nodeNameEquals(node, sel.elementName))
2194 if (!sel.ids.isEmpty()
2195 && sel.ids != nodeIds(node))
2201void StyleSelector::matchRule(NodePtr node,
const StyleRule &rule, StyleSheetOrigin origin,
2202 int depth, std::multimap<uint64_t, StyleRule> *weightedRules)
const
2204 for (
const Selector &selector : rule.selectors) {
2205 if (selectorMatches(selector, node)) {
2206 if (uint32_t(rule.order) >= 0x100000ULL)
2207 qWarning(
"StyleSelector: rule order is to large - style sheet"
2208 "must not contain more than 0x100000 entries");
2209 if (uint32_t(selector.specificity()) >= 0x100000ULL)
2210 qWarning(
"StyleSelector: selector specifity is to large - "
2211 "style sheet must not contain more than 0x100000 selectors "
2213 const uint64_t weight = rule.order
2214 + selector.specificity() * 0x100000ULL
2215 + (uint(origin) + depth) * 0x10000000000ULL;
2216 StyleRule newRule = rule;
2217 if (rule.selectors.size() > 1)
2218 newRule.selectors.push_back(selector);
2221 weightedRules->emplace(weight, std::move(newRule));
2228QList<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
2230 QList<StyleRule> rules;
2231 if (styleSheets.isEmpty())
2234 std::multimap<uint64_t, StyleRule> weightedRules;
2237 for (
const StyleSheet &styleSheet : std::as_const(styleSheets)) {
2238 for (
const StyleRule &styleRule : styleSheet.styleRules)
2239 matchRule(node, styleRule, styleSheet.origin, styleSheet.depth, &weightedRules);
2241 if (!styleSheet.idIndex.isEmpty()) {
2242 const QStringList ids = nodeIds(node);
2243 for (
const QString &key : ids) {
2244 auto it = styleSheet.idIndex.constFind(key);
2245 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
2246 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2251 if (!styleSheet.nameIndex.isEmpty()) {
2252 const QStringList names = nodeNames(node);
2253 for (QString name : names) {
2254 if (nameCaseSensitivity == Qt::CaseInsensitive)
2255 name = std::move(name).toLower();
2256 auto it = styleSheet.nameIndex.constFind(name);
2257 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
2258 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2263 if (!medium.isEmpty()) {
2264 for (
const MediaRule &mediaRule : styleSheet.mediaRules) {
2265 if (mediaRule.media.contains(medium, Qt::CaseInsensitive)) {
2266 for (
const StyleRule &styleRule : mediaRule.styleRules) {
2267 matchRule(node, styleRule, styleSheet.origin,
2268 styleSheet.depth, &weightedRules);
2275 rules.reserve(weightedRules.size());
2276 for (
const auto &weigthedRule : weightedRules)
2277 rules.push_back(std::move(weigthedRule.second));
2284QList<Declaration> StyleSelector::declarationsForNode(NodePtr node,
const char *extraPseudo)
2286 QList<Declaration> decls;
2287 const QList<StyleRule> rules = styleRulesForNode(node);
2288 for (
const StyleRule &styleRule : rules) {
2289 const Selector &selector = styleRule.selectors.at(0);
2290 const QString pseudoElement = selector.pseudoElement();
2292 if (extraPseudo && pseudoElement == QLatin1StringView(extraPseudo)) {
2293 decls += styleRule.declarations;
2297 if (!pseudoElement.isEmpty())
2299 quint64 pseudoClass = selector.pseudoClass();
2300 if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
2301 decls += styleRule.declarations;
2308 return (c >=
'0' && c <=
'9')
2309 || (c >=
'a' && c <=
'f')
2310 || (c >=
'A' && c <=
'F')
2314QString Scanner::preprocess(
const QString &input,
bool *hasEscapeSequences)
2316 QString output = input;
2318 if (hasEscapeSequences)
2319 *hasEscapeSequences =
false;
2322 while (i < output.size()) {
2323 if (output.at(i) == u'\\') {
2328 const int hexStart = i;
2329 while (i < output.size()
2330 && isHexDigit(output.at(i).toLatin1())
2335 if (hexCount == 0) {
2336 if (hasEscapeSequences)
2337 *hasEscapeSequences =
true;
2341 hexCount = qMin(hexCount, 6);
2343 const char16_t code = QStringView{output}.mid(hexStart, hexCount).toUShort(&ok, 16);
2345 output.replace(hexStart - 1, hexCount + 1, code);
2357int QCssScanner_Generated::handleCommentStart()
2359 while (pos < input.size() - 1) {
2360 if (input.at(pos) == u'*' && input.at(pos + 1) == u'/') {
2369void Scanner::scan(
const QString &preprocessedInput, QList<Symbol> *symbols)
2371 QCssScanner_Generated scanner(preprocessedInput);
2373 int tok = scanner.lex();
2375 sym.token =
static_cast<QCss::TokenType>(tok);
2376 sym.text = scanner.input;
2377 sym.start = scanner.lexemStart;
2378 sym.len = scanner.lexemLength;
2379 symbols->append(sym);
2380 tok = scanner.lex();
2388 result.reserve(
len);
2389 for (
int i = 0; i <
len; ++i) {
2390 if (text.at(start + i) == u'\\' && i < len - 1)
2392 result += text.at(start + i);
2397Parser::Parser(
const QString &css,
bool isFile)
2406 hasEscapeSequences =
false;
2409void Parser::init(
const QString &css,
bool isFile)
2411 QString styleSheet = css;
2414 if (file.open(QFile::ReadOnly)) {
2415 sourcePath = QFileInfo(styleSheet).absolutePath() + u'/';
2416 QTextStream stream(&file);
2417 styleSheet = stream.readAll();
2419 qWarning() <<
"QCss::Parser - Failed to load file " << css;
2426 hasEscapeSequences =
false;
2429 Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
2434bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
2436 if (testTokenAndEndsWith(ATKEYWORD_SYM,
"charset"_L1)) {
2437 while (test(S) || test(CDO) || test(CDC)) {}
2438 if (!next(STRING))
return false;
2439 if (!next(SEMICOLON))
return false;
2442 while (test(S) || test(CDO) || test(CDC)) {}
2444 while (testImport()) {
2446 if (!parseImport(&rule))
return false;
2447 styleSheet->importRules.append(rule);
2448 while (test(S) || test(CDO) || test(CDC)) {}
2454 if (!parseMedia(&rule))
return false;
2455 styleSheet->mediaRules.append(rule);
2456 }
else if (testPage()) {
2458 if (!parsePage(&rule))
return false;
2459 styleSheet->pageRules.append(rule);
2460 }
else if (testAnimation()) {
2462 if (!parseAnimation(&rule))
return false;
2463 styleSheet->animationRules.append(rule);
2464 }
else if (testRuleset()) {
2466 if (!parseRuleset(&rule))
return false;
2467 styleSheet->styleRules.append(rule);
2468 }
else if (test(ATKEYWORD_SYM)) {
2469 if (!until(RBRACE))
return false;
2470 }
else if (hasNext()) {
2473 while (test(S) || test(CDO) || test(CDC)) {}
2474 }
while (hasNext());
2475 styleSheet->buildIndexes(nameCaseSensitivity);
2479Symbol Parser::errorSymbol()
2481 if (errorIndex == -1)
return Symbol();
2482 return symbols.at(errorIndex);
2487 if (!str->startsWith(u'\'') && !str->startsWith(u'\"'))
2493bool Parser::parseImport(ImportRule *importRule)
2498 importRule->href = lexem();
2500 if (!testAndParseUri(&importRule->href))
return false;
2502 removeOptionalQuotes(&importRule->href);
2507 if (!parseMedium(&importRule->media))
return false;
2509 while (test(COMMA)) {
2511 if (!parseNextMedium(&importRule->media))
return false;
2515 if (!next(SEMICOLON))
return false;
2521bool Parser::parseMedia(MediaRule *mediaRule)
2525 if (!parseNextMedium(&mediaRule->media))
return false;
2526 }
while (test(COMMA));
2528 if (!next(LBRACE))
return false;
2531 while (testRuleset()) {
2533 if (!parseRuleset(&rule))
return false;
2534 mediaRule->styleRules.append(rule);
2537 if (!next(RBRACE))
return false;
2542bool Parser::parseMedium(QStringList *media)
2544 media->append(lexem());
2549bool Parser::parsePage(PageRule *pageRule)
2553 if (testPseudoPage())
2554 if (!parsePseudoPage(&pageRule->selector))
return false;
2557 if (!next(LBRACE))
return false;
2562 if (!parseNextDeclaration(&decl))
return false;
2563 if (!decl.isEmpty())
2564 pageRule->declarations.append(decl);
2565 }
while (test(SEMICOLON));
2567 if (!next(RBRACE))
return false;
2572bool Parser::parsePseudoPage(QString *selector)
2574 if (!next(IDENT))
return false;
2575 *selector = lexem();
2579bool Parser::parseNextOperator(Value *value)
2581 if (!hasNext())
return true;
2583 case SLASH: value->type = Value::TermOperatorSlash; skipSpace();
break;
2584 case COMMA: value->type = Value::TermOperatorComma; skipSpace();
break;
2585 default: prev();
break;
2590bool Parser::parseAnimation(AnimationRule *animationRule)
2593 if (!test(IDENT))
return false;
2595 animationRule->animName = lexem();
2597 if (!next(LBRACE))
return false;
2600 while (test(PERCENTAGE) || test(IDENT)) {
2601 AnimationRule::AnimationRuleSet set;
2602 if (lookup() == PERCENTAGE) {
2603 QString name = lexem();
2605 float keyFrame = name.toFloat() / 100;
2606 set.keyFrame = keyFrame;
2607 }
else if (lookup() == IDENT) {
2609 if (parseElementName(&name)) {
2610 if (name == QStringLiteral(
"from"))
2612 else if (name == QStringLiteral(
"to"))
2618 if (!next(LBRACE))
return false;
2619 const int declarationStart = index;
2624 const int rewind = index;
2625 if (!parseNextDeclaration(&decl)) {
2627 const bool foundSemicolon = until(SEMICOLON);
2628 const int semicolonIndex = index;
2630 index = declarationStart;
2631 const bool foundRBrace = until(RBRACE);
2633 if (foundSemicolon && semicolonIndex < index) {
2634 decl = Declaration();
2635 index = semicolonIndex - 1;
2641 if (!decl.isEmpty()) {
2642 if (decl.d->property ==
"animation-timing-function"_L1)
2643 set.timingFunction = std::move(decl);
2645 set.declarations.push_back(std::move(decl));
2647 }
while (test(SEMICOLON));
2649 if (!next(RBRACE))
return false;
2651 animationRule->ruleSets.append(set);
2654 if (!next(RBRACE))
return false;
2660bool Parser::parseCombinator(BasicSelector::Relation *relation)
2662 *relation = BasicSelector::NoRelation;
2663 if (lookup() == S) {
2664 *relation = BasicSelector::MatchNextSelectorIfAncestor;
2670 *relation = BasicSelector::MatchNextSelectorIfDirectAdjecent;
2671 }
else if (test(GREATER)) {
2672 *relation = BasicSelector::MatchNextSelectorIfParent;
2673 }
else if (test(TILDE)) {
2674 *relation = BasicSelector::MatchNextSelectorIfIndirectAdjecent;
2680bool Parser::parseProperty(Declaration *decl)
2682 decl->d->property = lexem();
2683 decl->d->propertyId =
static_cast<Property>(findKnownValue(decl->d->property, properties, NumProperties));
2684 decl->d->inheritable = isInheritable(decl->d->propertyId);
2689bool Parser::parseRuleset(StyleRule *styleRule)
2692 if (!parseSelector(&sel))
return false;
2693 styleRule->selectors.append(sel);
2695 while (test(COMMA)) {
2698 if (!parseNextSelector(&sel))
return false;
2699 styleRule->selectors.append(sel);
2703 if (!next(LBRACE))
return false;
2704 const int declarationStart = index;
2709 const int rewind = index;
2710 if (!parseNextDeclaration(&decl)) {
2712 const bool foundSemicolon = until(SEMICOLON);
2713 const int semicolonIndex = index;
2715 index = declarationStart;
2716 const bool foundRBrace = until(RBRACE);
2718 if (foundSemicolon && semicolonIndex < index) {
2719 decl = Declaration();
2720 index = semicolonIndex - 1;
2726 if (!decl.isEmpty())
2727 styleRule->declarations.append(decl);
2728 }
while (test(SEMICOLON));
2730 if (!next(RBRACE))
return false;
2735bool Parser::parseSelector(Selector *sel)
2737 BasicSelector basicSel;
2738 if (!parseSimpleSelector(&basicSel))
return false;
2739 while (testCombinator()) {
2740 if (!parseCombinator(&basicSel.relationToNext))
return false;
2742 if (!testSimpleSelector())
break;
2743 sel->basicSelectors.append(basicSel);
2745 basicSel = BasicSelector();
2746 if (!parseSimpleSelector(&basicSel))
return false;
2748 sel->basicSelectors.append(basicSel);
2752bool Parser::parseSimpleSelector(BasicSelector *basicSel)
2755 if (lookupElementName()) {
2756 if (!parseElementName(&basicSel->elementName))
return false;
2766 QString theid = lexem();
2769 basicSel->ids.append(theid);
2771 }
else if (testClass()) {
2773 AttributeSelector a;
2774 a.name =
"class"_L1;
2775 a.valueMatchCriterium = AttributeSelector::MatchIncludes;
2776 if (!parseClass(&a.value))
return false;
2777 basicSel->attributeSelectors.append(a);
2778 }
else if (testAttrib()) {
2780 AttributeSelector a;
2781 if (!parseAttrib(&a))
return false;
2782 basicSel->attributeSelectors.append(a);
2783 }
else if (testPseudo()) {
2786 if (!parsePseudo(&ps))
return false;
2787 basicSel->pseudos.append(ps);
2789 if (onceMore) ++count;
2791 return count >= minCount;
2794bool Parser::parseClass(QString *name)
2796 if (!next(IDENT))
return false;
2801bool Parser::parseElementName(QString *name)
2804 case STAR: name->clear();
break;
2805 case IDENT: *name = lexem();
break;
2806 default:
return false;
2811bool Parser::parseAttrib(AttributeSelector *attr)
2814 if (!next(IDENT))
return false;
2815 attr->name = lexem();
2819 attr->valueMatchCriterium = AttributeSelector::MatchEqual;
2820 }
else if (test(INCLUDES)) {
2821 attr->valueMatchCriterium = AttributeSelector::MatchIncludes;
2822 }
else if (test(DASHMATCH)) {
2823 attr->valueMatchCriterium = AttributeSelector::MatchDashMatch;
2824 }
else if (test(BEGINSWITH)) {
2825 attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
2826 }
else if (test(ENDSWITH)) {
2827 attr->valueMatchCriterium = AttributeSelector::MatchEndsWith;
2828 }
else if (test(CONTAINS)) {
2829 attr->valueMatchCriterium = AttributeSelector::MatchContains;
2831 return next(RBRACKET);
2836 if (!test(IDENT) && !test(STRING))
return false;
2837 attr->value = unquotedLexem();
2840 return next(RBRACKET);
2843bool Parser::parsePseudo(Pseudo *pseudo)
2846 pseudo->negated = test(EXCLAMATION_SYM);
2848 pseudo->name = lexem();
2849 pseudo->type =
static_cast<quint64>(findKnownValue(pseudo->name, pseudos, NumPseudos));
2852 if (!next(FUNCTION))
return false;
2853 pseudo->function = lexem();
2855 pseudo->function.chop(1);
2857 if (!test(IDENT))
return false;
2858 pseudo->name = lexem();
2860 return next(RPAREN);
2863bool Parser::parseNextDeclaration(Declaration *decl)
2865 if (!testProperty())
2867 if (!parseProperty(decl))
return false;
2868 if (!next(COLON))
return false;
2870 if (!parseNextExpr(&decl->d->values))
return false;
2872 if (!parsePrio(decl))
return false;
2876bool Parser::testPrio()
2878 const int rewind = index;
2879 if (!test(EXCLAMATION_SYM))
return false;
2885 if (lexem().compare(
"important"_L1, Qt::CaseInsensitive) != 0) {
2892bool Parser::parsePrio(Declaration *declaration)
2894 declaration->d->important =
true;
2899bool Parser::parseExpr(QList<Value> *values)
2902 if (!parseTerm(&val))
return false;
2903 values->append(val);
2908 if (!parseNextOperator(&val))
return false;
2909 if (val.type != QCss::Value::Unknown)
2910 values->append(val);
2914 if (!parseTerm(&val))
return false;
2915 values->append(val);
2921bool Parser::testTerm()
2923 return test(PLUS) || test(MINUS)
2933bool Parser::parseTerm(Value *value)
2935 QString str = lexem();
2936 bool haveUnary =
false;
2937 if (lookup() == PLUS || lookup() == MINUS) {
2939 if (!hasNext())
return false;
2944 value->variant = str;
2945 value->type = QCss::Value::String;
2948 value->type = Value::Number;
2949 value->variant.convert(QMetaType::fromType<
double>());
2952 value->type = Value::Percentage;
2954 value->variant = str;
2957 value->type = Value::Length;
2961 if (haveUnary)
return false;
2962 value->type = Value::String;
2965 value->variant = str;
2968 if (haveUnary)
return false;
2969 value->type = Value::Identifier;
2970 const int theid = findKnownValue(str, values, NumKnownValues);
2972 value->type = Value::KnownIdentifier;
2973 value->variant = theid;
2978 if (haveUnary)
return false;
2980 if (testHexColor()) {
2982 if (!parseHexColor(&col))
return false;
2983 value->type = Value::Color;
2984 value->variant = col;
2985 }
else if (testFunction()) {
2987 if (!parseFunction(&name, &args))
return false;
2988 if (name ==
"url"_L1) {
2989 value->type = Value::Uri;
2990 removeOptionalQuotes(&args);
2991 if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
2992 args.prepend(sourcePath);
2994 value->variant = args;
2996 value->type = Value::Function;
2997 value->variant = QStringList() << name << args;
3000 return recordError();
3009bool Parser::parseFunction(QString *name, QString *args)
3016 std::swap(start, index);
3017 if (!until(RPAREN))
return false;
3018 for (
int i = start; i < index - 1; ++i)
3019 args->append(symbols.at(i).lexem());
3021
3022
3023
3028bool Parser::parseHexColor(QColor *col)
3030 *col = QColor::fromString(lexem());
3031 if (!col->isValid()) {
3032 qWarning(
"QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
3039bool Parser::testAndParseUri(QString *uri)
3041 const int rewind = index;
3042 if (!testFunction())
return false;
3045 if (!parseFunction(&name, &args)) {
3049 if (name.compare(
"url"_L1, Qt::CaseInsensitive) != 0) {
3053 *uri = std::move(args);
3054 removeOptionalQuotes(uri);
3058bool Parser::testSimpleSelector()
3060 return testElementName()
3067bool Parser::next(QCss::TokenType t)
3069 if (hasNext() && next() == t)
3071 return recordError();
3074bool Parser::test(QCss::TokenType t)
3076 if (index >= symbols.size())
3078 if (symbols.at(index).token == t) {
3085QString Parser::unquotedLexem()
const
3087 QString s = lexem();
3088 if (lookup() == STRING) {
3095QString Parser::lexemUntil(QCss::TokenType t)
3098 while (hasNext() && next() != t)
3099 lexem += symbol().lexem();
3103bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
3109 switch(symbols.at(index-1).token) {
3110 case LBRACE: ++braceCount;
break;
3111 case LBRACKET: ++brackCount;
break;
3113 case LPAREN: ++parenCount;
break;
3117 while (index < symbols.size()) {
3118 QCss::TokenType t = symbols.at(index++).token;
3120 case LBRACE: ++braceCount;
break;
3121 case RBRACE: --braceCount;
break;
3122 case LBRACKET: ++brackCount;
break;
3123 case RBRACKET: --brackCount;
break;
3125 case LPAREN: ++parenCount;
break;
3126 case RPAREN: --parenCount;
break;
3129 if ((t == target || (target2 != NONE && t == target2))
3135 if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
3143bool Parser::testTokenAndEndsWith(QCss::TokenType t, QLatin1StringView str)
3145 if (!test(t))
return false;
3146 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)
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 quint64 findKnownValue(const QString &name, const QCssKnownValue *start, int numValues)
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 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[]
#define CHECK_ARRAY_IS_SORTED(array, Num)
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)