QT源码剖析之QSS样式表

时间:2024-06-18 22:36:44

1. "QApplication::setStyleSheet()"设置样式表:

  1. 创建新的样式表。

  2. 设置新的样式。

void QApplication::setStyleSheet(const QString& styleSheet)
{
QApplicationPrivate::styleSheet = styleSheet;
QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplicationPrivate::app_style);
if (styleSheet.isEmpty()) { // application style sheet removed
if (!proxy)
return; // there was no stylesheet before
setStyle(proxy->base);
} else if (proxy) { // style sheet update, just repolish
proxy->repolish(qApp);
} else { // stylesheet set the first time
QStyleSheetStyle *newProxy = new QStyleSheetStyle(QApplicationPrivate::app_style);
QApplicationPrivate::app_style->setParent(newProxy);
setStyle(newProxy);
}
}

2. "QApplication::setStyle"——设置样式:

void QApplication::setStyle(QStyle *style)
{
if (!style || style == QApplicationPrivate::app_style)
return; QWidgetList all = allWidgets(); // clean up the old style
if (QApplicationPrivate::app_style) {
if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
QWidget *w = *it;
if (!(w->windowType() == Qt::Desktop) && // except desktop
w->testAttribute(Qt::WA_WState_Polished)) { // has been polished
QApplicationPrivate::app_style->unpolish(w);
}
}
}
QApplicationPrivate::app_style->unpolish(qApp);
} QStyle *old = QApplicationPrivate::app_style; // save QApplicationPrivate::overrides_native_style =
nativeStyleClassName() == QByteArray(style->metaObject()->className()); #ifndef QT_NO_STYLE_STYLESHEET
if (!QApplicationPrivate::styleSheet.isEmpty() && !qobject_cast<QStyleSheetStyle *>(style)) {
// we have a stylesheet already and a new style is being set
QStyleSheetStyle *newProxy = new QStyleSheetStyle(style);
style->setParent(newProxy);
QApplicationPrivate::app_style = newProxy;
} else
#endif // QT_NO_STYLE_STYLESHEET
QApplicationPrivate::app_style = style;
QApplicationPrivate::app_style->setParent(qApp); // take ownership // take care of possible palette requirements of certain gui
// styles. Do it before polishing the application since the style
// might call QApplication::setPalette() itself
if (QApplicationPrivate::set_pal) {
QApplication::setPalette(*QApplicationPrivate::set_pal);
} else if (QApplicationPrivate::sys_pal) {
clearSystemPalette();
initSystemPalette();
QApplicationPrivate::initializeWidgetPaletteHash();
QApplicationPrivate::initializeWidgetFontHash();
QApplicationPrivate::setPalette_helper(*QApplicationPrivate::sys_pal, /*className=*/, /*clearWidgetPaletteHash=*/false);
} else if (!QApplicationPrivate::sys_pal) {
// Initialize the sys_pal if it hasn't happened yet...
QApplicationPrivate::setSystemPalette(QApplicationPrivate::app_style->standardPalette());
} // initialize the application with the new style
QApplicationPrivate::app_style->polish(qApp); // re-polish existing widgets if necessary
if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
QWidget *w = *it;
if (w->windowType() != Qt::Desktop && w->testAttribute(Qt::WA_WState_Polished)) {
if (w->style() == QApplicationPrivate::app_style)
QApplicationPrivate::app_style->polish(w); // repolish
#ifndef QT_NO_STYLE_STYLESHEET
else
w->setStyleSheet(w->styleSheet()); // touch
#endif
}
} for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
QWidget *w = *it;
if (w->windowType() != Qt::Desktop && !w->testAttribute(Qt::WA_SetStyle)) {
QEvent e(QEvent::StyleChange);
QApplication::sendEvent(w, &e);
w->update();
}
}
} #ifndef QT_NO_STYLE_STYLESHEET
if (QStyleSheetStyle *oldProxy = qobject_cast<QStyleSheetStyle *>(old)) {
oldProxy->deref();
} else
#endif
if (old && old->parent() == qApp) {
delete old;
} if (QApplicationPrivate::focus_widget) {
QFocusEvent in(QEvent::FocusIn, Qt::OtherFocusReason);
QApplication::sendEvent(QApplicationPrivate::focus_widget->style(), &in);
QApplicationPrivate::focus_widget->update();
}
}

  2-1. 获取所有的QWidget列表(在QWidget的构造函数中调用QWidgetPrivate::init函数,将当前QWidget加入到列表)。

  2-2. 移除所有QWidget上旧的样式。

  2-3. 设置所有QWidget新的样式。

  2-4. 更新所有的QWidget。

