QT源码剖析之QSS样式表

 

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=*/0, /*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 = 0; i < objectSs.count(); i++)
        objectSs[i].depth = objectSs.count() - i + 2;

    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(0);
    symbols.reserve(8);
    Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
    index = 0;
    errorIndex = -1;
}

 

    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 - 1;
            } 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)得到样式规则"":

 1 QVector<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
 2 {
 3     QVector<StyleRule> rules;
 4     if (styleSheets.isEmpty())
 5         return rules;
 6 
 7     QMap<uint, StyleRule> weightedRules; // (spec, rule) that will be sorted below
 8 
 9     //prune using indexed stylesheet
10     for (int sheetIdx = 0; sheetIdx < styleSheets.count(); ++sheetIdx) {
11         const StyleSheet &styleSheet = styleSheets.at(sheetIdx);
12         for (int i = 0; i < styleSheet.styleRules.count(); ++i) {
13             matchRule(node, styleSheet.styleRules.at(i), styleSheet.origin, styleSheet.depth, &weightedRules);
14         }
15 
16         if (!styleSheet.idIndex.isEmpty()) {
17             QStringList ids = nodeIds(node);
18             for (int i = 0; i < ids.count(); i++) {
19                 const QString &key = ids.at(i);
20                 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.idIndex.constFind(key);
21                 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
22                     matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
23                     ++it;
24                 }
25             }
26         }
27         if (!styleSheet.nameIndex.isEmpty()) {
28             QStringList names = nodeNames(node);
29             for (int i = 0; i < names.count(); i++) {
30                 QString name = names.at(i);
31                 if (nameCaseSensitivity == Qt::CaseInsensitive)
32                     name = name.toLower();
33                 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
34                 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
35                     matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
36                     ++it;
37                 }
38             }
39         }
40         if (!medium.isEmpty()) {
41             for (int i = 0; i < styleSheet.mediaRules.count(); ++i) {
42                 if (styleSheet.mediaRules.at(i).media.contains(medium, Qt::CaseInsensitive)) {
43                     for (int j = 0; j < styleSheet.mediaRules.at(i).styleRules.count(); ++j) {
44                         matchRule(node, styleSheet.mediaRules.at(i).styleRules.at(j), styleSheet.origin,
45                                styleSheet.depth, &weightedRules);
46                     }
47                 }
48             }
49         }
50     }
51 
52     rules.reserve(weightedRules.count());
53     QMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
54     for ( ; it != weightedRules.constEnd() ; ++it)
55         rules += *it;
56 
57     return rules;
58 }

  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(0), hasFont(false), pal(0), b(0), bg(0), bd(0), ou(0), geo(0), p(0), img(0), clipset(0)
{
    QPalette palette = QApplication::palette(); // ###: ideally widget's palette
    ValueExtractor v(declarations, palette)zhua
    features = v.extractStyleFeatures();

    int w = -1, h = -1, minw = -1, minh = -1, maxw = -1, maxh = -1;
    if (v.extractGeometry(&w, &h, &minw, &minh, &maxw, &maxh))
        geo = new QStyleSheetGeometryData(w, h, minw, minh, maxw, maxh);

    int left = 0, top = 0, right = 0, bottom = 0;
    Origin origin = Origin_Unknown;
    Qt::Alignment position = 0;
    QCss::PositionMode mode = PositionMode_Unknown;
    Qt::Alignment textAlignment = 0;
    if (v.extractPosition(&left, &top, &right, &bottom, &origin, &position, &mode, &textAlignment))
        p = new QStyleSheetPositionData(left, top, right, bottom, origin, position, mode, textAlignment);

    int margins[4], paddings[4], spacing = -1;
    for (int i = 0; i < 4; i++)
        margins[i] = paddings[i] = 0;
    if (v.extractBox(margins, paddings, &spacing))
        b = new QStyleSheetBoxData(margins, paddings, spacing);

    int borders[4];
    QBrush colors[4];
    QCss::BorderStyle styles[4];
    QSize radii[4];
    for (int i = 0; i < 4; i++) {
        borders[i] = 0;
        styles[i] = BorderStyle_None;
    }
    if (v.extractBorder(borders, colors, styles, radii))
        bd = new QStyleSheetBorderData(borders, colors, styles, radii);

    int offsets[4];
    for (int i = 0; i < 4; i++) {
        borders[i] = offsets[i] = 0;
        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 = -255;
    hasFont = v.extractFont(&font, &adj);

#ifndef QT_NO_TOOLTIP
    if (object && qstrcmp(object->metaObject()->className(), "QTipLabel") == 0)
        palette = QToolTip::palette();
#endif

    for (int i = 0; i < declarations.count(); i++) {
        const Declaration& decl = declarations.at(i);
        if (decl.d->propertyId == BorderImage) {
            QString uri;
            QCss::TileMode horizStretch, vertStretch;
            int cuts[4];

            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 = 0; i < 4; 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(0).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 = 0; i < numKnownStyleHints; i++) {
                QLatin1String styleHint(knownStyleHints[i]);
                if (decl.d->property.compare(styleHint) == 0) {
                   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() != 0 && decl.d->values.at(0).type == Value::String) {
                       hintValue = subControlLayout(decl.d->values.at(0).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 - 1] = {
    { "-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 - 1] = {
    { "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 }
};

 

posted on 2016-06-04 14:30  dchao  阅读(4178)  评论(0编辑  收藏  举报

导航