6#include <QtCore/qmap.h>
12#include <qfontmetrics.h>
14#include <qimagereader.h>
15#include <qtextformat.h>
19#ifndef QT_NO_CSSPARSER
23using namespace Qt::StringLiterals;
25QT_IMPL_METATYPE_EXTERN_TAGGED(QCss::BackgroundData, QCss__BackgroundData)
26QT_IMPL_METATYPE_EXTERN_TAGGED(QCss::LengthData, QCss__LengthData)
27QT_IMPL_METATYPE_EXTERN_TAGGED(QCss::BorderData, QCss__BorderData)
247static const short indexOfId[
NumKnownValues] = { 0, 44, 51, 45, 52, 53, 60, 37, 28, 78, 79, 27, 46, 6, 71, 50,
248 31, 65, 66, 29, 55, 69, 7, 11, 42, 62, 20, 14, 18, 19, 21, 23, 54, 26, 49, 75, 39, 3, 2, 43, 70, 17, 12,
249 63, 15, 34, 72, 35, 73, 61, 74, 36, 64, 22, 56, 41, 5, 57, 67, 77, 9, 30, 40, 13, 38, 68, 8, 10, 4, 76,
250 59, 24, 25, 32, 33, 1, 16, 0, 58, 48, 47 };
255 return QLatin1StringView(values[indexOfId[variant.toInt()]].name);
257 return variant.toString();
262 {
"active", PseudoClass_Active },
263 {
"adjoins-item", PseudoClass_Item },
264 {
"alternate", PseudoClass_Alternate },
265 {
"bottom", PseudoClass_Bottom },
266 {
"checked", PseudoClass_Checked },
267 {
"closable", PseudoClass_Closable },
268 {
"closed", PseudoClass_Closed },
269 {
"default", PseudoClass_Default },
270 {
"disabled", PseudoClass_Disabled },
271 {
"edit-focus", PseudoClass_EditFocus },
272 {
"editable", PseudoClass_Editable },
273 {
"enabled", PseudoClass_Enabled },
274 {
"exclusive", PseudoClass_Exclusive },
275 {
"first", PseudoClass_First },
276 {
"flat", PseudoClass_Flat },
277 {
"floatable", PseudoClass_Floatable },
278 {
"focus", PseudoClass_Focus },
279 {
"has-children", PseudoClass_Children },
280 {
"has-siblings", PseudoClass_Sibling },
281 {
"horizontal", PseudoClass_Horizontal },
282 {
"hover", PseudoClass_Hover },
283 {
"indeterminate" , PseudoClass_Indeterminate },
284 {
"last", PseudoClass_Last },
285 {
"left", PseudoClass_Left },
286 {
"maximized", PseudoClass_Maximized },
287 {
"middle", PseudoClass_Middle },
288 {
"minimized", PseudoClass_Minimized },
289 {
"movable", PseudoClass_Movable },
290 {
"next-selected", PseudoClass_NextSelected },
291 {
"no-frame", PseudoClass_Frameless },
292 {
"non-exclusive", PseudoClass_NonExclusive },
293 {
"off", PseudoClass_Unchecked },
294 {
"on", PseudoClass_Checked },
295 {
"only-one", PseudoClass_OnlyOne },
296 {
"open", PseudoClass_Open },
297 {
"pressed", PseudoClass_Pressed },
298 {
"previous-selected", PseudoClass_PreviousSelected },
299 {
"read-only", PseudoClass_ReadOnly },
300 {
"right", PseudoClass_Right },
301 {
"selected", PseudoClass_Selected },
302 {
"top", PseudoClass_Top },
303 {
"unchecked" , PseudoClass_Unchecked },
304 {
"vertical", PseudoClass_Vertical },
305 {
"window", PseudoClass_Window }
348 return QString::compare(name, QLatin1StringView(prop.name), Qt::CaseInsensitive) < 0;
353 return QString::compare(QLatin1StringView(prop.name), name, Qt::CaseInsensitive) < 0;
360 if ((prop == end) || (name
< *prop))
367 switch (propertyId) {
393ValueExtractor::ValueExtractor(
const QList<Declaration> &decls,
const QPalette &pal)
394: declarations(decls), adjustment(0), fontExtracted(
false), pal(pal)
398LengthData ValueExtractor::lengthValue(
const Value& v)
400 const QString str = v.variant.toString();
403 data.unit = LengthData::None;
404 if (s.endsWith(u"px", Qt::CaseInsensitive))
405 data.unit = LengthData::Px;
406 else if (s.endsWith(u"ex", Qt::CaseInsensitive))
407 data.unit = LengthData::Ex;
408 else if (s.endsWith(u"em", Qt::CaseInsensitive))
409 data.unit = LengthData::Em;
411 if (data.unit != LengthData::None)
413 else if (v.type == Value::Percentage)
414 data.unit = LengthData::Percent;
416 data.number = s.toDouble();
422 const int scale = (data.unit ==
LengthData::Ex ? QFontMetrics(f).xHeight()
425 return qRound(qBound(
double(INT_MIN) + 0.1, scale * data.number,
double(INT_MAX)));
428QTextLength ValueExtractor::textLength(
const Declaration &decl)
430 const LengthData data = lengthValue(decl.d->values.at(0));
431 if (data.unit == LengthData::Percent)
432 return QTextLength(QTextLength::PercentageLength, data.number);
434 return QTextLength(QTextLength::FixedLength, lengthValueFromData(data, f));
437int ValueExtractor::lengthValue(
const Declaration &decl)
439 if (decl.d->parsed.isValid())
440 return lengthValueFromData(qvariant_cast<LengthData>(decl.d->parsed), f);
441 if (decl.d->values.size() < 1)
443 LengthData data = lengthValue(decl.d->values.at(0));
444 decl.d->parsed = QVariant::fromValue<LengthData>(data);
445 return lengthValueFromData(data,f);
448void ValueExtractor::lengthValues(
const Declaration &decl,
int *m)
450 if (decl.d->parsed.isValid()) {
451 QList<QVariant> v = decl.d->parsed.toList();
452 Q_ASSERT(v.size() == 4);
453 for (
int i = 0; i < 4; i++)
454 m[i] = lengthValueFromData(qvariant_cast<LengthData>(v.at(i)), f);
460 for (i = 0; i < qMin(decl.d->values.size(), 4); i++)
461 datas[i] = lengthValue(decl.d->values[i]);
464 LengthData zero = {0.0, LengthData::None};
465 datas[0] = datas[1] = datas[2] = datas[3] = zero;
467 datas[3] = datas[2] = datas[1] = datas[0];
477 for (i = 0; i < 4; i++) {
478 v += QVariant::fromValue<LengthData>(datas[i]);
479 m[i] = lengthValueFromData(datas[i], f);
484bool ValueExtractor::extractGeometry(
int *w,
int *h,
int *minw,
int *minh,
int *maxw,
int *maxh)
488 for (
int i = 0; i < declarations.size(); i++) {
489 const Declaration &decl = declarations.at(i);
490 switch (decl.d->propertyId) {
491 case Width: *w = lengthValue(decl);
break;
492 case Height: *h = lengthValue(decl);
break;
493 case MinimumWidth: *minw = lengthValue(decl);
break;
494 case MinimumHeight: *minh = lengthValue(decl);
break;
495 case MaximumWidth: *maxw = lengthValue(decl);
break;
496 case MaximumHeight: *maxh = lengthValue(decl);
break;
505bool ValueExtractor::extractPosition(
int *left,
int *top,
int *right,
int *bottom, QCss::Origin *origin,
506 Qt::Alignment *position, QCss::PositionMode *mode, Qt::Alignment *textAlignment)
510 for (
int i = 0; i < declarations.size(); i++) {
511 const Declaration &decl = declarations.at(i);
512 switch (decl.d->propertyId) {
513 case Left: *left = lengthValue(decl);
break;
514 case Top: *top = lengthValue(decl);
break;
515 case Right: *right = lengthValue(decl);
break;
516 case Bottom: *bottom = lengthValue(decl);
break;
517 case QtOrigin: *origin = decl.originValue();
break;
518 case QtPosition: *position = decl.alignmentValue();
break;
519 case TextAlignment: *textAlignment = decl.alignmentValue();
break;
520 case Position: *mode = decl.positionValue();
break;
529bool ValueExtractor::extractBox(
int *margins,
int *paddings,
int *spacing)
533 for (
int i = 0; i < declarations.size(); i++) {
534 const Declaration &decl = declarations.at(i);
535 switch (decl.d->propertyId) {
536 case PaddingLeft: paddings[LeftEdge] = lengthValue(decl);
break;
537 case PaddingRight: paddings[RightEdge] = lengthValue(decl);
break;
538 case PaddingTop: paddings[TopEdge] = lengthValue(decl);
break;
539 case PaddingBottom: paddings[BottomEdge] = lengthValue(decl);
break;
540 case Padding: lengthValues(decl, paddings);
break;
542 case MarginLeft: margins[LeftEdge] = lengthValue(decl);
break;
543 case MarginRight: margins[RightEdge] = lengthValue(decl);
break;
544 case MarginTop: margins[TopEdge] = lengthValue(decl);
break;
545 case MarginBottom: margins[BottomEdge] = lengthValue(decl);
break;
546 case Margin: lengthValues(decl, margins);
break;
547 case QtSpacing:
if (spacing) *spacing = lengthValue(decl);
break;
557int ValueExtractor::extractStyleFeatures()
559 int features = StyleFeature_None;
560 for (
int i = 0; i < declarations.size(); i++) {
561 const Declaration &decl = declarations.at(i);
562 if (decl.d->propertyId == QtStyleFeatures)
563 features = decl.styleFeaturesValue();
568QSize ValueExtractor::sizeValue(
const Declaration &decl)
570 if (decl.d->parsed.isValid()) {
571 QList<QVariant> v = decl.d->parsed.toList();
572 return QSize(lengthValueFromData(qvariant_cast<LengthData>(v.at(0)), f),
573 lengthValueFromData(qvariant_cast<LengthData>(v.at(1)), f));
576 LengthData x[2] = { {0, LengthData::None }, {0, LengthData::None} };
577 if (decl.d->values.size() > 0)
578 x[0] = lengthValue(decl.d->values.at(0));
579 if (decl.d->values.size() > 1)
580 x[1] = lengthValue(decl.d->values.at(1));
584 v << QVariant::fromValue<LengthData>(x[0]) << QVariant::fromValue<LengthData>(x[1]);
586 return QSize(lengthValueFromData(x[0], f), lengthValueFromData(x[1], f));
589void ValueExtractor::sizeValues(
const Declaration &decl, QSize *radii)
591 radii[0] = sizeValue(decl);
592 for (
int i = 1; i < 4; i++)
596bool ValueExtractor::extractBorder(
int *borders, QBrush *colors, BorderStyle *styles,
601 for (
int i = 0; i < declarations.size(); i++) {
602 const Declaration &decl = declarations.at(i);
603 switch (decl.d->propertyId) {
604 case BorderLeftWidth: borders[LeftEdge] = lengthValue(decl);
break;
605 case BorderRightWidth: borders[RightEdge] = lengthValue(decl);
break;
606 case BorderTopWidth: borders[TopEdge] = lengthValue(decl);
break;
607 case BorderBottomWidth: borders[BottomEdge] = lengthValue(decl);
break;
608 case BorderWidth: lengthValues(decl, borders);
break;
610 case BorderLeftColor: colors[LeftEdge] = decl.brushValue(pal);
break;
611 case BorderRightColor: colors[RightEdge] = decl.brushValue(pal);
break;
612 case BorderTopColor: colors[TopEdge] = decl.brushValue(pal);
break;
613 case BorderBottomColor: colors[BottomEdge] = decl.brushValue(pal);
break;
614 case BorderColor: decl.brushValues(colors, pal);
break;
616 case BorderTopStyle: styles[TopEdge] = decl.styleValue();
break;
617 case BorderBottomStyle: styles[BottomEdge] = decl.styleValue();
break;
618 case BorderLeftStyle: styles[LeftEdge] = decl.styleValue();
break;
619 case BorderRightStyle: styles[RightEdge] = decl.styleValue();
break;
620 case BorderStyles: decl.styleValues(styles);
break;
622 case BorderTopLeftRadius: radii[0] = sizeValue(decl);
break;
623 case BorderTopRightRadius: radii[1] = sizeValue(decl);
break;
624 case BorderBottomLeftRadius: radii[2] = sizeValue(decl);
break;
625 case BorderBottomRightRadius: radii[3] = sizeValue(decl);
break;
626 case BorderRadius: sizeValues(decl, radii);
break;
629 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
632 borderValue(decl, &borders[TopEdge], &styles[TopEdge], &colors[TopEdge]);
635 borderValue(decl, &borders[RightEdge], &styles[RightEdge], &colors[RightEdge]);
638 borderValue(decl, &borders[BottomEdge], &styles[BottomEdge], &colors[BottomEdge]);
641 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
642 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
643 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
644 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
655bool ValueExtractor::extractOutline(
int *borders, QBrush *colors, BorderStyle *styles,
656 QSize *radii,
int *offsets)
660 for (
int i = 0; i < declarations.size(); i++) {
661 const Declaration &decl = declarations.at(i);
662 switch (decl.d->propertyId) {
663 case OutlineWidth: lengthValues(decl, borders);
break;
664 case OutlineColor: decl.brushValues(colors, pal);
break;
665 case OutlineStyle: decl.styleValues(styles);
break;
667 case OutlineTopLeftRadius: radii[0] = sizeValue(decl);
break;
668 case OutlineTopRightRadius: radii[1] = sizeValue(decl);
break;
669 case OutlineBottomLeftRadius: radii[2] = sizeValue(decl);
break;
670 case OutlineBottomRightRadius: radii[3] = sizeValue(decl);
break;
671 case OutlineRadius: sizeValues(decl, radii);
break;
672 case OutlineOffset: lengthValues(decl, offsets);
break;
675 borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
676 borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
677 styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
678 colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
691 Qt::Alignment a[2] = { { }, { } };
692 for (
int i = 0; i < qMin(2, count); i++) {
695 switch (values[i].variant.toInt()) {
696 case Value_Left: a[i] = Qt::AlignLeft;
break;
697 case Value_Right: a[i] = Qt::AlignRight;
break;
698 case Value_Top: a[i] = Qt::AlignTop;
break;
699 case Value_Bottom: a[i] = Qt::AlignBottom;
break;
700 case Value_Center: a[i] = Qt::AlignCenter;
break;
705 if (a[0] == Qt::AlignCenter && a[1] != 0 && a[1] != Qt::AlignCenter)
706 a[0] = (a[1] == Qt::AlignLeft || a[1] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
707 if ((a[1] == 0 || a[1] == Qt::AlignCenter) && a[0] != Qt::AlignCenter)
708 a[1] = (a[0] == Qt::AlignLeft || a[0] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
715 v.variant.convert(QMetaType::fromType<QColor>());
720 return qvariant_cast<QColor>(v.variant);
722 if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent)
723 return QColor(Qt::transparent);
728 QStringList lst = v.variant.toStringList();
732 const QString &identifier = lst.at(0);
733 if ((identifier.compare(
"palette"_L1, Qt::CaseInsensitive)) == 0) {
734 int role = findKnownValue(lst.at(1).trimmed(), values, NumKnownValues);
735 if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
736 return (QPalette::ColorRole)(role-Value_FirstColorRole);
741 const bool rgb = identifier.startsWith(
"rgb"_L1);
742 const bool hsv = !rgb && identifier.startsWith(
"hsv"_L1);
743 const bool hsl = !rgb && !hsv && identifier.startsWith(
"hsl"_L1);
745 if (!rgb && !hsv && !hsl)
748 const bool hasAlpha = identifier.size() == 4 && identifier.at(3) == u'a';
749 if (identifier.size() > 3 && !hasAlpha)
756 QList<QCss::Value> colorDigits;
757 if (!p.parseExpr(&colorDigits))
759 const int tokenCount = colorDigits.size();
761 for (
int i = 0; i < qMin(tokenCount, 7); i += 2) {
763 const qreal maxRange = (rgb || i != 0) ? 255. : 359.;
764 colorDigits[i].variant = colorDigits.at(i).variant.toReal() * (maxRange / 100.);
775 if (hasAlpha && tokenCount != 7) {
776 qWarning(
"QCssParser::parseColorValue: Specified color with alpha value but no alpha given: '%s'", qPrintable(lst.join(u' ')));
779 if (!hasAlpha && tokenCount != 5) {
780 qWarning(
"QCssParser::parseColorValue: Specified color without alpha value but alpha given: '%s'", qPrintable(lst.join(u' ')));
784 int v1 = colorDigits.at(0).variant.toInt();
785 int v2 = colorDigits.at(2).variant.toInt();
786 int v3 = colorDigits.at(4).variant.toInt();
788 if (tokenCount == 7) {
789 int alphaValue = colorDigits.at(6).variant.toInt();
791 alpha = colorDigits.at(6).variant.toReal() * 255.;
797 return QColor::fromRgb(v1, v2, v3, alpha);
799 return QColor::fromHsv(v1, v2, v3, alpha);
800 return QColor::fromHsl(v1, v2, v3, alpha);
808 return pal.color(c.role);
817 return QBrush(c.color);
825 QStringList lst = v.variant.toStringList();
829 QStringList gradFuncs;
830 gradFuncs <<
"qlineargradient"_L1 <<
"qradialgradient"_L1 <<
"qconicalgradient"_L1 <<
"qgradient"_L1;
833 if ((gradType = gradFuncs.indexOf(lst.at(0).toLower())) == -1)
836 QHash<QString, qreal> vars;
837 QList<QGradientStop> stops;
841 spreads <<
"pad"_L1 <<
"reflect"_L1 <<
"repeat"_L1;
843 int coordinateMode = -1;
844 QStringList coordinateModes;
845 coordinateModes <<
"logical"_L1 <<
"stretchtodevice"_L1 <<
"objectbounding"_L1 <<
"object"_L1;
847 bool dependsOnThePalette =
false;
849 while (parser.hasNext()) {
851 if (!parser.test(IDENT))
853 QString attr = parser.lexem();
855 if (!parser.test(COLON))
858 if (attr.compare(
"stop"_L1, Qt::CaseInsensitive) == 0) {
867 dependsOnThePalette =
true;
868 stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal)));
872 (
void)parser.parseTerm(&value);
873 if (attr.compare(
"spread"_L1, Qt::CaseInsensitive) == 0)
874 spread = spreads.indexOf(value.variant.toString());
875 else if (attr.compare(
"coordinatemode"_L1, Qt::CaseInsensitive) == 0)
876 coordinateMode = coordinateModes.indexOf(value.variant.toString());
878 vars[attr] = value.variant.toReal();
881 (
void)parser.test(COMMA);
886 vars.value(
"x2"_L1), vars.value(
"y2"_L1));
887 lg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
890 lg.setSpread(QGradient::Spread(spread));
892 if (dependsOnThePalette)
899 vars.value(
"radius"_L1), vars.value(
"fx"_L1),
900 vars.value(
"fy"_L1));
901 rg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
904 rg.setSpread(QGradient::Spread(spread));
906 if (dependsOnThePalette)
912 QConicalGradient cg(vars.value(
"cx"_L1), vars.value(
"cy"_L1), vars.value(
"angle"_L1));
913 cg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
916 cg.setSpread(QGradient::Spread(spread));
918 if (dependsOnThePalette)
929 return pal.color(c.role);
938 switch (v.variant.toInt()) {
971void ValueExtractor::borderValue(
const Declaration &decl,
int *width, QCss::BorderStyle *style, QBrush *color)
973 if (decl.d->parsed.isValid()) {
974 BorderData data = qvariant_cast<BorderData>(decl.d->parsed);
975 *width = lengthValueFromData(data.width, f);
977 *color = data.color.type != BrushData::Invalid ? brushFromData(data.color, pal) : QBrush(QColor());
982 *style = BorderStyle_None;
985 if (decl.d->values.isEmpty())
989 data.width.number = 0;
990 data.width.unit = LengthData::None;
991 data.style = BorderStyle_None;
994 if (decl.d->values.at(i).type == Value::Length || decl.d->values.at(i).type == Value::Number) {
995 data.width = lengthValue(decl.d->values.at(i));
996 *width = lengthValueFromData(data.width, f);
997 if (++i >= decl.d->values.size()) {
998 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1003 data.style = parseStyleValue(decl.d->values.at(i));
1004 if (data.style != BorderStyle_Unknown) {
1005 *style = data.style;
1006 if (++i >= decl.d->values.size()) {
1007 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1011 data.style = BorderStyle_None;
1014 data.color = parseBrushValue(decl.d->values.at(i), pal);
1015 if (data.color.type != BrushData::Invalid) {
1016 *color = brushFromData(data.color, pal);
1017 if (data.color.type != BrushData::DependsOnThePalette)
1018 decl.d->parsed = QVariant::fromValue<BorderData>(data);
1027 *alignment = Qt::AlignTop | Qt::AlignLeft;
1029 for (
int i = 0; i < values.size(); ++i) {
1032 *image = v.variant.toString();
1038 *brush = QBrush(Qt::transparent);
1041 Repeat repeatAttempt =
static_cast<Repeat>(findKnownValue(v.variant.toString(),
1042 repeats, NumKnownRepeats));
1044 *repeat = repeatAttempt;
1049 const int start = i;
1051 if (i < values.size() - 1
1056 Qt::Alignment a = parseAlignment(values.constData() + start, count);
1064 *brush = parseBrushValue(v, pal);
1068bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *repeat,
1069 Qt::Alignment *alignment, Origin *origin, Attachment *attachment,
1073 for (
int i = 0; i < declarations.size(); ++i) {
1074 const Declaration &decl = declarations.at(i);
1075 if (decl.d->values.isEmpty())
1077 const QCss::Value &val = decl.d->values.at(0);
1078 switch (decl.d->propertyId) {
1079 case BackgroundColor:
1080 *brush = decl.brushValue();
1082 case BackgroundImage:
1083 if (val.type == Value::Uri)
1084 *image = val.variant.toString();
1086 case BackgroundRepeat:
1087 if (decl.d->parsed.isValid()) {
1088 *repeat =
static_cast<Repeat>(decl.d->parsed.toInt());
1090 *repeat =
static_cast<Repeat>(findKnownValue(val.variant.toString(),
1091 repeats, NumKnownRepeats));
1092 decl.d->parsed = *repeat;
1095 case BackgroundPosition:
1096 *alignment = decl.alignmentValue();
1098 case BackgroundOrigin:
1099 *origin = decl.originValue();
1101 case BackgroundClip:
1102 *clip = decl.originValue();
1105 if (decl.d->parsed.isValid()) {
1106 BackgroundData data = qvariant_cast<BackgroundData>(decl.d->parsed);
1107 *brush = brushFromData(data.brush, pal);
1108 *image = data.image;
1109 *repeat = data.repeat;
1110 *alignment = data.alignment;
1112 BrushData brushData;
1113 parseShorthandBackgroundProperty(decl.d->values, &brushData, image, repeat, alignment, pal);
1114 *brush = brushFromData(brushData, pal);
1115 if (brushData.type != BrushData::DependsOnThePalette) {
1116 BackgroundData data = { brushData, *image, *repeat, *alignment };
1117 decl.d->parsed = QVariant::fromValue<BackgroundData>(data);
1121 case BackgroundAttachment:
1122 *attachment = decl.attachmentValue();
1135 switch (value.variant.toInt()) {
1136 case Value_Small: *fontSizeAdjustment = -1;
break;
1141 default: valid =
false;
break;
1149 QString s = value.variant.toString();
1150 if (s.endsWith(
"pt"_L1, Qt::CaseInsensitive)) {
1153 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1154 font->setPointSizeF(qBound(qreal(0), value.variant.toReal(), qreal(1 << 24) - 1));
1157 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1160 if (value.variant.convert(QMetaType::fromType<qreal>())) {
1161 font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
1172 switch (value.variant.toInt()) {
1173 case Value_Normal: font->setStyle(QFont::StyleNormal);
return true;
1174 case Value_Italic: font->setStyle(QFont::StyleItalic);
return true;
1175 case Value_Oblique: font->setStyle(QFont::StyleOblique);
return true;
1185 switch (value.variant.toInt()) {
1186 case Value_Normal: font->setKerning(
true);
return true;
1187 case Value_None: font->setKerning(
false);
return true;
1197 switch (value.variant.toInt()) {
1198 case Value_Normal: font->setWeight(QFont::Normal);
return true;
1199 case Value_Bold: font->setWeight(QFont::Bold);
return true;
1207 font->setWeight(QFont::Weight(qRound(qBound(0.0, value.variant.toDouble(), 1001.0))));
1212
1213
1214
1215
1219 QStringList families;
1220 bool shouldAddSpace =
false;
1221 for (
int i = start; i < values.size(); ++i) {
1226 shouldAddSpace =
false;
1229 const QString str = v.variant.toString();
1235 shouldAddSpace =
true;
1237 if (!family.isEmpty())
1239 if (families.isEmpty())
1241 font->setFamilies(families);
1247 for (
int i = 0; i < values.size(); ++i) {
1250 switch (values.at(i).variant.toInt()) {
1255 font->setUnderline(
false);
1256 font->setOverline(
false);
1257 font->setStrikeOut(
false);
1266 QString s = value.variant.toString();
1269 if (s.endsWith(
"em"_L1, Qt::CaseInsensitive)) {
1271 val = s.toDouble(&ok);
1273 font->setLetterSpacing(QFont::PercentageSpacing, (val + 1.0) * 100);
1274 }
else if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1276 val = s.toDouble(&ok);
1278 font->setLetterSpacing(QFont::AbsoluteSpacing, val);
1284 QString s = value.variant.toString();
1285 if (s.endsWith(
"px"_L1, Qt::CaseInsensitive)) {
1289 val = s.toDouble(&ok);
1291 font->setWordSpacing(val);
1297 font->setStyle(QFont::StyleNormal);
1298 font->setWeight(QFont::Normal);
1299 *fontSizeAdjustment = -255;
1302 while (i < values.size()) {
1303 if (setFontStyleFromValue(values.at(i), font)
1304 || setFontWeightFromValue(values.at(i), font))
1310 if (i < values.size()) {
1311 setFontSizeFromValue(values.at(i), font, fontSizeAdjustment);
1315 if (i < values.size()) {
1316 setFontFamilyFromValues(values, font, i);
1323 switch (value.variant.toInt()) {
1324 case Value_Normal: font->setCapitalization(QFont::MixedCase);
break;
1325 case Value_SmallCaps: font->setCapitalization(QFont::SmallCaps);
break;
1334 switch (value.variant.toInt()) {
1335 case Value_None: font->setCapitalization(QFont::MixedCase);
break;
1336 case Value_Uppercase: font->setCapitalization(QFont::AllUppercase);
break;
1337 case Value_Lowercase: font->setCapitalization(QFont::AllLowercase);
break;
1343bool ValueExtractor::extractFont(QFont *font,
int *fontSizeAdjustment)
1345 if (fontExtracted) {
1347 *fontSizeAdjustment = adjustment;
1348 return fontExtracted == 1;
1352 for (
int i = 0; i < declarations.size(); ++i) {
1353 const Declaration &decl = declarations.at(i);
1354 if (decl.d->values.isEmpty())
1356 const QCss::Value &val = decl.d->values.at(0);
1357 switch (decl.d->propertyId) {
1358 case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment);
break;
1359 case FontStyle: setFontStyleFromValue(val, font);
break;
1360 case FontWeight: setFontWeightFromValue(val, font);
break;
1361 case FontFamily: setFontFamilyFromValues(decl.d->values, font);
break;
1362 case FontKerning: setFontKerningFromValue(val, font);
break;
1363 case TextDecoration: setTextDecorationFromValues(decl.d->values, font);
break;
1364 case Font: parseShorthandFontProperty(decl.d->values, font, fontSizeAdjustment);
break;
1365 case FontVariant: setFontVariantFromValue(val, font);
break;
1366 case TextTransform: setTextTransformFromValue(val, font);
break;
1367 case LetterSpacing: setLetterSpacingFromValue(val, font);
break;
1368 case WordSpacing: setWordSpacingFromValue(val, font);
break;
1375 adjustment = *fontSizeAdjustment;
1376 fontExtracted = hit ? 1 : 2;
1380bool ValueExtractor::extractPalette(QBrush *foreground,
1381 QBrush *selectedForeground,
1382 QBrush *selectedBackground,
1383 QBrush *alternateBackground,
1384 QBrush *placeHolderTextForeground,
1388 for (
int i = 0; i < declarations.size(); ++i) {
1389 const Declaration &decl = declarations.at(i);
1390 switch (decl.d->propertyId) {
1391 case Color: *foreground = decl.brushValue(pal);
break;
1392 case QtSelectionForeground: *selectedForeground = decl.brushValue(pal);
break;
1393 case QtSelectionBackground: *selectedBackground = decl.brushValue(pal);
break;
1394 case QtAlternateBackground: *alternateBackground = decl.brushValue(pal);
break;
1395 case QtPlaceHolderTextColor: *placeHolderTextForeground = decl.brushValue(pal);
break;
1396 case QtAccent: *accent = decl.brushValue(pal);
break;
1404void ValueExtractor::extractFont()
1409 extractFont(&f, &dummy);
1412bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size)
1415 for (
int i = 0; i < declarations.size(); ++i) {
1416 const Declaration &decl = declarations.at(i);
1417 switch (decl.d->propertyId) {
1419 *icon = decl.iconValue();
1420 if (decl.d->values.size() > 0 && decl.d->values.at(0).type == Value::Uri) {
1422 QImageReader imageReader(decl.d->values.at(0).variant.toString());
1423 if ((*size = imageReader.size()).isNull()) {
1426 *size = imageReader.read().size();
1430 case QtImageAlignment: *a = decl.alignmentValue();
break;
1438bool ValueExtractor::extractIcon(QIcon *icon, QSize *size)
1441 const auto declaration = std::find_if(
1442 declarations.rbegin(), declarations.rend(),
1443 [](
const Declaration &decl) {
return decl.d->propertyId == QtIcon; });
1444 if (declaration == declarations.rend())
1447 *icon = declaration->iconValue();
1450 if (declaration->d->values.isEmpty())
1453 const auto &propertyValue = declaration->d->values.constFirst();
1454 if (propertyValue.type != Value::Uri)
1458 const QString url(propertyValue.variant.toString());
1459 QImageReader imageReader(url);
1460 *size = imageReader.size();
1461 if (!size->isNull())
1465 *size = imageReader.read().size();
1471QColor Declaration::colorValue(
const QPalette &pal)
const
1473 if (d->values.size() != 1)
1476 if (d->parsed.isValid()) {
1477 switch (d->parsed.typeId()) {
1478 case qMetaTypeId<QColor>():
1479 return qvariant_cast<QColor>(d->parsed);
1480 case qMetaTypeId<
int>():
1481 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1482 case qMetaTypeId<QList<QVariant>>():
1483 if (d->parsed.toList().size() == 1) {
1484 auto parsedList = d->parsed.toList();
1485 const auto &value = parsedList.at(0);
1486 return qvariant_cast<QColor>(value);
1492 ColorData color = parseColorValue(d->values.at(0));
1493 if (color.type == ColorData::Role) {
1494 d->parsed = QVariant::fromValue<
int>(color.role);
1495 return pal.color((QPalette::ColorRole)(color.role));
1497 d->parsed = QVariant::fromValue<QColor>(color.color);
1502QBrush Declaration::brushValue(
const QPalette &pal)
const
1504 if (d->values.size() != 1)
1507 if (d->parsed.isValid()) {
1508 if (d->parsed.userType() == QMetaType::QBrush)
1509 return qvariant_cast<QBrush>(d->parsed);
1510 if (d->parsed.userType() == QMetaType::Int)
1511 return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
1514 BrushData data = parseBrushValue(d->values.at(0), pal);
1516 if (data.type == BrushData::Role) {
1517 d->parsed = QVariant::fromValue<
int>(data.role);
1518 return pal.color((QPalette::ColorRole)(data.role));
1520 if (data.type != BrushData::DependsOnThePalette)
1521 d->parsed = QVariant::fromValue<QBrush>(data.brush);
1526void Declaration::brushValues(QBrush *c,
const QPalette &pal)
const
1528 int needParse = 0x1f;
1531 if (d->parsed.isValid()) {
1533 Q_ASSERT(d->parsed.metaType() == QMetaType::fromType<QList<QVariant>>());
1534 QList<QVariant> v = d->parsed.toList();
1535 for (i = 0; i < qMin(v.size(), 4); i++) {
1536 if (v.at(i).userType() == QMetaType::QBrush) {
1537 c[i] = qvariant_cast<QBrush>(v.at(i));
1538 }
else if (v.at(i).userType() == QMetaType::Int) {
1539 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1541 needParse |= (1<<i);
1545 if (needParse != 0) {
1547 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1548 if (!(needParse & (1<<i)))
1550 BrushData data = parseBrushValue(d->values.at(i), pal);
1551 if (data.type == BrushData::Role) {
1552 v += QVariant::fromValue<
int>(data.role);
1553 c[i] = pal.color((QPalette::ColorRole)(data.role));
1555 if (data.type != BrushData::DependsOnThePalette) {
1556 v += QVariant::fromValue<QBrush>(data.brush);
1563 if (needParse & 0x10)
1566 if (i == 0) c[0] = c[1] = c[2] = c[3] = QBrush();
1567 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1568 else if (i == 2) c[2] = c[0], c[3] = c[1];
1569 else if (i == 3) c[3] = c[1];
1572bool Declaration::realValue(qreal *real,
const char *unit)
const
1574 if (d->values.size() != 1)
1576 const Value &v = d->values.at(0);
1577 if (unit && v.type != Value::Length)
1579 const QString str = v.variant.toString();
1582 const QLatin1StringView unitStr(unit);
1583 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1585 s.chop(unitStr.size());
1588 qreal val = s.toDouble(&ok);
1598 const QString str = v.variant.toString();
1601 const QLatin1StringView unitStr(unit);
1602 if (!s.endsWith(unitStr, Qt::CaseInsensitive))
1604 s.chop(unitStr.size());
1607 int val = s.toInt(&ok);
1613bool Declaration::intValue(
int *i,
const char *unit)
const
1615 if (d->values.size() != 1)
1617 return intValueHelper(d->values.at(0), i, unit);
1620QSize Declaration::sizeValue()
const
1622 if (d->parsed.isValid())
1623 return qvariant_cast<QSize>(d->parsed);
1625 int x[2] = { 0, 0 };
1626 const int count = d->values.size();
1627 for (
int i = 0; i < count; ++i) {
1629 qWarning(
"QCssParser::sizeValue: Too many values provided");
1632 const auto &value = d->values.at(i);
1633 const QString valueString = value.variant.toString();
1634 if (valueString.endsWith(u"pt", Qt::CaseInsensitive)) {
1635 intValueHelper(value, &x[i],
"pt");
1638 x[i] = (x[i] * 72) / 96;
1641 intValueHelper(value, &x[i],
"px");
1646 QSize size(x[0], x[1]);
1647 d->parsed = QVariant::fromValue<QSize>(size);
1651QRect Declaration::rectValue()
const
1653 if (d->values.size() != 1)
1656 if (d->parsed.isValid())
1657 return qvariant_cast<QRect>(d->parsed);
1659 const QCss::Value &v = d->values.at(0);
1660 if (v.type != Value::Function)
1662 const QStringList func = v.variant.toStringList();
1663 if (func.size() != 2 || func.at(0).compare(
"rect"_L1) != 0)
1665 const auto args = QStringView{func[1]}.split(u' ', Qt::SkipEmptyParts);
1666 if (args.size() != 4)
1668 QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
1669 d->parsed = QVariant::fromValue<QRect>(rect);
1673void Declaration::colorValues(QColor *c,
const QPalette &pal)
const
1676 if (d->parsed.isValid()) {
1677 QList<QVariant> v = d->parsed.toList();
1678 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1679 if (v.at(i).userType() == QMetaType::QColor) {
1680 c[i] = qvariant_cast<QColor>(v.at(i));
1682 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
1687 for (i = 0; i < qMin(d->values.size(), 4); i++) {
1688 ColorData color = parseColorValue(d->values.at(i));
1689 if (color.type == ColorData::Role) {
1690 v += QVariant::fromValue<
int>(color.role);
1691 c[i] = pal.color((QPalette::ColorRole)(color.role));
1693 v += QVariant::fromValue<QColor>(color.color);
1700 if (i == 0) c[0] = c[1] = c[2] = c[3] = QColor();
1701 else if (i == 1) c[3] = c[2] = c[1] = c[0];
1702 else if (i == 2) c[2] = c[0], c[3] = c[1];
1703 else if (i == 3) c[3] = c[1];
1706BorderStyle Declaration::styleValue()
const
1708 if (d->values.size() != 1)
1709 return BorderStyle_None;
1710 return parseStyleValue(d->values.at(0));
1713void Declaration::styleValues(BorderStyle *s)
const
1716 for (i = 0; i < qMin(d->values.size(), 4); i++)
1717 s[i] = parseStyleValue(d->values.at(i));
1718 if (i == 0) s[0] = s[1] = s[2] = s[3] = BorderStyle_None;
1719 else if (i == 1) s[3] = s[2] = s[1] = s[0];
1720 else if (i == 2) s[2] = s[0], s[3] = s[1];
1721 else if (i == 3) s[3] = s[1];
1724Repeat Declaration::repeatValue()
const
1726 if (d->parsed.isValid())
1727 return static_cast<Repeat>(d->parsed.toInt());
1728 if (d->values.size() != 1)
1729 return Repeat_Unknown;
1730 int v = findKnownValue(d->values.at(0).variant.toString(),
1731 repeats, NumKnownRepeats);
1733 return static_cast<Repeat>(v);
1736Origin Declaration::originValue()
const
1738 if (d->parsed.isValid())
1739 return static_cast<Origin>(d->parsed.toInt());
1740 if (d->values.size() != 1)
1741 return Origin_Unknown;
1742 int v = findKnownValue(d->values.at(0).variant.toString(),
1743 origins, NumKnownOrigins);
1745 return static_cast<Origin>(v);
1748PositionMode Declaration::positionValue()
const
1750 if (d->parsed.isValid())
1751 return static_cast<PositionMode>(d->parsed.toInt());
1752 if (d->values.size() != 1)
1753 return PositionMode_Unknown;
1754 int v = findKnownValue(d->values.at(0).variant.toString(),
1755 positions, NumKnownPositionModes);
1757 return static_cast<PositionMode>(v);
1760Attachment Declaration::attachmentValue()
const
1762 if (d->parsed.isValid())
1763 return static_cast<Attachment>(d->parsed.toInt());
1764 if (d->values.size() != 1)
1765 return Attachment_Unknown;
1766 int v = findKnownValue(d->values.at(0).variant.toString(),
1767 attachments, NumKnownAttachments);
1769 return static_cast<Attachment>(v);
1772int Declaration::styleFeaturesValue()
const
1774 Q_ASSERT(d->propertyId == QtStyleFeatures);
1775 if (d->parsed.isValid())
1776 return d->parsed.toInt();
1777 int features = StyleFeature_None;
1778 for (
int i = 0; i < d->values.size(); i++) {
1779 features |=
static_cast<
int>(findKnownValue(d->values.value(i).variant.toString(),
1780 styleFeatures, NumKnownStyleFeatures));
1782 d->parsed = features;
1786QString Declaration::uriValue()
const
1788 if (d->values.isEmpty() || d->values.at(0).type != Value::Uri)
1790 return d->values.at(0).variant.toString();
1793Qt::Alignment Declaration::alignmentValue()
const
1795 if (d->parsed.isValid())
1796 return Qt::Alignment(d->parsed.toInt());
1797 if (d->values.isEmpty() || d->values.size() > 2)
1798 return Qt::AlignLeft | Qt::AlignTop;
1800 Qt::Alignment v = parseAlignment(d->values.constData(), d->values.size());
1805void Declaration::borderImageValue(QString *image,
int *cuts,
1806 TileMode *h, TileMode *v)
const
1808 const DeclarationData *d =
this->d.data();
1809 *image = uriValue();
1810 for (
int i = 0; i < 4; i++)
1812 *h = *v = TileMode_Stretch;
1814 if (d->values.size() < 2)
1817 if (d->values.at(1).type == Value::Number) {
1819 for (i = 0; i < qMin(d->values.size()-1, 4); i++) {
1820 const Value& v = d->values.at(i+1);
1821 if (v.type != Value::Number)
1823 cuts[i] = v.variant.toString().toInt();
1825 if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
1826 else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];
1827 else if (i == 2) cuts[2] = cuts[0], cuts[3] = cuts[1];
1828 else if (i == 3) cuts[3] = cuts[1];
1831 if (d->values.last().type == Value::Identifier) {
1832 *v =
static_cast<TileMode>(findKnownValue(d->values.last().variant.toString(),
1833 tileModes, NumKnownTileModes));
1835 if (d->values[d->values.size() - 2].type == Value::Identifier) {
1836 *h =
static_cast<TileMode>
1837 (findKnownValue(d->values[d->values.size()-2].variant.toString(),
1838 tileModes, NumKnownTileModes));
1843bool Declaration::borderCollapseValue()
const
1845 if (d->values.size() != 1)
1848 return d->values.at(0).toString() ==
"collapse"_L1;
1851QList<qreal> Declaration::dashArray()
const
1853 if (d->propertyId != Property::QtStrokeDashArray || d->values.empty())
1854 return QList<qreal>();
1856 bool isValid =
true;
1857 QList<qreal> dashes;
1858 for (
int i = 0; i < d->values.size(); i++) {
1859 Value v = d->values[i];
1861 bool isValidSeparator = (i & 1) && v.type == Value::TermOperatorComma;
1862 bool isValidNumber = !(i & 1) && v.type == Value::Number;
1863 if (!isValidNumber && !isValidSeparator) {
1866 }
else if (isValidNumber) {
1868 dashes.append(v.variant.toReal(&ok));
1876 isValid &= !(dashes.size() & 1);
1877 return isValid ? dashes : QList<qreal>();
1880QIcon Declaration::iconValue()
const
1882 if (d->parsed.isValid())
1883 return qvariant_cast<QIcon>(d->parsed);
1886 for (
int i = 0; i < d->values.size();) {
1887 const Value &value = d->values.at(i++);
1888 if (value.type != Value::Uri)
1890 QString uri = value.variant.toString();
1891 QIcon::Mode mode = QIcon::Normal;
1892 QIcon::State state = QIcon::Off;
1893 for (
int j = 0; j < 2; j++) {
1894 if (i != d->values.size() && d->values.at(i).type == Value::KnownIdentifier) {
1895 switch (d->values.at(i).variant.toInt()) {
1896 case Value_Disabled: mode = QIcon::Disabled;
break;
1897 case Value_Active: mode = QIcon::Active;
break;
1898 case Value_Selected: mode = QIcon::Selected;
break;
1899 case Value_Normal: mode = QIcon::Normal;
break;
1900 case Value_On: state = QIcon::On;
break;
1901 case Value_Off: state = QIcon::Off;
break;
1914 icon.addPixmap(uri, mode, state);
1916 if (i == d->values.size())
1919 if (d->values.at(i).type == Value::TermOperatorComma)
1923 d->parsed = QVariant::fromValue<QIcon>(icon);
1929int Selector::specificity()
const
1932 for (
int i = 0; i < basicSelectors.size(); ++i) {
1933 const BasicSelector &sel = basicSelectors.at(i);
1934 if (!sel.elementName.isEmpty())
1937 val += (sel.pseudos.size() + sel.attributeSelectors.size()) * 0x10;
1938 val += sel.ids.size() * 0x100;
1943QString Selector::pseudoElement()
const
1945 const BasicSelector& bs = basicSelectors.last();
1946 if (!bs.pseudos.isEmpty() && bs.pseudos.at(0).type == PseudoClass_Unknown)
1947 return bs.pseudos.at(0).name;
1951quint64 Selector::pseudoClass(quint64 *negated)
const
1953 const BasicSelector& bs = basicSelectors.last();
1954 if (bs.pseudos.isEmpty())
1955 return PseudoClass_Unspecified;
1956 quint64 pc = PseudoClass_Unknown;
1957 for (
int i = !pseudoElement().isEmpty(); i < bs.pseudos.size(); i++) {
1958 const Pseudo &pseudo = bs.pseudos.at(i);
1959 if (pseudo.type == PseudoClass_Unknown)
1960 return PseudoClass_Unknown;
1961 if (!pseudo.negated)
1964 *negated |= pseudo.type;
1973 QList<StyleRule> universals;
1974 for (
int i = 0; i < styleRules.size(); ++i) {
1975 const StyleRule &rule = styleRules.at(i);
1976 QList<Selector> universalsSelectors;
1977 for (
int j = 0; j < rule.selectors.size(); ++j) {
1978 const Selector& selector = rule.selectors.at(j);
1980 if (selector.basicSelectors.isEmpty())
1984 if (selector.basicSelectors.size() != 1)
1986 }
else if (selector.basicSelectors.size() <= 1) {
1990 const BasicSelector &sel = selector.basicSelectors.at(selector.basicSelectors.size() - 1);
1992 if (!sel.ids.isEmpty()) {
1994 nr.selectors += selector;
1995 nr.declarations = rule.declarations;
1997 idIndex.insert(sel.ids.at(0), nr);
1998 }
else if (!sel.elementName.isEmpty()) {
2000 nr.selectors += selector;
2001 nr.declarations = rule.declarations;
2003 QString name = sel.elementName;
2004 if (nameCaseSensitivity == Qt::CaseInsensitive)
2005 name =
std::move(name).toLower();
2006 nameIndex.insert(name, nr);
2008 universalsSelectors += selector;
2011 if (!universalsSelectors.isEmpty()) {
2013 nr.selectors = universalsSelectors;
2014 nr.declarations = rule.declarations;
2019 styleRules = universals;
2024StyleSelector::~StyleSelector()
2028bool StyleSelector::nodeNameEquals(NodePtr node,
const QString& nodeName)
const
2030 return nodeNames(node).contains(nodeName, nameCaseSensitivity);
2033QStringList StyleSelector::nodeIds(NodePtr node)
const
2035 return QStringList(attributeValue(node, QCss::AttributeSelector{
"id"_L1, {}, AttributeSelector::NoMatch}));
2038bool StyleSelector::selectorMatches(
const Selector &selector, NodePtr node)
2040 if (selector.basicSelectors.isEmpty())
2043 if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
2044 if (selector.basicSelectors.size() != 1)
2046 return basicSelectorMatches(selector.basicSelectors.at(0), node);
2048 if (selector.basicSelectors.size() <= 1)
2051 int i = selector.basicSelectors.size() - 1;
2052 node = duplicateNode(node);
2055 BasicSelector sel = selector.basicSelectors.at(i);
2057 match = basicSelectorMatches(sel, node);
2059 if (i == selector.basicSelectors.size() - 1)
2061 if (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2062 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent)
2066 if (match || (sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor &&
2067 sel.relationToNext != BasicSelector::MatchNextSelectorIfIndirectAdjecent))
2073 sel = selector.basicSelectors.at(i);
2074 if (sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2075 || sel.relationToNext == BasicSelector::MatchNextSelectorIfParent) {
2077 NodePtr nextParent = parentNode(node);
2080 }
else if (sel.relationToNext == BasicSelector::MatchNextSelectorIfDirectAdjecent
2081 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent) {
2082 NodePtr previousSibling = previousSiblingNode(node);
2084 node = previousSibling;
2086 if (isNullNode(node)) {
2090 }
while (i >= 0 && (match || sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
2091 || sel.relationToNext == BasicSelector::MatchNextSelectorIfIndirectAdjecent));
2098bool StyleSelector::basicSelectorMatches(
const BasicSelector &sel, NodePtr node)
2100 if (!sel.attributeSelectors.isEmpty()) {
2101 if (!hasAttributes(node))
2104 for (
int i = 0; i < sel.attributeSelectors.size(); ++i) {
2105 const QCss::AttributeSelector &a = sel.attributeSelectors.at(i);
2107 const QString attrValue = attributeValue(node, a);
2108 if (attrValue.isNull())
2111 switch (a.valueMatchCriterium) {
2112 case QCss::AttributeSelector::NoMatch:
2114 case QCss::AttributeSelector::MatchEqual:
2115 if (attrValue != a.value)
2118 case QCss::AttributeSelector::MatchIncludes: {
2119 const auto lst = QStringView{attrValue}.tokenize(u' ');
2121 for (
auto s : lst) {
2131 case QCss::AttributeSelector::MatchDashMatch: {
2132 const QString dashPrefix = a.value + u'-';
2133 if (attrValue != a.value && !attrValue.startsWith(dashPrefix))
2137 case QCss::AttributeSelector::MatchBeginsWith:
2138 if (!attrValue.startsWith(a.value))
2141 case QCss::AttributeSelector::MatchEndsWith:
2142 if (!attrValue.endsWith(a.value))
2145 case QCss::AttributeSelector::MatchContains:
2146 if (!attrValue.contains(a.value))
2153 if (!sel.elementName.isEmpty()
2154 && !nodeNameEquals(node, sel.elementName))
2157 if (!sel.ids.isEmpty()
2158 && sel.ids != nodeIds(node))
2164void StyleSelector::matchRule(NodePtr node,
const StyleRule &rule, StyleSheetOrigin origin,
2165 int depth, QMultiMap<uint, StyleRule> *weightedRules)
2167 for (
int j = 0; j < rule.selectors.size(); ++j) {
2168 const Selector& selector = rule.selectors.at(j);
2169 if (selectorMatches(selector, node)) {
2170 uint weight = rule.order
2171 + selector.specificity() *0x100
2172 + (uint(origin) + depth)*0x100000;
2173 StyleRule newRule = rule;
2174 if (rule.selectors.size() > 1) {
2175 newRule.selectors.resize(1);
2176 newRule.selectors[0] = selector;
2179 weightedRules->insert(weight, newRule);
2186QList<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
2188 QList<StyleRule> rules;
2189 if (styleSheets.isEmpty())
2192 QMultiMap<uint, StyleRule> weightedRules;
2195 for (
int sheetIdx = 0; sheetIdx < styleSheets.size(); ++sheetIdx) {
2196 const StyleSheet &styleSheet = styleSheets.at(sheetIdx);
2197 for (
int i = 0; i < styleSheet.styleRules.size(); ++i) {
2198 matchRule(node, styleSheet.styleRules.at(i), styleSheet.origin, styleSheet.depth, &weightedRules);
2201 if (!styleSheet.idIndex.isEmpty()) {
2202 QStringList ids = nodeIds(node);
2203 for (
int i = 0; i < ids.size(); i++) {
2204 const QString &key = ids.at(i);
2205 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.idIndex.constFind(key);
2206 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
2207 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2212 if (!styleSheet.nameIndex.isEmpty()) {
2213 QStringList names = nodeNames(node);
2214 for (
int i = 0; i < names.size(); i++) {
2215 QString name = names.at(i);
2216 if (nameCaseSensitivity == Qt::CaseInsensitive)
2217 name = std::move(name).toLower();
2218 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
2219 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
2220 matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
2225 if (!medium.isEmpty()) {
2226 for (
int i = 0; i < styleSheet.mediaRules.size(); ++i) {
2227 if (styleSheet.mediaRules.at(i).media.contains(medium, Qt::CaseInsensitive)) {
2228 for (
int j = 0; j < styleSheet.mediaRules.at(i).styleRules.size(); ++j) {
2229 matchRule(node, styleSheet.mediaRules.at(i).styleRules.at(j), styleSheet.origin,
2230 styleSheet.depth, &weightedRules);
2237 rules.reserve(weightedRules.size());
2238 QMultiMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
2239 for ( ; it != weightedRules.constEnd() ; ++it)
2247QList<Declaration> StyleSelector::declarationsForNode(NodePtr node,
const char *extraPseudo)
2249 QList<Declaration> decls;
2250 QList<StyleRule> rules = styleRulesForNode(node);
2251 for (
int i = 0; i < rules.size(); i++) {
2252 const Selector& selector = rules.at(i).selectors.at(0);
2253 const QString pseudoElement = selector.pseudoElement();
2255 if (extraPseudo && pseudoElement == QLatin1StringView(extraPseudo)) {
2256 decls += rules.at(i).declarations;
2260 if (!pseudoElement.isEmpty())
2262 quint64 pseudoClass = selector.pseudoClass();
2263 if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
2264 decls += rules.at(i).declarations;
2271 return (c >=
'0' && c <=
'9')
2272 || (c >=
'a' && c <=
'f')
2273 || (c >=
'A' && c <=
'F')
2277QString Scanner::preprocess(
const QString &input,
bool *hasEscapeSequences)
2279 QString output = input;
2281 if (hasEscapeSequences)
2282 *hasEscapeSequences =
false;
2285 while (i < output.size()) {
2286 if (output.at(i) == u'\\') {
2291 const int hexStart = i;
2292 while (i < output.size()
2293 && isHexDigit(output.at(i).toLatin1())
2298 if (hexCount == 0) {
2299 if (hasEscapeSequences)
2300 *hasEscapeSequences =
true;
2304 hexCount = qMin(hexCount, 6);
2306 const char16_t code = QStringView{output}.mid(hexStart, hexCount).toUShort(&ok, 16);
2308 output.replace(hexStart - 1, hexCount + 1, code);
2320int QCssScanner_Generated::handleCommentStart()
2322 while (pos < input.size() - 1) {
2323 if (input.at(pos) == u'*' && input.at(pos + 1) == u'/') {
2332void Scanner::scan(
const QString &preprocessedInput, QList<Symbol> *symbols)
2334 QCssScanner_Generated scanner(preprocessedInput);
2336 int tok = scanner.lex();
2338 sym.token =
static_cast<QCss::TokenType>(tok);
2339 sym.text = scanner.input;
2340 sym.start = scanner.lexemStart;
2341 sym.len = scanner.lexemLength;
2342 symbols->append(sym);
2343 tok = scanner.lex();
2351 result.reserve(
len);
2352 for (
int i = 0; i <
len; ++i) {
2353 if (text.at(start + i) == u'\\' && i < len - 1)
2355 result += text.at(start + i);
2360Parser::Parser(
const QString &css,
bool isFile)
2369 hasEscapeSequences =
false;
2372void Parser::init(
const QString &css,
bool isFile)
2374 QString styleSheet = css;
2377 if (file.open(QFile::ReadOnly)) {
2378 sourcePath = QFileInfo(styleSheet).absolutePath() + u'/';
2379 QTextStream stream(&file);
2380 styleSheet = stream.readAll();
2382 qWarning() <<
"QCss::Parser - Failed to load file " << css;
2389 hasEscapeSequences =
false;
2392 Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
2397bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
2399 if (testTokenAndEndsWith(ATKEYWORD_SYM,
"charset"_L1)) {
2400 while (test(S) || test(CDO) || test(CDC)) {}
2401 if (!next(STRING))
return false;
2402 if (!next(SEMICOLON))
return false;
2405 while (test(S) || test(CDO) || test(CDC)) {}
2407 while (testImport()) {
2409 if (!parseImport(&rule))
return false;
2410 styleSheet->importRules.append(rule);
2411 while (test(S) || test(CDO) || test(CDC)) {}
2417 if (!parseMedia(&rule))
return false;
2418 styleSheet->mediaRules.append(rule);
2419 }
else if (testPage()) {
2421 if (!parsePage(&rule))
return false;
2422 styleSheet->pageRules.append(rule);
2423 }
else if (testRuleset()) {
2425 if (!parseRuleset(&rule))
return false;
2426 styleSheet->styleRules.append(rule);
2427 }
else if (test(ATKEYWORD_SYM)) {
2428 if (!until(RBRACE))
return false;
2429 }
else if (hasNext()) {
2432 while (test(S) || test(CDO) || test(CDC)) {}
2433 }
while (hasNext());
2434 styleSheet->buildIndexes(nameCaseSensitivity);
2438Symbol Parser::errorSymbol()
2440 if (errorIndex == -1)
return Symbol();
2441 return symbols.at(errorIndex);
2446 if (!str->startsWith(u'\'') && !str->startsWith(u'\"'))
2452bool Parser::parseImport(ImportRule *importRule)
2457 importRule->href = lexem();
2459 if (!testAndParseUri(&importRule->href))
return false;
2461 removeOptionalQuotes(&importRule->href);
2466 if (!parseMedium(&importRule->media))
return false;
2468 while (test(COMMA)) {
2470 if (!parseNextMedium(&importRule->media))
return false;
2474 if (!next(SEMICOLON))
return false;
2480bool Parser::parseMedia(MediaRule *mediaRule)
2484 if (!parseNextMedium(&mediaRule->media))
return false;
2485 }
while (test(COMMA));
2487 if (!next(LBRACE))
return false;
2490 while (testRuleset()) {
2492 if (!parseRuleset(&rule))
return false;
2493 mediaRule->styleRules.append(rule);
2496 if (!next(RBRACE))
return false;
2501bool Parser::parseMedium(QStringList *media)
2503 media->append(lexem());
2508bool Parser::parsePage(PageRule *pageRule)
2512 if (testPseudoPage())
2513 if (!parsePseudoPage(&pageRule->selector))
return false;
2516 if (!next(LBRACE))
return false;
2521 if (!parseNextDeclaration(&decl))
return false;
2522 if (!decl.isEmpty())
2523 pageRule->declarations.append(decl);
2524 }
while (test(SEMICOLON));
2526 if (!next(RBRACE))
return false;
2531bool Parser::parsePseudoPage(QString *selector)
2533 if (!next(IDENT))
return false;
2534 *selector = lexem();
2538bool Parser::parseNextOperator(Value *value)
2540 if (!hasNext())
return true;
2542 case SLASH: value->type = Value::TermOperatorSlash; skipSpace();
break;
2543 case COMMA: value->type = Value::TermOperatorComma; skipSpace();
break;
2544 default: prev();
break;
2549bool Parser::parseCombinator(BasicSelector::Relation *relation)
2551 *relation = BasicSelector::NoRelation;
2552 if (lookup() == S) {
2553 *relation = BasicSelector::MatchNextSelectorIfAncestor;
2559 *relation = BasicSelector::MatchNextSelectorIfDirectAdjecent;
2560 }
else if (test(GREATER)) {
2561 *relation = BasicSelector::MatchNextSelectorIfParent;
2562 }
else if (test(TILDE)) {
2563 *relation = BasicSelector::MatchNextSelectorIfIndirectAdjecent;
2569bool Parser::parseProperty(Declaration *decl)
2571 decl->d->property = lexem();
2572 decl->d->propertyId =
static_cast<Property>(findKnownValue(decl->d->property, properties, NumProperties));
2573 decl->d->inheritable = isInheritable(decl->d->propertyId);
2578bool Parser::parseRuleset(StyleRule *styleRule)
2581 if (!parseSelector(&sel))
return false;
2582 styleRule->selectors.append(sel);
2584 while (test(COMMA)) {
2587 if (!parseNextSelector(&sel))
return false;
2588 styleRule->selectors.append(sel);
2592 if (!next(LBRACE))
return false;
2593 const int declarationStart = index;
2598 const int rewind = index;
2599 if (!parseNextDeclaration(&decl)) {
2601 const bool foundSemicolon = until(SEMICOLON);
2602 const int semicolonIndex = index;
2604 index = declarationStart;
2605 const bool foundRBrace = until(RBRACE);
2607 if (foundSemicolon && semicolonIndex < index) {
2608 decl = Declaration();
2609 index = semicolonIndex - 1;
2615 if (!decl.isEmpty())
2616 styleRule->declarations.append(decl);
2617 }
while (test(SEMICOLON));
2619 if (!next(RBRACE))
return false;
2624bool Parser::parseSelector(Selector *sel)
2626 BasicSelector basicSel;
2627 if (!parseSimpleSelector(&basicSel))
return false;
2628 while (testCombinator()) {
2629 if (!parseCombinator(&basicSel.relationToNext))
return false;
2631 if (!testSimpleSelector())
break;
2632 sel->basicSelectors.append(basicSel);
2634 basicSel = BasicSelector();
2635 if (!parseSimpleSelector(&basicSel))
return false;
2637 sel->basicSelectors.append(basicSel);
2641bool Parser::parseSimpleSelector(BasicSelector *basicSel)
2644 if (lookupElementName()) {
2645 if (!parseElementName(&basicSel->elementName))
return false;
2655 QString theid = lexem();
2658 basicSel->ids.append(theid);
2660 }
else if (testClass()) {
2662 AttributeSelector a;
2663 a.name =
"class"_L1;
2664 a.valueMatchCriterium = AttributeSelector::MatchIncludes;
2665 if (!parseClass(&a.value))
return false;
2666 basicSel->attributeSelectors.append(a);
2667 }
else if (testAttrib()) {
2669 AttributeSelector a;
2670 if (!parseAttrib(&a))
return false;
2671 basicSel->attributeSelectors.append(a);
2672 }
else if (testPseudo()) {
2675 if (!parsePseudo(&ps))
return false;
2676 basicSel->pseudos.append(ps);
2678 if (onceMore) ++count;
2680 return count >= minCount;
2683bool Parser::parseClass(QString *name)
2685 if (!next(IDENT))
return false;
2690bool Parser::parseElementName(QString *name)
2693 case STAR: name->clear();
break;
2694 case IDENT: *name = lexem();
break;
2695 default:
return false;
2700bool Parser::parseAttrib(AttributeSelector *attr)
2703 if (!next(IDENT))
return false;
2704 attr->name = lexem();
2708 attr->valueMatchCriterium = AttributeSelector::MatchEqual;
2709 }
else if (test(INCLUDES)) {
2710 attr->valueMatchCriterium = AttributeSelector::MatchIncludes;
2711 }
else if (test(DASHMATCH)) {
2712 attr->valueMatchCriterium = AttributeSelector::MatchDashMatch;
2713 }
else if (test(BEGINSWITH)) {
2714 attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
2715 }
else if (test(ENDSWITH)) {
2716 attr->valueMatchCriterium = AttributeSelector::MatchEndsWith;
2717 }
else if (test(CONTAINS)) {
2718 attr->valueMatchCriterium = AttributeSelector::MatchContains;
2720 return next(RBRACKET);
2725 if (!test(IDENT) && !test(STRING))
return false;
2726 attr->value = unquotedLexem();
2729 return next(RBRACKET);
2732bool Parser::parsePseudo(Pseudo *pseudo)
2735 pseudo->negated = test(EXCLAMATION_SYM);
2737 pseudo->name = lexem();
2738 pseudo->type =
static_cast<quint64>(findKnownValue(pseudo->name, pseudos, NumPseudos));
2741 if (!next(FUNCTION))
return false;
2742 pseudo->function = lexem();
2744 pseudo->function.chop(1);
2746 if (!test(IDENT))
return false;
2747 pseudo->name = lexem();
2749 return next(RPAREN);
2752bool Parser::parseNextDeclaration(Declaration *decl)
2754 if (!testProperty())
2756 if (!parseProperty(decl))
return false;
2757 if (!next(COLON))
return false;
2759 if (!parseNextExpr(&decl->d->values))
return false;
2761 if (!parsePrio(decl))
return false;
2765bool Parser::testPrio()
2767 const int rewind = index;
2768 if (!test(EXCLAMATION_SYM))
return false;
2774 if (lexem().compare(
"important"_L1, Qt::CaseInsensitive) != 0) {
2781bool Parser::parsePrio(Declaration *declaration)
2783 declaration->d->important =
true;
2788bool Parser::parseExpr(QList<Value> *values)
2791 if (!parseTerm(&val))
return false;
2792 values->append(val);
2797 if (!parseNextOperator(&val))
return false;
2798 if (val.type != QCss::Value::Unknown)
2799 values->append(val);
2803 if (!parseTerm(&val))
return false;
2804 values->append(val);
2810bool Parser::testTerm()
2812 return test(PLUS) || test(MINUS)
2822bool Parser::parseTerm(Value *value)
2824 QString str = lexem();
2825 bool haveUnary =
false;
2826 if (lookup() == PLUS || lookup() == MINUS) {
2828 if (!hasNext())
return false;
2833 value->variant = str;
2834 value->type = QCss::Value::String;
2837 value->type = Value::Number;
2838 value->variant.convert(QMetaType::fromType<
double>());
2841 value->type = Value::Percentage;
2843 value->variant = str;
2846 value->type = Value::Length;
2850 if (haveUnary)
return false;
2851 value->type = Value::String;
2854 value->variant = str;
2857 if (haveUnary)
return false;
2858 value->type = Value::Identifier;
2859 const int theid = findKnownValue(str, values, NumKnownValues);
2861 value->type = Value::KnownIdentifier;
2862 value->variant = theid;
2867 if (haveUnary)
return false;
2869 if (testHexColor()) {
2871 if (!parseHexColor(&col))
return false;
2872 value->type = Value::Color;
2873 value->variant = col;
2874 }
else if (testFunction()) {
2876 if (!parseFunction(&name, &args))
return false;
2877 if (name ==
"url"_L1) {
2878 value->type = Value::Uri;
2879 removeOptionalQuotes(&args);
2880 if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
2881 args.prepend(sourcePath);
2883 value->variant = args;
2885 value->type = Value::Function;
2886 value->variant = QStringList() << name << args;
2889 return recordError();
2898bool Parser::parseFunction(QString *name, QString *args)
2905 std::swap(start, index);
2906 if (!until(RPAREN))
return false;
2907 for (
int i = start; i < index - 1; ++i)
2908 args->append(symbols.at(i).lexem());
2910
2911
2912
2917bool Parser::parseHexColor(QColor *col)
2919 *col = QColor::fromString(lexem());
2920 if (!col->isValid()) {
2921 qWarning(
"QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
2928bool Parser::testAndParseUri(QString *uri)
2930 const int rewind = index;
2931 if (!testFunction())
return false;
2934 if (!parseFunction(&name, &args)) {
2938 if (name.compare(
"url"_L1, Qt::CaseInsensitive) != 0) {
2943 removeOptionalQuotes(uri);
2947bool Parser::testSimpleSelector()
2949 return testElementName()
2956bool Parser::next(QCss::TokenType t)
2958 if (hasNext() && next() == t)
2960 return recordError();
2963bool Parser::test(QCss::TokenType t)
2965 if (index >= symbols.size())
2967 if (symbols.at(index).token == t) {
2974QString Parser::unquotedLexem()
const
2976 QString s = lexem();
2977 if (lookup() == STRING) {
2984QString Parser::lexemUntil(QCss::TokenType t)
2987 while (hasNext() && next() != t)
2988 lexem += symbol().lexem();
2992bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
2998 switch(symbols.at(index-1).token) {
2999 case LBRACE: ++braceCount;
break;
3000 case LBRACKET: ++brackCount;
break;
3002 case LPAREN: ++parenCount;
break;
3006 while (index < symbols.size()) {
3007 QCss::TokenType t = symbols.at(index++).token;
3009 case LBRACE: ++braceCount;
break;
3010 case RBRACE: --braceCount;
break;
3011 case LBRACKET: ++brackCount;
break;
3012 case RBRACKET: --brackCount;
break;
3014 case LPAREN: ++parenCount;
break;
3015 case RPAREN: --parenCount;
break;
3018 if ((t == target || (target2 != NONE && t == target2))
3024 if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
3032bool Parser::testTokenAndEndsWith(QCss::TokenType t, QLatin1StringView str)
3034 if (!test(t))
return false;
3035 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 const QCssKnownValue origins[NumKnownOrigins - 1]
static bool operator<(const QString &name, const QCssKnownValue &prop)
static void removeOptionalQuotes(QString *str)
static const QCssKnownValue attachments[NumKnownAttachments - 1]
static bool setFontFamilyFromValues(const QList< QCss::Value > &values, QFont *font, int start=0)
static bool setFontWeightFromValue(const QCss::Value &value, QFont *font)
static const QCssKnownValue repeats[NumKnownRepeats - 1]
static int lengthValueFromData(const LengthData &data, const QFont &f)
static bool operator<(const QCssKnownValue &prop, const QString &name)
static const QCssKnownValue pseudos[NumPseudos - 1]
static void setTextTransformFromValue(const QCss::Value &value, QFont *font)
static const short indexOfId[NumKnownValues]
static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAdjustment)
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 const QCssKnownValue values[NumKnownValues - 1]
static bool intValueHelper(const QCss::Value &v, int *i, const char *unit)
static quint64 findKnownValue(const QString &name, const QCssKnownValue *start, int numValues)
static const QCssKnownValue tileModes[NumKnownTileModes - 1]
static Qt::Alignment parseAlignment(const QCss::Value *values, int count)
static const QCssKnownValue styleFeatures[NumKnownStyleFeatures - 1]
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 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 const QCssKnownValue properties[NumProperties - 1]
static const QCssKnownValue positions[NumKnownPositionModes - 1]
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 QColor colorFromData(const ColorData &c, const QPalette &pal)
Q_GUI_EXPORT void buildIndexes(Qt::CaseSensitivity nameCaseSensitivity=Qt::CaseSensitive)