4. "QStyleSheetStyle::styleRules"——经过一系列调用到这个函数中,获取样式规则:

QVector<QCss::StyleRule> QStyleSheetStyle::styleRules(const QObject *obj) const
{
QHash<const QObject *, QVector<StyleRule> >::const_iterator cacheIt = styleSheetCaches->styleRulesCache.constFind(obj);
if (cacheIt != styleSheetCaches->styleRulesCache.constEnd())
return cacheIt.value(); if (!initObject(obj)) {
return QVector<StyleRule>();
} QStyleSheetStyleSelector styleSelector; StyleSheet defaultSs;
QHash<const void *, StyleSheet>::const_iterator defaultCacheIt = styleSheetCaches->styleSheetCache.constFind(baseStyle());
if (defaultCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
defaultSs = getDefaultStyleSheet();
QStyle *bs = baseStyle();
styleSheetCaches->styleSheetCache.insert(bs, defaultSs);
QObject::connect(bs, SIGNAL(destroyed(QObject*)), styleSheetCaches, SLOT(styleDestroyed(QObject*)), Qt::UniqueConnection);
} else {
defaultSs = defaultCacheIt.value();
}
styleSelector.styleSheets += defaultSs; if (!qApp->styleSheet().isEmpty()) {
StyleSheet appSs;
QHash<const void *, StyleSheet>::const_iterator appCacheIt = styleSheetCaches->styleSheetCache.constFind(qApp);
if (appCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
QString ss = qApp->styleSheet();
if (ss.startsWith(QLatin1String("file:///")))
ss.remove(0, 8);
parser.init(ss, qApp->styleSheet() != ss);
if (!parser.parse(&appSs))
qWarning("Could not parse application stylesheet");
appSs.origin = StyleSheetOrigin_Inline;
appSs.depth = 1;
styleSheetCaches->styleSheetCache.insert(qApp, appSs);
} else {
appSs = appCacheIt.value();
}
styleSelector.styleSheets += appSs;
} QVector<QCss::StyleSheet> objectSs;
for (const QObject *o = obj; o; o = parentObject(o)) {
QString styleSheet = o->property("styleSheet").toString();
if (styleSheet.isEmpty())
continue;
StyleSheet ss;
QHash<const void *, StyleSheet>::const_iterator objCacheIt = styleSheetCaches->styleSheetCache.constFind(o);
if (objCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
parser.init(styleSheet);
if (!parser.parse(&ss)) {
parser.init(QLatin1String("* {") + styleSheet + QLatin1Char('}'));
if (!parser.parse(&ss))
qWarning("Could not parse stylesheet of object %p", o);
}
ss.origin = StyleSheetOrigin_Inline;
styleSheetCaches->styleSheetCache.insert(o, ss);
} else {
ss = objCacheIt.value();
}
objectSs.append(ss);
} for (int i = ; i < objectSs.count(); i++)
objectSs[i].depth = objectSs.count() - i + ; styleSelector.styleSheets += objectSs; StyleSelector::NodePtr n;
n.ptr = const_cast<QObject *>(obj);
QVector<QCss::StyleRule> rules = styleSelector.styleRulesForNode(n);
styleSheetCaches->styleRulesCache.insert(obj, rules);
return rules;
}

  4-1. 初始化如果缓存中没有样式,先进行初始化。

  4-2. 获取基本样式到@defaultSs中,并添加到@styleSelector.styleSheets

  4-3. 在缓存中获取全局@qApp样式到@appSs中,并添加到@styleSelector.styleSheets。

    4-3-1. 如果在缓存中没有找到全局@qApp样式,则获取@qApp样式表字符串进行解析生成StyleSheet

  4-4. 不断遍历基类,从缓存中获取基类的样式到@objectSs中,并添加到@styleSelector.styleSheets。

    4-4-1. 如果缓存没有找到样式,则利用字符串重新解析生成StyleSheet

  4-5. 根据样式选着器(QStyleSheetStyleSelector)获取样式规添加到@rules。

  4-6. 最后将对象(QObject)与样式规则(StyleRule)插入到缓存@styleSheetCaches->styleRulesCache中。

