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, QMultiMap<uint, StyleRule> *weightedRules)
const
2204 for (
const Selector &selector : rule.selectors) {
2205 if (selectorMatches(selector, node)) {
2206 uint weight = rule.order
2207 + selector.specificity() *0x100
2208 + (uint(origin) + depth)*0x100000;
2209 StyleRule newRule = rule;
2210 if (rule.selectors.size() > 1) {
2211 newRule.selectors.resize(1);
2212 newRule.selectors[0] = selector;
2215 weightedRules->insert(weight, newRule);
2222QList<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
2224 QList<StyleRule> rules;
2225 if (styleSheets.isEmpty())
2228 QMultiMap<uint, StyleRule> weightedRules;
2231 for (
const StyleSheet &styleSheet : std::as_const(styleSheets)) {
2232 for (
const StyleRule &styleRule : styleSheet.styleRules)
2233 matchRule(node, styleRule, styleSheet.origin, styleSheet.depth, &weightedRules);
2235 if (!styleSheet.idIndex.isEmpty()) {
2236 const QStringList ids = nodeIds(node);
2237 for (
const QString &key : ids) {
2238 auto it = styleSheet.idIndex.constFind(key);
2239 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
2240 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2245 if (!styleSheet.nameIndex.isEmpty()) {
2246 const QStringList names = nodeNames(node);
2247 for (QString name : names) {
2248 if (nameCaseSensitivity == Qt::CaseInsensitive)
2249 name = std::move(name).toLower();
2250 auto it = styleSheet.nameIndex.constFind(name);
2251 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
2252 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2257 if (!medium.isEmpty()) {
2258 for (
const MediaRule &mediaRule : styleSheet.mediaRules) {
2259 if (mediaRule.media.contains(medium, Qt::CaseInsensitive)) {
2260 for (
const StyleRule &styleRule : mediaRule.styleRules) {
2261 matchRule(node, styleRule, styleSheet.origin,
2262 styleSheet.depth, &weightedRules);
2269 rules.reserve(weightedRules.size());
2270 QMultiMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
2271 for ( ; it != weightedRules.constEnd() ; ++it)
2279QList<Declaration> StyleSelector::declarationsForNode(NodePtr node,
const char *extraPseudo)
2281 QList<Declaration> decls;
2282 const QList<StyleRule> rules = styleRulesForNode(node);
2283 for (
const StyleRule &styleRule : rules) {
2284 const Selector &selector = styleRule.selectors.at(0);
2285 const QString pseudoElement = selector.pseudoElement();
2287 if (extraPseudo && pseudoElement == QLatin1StringView(extraPseudo)) {
2288 decls += styleRule.declarations;
2292 if (!pseudoElement.isEmpty())
2294 quint64 pseudoClass = selector.pseudoClass();
2295 if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
2296 decls += styleRule.declarations;
2303 return (c >=
'0' && c <=
'9')
2304 || (c >=
'a' && c <=
'f')
2305 || (c >=
'A' && c <=
'F')
2309QString Scanner::preprocess(
const QString &input,
bool *hasEscapeSequences)
2311 QString output = input;
2313 if (hasEscapeSequences)
2314 *hasEscapeSequences =
false;
2317 while (i < output.size()) {
2318 if (output.at(i) == u'\\') {
2323 const int hexStart = i;
2324 while (i < output.size()
2325 && isHexDigit(output.at(i).toLatin1())
2330 if (hexCount == 0) {
2331 if (hasEscapeSequences)
2332 *hasEscapeSequences =
true;
2336 hexCount = qMin(hexCount, 6);
2338 const char16_t code = QStringView{output}.mid(hexStart, hexCount).toUShort(&ok, 16);
2340 output.replace(hexStart - 1, hexCount + 1, code);
2352int QCssScanner_Generated::handleCommentStart()
2354 while (pos < input.size() - 1) {
2355 if (input.at(pos) == u'*' && input.at(pos + 1) == u'/') {
2364void Scanner::scan(
const QString &preprocessedInput, QList<Symbol> *symbols)
2366 QCssScanner_Generated scanner(preprocessedInput);
2368 int tok = scanner.lex();
2370 sym.token =
static_cast<QCss::TokenType>(tok);
2371 sym.text = scanner.input;
2372 sym.start = scanner.lexemStart;
2373 sym.len = scanner.lexemLength;
2374 symbols->append(sym);
2375 tok = scanner.lex();
2383 result.reserve(
len);
2384 for (
int i = 0; i <
len; ++i) {
2385 if (text.at(start + i) == u'\\' && i < len - 1)
2387 result += text.at(start + i);
2392Parser::Parser(
const QString &css,
bool isFile)
2401 hasEscapeSequences =
false;
2404void Parser::init(
const QString &css,
bool isFile)
2406 QString styleSheet = css;
2409 if (file.open(QFile::ReadOnly)) {
2410 sourcePath = QFileInfo(styleSheet).absolutePath() + u'/';
2411 QTextStream stream(&file);
2412 styleSheet = stream.readAll();
2414 qWarning() <<
"QCss::Parser - Failed to load file " << css;
2421 hasEscapeSequences =
false;
2424 Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
2429bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
2431 if (testTokenAndEndsWith(ATKEYWORD_SYM,
"charset"_L1)) {
2432 while (test(S) || test(CDO) || test(CDC)) {}
2433 if (!next(STRING))
return false;
2434 if (!next(SEMICOLON))
return false;
2437 while (test(S) || test(CDO) || test(CDC)) {}
2439 while (testImport()) {
2441 if (!parseImport(&rule))
return false;
2442 styleSheet->importRules.append(rule);
2443 while (test(S) || test(CDO) || test(CDC)) {}
2449 if (!parseMedia(&rule))
return false;
2450 styleSheet->mediaRules.append(rule);
2451 }
else if (testPage()) {
2453 if (!parsePage(&rule))
return false;
2454 styleSheet->pageRules.append(rule);
2455 }
else if (testAnimation()) {
2457 if (!parseAnimation(&rule))
return false;
2458 styleSheet->animationRules.append(rule);
2459 }
else if (testRuleset()) {
2461 if (!parseRuleset(&rule))
return false;
2462 styleSheet->styleRules.append(rule);
2463 }
else if (test(ATKEYWORD_SYM)) {
2464 if (!until(RBRACE))
return false;
2465 }
else if (hasNext()) {
2468 while (test(S) || test(CDO) || test(CDC)) {}
2469 }
while (hasNext());
2470 styleSheet->buildIndexes(nameCaseSensitivity);
2474Symbol Parser::errorSymbol()
2476 if (errorIndex == -1)
return Symbol();
2477 return symbols.at(errorIndex);
2482 if (!str->startsWith(u'\'') && !str->startsWith(u'\"'))
2488bool Parser::parseImport(ImportRule *importRule)
2493 importRule->href = lexem();
2495 if (!testAndParseUri(&importRule->href))
return false;
2497 removeOptionalQuotes(&importRule->href);
2502 if (!parseMedium(&importRule->media))
return false;
2504 while (test(COMMA)) {
2506 if (!parseNextMedium(&importRule->media))
return false;
2510 if (!next(SEMICOLON))
return false;
2516bool Parser::parseMedia(MediaRule *mediaRule)
2520 if (!parseNextMedium(&mediaRule->media))
return false;
2521 }
while (test(COMMA));
2523 if (!next(LBRACE))
return false;
2526 while (testRuleset()) {
2528 if (!parseRuleset(&rule))
return false;
2529 mediaRule->styleRules.append(rule);
2532 if (!next(RBRACE))
return false;
2537bool Parser::parseMedium(QStringList *media)
2539 media->append(lexem());
2544bool Parser::parsePage(PageRule *pageRule)
2548 if (testPseudoPage())
2549 if (!parsePseudoPage(&pageRule->selector))
return false;
2552 if (!next(LBRACE))
return false;
2557 if (!parseNextDeclaration(&decl))
return false;
2558 if (!decl.isEmpty())
2559 pageRule->declarations.append(decl);
2560 }
while (test(SEMICOLON));
2562 if (!next(RBRACE))
return false;
2567bool Parser::parsePseudoPage(QString *selector)
2569 if (!next(IDENT))
return false;
2570 *selector = lexem();
2574bool Parser::parseNextOperator(Value *value)
2576 if (!hasNext())
return true;
2578 case SLASH: value->type = Value::TermOperatorSlash; skipSpace();
break;
2579 case COMMA: value->type = Value::TermOperatorComma; skipSpace();
break;
2580 default: prev();
break;
2585bool Parser::parseAnimation(AnimationRule *animationRule)
2588 if (!test(IDENT))
return false;
2590 animationRule->animName = lexem();
2592 if (!next(LBRACE))
return false;
2595 while (test(PERCENTAGE) || test(IDENT)) {
2596 AnimationRule::AnimationRuleSet set;
2597 if (lookup() == PERCENTAGE) {
2598 QString name = lexem();
2600 float keyFrame = name.toFloat() / 100;
2601 set.keyFrame = keyFrame;
2602 }
else if (lookup() == IDENT) {
2604 if (parseElementName(&name)) {
2605 if (name == QStringLiteral(
"from"))
2607 else if (name == QStringLiteral(
"to"))
2613 if (!next(LBRACE))
return false;
2614 const int declarationStart = index;
2619 const int rewind = index;
2620 if (!parseNextDeclaration(&decl)) {
2622 const bool foundSemicolon = until(SEMICOLON);
2623 const int semicolonIndex = index;
2625 index = declarationStart;
2626 const bool foundRBrace = until(RBRACE);
2628 if (foundSemicolon && semicolonIndex < index) {
2629 decl = Declaration();
2630 index = semicolonIndex - 1;
2636 if (!decl.isEmpty())
2637 set.declarations.append(decl);
2638 }
while (test(SEMICOLON));
2640 if (!next(RBRACE))
return false;
2642 animationRule->ruleSets.append(set);
2645 if (!next(RBRACE))
return false;
2651bool Parser::parseCombinator(BasicSelector::Relation *relation)
2653 *relation = BasicSelector::NoRelation;
2654 if (lookup() == S) {
2655 *relation = BasicSelector::MatchNextSelectorIfAncestor;
2661 *relation = BasicSelector::MatchNextSelectorIfDirectAdjecent;
2662 }
else if (test(GREATER)) {
2663 *relation = BasicSelector::MatchNextSelectorIfParent;
2664 }
else if (test(TILDE)) {
2665 *relation = BasicSelector::MatchNextSelectorIfIndirectAdjecent;
2671bool Parser::parseProperty(Declaration *decl)
2673 decl->d->property = lexem();
2674 decl->d->propertyId =
static_cast<Property>(findKnownValue(decl->d->property, properties, NumProperties));
2675 decl->d->inheritable = isInheritable(decl->d->propertyId);
2680bool Parser::parseRuleset(StyleRule *styleRule)
2683 if (!parseSelector(&sel))
return false;
2684 styleRule->selectors.append(sel);
2686 while (test(COMMA)) {
2689 if (!parseNextSelector(&sel))
return false;
2690 styleRule->selectors.append(sel);
2694 if (!next(LBRACE))
return false;
2695 const int declarationStart = index;
2700 const int rewind = index;
2701 if (!parseNextDeclaration(&decl)) {
2703 const bool foundSemicolon = until(SEMICOLON);
2704 const int semicolonIndex = index;
2706 index = declarationStart;
2707 const bool foundRBrace = until(RBRACE);
2709 if (foundSemicolon && semicolonIndex < index) {
2710 decl = Declaration();
2711 index = semicolonIndex - 1;
2717 if (!decl.isEmpty())
2718 styleRule->declarations.append(decl);
2719 }
while (test(SEMICOLON));
2721 if (!next(RBRACE))
return false;
2726bool Parser::parseSelector(Selector *sel)
2728 BasicSelector basicSel;
2729 if (!parseSimpleSelector(&basicSel))
return false;
2730 while (testCombinator()) {
2731 if (!parseCombinator(&basicSel.relationToNext))
return false;
2733 if (!testSimpleSelector())
break;
2734 sel->basicSelectors.append(basicSel);
2736 basicSel = BasicSelector();
2737 if (!parseSimpleSelector(&basicSel))
return false;
2739 sel->basicSelectors.append(basicSel);
2743bool Parser::parseSimpleSelector(BasicSelector *basicSel)
2746 if (lookupElementName()) {
2747 if (!parseElementName(&basicSel->elementName))
return false;
2757 QString theid = lexem();
2760 basicSel->ids.append(theid);
2762 }
else if (testClass()) {
2764 AttributeSelector a;
2765 a.name =
"class"_L1;
2766 a.valueMatchCriterium = AttributeSelector::MatchIncludes;
2767 if (!parseClass(&a.value))
return false;
2768 basicSel->attributeSelectors.append(a);
2769 }
else if (testAttrib()) {
2771 AttributeSelector a;
2772 if (!parseAttrib(&a))
return false;
2773 basicSel->attributeSelectors.append(a);
2774 }
else if (testPseudo()) {
2777 if (!parsePseudo(&ps))
return false;
2778 basicSel->pseudos.append(ps);
2780 if (onceMore) ++count;
2782 return count >= minCount;
2785bool Parser::parseClass(QString *name)
2787 if (!next(IDENT))
return false;
2792bool Parser::parseElementName(QString *name)
2795 case STAR: name->clear();
break;
2796 case IDENT: *name = lexem();
break;
2797 default:
return false;
2802bool Parser::parseAttrib(AttributeSelector *attr)
2805 if (!next(IDENT))
return false;
2806 attr->name = lexem();
2810 attr->valueMatchCriterium = AttributeSelector::MatchEqual;
2811 }
else if (test(INCLUDES)) {
2812 attr->valueMatchCriterium = AttributeSelector::MatchIncludes;
2813 }
else if (test(DASHMATCH)) {
2814 attr->valueMatchCriterium = AttributeSelector::MatchDashMatch;
2815 }
else if (test(BEGINSWITH)) {
2816 attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
2817 }
else if (test(ENDSWITH)) {
2818 attr->valueMatchCriterium = AttributeSelector::MatchEndsWith;
2819 }
else if (test(CONTAINS)) {
2820 attr->valueMatchCriterium = AttributeSelector::MatchContains;
2822 return next(RBRACKET);
2827 if (!test(IDENT) && !test(STRING))
return false;
2828 attr->value = unquotedLexem();
2831 return next(RBRACKET);
2834bool Parser::parsePseudo(Pseudo *pseudo)
2837 pseudo->negated = test(EXCLAMATION_SYM);
2839 pseudo->name = lexem();
2840 pseudo->type =
static_cast<quint64>(findKnownValue(pseudo->name, pseudos, NumPseudos));
2843 if (!next(FUNCTION))
return false;
2844 pseudo->function = lexem();
2846 pseudo->function.chop(1);
2848 if (!test(IDENT))
return false;
2849 pseudo->name = lexem();
2851 return next(RPAREN);
2854bool Parser::parseNextDeclaration(Declaration *decl)
2856 if (!testProperty())
2858 if (!parseProperty(decl))
return false;
2859 if (!next(COLON))
return false;
2861 if (!parseNextExpr(&decl->d->values))
return false;
2863 if (!parsePrio(decl))
return false;
2867bool Parser::testPrio()
2869 const int rewind = index;
2870 if (!test(EXCLAMATION_SYM))
return false;
2876 if (lexem().compare(
"important"_L1, Qt::CaseInsensitive) != 0) {
2883bool Parser::parsePrio(Declaration *declaration)
2885 declaration->d->important =
true;
2890bool Parser::parseExpr(QList<Value> *values)
2893 if (!parseTerm(&val))
return false;
2894 values->append(val);
2899 if (!parseNextOperator(&val))
return false;
2900 if (val.type != QCss::Value::Unknown)
2901 values->append(val);
2905 if (!parseTerm(&val))
return false;
2906 values->append(val);
2912bool Parser::testTerm()
2914 return test(PLUS) || test(MINUS)
2924bool Parser::parseTerm(Value *value)
2926 QString str = lexem();
2927 bool haveUnary =
false;
2928 if (lookup() == PLUS || lookup() == MINUS) {
2930 if (!hasNext())
return false;
2935 value->variant = str;
2936 value->type = QCss::Value::String;
2939 value->type = Value::Number;
2940 value->variant.convert(QMetaType::fromType<
double>());
2943 value->type = Value::Percentage;
2945 value->variant = str;
2948 value->type = Value::Length;
2952 if (haveUnary)
return false;
2953 value->type = Value::String;
2956 value->variant = str;
2959 if (haveUnary)
return false;
2960 value->type = Value::Identifier;
2961 const int theid = findKnownValue(str, values, NumKnownValues);
2963 value->type = Value::KnownIdentifier;
2964 value->variant = theid;
2969 if (haveUnary)
return false;
2971 if (testHexColor()) {
2973 if (!parseHexColor(&col))
return false;
2974 value->type = Value::Color;
2975 value->variant = col;
2976 }
else if (testFunction()) {
2978 if (!parseFunction(&name, &args))
return false;
2979 if (name ==
"url"_L1) {
2980 value->type = Value::Uri;
2981 removeOptionalQuotes(&args);
2982 if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
2983 args.prepend(sourcePath);
2985 value->variant = args;
2987 value->type = Value::Function;
2988 value->variant = QStringList() << name << args;
2991 return recordError();
3000bool Parser::parseFunction(QString *name, QString *args)
3007 std::swap(start, index);
3008 if (!until(RPAREN))
return false;
3009 for (
int i = start; i < index - 1; ++i)
3010 args->append(symbols.at(i).lexem());
3012
3013
3014
3019bool Parser::parseHexColor(QColor *col)
3021 *col = QColor::fromString(lexem());
3022 if (!col->isValid()) {
3023 qWarning(
"QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
3030bool Parser::testAndParseUri(QString *uri)
3032 const int rewind = index;
3033 if (!testFunction())
return false;
3036 if (!parseFunction(&name, &args)) {
3040 if (name.compare(
"url"_L1, Qt::CaseInsensitive) != 0) {
3045 removeOptionalQuotes(uri);
3049bool Parser::testSimpleSelector()
3051 return testElementName()
3058bool Parser::next(QCss::TokenType t)
3060 if (hasNext() && next() == t)
3062 return recordError();
3065bool Parser::test(QCss::TokenType t)
3067 if (index >= symbols.size())
3069 if (symbols.at(index).token == t) {
3076QString Parser::unquotedLexem()
const
3078 QString s = lexem();
3079 if (lookup() == STRING) {
3086QString Parser::lexemUntil(QCss::TokenType t)
3089 while (hasNext() && next() != t)
3090 lexem += symbol().lexem();
3094bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
3100 switch(symbols.at(index-1).token) {
3101 case LBRACE: ++braceCount;
break;
3102 case LBRACKET: ++brackCount;
break;
3104 case LPAREN: ++parenCount;
break;
3108 while (index < symbols.size()) {
3109 QCss::TokenType t = symbols.at(index++).token;
3111 case LBRACE: ++braceCount;
break;
3112 case RBRACE: --braceCount;
break;
3113 case LBRACKET: ++brackCount;
break;
3114 case RBRACKET: --brackCount;
break;
3116 case LPAREN: ++parenCount;
break;
3117 case RPAREN: --parenCount;
break;
3120 if ((t == target || (target2 != NONE && t == target2))
3126 if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
3134bool Parser::testTokenAndEndsWith(QCss::TokenType t, QLatin1StringView str)
3136 if (!test(t))
return false;
3137 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)