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 (
int i = 0; i < declarations.size(); i++) {
530 const Declaration &decl = declarations.at(i);
531 switch (decl.d->propertyId) {
532 case Width: *w = lengthValue(decl);
break;
533 case Height: *h = lengthValue(decl);
break;
534 case MinimumWidth: *minw = lengthValue(decl);
break;
535 case MinimumHeight: *minh = lengthValue(decl);
break;
536 case MaximumWidth: *maxw = lengthValue(decl);
break;
537 case MaximumHeight: *maxh = lengthValue(decl);
break;
546bool ValueExtractor::extractPosition(
int *left,
int *top,
int *right,
int *bottom, QCss::Origin *origin,
547 Qt::Alignment *position, QCss::PositionMode *mode, Qt::Alignment *textAlignment)
551 for (
int i = 0; i < declarations.size(); i++) {
552 const Declaration &decl = declarations.at(i);
553 switch (decl.d->propertyId) {
554 case Left: *left = lengthValue(decl);
break;
555 case Top: *top = lengthValue(decl);
break;
556 case Right: *right = lengthValue(decl);
break;
557 case Bottom: *bottom = lengthValue(decl);
break;
558 case QtOrigin: *origin = decl.originValue();
break;
559 case QtPosition: *position = decl.alignmentValue();
break;
560 case TextAlignment: *textAlignment = decl.alignmentValue();
break;
561 case Position: *mode = decl.positionValue();
break;
570bool ValueExtractor::extractBox(
int *margins,
int *paddings,
int *spacing)
574 for (
int i = 0; i < declarations.size(); i++) {
575 const Declaration &decl = declarations.at(i);
576 switch (decl.d->propertyId) {
577 case PaddingLeft: paddings[LeftEdge] = lengthValue(decl);
break;
578 case PaddingRight: paddings[RightEdge] = lengthValue(decl);
break;
579 case PaddingTop: paddings[TopEdge] = lengthValue(decl);
break;
580 case PaddingBottom: paddings[BottomEdge] = lengthValue(decl);
break;
581 case Padding: lengthValues(decl, paddings);
break;
583 case MarginLeft: margins[LeftEdge] = lengthValue(decl);
break;
584 case MarginRight: margins[RightEdge] = lengthValue(decl);
break;
585 case MarginTop: margins[TopEdge] = lengthValue(decl);
break;
586 case MarginBottom: margins[BottomEdge] = lengthValue(decl);
break;
587 case Margin: lengthValues(decl, margins);
break;
588 case QtSpacing:
if (spacing) *spacing = lengthValue(decl);
break;
598int ValueExtractor::extractStyleFeatures()
600 int features = StyleFeature_None;
601 for (
int i = 0; i < declarations.size(); i++) {
602 const Declaration &decl = declarations.at(i);
603 if (decl.d->propertyId == QtStyleFeatures)
604 features = decl.styleFeaturesValue();
609QSize ValueExtractor::sizeValue(
const Declaration &decl)
611 if (decl.d->parsed.isValid()) {
612 QList<QVariant> v = decl.d->parsed.toList();
613 return QSize(lengthValueFromData(qvariant_cast<LengthData>(v.at(0)), f),
614 lengthValueFromData(qvariant_cast<LengthData>(v.at(1)), f));
617 LengthData x[2] = { {0, LengthData::None }, {0, LengthData::None} };
618 if (decl.d->values.size() > 0)
619 x[0] = lengthValue(decl.d->values.at(0));
620 if (decl.d->values.size() > 1)
621 x[1] = lengthValue(decl.d->values.at(1));
625 v << QVariant::fromValue<LengthData>(x[0]) << QVariant::fromValue<LengthData>(x[1]);
627 return QSize(lengthValueFromData(x[0], f), lengthValueFromData(x[1], f));
630void ValueExtractor::sizeValues(
const Declaration &decl, QSize *radii)
632 radii[0] = sizeValue(decl);
633 for (
int i = 1; i < 4; i++)
637bool ValueExtractor::extractBorder(
int *borders, QBrush *colors, BorderStyle *styles,
642 for (
int i = 0; i < declarations.size(); i++) {
643 const Declaration &decl = declarations.at(i);
644 switch (decl.d->propertyId) {
645 case BorderLeftWidth: borders[LeftEdge] = lengthValue(decl);
break;
646 case BorderRightWidth: borders[RightEdge] = lengthValue(decl);
break;
647 case BorderTopWidth: borders[TopEdge] = lengthValue(decl);
break;
648 case BorderBottomWidth: borders[BottomEdge] = lengthValue(decl);
break;
649 case BorderWidth: lengthValues(decl, borders);
break;
651 case BorderLeftColor: colors[LeftEdge] = decl.brushValue(pal);
break;
652 case BorderRightColor: colors[RightEdge] = decl.brushValue(pal);
break;
653 case BorderTopColor: colors[TopEdge] = decl.brushValue(pal);
break;
654 case BorderBottomColor: colors[BottomEdge] = decl.brushValue(pal);
break;
655 case BorderColor: decl.brushValues(colors, pal);
break;
657 case BorderTopStyle: styles[TopEdge] = decl.styleValue();
break;
658 case BorderBottomStyle: styles[BottomEdge] = decl.styleValue();
break;
659 case BorderLeftStyle: styles[LeftEdge] = decl.styleValue();
break;
660 case BorderRightStyle: styles[RightEdge] = decl.styleValue();
break;
661 case BorderStyles: decl.styleValues(styles);
break;
663 case BorderTopLeftRadius: radii[0] = sizeValue(decl);
break;
664 case BorderTopRightRadius: radii[1] = sizeValue(decl);
break;
665 case BorderBottomLeftRadius: radii[2] = sizeValue(decl);
break;
666 case BorderBottomRightRadius: radii[3] = sizeValue(decl);
break;
667 case BorderRadius: sizeValues(decl, radii);
break;
670 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
673 borderValue(decl, &borders[TopEdge], &styles[TopEdge], &colors[TopEdge]);
676 borderValue(decl, &borders[RightEdge], &styles[RightEdge], &colors[RightEdge]);
679 borderValue(decl, &borders[BottomEdge], &styles[BottomEdge], &colors[BottomEdge]);
682 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
683 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
684 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
685 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
696bool ValueExtractor::extractOutline(
int *borders, QBrush *colors, BorderStyle *styles,
697 QSize *radii,
int *offsets)
701 for (
int i = 0; i < declarations.size(); i++) {
702 const Declaration &decl = declarations.at(i);
703 switch (decl.d->propertyId) {
704 case OutlineWidth: lengthValues(decl, borders);
break;
705 case OutlineColor: decl.brushValues(colors, pal);
break;
706 case OutlineStyle: decl.styleValues(styles);
break;
708 case OutlineTopLeftRadius: radii[0] = sizeValue(decl);
break;
709 case OutlineTopRightRadius: radii[1] = sizeValue(decl);
break;
710 case OutlineBottomLeftRadius: radii[2] = sizeValue(decl);
break;
711 case OutlineBottomRightRadius: radii[3] = sizeValue(decl);
break;
712 case OutlineRadius: sizeValues(decl, radii);
break;
713 case OutlineOffset: lengthValues(decl, offsets);
break;
716 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
717 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
718 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
719 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
732 Qt::Alignment a[2] = { { }, { } };
733 for (
int i = 0; i < qMin(2, count); i++) {
736 switch (values[i].variant.toInt()) {
737 case Value_Left: a[i] = Qt::AlignLeft;
break;
738 case Value_Right: a[i] = Qt::AlignRight;
break;
739 case Value_Top: a[i] = Qt::AlignTop;
break;
740 case Value_Bottom: a[i] = Qt::AlignBottom;
break;
741 case Value_Center: a[i] = Qt::AlignCenter;
break;
746 if (a[0] == Qt::AlignCenter && a[1] != 0 && a[1] != Qt::AlignCenter)
747 a[0] = (a[1] == Qt::AlignLeft || a[1] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
748 if ((a[1] == 0 || a[1] == Qt::AlignCenter) && a[0] != Qt::AlignCenter)
749 a[1] = (a[0] == Qt::AlignLeft || a[0] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
756 v.variant.convert(QMetaType::fromType<QColor>());
761 return qvariant_cast<QColor>(v.variant);
763 if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent)
764 return QColor(Qt::transparent);
769 QStringList lst = v.variant.toStringList();
773 const QString &identifier = lst.at(0);
774 if ((identifier.compare(
"palette"_L1, Qt::CaseInsensitive)) == 0) {
775 static_assert((Value_LastColorRole - Value_FirstColorRole + 1) == QPalette::ColorRole::NColorRoles);
777 int role = findKnownValue(lst.at(1).trimmed(), values, NumKnownValues);
778 if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
779 return (QPalette::ColorRole)(role-Value_FirstColorRole);
784 const bool rgb = identifier.startsWith(
"rgb"_L1);
785 const bool hsv = !rgb && identifier.startsWith(
"hsv"_L1);
786 const bool hsl = !rgb && !hsv && identifier.startsWith(
"hsl"_L1);
788 if (!rgb && !hsv && !hsl)
791 const bool hasAlpha = identifier.size() == 4 && identifier.at(3) == u'a';
792 if (identifier.size() > 3 && !hasAlpha)
799 QList<QCss::Value> colorDigits;
800 if (!p.parseExpr(&colorDigits))
802 const int tokenCount = colorDigits.size();
804 for (
int i = 0; i < qMin(tokenCount, 7); i += 2) {
806 const qreal maxRange = (rgb || i != 0) ? 255. : 359.;
807 colorDigits[i].variant = colorDigits.at(i).variant.toReal() * (maxRange / 100.);
818 if (hasAlpha && tokenCount != 7) {
819 qWarning(
"QCssParser::parseColorValue: Specified color with alpha value but no alpha given: '%s'", qPrintable(lst.join(u' ')));
822 if (!hasAlpha && tokenCount != 5) {
823 qWarning(
"QCssParser::parseColorValue: Specified color without alpha value but alpha given: '%s'", qPrintable(lst.join(u' ')));
827 int v1 = colorDigits.at(0).variant.toInt();
828 int v2 = colorDigits.at(2).variant.toInt();
829 int v3 = colorDigits.at(4).variant.toInt();
831 if (tokenCount == 7) {
832 int alphaValue = colorDigits.at(6).variant.toInt();
834 alpha = colorDigits.at(6).variant.toReal() * 255.;
840 return QColor::fromRgb(v1, v2, v3, alpha);
842 return QColor::fromHsv(v1, v2, v3, alpha);
843 return QColor::fromHsl(v1, v2, v3, alpha);
851 return pal.color(c.role);
860 return QBrush(c.color);
868 QStringList lst = v.variant.toStringList();
872 QStringList gradFuncs;
873 gradFuncs <<
"qlineargradient"_L1 <<
"qradialgradient"_L1 <<
"qconicalgradient"_L1 <<
"qgradient"_L1;
876 if ((gradType = gradFuncs.indexOf(lst.at(0).toLower())) == -1)
879 QHash<QString, qreal> vars;
880 QList<QGradientStop> stops;
884 spreads <<
"pad"_L1 <<
"reflect"_L1 <<
"repeat"_L1;
886 int coordinateMode = -1;
887 QStringList coordinateModes;
888 coordinateModes <<
"logical"_L1 <<
"stretchtodevice"_L1 <<
"objectbounding"_L1 <<
"object"_L1;
890 bool dependsOnThePalette =
false;
892 while (parser.hasNext()) {
894 if (!parser.test(IDENT))
896 QString attr = parser.lexem();
898 if (!parser.test(COLON))
901 if (attr.compare(
"stop"_L1, Qt::CaseInsensitive) == 0) {
910 dependsOnThePalette =
true;
911 stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal)));
915 (
void)parser.parseTerm(&value);
916 if (attr.compare(
"spread"_L1, Qt::CaseInsensitive) == 0)
917 spread = spreads.indexOf(value.variant.toString());
918 else if (attr.compare(
"coordinatemode"_L1, Qt::CaseInsensitive) == 0)
919 coordinateMode = coordinateModes.indexOf(value.variant.toString());
921 vars[attr] = value.variant.toReal();
924 (
void)parser.test(COMMA);
929 vars.value(
"x2"_L1), vars.value(
"y2"_L1));
930 lg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
933 lg.setSpread(QGradient::Spread(spread));
935 if (dependsOnThePalette)
942 vars.value(
"radius"_L1), vars.value(
"fx"_L1),
943 vars.value(
"fy"_L1));
944 rg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
947 rg.setSpread(QGradient::Spread(spread));
949 if (dependsOnThePalette)
955 QConicalGradient cg(vars.value(
"cx"_L1), vars.value(
"cy"_L1), vars.value(
"angle"_L1));
956 cg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
959 cg.setSpread(QGradient::Spread(spread));
961 if (dependsOnThePalette)
972 return pal.color(c.role);
981 switch (v.variant.toInt()) {
1014void ValueExtractor::borderValue(
const Declaration &decl,
int *width, QCss::BorderStyle *style, QBrush *color)
1016 if (decl.d->parsed.isValid()) {
1017 BorderData data = qvariant_cast<BorderData>(decl.d->parsed);
1018 *width = lengthValueFromData(data.width, f);
1019 *style = data.style;
1020 *color = data.color.type != BrushData::Invalid ? brushFromData(data.color, pal) : QBrush(QColor());
1025 *style = BorderStyle_None;
1028 if (decl.d->values.isEmpty())
1032 data.width.number = 0;
1033 data.width.unit = LengthData::None;
1034 data.style = BorderStyle_None;
1037 if (decl.d->values.at(i).type == Value::Length || decl.d->values.at(i).type == Value::Number) {
1038 data.width = lengthValue(decl.d->values.at(i));
1039 *width = lengthValueFromData(data.width, f);
1040 if (++i >= decl.d->values.size()) {
1041 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1046 data.style = parseStyleValue(decl.d->values.at(i));
1047 if (data.style != BorderStyle_Unknown) {
1048 *style = data.style;
1049 if (++i >= decl.d->values.size()) {
1050 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1054 data.style = BorderStyle_None;
1057 data.color = parseBrushValue(decl.d->values.at(i), pal);
1058 if (data.color.type != BrushData::Invalid) {
1059 *color = brushFromData(data.color, pal);
1060 if (data.color.type != BrushData::DependsOnThePalette)
1061 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1070 *alignment = Qt::AlignTop | Qt::AlignLeft;
1072 for (
int i = 0; i < values.size(); ++i) {
1075 *image = v.variant.toString();
1081 *brush = QBrush(Qt::transparent);
1084 Repeat repeatAttempt =
static_cast<Repeat>(findKnownValue(v.variant.toString(),
1085 repeats, NumKnownRepeats));
1087 *repeat = repeatAttempt;
1092 const int start = i;
1094 if (i < values.size() - 1
1099 Qt::Alignment a = parseAlignment(values.constData() + start, count);
1107 *brush = parseBrushValue(v, pal);
1111bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *repeat,
1112 Qt::Alignment *alignment, Origin *origin, Attachment *attachment,
1116 for (
int i = 0; i < declarations.size(); ++i) {
1117 const Declaration &decl = declarations.at(i);
1118 if (decl.d->values.isEmpty())
1120 const QCss::Value &val = decl.d->values.at(0);
1121 switch (decl.d->propertyId) {
1122 case BackgroundColor:
1123 *brush = decl.brushValue();
1125 case BackgroundImage:
1126 if (val.type == Value::Uri)
1127 *image = val.variant.toString();
1129 case BackgroundRepeat:
1130 if (decl.d->parsed.isValid()) {
1131 *repeat =
static_cast<Repeat>(decl.d->parsed.toInt());
1133 *repeat =
static_cast<Repeat>(findKnownValue(val.variant.toString(),
1134 repeats, NumKnownRepeats));
1135 decl.d->parsed = *repeat;
1138 case BackgroundPosition:
1139 *alignment = decl.alignmentValue();
1141 case BackgroundOrigin:
1142 *origin = decl.originValue();
1144 case BackgroundClip:
1145 *clip = decl.originValue();
1148 if (decl.d->parsed.isValid()) {
1149 BackgroundData data = qvariant_cast<BackgroundData>(decl.d->parsed);
1150 *brush = brushFromData(data.brush, pal);
1151 *image = data.image;
1152 *repeat = data.repeat;
1153 *alignment = data.alignment;
1155 BrushData brushData;
1156 parseShorthandBackgroundProperty(decl.d->values, &brushData, image, repeat, alignment, pal);
1157 *brush = brushFromData(brushData, pal);
1158 if (brushData.type != BrushData::DependsOnThePalette) {
1159 BackgroundData data = { brushData, *image, *repeat, *alignment };
1160 decl.d->parsed = QVariant::fromValue<BackgroundData>(data);
1164 case BackgroundAttachment:
1165 *attachment = decl.attachmentValue();
1178 switch (value.variant.toInt()) {
1179 case Value_Small: *fontSizeAdjustment = -1;
break;
1184 default: valid =
false;
break;
1192 QString s = value.variant.toString();
1193 if (s.endsWith(
"pt"_L1, Qt::CaseInsensitive)) {
1196 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1197 font->setPointSizeF(qBound(qreal(0), value.variant.toReal(), qreal(1 << 24) - 1));
1200 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1203 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1204 font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
1215 switch (value.variant.toInt()) {
1216 case Value_Normal: font->setStyle(QFont::StyleNormal);
return true;
1217 case Value_Italic: font->setStyle(QFont::StyleItalic);
return true;
1218 case Value_Oblique: font->setStyle(QFont::StyleOblique);
return true;
1228 switch (value.variant.toInt()) {
1229 case Value_Normal: font->setKerning(
true);
return true;
1230 case Value_None: font->setKerning(
false);
return true;
1240 switch (value.variant.toInt()) {
1241 case Value_Normal: font->setWeight(QFont::Normal);
return true;
1242 case Value_Bold: font->setWeight(QFont::Bold);
return true;
1250 font->setWeight(QFont::Weight(qRound(qBound(0.0, value.variant.toDouble(), 1001.0))));
1255
1256
1257
1258
1262 QStringList families;
1263 bool shouldAddSpace =
false;
1264 for (
int i = start; i < values.size(); ++i) {
1269 shouldAddSpace =
false;
1272 const QString str = v.variant.toString();
1278 shouldAddSpace =
true;
1280 if (!family.isEmpty())
1282 if (families.isEmpty())
1284 font->setFamilies(families);
1290 for (
int i = 0; i < values.size(); ++i) {
1293 switch (values.at(i).variant.toInt()) {
1298 font->setUnderline(
false);
1299 font->setOverline(
false);
1300 font->setStrikeOut(
false);
1309 QString s = value.variant.toString();
1312 if (s.endsWith(
"em"_L1, Qt::CaseInsensitive)) {
1314 val = s.toDouble(&ok);
1316 font->setLetterSpacing(QFont::PercentageSpacing, (val + 1.0) * 100);
1317 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1319 val = s.toDouble(&ok);
1321 font->setLetterSpacing(QFont::AbsoluteSpacing, val);
1327 QString s = value.variant.toString();
1328 if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1332 val = s.toDouble(&ok);
1334 font->setWordSpacing(val);
1340 font->setStyle(QFont::StyleNormal);
1341 font->setWeight(QFont::Normal);
1342 *fontSizeAdjustment = -255;
1345 while (i < values.size()) {
1346 if (setFontStyleFromValue(values.at(i), font)
1347 || setFontWeightFromValue(values.at(i), font))
1353 if (i < values.size()) {
1354 setFontSizeFromValue(values.at(i), font, fontSizeAdjustment);
1358 if (i < values.size()) {
1359 setFontFamilyFromValues(values, font, i);
1366 switch (value.variant.toInt()) {
1367 case Value_Normal: font->setCapitalization(QFont::MixedCase);
break;
1368 case Value_SmallCaps: font->setCapitalization(QFont::SmallCaps);
break;
1377 switch (value.variant.toInt()) {
1378 case Value_None: font->setCapitalization(QFont::MixedCase);
break;
1379 case Value_Uppercase: font->setCapitalization(QFont::AllUppercase);
break;
1380 case Value_Lowercase: font->setCapitalization(QFont::AllLowercase);
break;
1386bool ValueExtractor::extractFont(QFont *font,
int *fontSizeAdjustment)
1388 if (fontExtracted) {
1390 *fontSizeAdjustment = adjustment;
1391 return fontExtracted == 1;
1395 for (
int i = 0; i < declarations.size(); ++i) {
1396 const Declaration &decl = declarations.at(i);
1397 if (decl.d->values.isEmpty())
1399 const QCss::Value &val = decl.d->values.at(0);
1400 switch (decl.d->propertyId) {
1401 case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment);
break;
1402 case FontStyle: setFontStyleFromValue(val, font);
break;
1403 case FontWeight: setFontWeightFromValue(val, font);
break;
1404 case FontFamily: setFontFamilyFromValues(decl.d->values, font);
break;
1405 case FontKerning: setFontKerningFromValue(val, font);
break;
1406 case TextDecoration: setTextDecorationFromValues(decl.d->values, font);
break;
1407 case Font: parseShorthandFontProperty(decl.d->values, font, fontSizeAdjustment);
break;
1408 case FontVariant: setFontVariantFromValue(val, font);
break;
1409 case TextTransform: setTextTransformFromValue(val, font);
break;
1410 case LetterSpacing: setLetterSpacingFromValue(val, font);
break;
1411 case WordSpacing: setWordSpacingFromValue(val, font);
break;
1418 adjustment = *fontSizeAdjustment;
1419 fontExtracted = hit ? 1 : 2;
1423bool ValueExtractor::extractPalette(QBrush *foreground,
1424 QBrush *selectedForeground,
1425 QBrush *selectedBackground,
1426 QBrush *alternateBackground,
1427 QBrush *placeHolderTextForeground,
1431 for (
int i = 0; i < declarations.size(); ++i) {
1432 const Declaration &decl = declarations.at(i);
1433 switch (decl.d->propertyId) {
1434 case Color: *foreground = decl.brushValue(pal);
break;
1435 case QtSelectionForeground: *selectedForeground = decl.brushValue(pal);
break;
1436 case QtSelectionBackground: *selectedBackground = decl.brushValue(pal);
break;
1437 case QtAlternateBackground: *alternateBackground = decl.brushValue(pal);
break;
1438 case QtPlaceHolderTextColor: *placeHolderTextForeground = decl.brushValue(pal);
break;
1439 case QtAccent: *accent = decl.brushValue(pal);
break;
1447void ValueExtractor::extractFont()
1452 extractFont(&f, &dummy);
1455bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size)
1458 for (
int i = 0; i < declarations.size(); ++i) {
1459 const Declaration &decl = declarations.at(i);
1460 switch (decl.d->propertyId) {
1462 *icon = decl.iconValue();
1463 if (decl.d->values.size() > 0 && decl.d->values.at(0).type == Value::Uri) {
1465 QImageReader imageReader(decl.d->values.at(0).variant.toString());
1466 if ((*size = imageReader.size()).isNull()) {
1469 *size = imageReader.read().size();
1473 case QtImageAlignment: *a = decl.alignmentValue();
break;
1481bool ValueExtractor::extractIcon(QIcon *icon, QSize *size)
1484 const auto declaration = std::find_if(
1485 declarations.rbegin(), declarations.rend(),
1486 [](
const Declaration &decl) {
return decl.d->propertyId == QtIcon; });
1487 if (declaration == declarations.rend())
1490 *icon = declaration->iconValue();
1493 if (declaration->d->values.isEmpty())
1496 const auto &propertyValue = declaration->d->values.constFirst();
1497 if (propertyValue.type != Value::Uri)
1501 const QString url(propertyValue.variant.toString());
1502 QImageReader imageReader(url);
1503 *size = imageReader.size();
1504 if (!size->isNull())
1508 *size = imageReader.read().size();
1514QColor Declaration::colorValue(
const QPalette &pal)
const
1516 if (d->values.size() != 1)
1519 if (d->parsed.isValid()) {
1520 switch (d->parsed.typeId()) {
1521 case qMetaTypeId<QColor>():
1522 return qvariant_cast<QColor>(d->parsed);
1523 case qMetaTypeId<
int>():
1524 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1525 case qMetaTypeId<QList<QVariant>>():
1526 if (d->parsed.toList().size() == 1) {
1527 auto parsedList = d->parsed.toList();
1528 const auto &value = parsedList.at(0);
1529 return qvariant_cast<QColor>(value);
1535 ColorData color = parseColorValue(d->values.at(0));
1536 if (color.type == ColorData::Role) {
1537 d->parsed = QVariant::fromValue<
int>(color.role);
1538 return pal.color((QPalette::ColorRole)(color.role));
1540 d->parsed = QVariant::fromValue<QColor>(color.color);
1545QBrush Declaration::brushValue(
const QPalette &pal)
const
1547 if (d->values.size() != 1)
1550 if (d->parsed.isValid()) {
1551 if (d->parsed.userType() == QMetaType::QBrush)
1552 return qvariant_cast<QBrush>(d->parsed);
1553 if (d->parsed.userType() == QMetaType::Int)
1554 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1557 BrushData data = parseBrushValue(d->values.at(0), pal);
1559 if (data.type == BrushData::Role) {
1560 d->parsed = QVariant::fromValue<
int>(data.role);
1561 return pal.color((QPalette::ColorRole)(data.role));
1563 if (data.type != BrushData::DependsOnThePalette)
1564 d->parsed = QVariant::fromValue<QBrush>(data.brush);
1569void Declaration::brushValues(QBrush *c,
const QPalette &pal)
const
1571 int needParse = 0x1f;
1574 if (d->parsed.isValid()) {
1576 Q_ASSERT(d->parsed.metaType() == QMetaType::fromType<QList<QVariant>>());
1577 QList<QVariant> v = d->parsed.toList();
1578 for (i = 0; i < qMin(v.size(), 4); i++) {
1579 if (v.at(i).userType() == QMetaType::QBrush) {
1580 c[i] = qvariant_cast<QBrush>(v.at(i));
1581 }
else if (v.at(i).userType() == QMetaType::Int) {
1582 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1584 needParse |= (1<<i);
1588 if (needParse != 0) {
1590 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1591 if (!(needParse & (1<<i)))
1593 BrushData data = parseBrushValue(d->values.at(i), pal);
1594 if (data.type == BrushData::Role) {
1595 v += QVariant::fromValue<
int>(data.role);
1596 c[i] = pal.color((QPalette::ColorRole)(data.role));
1598 if (data.type != BrushData::DependsOnThePalette) {
1599 v += QVariant::fromValue<QBrush>(data.brush);
1606 if (needParse & 0x10)
1609 if (i == 0) c[0] = c[1] = c[2] = c[3] = QBrush();
1610 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1611 else if (i == 2) c[2] = c[0], c[3] = c[1];
1612 else if (i == 3) c[3] = c[1];
1615bool Declaration::realValue(qreal *real,
const char *unit)
const
1617 if (d->values.size() != 1)
1619 const Value &v = d->values.at(0);
1620 if (unit && v.type != Value::Length)
1622 const QString str = v.variant.toString();
1625 const QLatin1StringView unitStr(unit);
1626 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1628 s.chop(unitStr.size());
1631 qreal val = s.toDouble(&ok);
1641 const QString str = v.variant.toString();
1644 const QLatin1StringView unitStr(unit);
1645 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1647 s.chop(unitStr.size());
1650 int val = s.toInt(&ok);
1656bool Declaration::intValue(
int *i,
const char *unit)
const
1658 if (d->values.size() != 1)
1660 return intValueHelper(d->values.at(0), i, unit);
1663QSize Declaration::sizeValue()
const
1665 if (d->parsed.isValid())
1666 return qvariant_cast<QSize>(d->parsed);
1668 int x[2] = { 0, 0 };
1669 const int count = d->values.size();
1670 for (
int i = 0; i < count; ++i) {
1672 qWarning(
"QCssParser::sizeValue: Too many values provided");
1675 const auto &value = d->values.at(i);
1676 const QString valueString = value.variant.toString();
1677 if (valueString.endsWith(u"pt", Qt::CaseInsensitive)) {
1678 intValueHelper(value, &x[i],
"pt");
1681 x[i] = (x[i] * 72) / 96;
1684 intValueHelper(value, &x[i],
"px");
1689 QSize size(x[0], x[1]);
1690 d->parsed = QVariant::fromValue<QSize>(size);
1694QRect Declaration::rectValue()
const
1696 if (d->values.size() != 1)
1699 if (d->parsed.isValid())
1700 return qvariant_cast<QRect>(d->parsed);
1702 const QCss::Value &v = d->values.at(0);
1703 if (v.type != Value::Function)
1705 const QStringList func = v.variant.toStringList();
1706 if (func.size() != 2 || func.at(0).compare(
"rect"_L1) != 0)
1708 const auto args = QStringView{func[1]}.split(u' ', Qt::SkipEmptyParts);
1709 if (args.size() != 4)
1711 QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
1712 d->parsed = QVariant::fromValue<QRect>(rect);
1716void Declaration::colorValues(QColor *c,
const QPalette &pal)
const
1719 if (d->parsed.isValid()) {
1720 QList<QVariant> v = d->parsed.toList();
1721 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1722 if (v.at(i).userType() == QMetaType::QColor) {
1723 c[i] = qvariant_cast<QColor>(v.at(i));
1725 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1730 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1731 ColorData color = parseColorValue(d->values.at(i));
1732 if (color.type == ColorData::Role) {
1733 v += QVariant::fromValue<
int>(color.role);
1734 c[i] = pal.color((QPalette::ColorRole)(color.role));
1736 v += QVariant::fromValue<QColor>(color.color);
1743 if (i == 0) c[0] = c[1] = c[2] = c[3] = QColor();
1744 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1745 else if (i == 2) c[2] = c[0], c[3] = c[1];
1746 else if (i == 3) c[3] = c[1];
1749BorderStyle Declaration::styleValue()
const
1751 if (d->values.size() != 1)
1752 return BorderStyle_None;
1753 return parseStyleValue(d->values.at(0));
1756void Declaration::styleValues(BorderStyle *s)
const
1759 for (i = 0; i < qMin(d->values.size(), 4); i++)
1760 s[i] = parseStyleValue(d->values.at(i));
1761 if (i == 0) s[0] = s[1] = s[2] = s[3] = BorderStyle_None;
1762 else if (i == 1) s[3] = s[2] = s[1] = s[0];
1763 else if (i == 2) s[2] = s[0], s[3] = s[1];
1764 else if (i == 3) s[3] = s[1];
1767Repeat Declaration::repeatValue()
const
1769 if (d->parsed.isValid())
1770 return static_cast<Repeat>(d->parsed.toInt());
1771 if (d->values.size() != 1)
1772 return Repeat_Unknown;
1773 int v = findKnownValue(d->values.at(0).variant.toString(),
1774 repeats, NumKnownRepeats);
1776 return static_cast<Repeat>(v);
1779Origin Declaration::originValue()
const
1781 if (d->parsed.isValid())
1782 return static_cast<Origin>(d->parsed.toInt());
1783 if (d->values.size() != 1)
1784 return Origin_Unknown;
1785 int v = findKnownValue(d->values.at(0).variant.toString(),
1786 origins, NumKnownOrigins);
1788 return static_cast<Origin>(v);
1791PositionMode Declaration::positionValue()
const
1793 if (d->parsed.isValid())
1794 return static_cast<PositionMode>(d->parsed.toInt());
1795 if (d->values.size() != 1)
1796 return PositionMode_Unknown;
1797 int v = findKnownValue(d->values.at(0).variant.toString(),
1798 positions, NumKnownPositionModes);
1800 return static_cast<PositionMode>(v);
1803Attachment Declaration::attachmentValue()
const
1805 if (d->parsed.isValid())
1806 return static_cast<Attachment>(d->parsed.toInt());
1807 if (d->values.size() != 1)
1808 return Attachment_Unknown;
1809 int v = findKnownValue(d->values.at(0).variant.toString(),
1810 attachments, NumKnownAttachments);
1812 return static_cast<Attachment>(v);
1815int Declaration::styleFeaturesValue()
const
1817 Q_ASSERT(d->propertyId == QtStyleFeatures);
1818 if (d->parsed.isValid())
1819 return d->parsed.toInt();
1820 int features = StyleFeature_None;
1821 for (
int i = 0; i < d->values.size(); i++) {
1822 features |=
static_cast<
int>(findKnownValue(d->values.value(i).variant.toString(),
1823 styleFeatures, NumKnownStyleFeatures));
1825 d->parsed = features;
1829QString Declaration::uriValue()
const
1831 if (d->values.isEmpty() || d->values.at(0).type != Value::Uri)
1833 return d->values.at(0).variant.toString();
1836Qt::Alignment Declaration::alignmentValue()
const
1838 if (d->parsed.isValid())
1839 return Qt::Alignment(d->parsed.toInt());
1840 if (d->values.isEmpty() || d->values.size() > 2)
1841 return Qt::AlignLeft | Qt::AlignTop;
1843 Qt::Alignment v = parseAlignment(d->values.constData(), d->values.size());
1848void Declaration::borderImageValue(QString *image,
int *cuts,
1849 TileMode *h, TileMode *v)
const
1851 const DeclarationData *d =
this->d.data();
1852 *image = uriValue();
1853 for (
int i = 0; i < 4; i++)
1855 *h = *v = TileMode_Stretch;
1857 if (d->values.size() < 2)
1860 if (d->values.at(1).type == Value::Number) {
1862 for (i = 0; i < qMin(d->values.size()-1, 4); i++) {
1863 const Value& v = d->values.at(i+1);
1864 if (v.type != Value::Number)
1866 cuts[i] = v.variant.toString().toInt();
1868 qWarning(
"Declaration::borderImageValue: Invalid cut value %d at position %d",
1870 cuts[0] = cuts[1] = cuts[2] = cuts[3] = -1;
1875 if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
1876 else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];
1877 else if (i == 2) cuts[2] = cuts[0], cuts[3] = cuts[1];
1878 else if (i == 3) cuts[3] = cuts[1];
1881 if (d->values.last().type == Value::Identifier) {
1882 *v =
static_cast<TileMode>(findKnownValue(d->values.last().variant.toString(),
1883 tileModes, NumKnownTileModes));
1885 if (d->values[d->values.size() - 2].type == Value::Identifier) {
1886 *h =
static_cast<TileMode>
1887 (findKnownValue(d->values[d->values.size()-2].variant.toString(),
1888 tileModes, NumKnownTileModes));
1893bool Declaration::borderCollapseValue()
const
1895 if (d->values.size() != 1)
1898 return d->values.at(0).toString() ==
"collapse"_L1;
1901QList<qreal> Declaration::dashArray()
const
1903 if (d->propertyId != Property::QtStrokeDashArray || d->values.empty())
1904 return QList<qreal>();
1906 bool isValid =
true;
1907 QList<qreal> dashes;
1908 for (
int i = 0; i < d->values.size(); i++) {
1909 Value v = d->values[i];
1911 bool isValidSeparator = (i & 1) && v.type == Value::TermOperatorComma;
1912 bool isValidNumber = !(i & 1) && v.type == Value::Number;
1913 if (!isValidNumber && !isValidSeparator) {
1916 }
else if (isValidNumber) {
1918 dashes.append(v.variant.toReal(&ok));
1926 isValid &= !(dashes.size() & 1);
1927 return isValid ? dashes : QList<qreal>();
1930QIcon Declaration::iconValue()
const
1932 if (d->parsed.isValid())
1933 return qvariant_cast<QIcon>(d->parsed);
1936 for (
int i = 0; i < d->values.size();) {
1937 const Value &value = d->values.at(i++);
1938 if (value.type != Value::Uri)
1940 QString uri = value.variant.toString();
1941 QIcon::Mode mode = QIcon::Normal;
1942 QIcon::State state = QIcon::Off;
1943 for (
int j = 0; j < 2; j++) {
1944 if (i != d->values.size() && d->values.at(i).type == Value::KnownIdentifier) {
1945 switch (d->values.at(i).variant.toInt()) {
1946 case Value_Disabled: mode = QIcon::Disabled;
break;
1947 case Value_Active: mode = QIcon::Active;
break;
1948 case Value_Selected: mode = QIcon::Selected;
break;
1949 case Value_Normal: mode = QIcon::Normal;
break;
1950 case Value_On: state = QIcon::On;
break;
1951 case Value_Off: state = QIcon::Off;
break;
1964 icon.addPixmap(uri, mode, state);
1966 if (i == d->values.size())
1969 if (d->values.at(i).type == Value::TermOperatorComma)
1973 d->parsed = QVariant::fromValue<QIcon>(icon);
1979int Selector::specificity()
const
1982 for (
int i = 0; i < basicSelectors.size(); ++i) {
1983 const BasicSelector &sel = basicSelectors.at(i);
1984 if (!sel.elementName.isEmpty())
1987 val += (sel.pseudos.size() + sel.attributeSelectors.size()) * 0x10;
1988 val += sel.ids.size() * 0x100;
1993QString Selector::pseudoElement()
const
1995 const BasicSelector& bs = basicSelectors.last();
1996 if (!bs.pseudos.isEmpty() && bs.pseudos.at(0).type == PseudoClass_Unknown)
1997 return bs.pseudos.at(0).name;
2001quint64 Selector::pseudoClass(quint64 *negated)
const
2003 const BasicSelector& bs = basicSelectors.last();
2004 if (bs.pseudos.isEmpty())
2005 return PseudoClass_Unspecified;
2006 quint64 pc = PseudoClass_Unknown;
2007 for (
int i = !pseudoElement().isEmpty(); i < bs.pseudos.size(); i++) {
2008 const Pseudo &pseudo = bs.pseudos.at(i);
2009 if (pseudo.type == PseudoClass_Unknown)
2010 return PseudoClass_Unknown;
2011 if (!pseudo.negated)
2014 *negated |= pseudo.type;
2023 QList<StyleRule> universals;
2024 for (
int i = 0; i < styleRules.size(); ++i) {
2025 const StyleRule &rule = styleRules.at(i);
2026 QList<Selector> universalsSelectors;
2027 for (
int j = 0; j < rule.selectors.size(); ++j) {
2028 const Selector& selector = rule.selectors.at(j);
2030 if (selector.basicSelectors.isEmpty())
2034 if (selector.basicSelectors.size() != 1)
2036 }
else if (selector.basicSelectors.size() <= 1) {
2040 const BasicSelector &sel = selector.basicSelectors.at(selector.basicSelectors.size() - 1);
2042 if (!sel.ids.isEmpty()) {
2044 nr.selectors += selector;
2045 nr.declarations = rule.declarations;
2047 idIndex.insert(sel.ids.at(0), nr);
2048 }
else if (!sel.elementName.isEmpty()) {
2050 nr.selectors += selector;
2051 nr.declarations = rule.declarations;
2053 QString name = sel.elementName;
2054 if (nameCaseSensitivity == Qt::CaseInsensitive)
2055 name = std::move(name).toLower();
2056 nameIndex.insert(name, nr);
2058 universalsSelectors += selector;
2061 if (!universalsSelectors.isEmpty()) {
2063 nr.selectors = universalsSelectors;
2064 nr.declarations = rule.declarations;
2069 styleRules = universals;
2074StyleSelector::~StyleSelector()
2078bool StyleSelector::nodeNameEquals(NodePtr node,
const QString& nodeName)
const
2080 return nodeNames(node).contains(nodeName, nameCaseSensitivity);
2083QStringList StyleSelector::nodeIds(NodePtr node)
const
2085 return QStringList(attributeValue(node, QCss::AttributeSelector{
"id"_L1, {}, AttributeSelector::NoMatch}));
2088bool StyleSelector::selectorMatches(
const Selector &selector, NodePtr node)
2090 if (selector.basicSelectors.isEmpty())
2093 if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
2094 if (selector.basicSelectors.size() != 1)
2096 return basicSelectorMatches(selector.basicSelectors.at(0), node);
2098 if (selector.basicSelectors.size() <= 1)
2101 int i = selector.basicSelectors.size() - 1;
2102 node = duplicateNode(node);
2105 BasicSelector sel = selector.basicSelectors.at(i);
2107 match = basicSelectorMatches(sel, node);
2109 if (i == selector.basicSelectors.size() - 1)
2111 if (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2112 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent)
2116 if (match || (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2117 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent))
2123 sel = selector.basicSelectors.at(i);
2124 if (sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2125 || sel.relationToNext == BasicSelector::MatchNextSelectorIfParent) {
2127 NodePtr nextParent = parentNode(node);
2130 }
else if (sel.relationToNext == BasicSelector::MatchNextSelectorIfDirectAdjecent
2131 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent) {
2132 NodePtr previousSibling = previousSiblingNode(node);
2134 node = previousSibling;
2136 if (isNullNode(node)) {
2140 }
while (i >= 0 && (match || sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2141 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent));
2148bool StyleSelector::basicSelectorMatches(
const BasicSelector &sel, NodePtr node)
2150 if (!sel.attributeSelectors.isEmpty()) {
2151 if (!hasAttributes(node))
2154 for (
int i = 0; i < sel.attributeSelectors.size(); ++i) {
2155 const QCss::AttributeSelector &a = sel.attributeSelectors.at(i);
2157 const QString attrValue = attributeValue(node, a);
2158 if (attrValue.isNull())
2161 switch (a.valueMatchCriterium) {
2162 case QCss::AttributeSelector::NoMatch:
2164 case QCss::AttributeSelector::MatchEqual:
2165 if (attrValue != a.value)
2168 case QCss::AttributeSelector::MatchIncludes: {
2169 const auto lst = QStringView{attrValue}.tokenize(u' ');
2171 for (
auto s : lst) {
2181 case QCss::AttributeSelector::MatchDashMatch: {
2182 const QString dashPrefix = a.value + u'-';
2183 if (attrValue != a.value && !attrValue.startsWith(dashPrefix))
2187 case QCss::AttributeSelector::MatchBeginsWith:
2188 if (!attrValue.startsWith(a.value))
2191 case QCss::AttributeSelector::MatchEndsWith:
2192 if (!attrValue.endsWith(a.value))
2195 case QCss::AttributeSelector::MatchContains:
2196 if (!attrValue.contains(a.value))
2203 if (!sel.elementName.isEmpty()
2204 && !nodeNameEquals(node, sel.elementName))
2207 if (!sel.ids.isEmpty()
2208 && sel.ids != nodeIds(node))
2214void StyleSelector::matchRule(NodePtr node,
const StyleRule &rule, StyleSheetOrigin origin,
2215 int depth, QMultiMap<uint, StyleRule> *weightedRules)
2217 for (
int j = 0; j < rule.selectors.size(); ++j) {
2218 const Selector& selector = rule.selectors.at(j);
2219 if (selectorMatches(selector, node)) {
2220 uint weight = rule.order
2221 + selector.specificity() *0x100
2222 + (uint(origin) + depth)*0x100000;
2223 StyleRule newRule = rule;
2224 if (rule.selectors.size() > 1) {
2225 newRule.selectors.resize(1);
2226 newRule.selectors[0] = selector;
2229 weightedRules->insert(weight, newRule);
2236QList<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
2238 QList<StyleRule> rules;
2239 if (styleSheets.isEmpty())
2242 QMultiMap<uint, StyleRule> weightedRules;
2245 for (
int sheetIdx = 0; sheetIdx < styleSheets.size(); ++sheetIdx) {
2246 const StyleSheet &styleSheet = styleSheets.at(sheetIdx);
2247 for (
int i = 0; i < styleSheet.styleRules.size(); ++i) {
2248 matchRule(node, styleSheet.styleRules.at(i), styleSheet.origin, styleSheet.depth, &weightedRules);
2251 if (!styleSheet.idIndex.isEmpty()) {
2252 QStringList ids = nodeIds(node);
2253 for (
int i = 0; i < ids.size(); i++) {
2254 const QString &key = ids.at(i);
2255 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.idIndex.constFind(key);
2256 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
2257 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2262 if (!styleSheet.nameIndex.isEmpty()) {
2263 QStringList names = nodeNames(node);
2264 for (
int i = 0; i < names.size(); i++) {
2265 QString name = names.at(i);
2266 if (nameCaseSensitivity == Qt::CaseInsensitive)
2267 name = std::move(name).toLower();
2268 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
2269 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
2270 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2275 if (!medium.isEmpty()) {
2276 for (
int i = 0; i < styleSheet.mediaRules.size(); ++i) {
2277 if (styleSheet.mediaRules.at(i).media.contains(medium, Qt::CaseInsensitive)) {
2278 for (
int j = 0; j < styleSheet.mediaRules.at(i).styleRules.size(); ++j) {
2279 matchRule(node, styleSheet.mediaRules.at(i).styleRules.at(j), styleSheet.origin,
2280 styleSheet.depth, &weightedRules);
2287 rules.reserve(weightedRules.size());
2288 QMultiMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
2289 for ( ; it != weightedRules.constEnd() ; ++it)
2297QList<Declaration> StyleSelector::declarationsForNode(NodePtr node,
const char *extraPseudo)
2299 QList<Declaration> decls;
2300 QList<StyleRule> rules = styleRulesForNode(node);
2301 for (
int i = 0; i < rules.size(); i++) {
2302 const Selector& selector = rules.at(i).selectors.at(0);
2303 const QString pseudoElement = selector.pseudoElement();
2305 if (extraPseudo && pseudoElement == QLatin1StringView(extraPseudo)) {
2306 decls += rules.at(i).declarations;
2310 if (!pseudoElement.isEmpty())
2312 quint64 pseudoClass = selector.pseudoClass();
2313 if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
2314 decls += rules.at(i).declarations;
2321 return (c >=
'0' && c <=
'9')
2322 || (c >=
'a' && c <=
'f')
2323 || (c >=
'A' && c <=
'F')
2327QString Scanner::preprocess(
const QString &input,
bool *hasEscapeSequences)
2329 QString output = input;
2331 if (hasEscapeSequences)
2332 *hasEscapeSequences =
false;
2335 while (i < output.size()) {
2336 if (output.at(i) == u'\\') {
2341 const int hexStart = i;
2342 while (i < output.size()
2343 && isHexDigit(output.at(i).toLatin1())
2348 if (hexCount == 0) {
2349 if (hasEscapeSequences)
2350 *hasEscapeSequences =
true;
2354 hexCount = qMin(hexCount, 6);
2356 const char16_t code = QStringView{output}.mid(hexStart, hexCount).toUShort(&ok, 16);
2358 output.replace(hexStart - 1, hexCount + 1, code);
2370int QCssScanner_Generated::handleCommentStart()
2372 while (pos < input.size() - 1) {
2373 if (input.at(pos) == u'*' && input.at(pos + 1) == u'/') {
2382void Scanner::scan(
const QString &preprocessedInput, QList<Symbol> *symbols)
2384 QCssScanner_Generated scanner(preprocessedInput);
2386 int tok = scanner.lex();
2388 sym.token =
static_cast<QCss::TokenType>(tok);
2389 sym.text = scanner.input;
2390 sym.start = scanner.lexemStart;
2391 sym.len = scanner.lexemLength;
2392 symbols->append(sym);
2393 tok = scanner.lex();
2401 result.reserve(
len);
2402 for (
int i = 0; i <
len; ++i) {
2403 if (text.at(start + i) == u'\\' && i < len - 1)
2405 result += text.at(start + i);
2410Parser::Parser(
const QString &css,
bool isFile)
2419 hasEscapeSequences =
false;
2422void Parser::init(
const QString &css,
bool isFile)
2424 QString styleSheet = css;
2427 if (file.open(QFile::ReadOnly)) {
2428 sourcePath = QFileInfo(styleSheet).absolutePath() + u'/';
2429 QTextStream stream(&file);
2430 styleSheet = stream.readAll();
2432 qWarning() <<
"QCss::Parser - Failed to load file " << css;
2439 hasEscapeSequences =
false;
2442 Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
2447bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
2449 if (testTokenAndEndsWith(ATKEYWORD_SYM,
"charset"_L1)) {
2450 while (test(S) || test(CDO) || test(CDC)) {}
2451 if (!next(STRING))
return false;
2452 if (!next(SEMICOLON))
return false;
2455 while (test(S) || test(CDO) || test(CDC)) {}
2457 while (testImport()) {
2459 if (!parseImport(&rule))
return false;
2460 styleSheet->importRules.append(rule);
2461 while (test(S) || test(CDO) || test(CDC)) {}
2467 if (!parseMedia(&rule))
return false;
2468 styleSheet->mediaRules.append(rule);
2469 }
else if (testPage()) {
2471 if (!parsePage(&rule))
return false;
2472 styleSheet->pageRules.append(rule);
2473 }
else if (testAnimation()) {
2475 if (!parseAnimation(&rule))
return false;
2476 styleSheet->animationRules.append(rule);
2477 }
else if (testRuleset()) {
2479 if (!parseRuleset(&rule))
return false;
2480 styleSheet->styleRules.append(rule);
2481 }
else if (test(ATKEYWORD_SYM)) {
2482 if (!until(RBRACE))
return false;
2483 }
else if (hasNext()) {
2486 while (test(S) || test(CDO) || test(CDC)) {}
2487 }
while (hasNext());
2488 styleSheet->buildIndexes(nameCaseSensitivity);
2492Symbol Parser::errorSymbol()
2494 if (errorIndex == -1)
return Symbol();
2495 return symbols.at(errorIndex);
2500 if (!str->startsWith(u'\'') && !str->startsWith(u'\"'))
2506bool Parser::parseImport(ImportRule *importRule)
2511 importRule->href = lexem();
2513 if (!testAndParseUri(&importRule->href))
return false;
2515 removeOptionalQuotes(&importRule->href);
2520 if (!parseMedium(&importRule->media))
return false;
2522 while (test(COMMA)) {
2524 if (!parseNextMedium(&importRule->media))
return false;
2528 if (!next(SEMICOLON))
return false;
2534bool Parser::parseMedia(MediaRule *mediaRule)
2538 if (!parseNextMedium(&mediaRule->media))
return false;
2539 }
while (test(COMMA));
2541 if (!next(LBRACE))
return false;
2544 while (testRuleset()) {
2546 if (!parseRuleset(&rule))
return false;
2547 mediaRule->styleRules.append(rule);
2550 if (!next(RBRACE))
return false;
2555bool Parser::parseMedium(QStringList *media)
2557 media->append(lexem());
2562bool Parser::parsePage(PageRule *pageRule)
2566 if (testPseudoPage())
2567 if (!parsePseudoPage(&pageRule->selector))
return false;
2570 if (!next(LBRACE))
return false;
2575 if (!parseNextDeclaration(&decl))
return false;
2576 if (!decl.isEmpty())
2577 pageRule->declarations.append(decl);
2578 }
while (test(SEMICOLON));
2580 if (!next(RBRACE))
return false;
2585bool Parser::parsePseudoPage(QString *selector)
2587 if (!next(IDENT))
return false;
2588 *selector = lexem();
2592bool Parser::parseNextOperator(Value *value)
2594 if (!hasNext())
return true;
2596 case SLASH: value->type = Value::TermOperatorSlash; skipSpace();
break;
2597 case COMMA: value->type = Value::TermOperatorComma; skipSpace();
break;
2598 default: prev();
break;
2603bool Parser::parseAnimation(AnimationRule *animationRule)
2606 if (!test(IDENT))
return false;
2608 animationRule->animName = lexem();
2610 if (!next(LBRACE))
return false;
2613 while (test(PERCENTAGE) || test(IDENT)) {
2614 AnimationRule::AnimationRuleSet set;
2615 if (lookup() == PERCENTAGE) {
2616 QString name = lexem();
2618 float keyFrame = name.toFloat() / 100;
2619 set.keyFrame = keyFrame;
2620 }
else if (lookup() == IDENT) {
2622 if (parseElementName(&name)) {
2623 if (name == QStringLiteral(
"from"))
2625 else if (name == QStringLiteral(
"to"))
2631 if (!next(LBRACE))
return false;
2632 const int declarationStart = index;
2637 const int rewind = index;
2638 if (!parseNextDeclaration(&decl)) {
2640 const bool foundSemicolon = until(SEMICOLON);
2641 const int semicolonIndex = index;
2643 index = declarationStart;
2644 const bool foundRBrace = until(RBRACE);
2646 if (foundSemicolon && semicolonIndex < index) {
2647 decl = Declaration();
2648 index = semicolonIndex - 1;
2654 if (!decl.isEmpty())
2655 set.declarations.append(decl);
2656 }
while (test(SEMICOLON));
2658 if (!next(RBRACE))
return false;
2660 animationRule->ruleSets.append(set);
2663 if (!next(RBRACE))
return false;
2669bool Parser::parseCombinator(BasicSelector::Relation *relation)
2671 *relation = BasicSelector::NoRelation;
2672 if (lookup() == S) {
2673 *relation = BasicSelector::MatchNextSelectorIfAncestor;
2679 *relation = BasicSelector::MatchNextSelectorIfDirectAdjecent;
2680 }
else if (test(GREATER)) {
2681 *relation = BasicSelector::MatchNextSelectorIfParent;
2682 }
else if (test(TILDE)) {
2683 *relation = BasicSelector::MatchNextSelectorIfIndirectAdjecent;
2689bool Parser::parseProperty(Declaration *decl)
2691 decl->d->property = lexem();
2692 decl->d->propertyId =
static_cast<Property>(findKnownValue(decl->d->property, properties, NumProperties));
2693 decl->d->inheritable = isInheritable(decl->d->propertyId);
2698bool Parser::parseRuleset(StyleRule *styleRule)
2701 if (!parseSelector(&sel))
return false;
2702 styleRule->selectors.append(sel);
2704 while (test(COMMA)) {
2707 if (!parseNextSelector(&sel))
return false;
2708 styleRule->selectors.append(sel);
2712 if (!next(LBRACE))
return false;
2713 const int declarationStart = index;
2718 const int rewind = index;
2719 if (!parseNextDeclaration(&decl)) {
2721 const bool foundSemicolon = until(SEMICOLON);
2722 const int semicolonIndex = index;
2724 index = declarationStart;
2725 const bool foundRBrace = until(RBRACE);
2727 if (foundSemicolon && semicolonIndex < index) {
2728 decl = Declaration();
2729 index = semicolonIndex - 1;
2735 if (!decl.isEmpty())
2736 styleRule->declarations.append(decl);
2737 }
while (test(SEMICOLON));
2739 if (!next(RBRACE))
return false;
2744bool Parser::parseSelector(Selector *sel)
2746 BasicSelector basicSel;
2747 if (!parseSimpleSelector(&basicSel))
return false;
2748 while (testCombinator()) {
2749 if (!parseCombinator(&basicSel.relationToNext))
return false;
2751 if (!testSimpleSelector())
break;
2752 sel->basicSelectors.append(basicSel);
2754 basicSel = BasicSelector();
2755 if (!parseSimpleSelector(&basicSel))
return false;
2757 sel->basicSelectors.append(basicSel);
2761bool Parser::parseSimpleSelector(BasicSelector *basicSel)
2764 if (lookupElementName()) {
2765 if (!parseElementName(&basicSel->elementName))
return false;
2775 QString theid = lexem();
2778 basicSel->ids.append(theid);
2780 }
else if (testClass()) {
2782 AttributeSelector a;
2783 a.name =
"class"_L1;
2784 a.valueMatchCriterium = AttributeSelector::MatchIncludes;
2785 if (!parseClass(&a.value))
return false;
2786 basicSel->attributeSelectors.append(a);
2787 }
else if (testAttrib()) {
2789 AttributeSelector a;
2790 if (!parseAttrib(&a))
return false;
2791 basicSel->attributeSelectors.append(a);
2792 }
else if (testPseudo()) {
2795 if (!parsePseudo(&ps))
return false;
2796 basicSel->pseudos.append(ps);
2798 if (onceMore) ++count;
2800 return count >= minCount;
2803bool Parser::parseClass(QString *name)
2805 if (!next(IDENT))
return false;
2810bool Parser::parseElementName(QString *name)
2813 case STAR: name->clear();
break;
2814 case IDENT: *name = lexem();
break;
2815 default:
return false;
2820bool Parser::parseAttrib(AttributeSelector *attr)
2823 if (!next(IDENT))
return false;
2824 attr->name = lexem();
2828 attr->valueMatchCriterium = AttributeSelector::MatchEqual;
2829 }
else if (test(INCLUDES)) {
2830 attr->valueMatchCriterium = AttributeSelector::MatchIncludes;
2831 }
else if (test(DASHMATCH)) {
2832 attr->valueMatchCriterium = AttributeSelector::MatchDashMatch;
2833 }
else if (test(BEGINSWITH)) {
2834 attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
2835 }
else if (test(ENDSWITH)) {
2836 attr->valueMatchCriterium = AttributeSelector::MatchEndsWith;
2837 }
else if (test(CONTAINS)) {
2838 attr->valueMatchCriterium = AttributeSelector::MatchContains;
2840 return next(RBRACKET);
2845 if (!test(IDENT) && !test(STRING))
return false;
2846 attr->value = unquotedLexem();
2849 return next(RBRACKET);
2852bool Parser::parsePseudo(Pseudo *pseudo)
2855 pseudo->negated = test(EXCLAMATION_SYM);
2857 pseudo->name = lexem();
2858 pseudo->type =
static_cast<quint64>(findKnownValue(pseudo->name, pseudos, NumPseudos));
2861 if (!next(FUNCTION))
return false;
2862 pseudo->function = lexem();
2864 pseudo->function.chop(1);
2866 if (!test(IDENT))
return false;
2867 pseudo->name = lexem();
2869 return next(RPAREN);
2872bool Parser::parseNextDeclaration(Declaration *decl)
2874 if (!testProperty())
2876 if (!parseProperty(decl))
return false;
2877 if (!next(COLON))
return false;
2879 if (!parseNextExpr(&decl->d->values))
return false;
2881 if (!parsePrio(decl))
return false;
2885bool Parser::testPrio()
2887 const int rewind = index;
2888 if (!test(EXCLAMATION_SYM))
return false;
2894 if (lexem().compare(
"important"_L1, Qt::CaseInsensitive) != 0) {
2901bool Parser::parsePrio(Declaration *declaration)
2903 declaration->d->important =
true;
2908bool Parser::parseExpr(QList<Value> *values)
2911 if (!parseTerm(&val))
return false;
2912 values->append(val);
2917 if (!parseNextOperator(&val))
return false;
2918 if (val.type != QCss::Value::Unknown)
2919 values->append(val);
2923 if (!parseTerm(&val))
return false;
2924 values->append(val);
2930bool Parser::testTerm()
2932 return test(PLUS) || test(MINUS)
2942bool Parser::parseTerm(Value *value)
2944 QString str = lexem();
2945 bool haveUnary =
false;
2946 if (lookup() == PLUS || lookup() == MINUS) {
2948 if (!hasNext())
return false;
2953 value->variant = str;
2954 value->type = QCss::Value::String;
2957 value->type = Value::Number;
2958 value->variant.convert(QMetaType::fromType<
double>());
2961 value->type = Value::Percentage;
2963 value->variant = str;
2966 value->type = Value::Length;
2970 if (haveUnary)
return false;
2971 value->type = Value::String;
2974 value->variant = str;
2977 if (haveUnary)
return false;
2978 value->type = Value::Identifier;
2979 const int theid = findKnownValue(str, values, NumKnownValues);
2981 value->type = Value::KnownIdentifier;
2982 value->variant = theid;
2987 if (haveUnary)
return false;
2989 if (testHexColor()) {
2991 if (!parseHexColor(&col))
return false;
2992 value->type = Value::Color;
2993 value->variant = col;
2994 }
else if (testFunction()) {
2996 if (!parseFunction(&name, &args))
return false;
2997 if (name ==
"url"_L1) {
2998 value->type = Value::Uri;
2999 removeOptionalQuotes(&args);
3000 if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
3001 args.prepend(sourcePath);
3003 value->variant = args;
3005 value->type = Value::Function;
3006 value->variant = QStringList() << name << args;
3009 return recordError();
3018bool Parser::parseFunction(QString *name, QString *args)
3025 std::swap(start, index);
3026 if (!until(RPAREN))
return false;
3027 for (
int i = start; i < index - 1; ++i)
3028 args->append(symbols.at(i).lexem());
3030
3031
3032
3037bool Parser::parseHexColor(QColor *col)
3039 *col = QColor::fromString(lexem());
3040 if (!col->isValid()) {
3041 qWarning(
"QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
3048bool Parser::testAndParseUri(QString *uri)
3050 const int rewind = index;
3051 if (!testFunction())
return false;
3054 if (!parseFunction(&name, &args)) {
3058 if (name.compare(
"url"_L1, Qt::CaseInsensitive) != 0) {
3063 removeOptionalQuotes(uri);
3067bool Parser::testSimpleSelector()
3069 return testElementName()
3076bool Parser::next(QCss::TokenType t)
3078 if (hasNext() && next() == t)
3080 return recordError();
3083bool Parser::test(QCss::TokenType t)
3085 if (index >= symbols.size())
3087 if (symbols.at(index).token == t) {
3094QString Parser::unquotedLexem()
const
3096 QString s = lexem();
3097 if (lookup() == STRING) {
3104QString Parser::lexemUntil(QCss::TokenType t)
3107 while (hasNext() && next() != t)
3108 lexem += symbol().lexem();
3112bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
3118 switch(symbols.at(index-1).token) {
3119 case LBRACE: ++braceCount;
break;
3120 case LBRACKET: ++brackCount;
break;
3122 case LPAREN: ++parenCount;
break;
3126 while (index < symbols.size()) {
3127 QCss::TokenType t = symbols.at(index++).token;
3129 case LBRACE: ++braceCount;
break;
3130 case RBRACE: --braceCount;
break;
3131 case LBRACKET: ++brackCount;
break;
3132 case RBRACKET: --brackCount;
break;
3134 case LPAREN: ++parenCount;
break;
3135 case RPAREN: --parenCount;
break;
3138 if ((t == target || (target2 != NONE && t == target2))
3144 if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
3152bool Parser::testTokenAndEndsWith(QCss::TokenType t, QLatin1StringView str)
3154 if (!test(t))
return false;
3155 if (!lexem().endsWith(str, Qt::CaseInsensitive)) {
@ StyleFeature_BackgroundGradient
@ StyleFeature_BackgroundColor
@ OutlineBottomRightRadius
@ BorderBottomRightRadius
@ OutlineBottomLeftRadius
@ QtForegroundTextureCacheKey
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)