5. 将字符串解析生成样式表StyleSheet(主要在qcssparser.cpp文件中):

  在"QStyleSheetStyle::styleRules"主要通过通过两个函数"Parser::init"和"Parser::parse"。

  5-1. 初始化解析器:

void Parser::init(const QString &css, bool isFile)
{
QString styleSheet = css;
if (isFile) {
QFile file(css);
if (file.open(QFile::ReadOnly)) {
sourcePath = QFileInfo(styleSheet).absolutePath() + QLatin1Char('/');
QTextStream stream(&file);
styleSheet = stream.readAll();
} else {
qWarning() << "QCss::Parser - Failed to load file " << css;
styleSheet.clear();
}
} else {
sourcePath.clear();
} hasEscapeSequences = false;
symbols.resize();
symbols.reserve();
Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
index = ;
errorIndex = -;
}

    5-1-1. 将字符串进行预处理(这里主要是处理转义字符)。

    5-1-2. 逐个扫描形成一个一个符号(与编译原理中的扫描程序一致,形成符号后,方便后面进一步处理)。

  5-2. 解析样式表:

bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
{
if (testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("charset"))) {
if (!next(STRING)) return false;
if (!next(SEMICOLON)) return false;
} while (test(S) || test(CDO) || test(CDC)) {} while (testImport()) {
ImportRule rule;
if (!parseImport(&rule)) return false;
styleSheet->importRules.append(rule);
while (test(S) || test(CDO) || test(CDC)) {}
} do {
if (testMedia()) {
MediaRule rule;
if (!parseMedia(&rule)) return false;
styleSheet->mediaRules.append(rule);
} else if (testPage()) {
PageRule rule;
if (!parsePage(&rule)) return false;
styleSheet->pageRules.append(rule);
} else if (testRuleset()) {
StyleRule rule;
if (!parseRuleset(&rule)) return false;
styleSheet->styleRules.append(rule);
} else if (test(ATKEYWORD_SYM)) {
if (!until(RBRACE)) return false;
} else if (hasNext()) {
return false;
}
while (test(S) || test(CDO) || test(CDC)) {}
} while (hasNext());
styleSheet->buildIndexes(nameCaseSensitivity);
return true;
}

    5-2-1. 遍历所有符号,根据符号的类型进行相应的处理(这里我们只关注样式规则"parseRuleset(&rule)")。

    5-2-2. 解析样式规则:

bool Parser::parseRuleset(StyleRule *styleRule)
{
Selector sel;
if (!parseSelector(&sel)) return false;
styleRule->selectors.append(sel); while (test(COMMA)) {
skipSpace();
Selector sel;
if (!parseNextSelector(&sel)) return false;
styleRule->selectors.append(sel);
} skipSpace();
if (!next(LBRACE)) return false;
const int declarationStart = index; do {
skipSpace();
Declaration decl;
const int rewind = index;
if (!parseNextDeclaration(&decl)) {
index = rewind;
const bool foundSemicolon = until(SEMICOLON);
const int semicolonIndex = index; index = declarationStart;
const bool foundRBrace = until(RBRACE); if (foundSemicolon && semicolonIndex < index) {
decl = Declaration();
index = semicolonIndex - ;
} else {
skipSpace();
return foundRBrace;
}
}
if (!decl.isEmpty())
styleRule->declarations.append(decl);
} while (test(SEMICOLON)); if (!next(RBRACE)) return false;
skipSpace();
return true;
}

    5-2-2-1. 解析选择器(id选着器,class选着器,属性选着器等)。

    5-2-2-2. 解析声明,包括属性名、属性值等。

    5-2-2-3. 将解析的声明添加到样式规则中。

6. (4-5的细化)根据样式选着器(QStyleSheetStyleSelector)得到样式规则"":

 QVector<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
{
QVector<StyleRule> rules;
if (styleSheets.isEmpty())
return rules; QMap<uint, StyleRule> weightedRules; // (spec, rule) that will be sorted below //prune using indexed stylesheet
for (int sheetIdx = ; sheetIdx < styleSheets.count(); ++sheetIdx) {
const StyleSheet &styleSheet = styleSheets.at(sheetIdx);
for (int i = 0; i < styleSheet.styleRules.count(); ++i) {
matchRule(node, styleSheet.styleRules.at(i), styleSheet.origin, styleSheet.depth, &weightedRules);
} if (!styleSheet.idIndex.isEmpty()) {
QStringList ids = nodeIds(node);
for (int i = 0; i < ids.count(); i++) {
const QString &key = ids.at(i);
QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.idIndex.constFind(key);
while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
++it;
}
}
}
if (!styleSheet.nameIndex.isEmpty()) {
QStringList names = nodeNames(node);
for (int i = 0; i < names.count(); i++) {
QString name = names.at(i);
if (nameCaseSensitivity == Qt::CaseInsensitive)
name = name.toLower();
QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
++it;
}
}
}
if (!medium.isEmpty()) {
for (int i = ; i < styleSheet.mediaRules.count(); ++i) {
if (styleSheet.mediaRules.at(i).media.contains(medium, Qt::CaseInsensitive)) {
for (int j = ; j < styleSheet.mediaRules.at(i).styleRules.count(); ++j) {
matchRule(node, styleSheet.mediaRules.at(i).styleRules.at(j), styleSheet.origin,
styleSheet.depth, &weightedRules);
}
}
}
}
} rules.reserve(weightedRules.count());
QMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
for ( ; it != weightedRules.constEnd() ; ++it)
rules += *it; return rules;
}

  6-1. 遍历已有的样式规则(styleSheet.styleRules),如果匹配规则,将规则添加到@weightedRules中。

  6-2. 遍历id样式(styleSheet.idIndex),获取当前对象的名称(objectName),对象名称相同则匹配规则,将匹配的规则添加到@weightedRules中。

  6-3. 遍历class样式(styleSheet.nameIndex),获取当前对象的类名称(className)和基类的类名称,类名称相同则匹配规则,将规则添加到@weightedRules中。

  6-4. 将@weightedRules中的样式规则添加到@rules,并返回@rules

7. 最后需要渲染规则,将得到的样式规则转换为绘制时需要的对象(字体、颜色、背景画刷、背景图片等等):

QRenderRule::QRenderRule(const QVector<Declaration> &declarations, const QObject *object)
: features(), hasFont(false), pal(), b(), bg(), bd(), ou(), geo(), p(), img(), clipset()
{
QPalette palette = QApplication::palette(); // ###: ideally widget's palette
ValueExtractor v(declarations, palette)zhua
features = v.extractStyleFeatures(); int w = -, h = -, minw = -, minh = -, maxw = -, maxh = -;
if (v.extractGeometry(&w, &h, &minw, &minh, &maxw, &maxh))
geo = new QStyleSheetGeometryData(w, h, minw, minh, maxw, maxh); int left = , top = , right = , bottom = ;
Origin origin = Origin_Unknown;
Qt::Alignment position = ;
QCss::PositionMode mode = PositionMode_Unknown;
Qt::Alignment textAlignment = ;
if (v.extractPosition(&left, &top, &right, &bottom, &origin, &position, &mode, &textAlignment))
p = new QStyleSheetPositionData(left, top, right, bottom, origin, position, mode, textAlignment); int margins[], paddings[], spacing = -;
for (int i = ; i < ; i++)
margins[i] = paddings[i] = ;
if (v.extractBox(margins, paddings, &spacing))
b = new QStyleSheetBoxData(margins, paddings, spacing); int borders[];
QBrush colors[];
QCss::BorderStyle styles[];
QSize radii[];
for (int i = ; i < ; i++) {
borders[i] = ;
styles[i] = BorderStyle_None;
}
if (v.extractBorder(borders, colors, styles, radii))
bd = new QStyleSheetBorderData(borders, colors, styles, radii); int offsets[];
for (int i = ; i < ; i++) {
borders[i] = offsets[i] = ;
styles[i] = BorderStyle_None;
}
if (v.extractOutline(borders, colors, styles, radii, offsets))
ou = new QStyleSheetOutlineData(borders, colors, styles, radii, offsets); QBrush brush;
QString uri;
Repeat repeat = Repeat_XY;
Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft;
Attachment attachment = Attachment_Scroll;
origin = Origin_Padding;
Origin clip = Origin_Border;
if (v.extractBackground(&brush, &uri, &repeat, &alignment, &origin, &attachment, &clip))
bg = new QStyleSheetBackgroundData(brush, QPixmap(uri), repeat, alignment, origin, attachment, clip); QBrush sfg, fg;
QBrush sbg, abg;
if (v.extractPalette(&fg, &sfg, &sbg, &abg))
pal = new QStyleSheetPaletteData(fg, sfg, sbg, abg); QIcon icon;
alignment = Qt::AlignCenter;
QSize size;
if (v.extractImage(&icon, &alignment, &size))
img = new QStyleSheetImageData(icon, alignment, size); int adj = -;
hasFont = v.extractFont(&font, &adj); #ifndef QT_NO_TOOLTIP
if (object && qstrcmp(object->metaObject()->className(), "QTipLabel") == )
palette = QToolTip::palette();
#endif for (int i = ; i < declarations.count(); i++) {
const Declaration& decl = declarations.at(i);
if (decl.d->propertyId == BorderImage) {
QString uri;
QCss::TileMode horizStretch, vertStretch;
int cuts[]; decl.borderImageValue(&uri, cuts, &horizStretch, &vertStretch);
if (uri.isEmpty() || uri == QLatin1String("none")) {
if (bd && bd->bi)
bd->bi->pixmap = QPixmap();
} else {
if (!bd)
bd = new QStyleSheetBorderData;
if (!bd->bi)
bd->bi = new QStyleSheetBorderImageData; QStyleSheetBorderImageData *bi = bd->bi;
bi->pixmap = QPixmap(uri);
for (int i = ; i < ; i++)
bi->cuts[i] = cuts[i];
bi->horizStretch = horizStretch;
bi->vertStretch = vertStretch;
}
} else if (decl.d->propertyId == QtBackgroundRole) {
if (bg && bg->brush.style() != Qt::NoBrush)
continue;
int role = decl.d->values.at().variant.toInt();
if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
defaultBackground = palette.color((QPalette::ColorRole)(role-Value_FirstColorRole));
} else if (decl.d->property.startsWith(QLatin1String("qproperty-"), Qt::CaseInsensitive)) {
// intentionally left blank...
} else if (decl.d->propertyId == UnknownProperty) {
bool knownStyleHint = false;
for (int i = ; i < numKnownStyleHints; i++) {
QLatin1String styleHint(knownStyleHints[i]);
if (decl.d->property.compare(styleHint) == ) {
QString hintName = QString(styleHint);
QVariant hintValue;
if (hintName.endsWith(QLatin1String("alignment"))) {
hintValue = (int) decl.alignmentValue();
} else if (hintName.endsWith(QLatin1String("color"))) {
hintValue = (int) decl.colorValue().rgba();
} else if (hintName.endsWith(QLatin1String("size"))) {
hintValue = decl.sizeValue();
} else if (hintName.endsWith(QLatin1String("icon"))) {
hintValue = decl.iconValue();
} else if (hintName == QLatin1String("button-layout")
&& decl.d->values.count() != && decl.d->values.at().type == Value::String) {
hintValue = subControlLayout(decl.d->values.at().variant.toString());
} else {
int integer;
decl.intValue(&integer);
hintValue = integer;
}
styleHints[decl.d->property] = hintValue;
knownStyleHint = true;
break;
}
}
if (!knownStyleHint)
qDebug("Unknown property %s", qPrintable(decl.d->property));
}
} if (const QWidget *widget = qobject_cast<const QWidget *>(object)) {
QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle);
if (!style)
style = qobject_cast<QStyleSheetStyle *>(widget->style());
if (style)
fixupBorder(style->nativeFrameWidth(widget));
}
if (hasBorder() && border()->hasBorderImage())
defaultBackground = QBrush();
}

  从样式规则中得到样式声明,然后根据样式声明去创建不同的绘制对象,为后面的绘制做准备。

  绘制对象包括:位置(Geomeory、Position、Box)、边框(Border、Outline)、背景(BackgroundColor、BackgroundImage等)、字体(FontFamily、FontSize、FontStyle、FontWeight等)等等。

最后如果想查看QSS属性名称和值的列表,可以查看qtbase\src\gui\text\qcssparser.cpp文件:

static const QCssKnownValue properties[NumProperties - ] = {
{ "-qt-background-role", QtBackgroundRole },
{ "-qt-block-indent", QtBlockIndent },
{ "-qt-list-indent", QtListIndent },
{ "-qt-list-number-prefix", QtListNumberPrefix },
{ "-qt-list-number-suffix", QtListNumberSuffix },
{ "-qt-paragraph-type", QtParagraphType },
{ "-qt-style-features", QtStyleFeatures },
{ "-qt-table-type", QtTableType },
{ "-qt-user-state", QtUserState },
{ "alternate-background-color", QtAlternateBackground },
{ "background", Background },
{ "background-attachment", BackgroundAttachment },
{ "background-clip", BackgroundClip },
{ "background-color", BackgroundColor },
{ "background-image", BackgroundImage },
{ "background-origin", BackgroundOrigin },
{ "background-position", BackgroundPosition },
{ "background-repeat", BackgroundRepeat },
{ "border", Border },
{ "border-bottom", BorderBottom },
{ "border-bottom-color", BorderBottomColor },
{ "border-bottom-left-radius", BorderBottomLeftRadius },
{ "border-bottom-right-radius", BorderBottomRightRadius },
{ "border-bottom-style", BorderBottomStyle },
{ "border-bottom-width", BorderBottomWidth },
{ "border-color", BorderColor },
{ "border-image", BorderImage },
{ "border-left", BorderLeft },
{ "border-left-color", BorderLeftColor },
{ "border-left-style", BorderLeftStyle },
{ "border-left-width", BorderLeftWidth },
{ "border-radius", BorderRadius },
{ "border-right", BorderRight },
{ "border-right-color", BorderRightColor },
{ "border-right-style", BorderRightStyle },
{ "border-right-width", BorderRightWidth },
{ "border-style", BorderStyles },
{ "border-top", BorderTop },
{ "border-top-color", BorderTopColor },
{ "border-top-left-radius", BorderTopLeftRadius },
{ "border-top-right-radius", BorderTopRightRadius },
{ "border-top-style", BorderTopStyle },
{ "border-top-width", BorderTopWidth },
{ "border-width", BorderWidth },
{ "bottom", Bottom },
{ "color", Color },
{ "float", Float },
{ "font", Font },
{ "font-family", FontFamily },
{ "font-size", FontSize },
{ "font-style", FontStyle },
{ "font-variant", FontVariant },
{ "font-weight", FontWeight },
{ "height", Height },
{ "image", QtImage },
{ "image-position", QtImageAlignment },
{ "left", Left },
{ "line-height", LineHeight },
{ "list-style", ListStyle },
{ "list-style-type", ListStyleType },
{ "margin" , Margin },
{ "margin-bottom", MarginBottom },
{ "margin-left", MarginLeft },
{ "margin-right", MarginRight },
{ "margin-top", MarginTop },
{ "max-height", MaximumHeight },
{ "max-width", MaximumWidth },
{ "min-height", MinimumHeight },
{ "min-width", MinimumWidth },
{ "outline", Outline },
{ "outline-bottom-left-radius", OutlineBottomLeftRadius },
{ "outline-bottom-right-radius", OutlineBottomRightRadius },
{ "outline-color", OutlineColor },
{ "outline-offset", OutlineOffset },
{ "outline-radius", OutlineRadius },
{ "outline-style", OutlineStyle },
{ "outline-top-left-radius", OutlineTopLeftRadius },
{ "outline-top-right-radius", OutlineTopRightRadius },
{ "outline-width", OutlineWidth },
{ "padding", Padding },
{ "padding-bottom", PaddingBottom },
{ "padding-left", PaddingLeft },
{ "padding-right", PaddingRight },
{ "padding-top", PaddingTop },
{ "page-break-after", PageBreakAfter },
{ "page-break-before", PageBreakBefore },
{ "position", Position },
{ "right", Right },
{ "selection-background-color", QtSelectionBackground },
{ "selection-color", QtSelectionForeground },
{ "spacing", QtSpacing },
{ "subcontrol-origin", QtOrigin },
{ "subcontrol-position", QtPosition },
{ "text-align", TextAlignment },
{ "text-decoration", TextDecoration },
{ "text-indent", TextIndent },
{ "text-transform", TextTransform },
{ "text-underline-style", TextUnderlineStyle },
{ "top", Top },
{ "vertical-align", VerticalAlignment },
{ "white-space", Whitespace },
{ "width", Width }
}; static const QCssKnownValue values[NumKnownValues - ] = {
{ "active", Value_Active },
{ "alternate-base", Value_AlternateBase },
{ "always", Value_Always },
{ "auto", Value_Auto },
{ "base", Value_Base },
{ "bold", Value_Bold },
{ "bottom", Value_Bottom },
{ "bright-text", Value_BrightText },
{ "button", Value_Button },
{ "button-text", Value_ButtonText },
{ "center", Value_Center },
{ "circle", Value_Circle },
{ "dark", Value_Dark },
{ "dashed", Value_Dashed },
{ "decimal", Value_Decimal },
{ "disabled", Value_Disabled },
{ "disc", Value_Disc },
{ "dot-dash", Value_DotDash },
{ "dot-dot-dash", Value_DotDotDash },
{ "dotted", Value_Dotted },
{ "double", Value_Double },
{ "groove", Value_Groove },
{ "highlight", Value_Highlight },
{ "highlighted-text", Value_HighlightedText },
{ "inset", Value_Inset },
{ "italic", Value_Italic },
{ "large", Value_Large },
{ "left", Value_Left },
{ "light", Value_Light },
{ "line-through", Value_LineThrough },
{ "link", Value_Link },
{ "link-visited", Value_LinkVisited },
{ "lower-alpha", Value_LowerAlpha },
{ "lower-roman", Value_LowerRoman },
{ "lowercase", Value_Lowercase },
{ "medium", Value_Medium },
{ "mid", Value_Mid },
{ "middle", Value_Middle },
{ "midlight", Value_Midlight },
{ "native", Value_Native },
{ "none", Value_None },
{ "normal", Value_Normal },
{ "nowrap", Value_NoWrap },
{ "oblique", Value_Oblique },
{ "off", Value_Off },
{ "on", Value_On },
{ "outset", Value_Outset },
{ "overline", Value_Overline },
{ "pre", Value_Pre },
{ "pre-wrap", Value_PreWrap },
{ "ridge", Value_Ridge },
{ "right", Value_Right },
{ "selected", Value_Selected },
{ "shadow", Value_Shadow },
{ "small" , Value_Small },
{ "small-caps", Value_SmallCaps },
{ "solid", Value_Solid },
{ "square", Value_Square },
{ "sub", Value_Sub },
{ "super", Value_Super },
{ "text", Value_Text },
{ "top", Value_Top },
{ "transparent", Value_Transparent },
{ "underline", Value_Underline },
{ "upper-alpha", Value_UpperAlpha },
{ "upper-roman", Value_UpperRoman },
{ "uppercase", Value_Uppercase },
{ "wave", Value_Wave },
{ "window", Value_Window },
{ "window-text", Value_WindowText },
{ "x-large", Value_XLarge },
{ "xx-large", Value_XXLarge }
};