util/src/gui/text/qcssparser.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qcssparser_p.h"
       
    43 
       
    44 #include <qdebug.h>
       
    45 #include <qcolor.h>
       
    46 #include <qfont.h>
       
    47 #include <qfileinfo.h>
       
    48 #include <qfontmetrics.h>
       
    49 #include <qbrush.h>
       
    50 #include <qimagereader.h>
       
    51 #include "private/qfunctions_p.h"
       
    52 
       
    53 #ifndef QT_NO_CSSPARSER
       
    54 
       
    55 QT_BEGIN_NAMESPACE
       
    56 
       
    57 #include "qcssscanner.cpp"
       
    58 
       
    59 using namespace QCss;
       
    60 
       
    61 struct QCssKnownValue
       
    62 {
       
    63     const char *name;
       
    64     quint64 id;
       
    65 };
       
    66 
       
    67 static const QCssKnownValue properties[NumProperties - 1] = {
       
    68     { "-qt-background-role", QtBackgroundRole },
       
    69     { "-qt-block-indent", QtBlockIndent },
       
    70     { "-qt-list-indent", QtListIndent },
       
    71     { "-qt-paragraph-type", QtParagraphType },
       
    72     { "-qt-style-features", QtStyleFeatures },
       
    73     { "-qt-table-type", QtTableType },
       
    74     { "-qt-user-state", QtUserState },
       
    75     { "alternate-background-color", QtAlternateBackground },
       
    76     { "background", Background },
       
    77     { "background-attachment", BackgroundAttachment },
       
    78     { "background-clip", BackgroundClip },
       
    79     { "background-color", BackgroundColor },
       
    80     { "background-image", BackgroundImage },
       
    81     { "background-origin", BackgroundOrigin },
       
    82     { "background-position", BackgroundPosition },
       
    83     { "background-repeat", BackgroundRepeat },
       
    84     { "border", Border },
       
    85     { "border-bottom", BorderBottom },
       
    86     { "border-bottom-color", BorderBottomColor },
       
    87     { "border-bottom-left-radius", BorderBottomLeftRadius },
       
    88     { "border-bottom-right-radius", BorderBottomRightRadius },
       
    89     { "border-bottom-style", BorderBottomStyle },
       
    90     { "border-bottom-width", BorderBottomWidth },
       
    91     { "border-color", BorderColor },
       
    92     { "border-image", BorderImage },
       
    93     { "border-left", BorderLeft },
       
    94     { "border-left-color", BorderLeftColor },
       
    95     { "border-left-style", BorderLeftStyle },
       
    96     { "border-left-width", BorderLeftWidth },
       
    97     { "border-radius", BorderRadius },
       
    98     { "border-right", BorderRight },
       
    99     { "border-right-color", BorderRightColor },
       
   100     { "border-right-style", BorderRightStyle },
       
   101     { "border-right-width", BorderRightWidth },
       
   102     { "border-style", BorderStyles },
       
   103     { "border-top", BorderTop },
       
   104     { "border-top-color", BorderTopColor },
       
   105     { "border-top-left-radius", BorderTopLeftRadius },
       
   106     { "border-top-right-radius", BorderTopRightRadius },
       
   107     { "border-top-style", BorderTopStyle },
       
   108     { "border-top-width", BorderTopWidth },
       
   109     { "border-width", BorderWidth },
       
   110     { "bottom", Bottom },
       
   111     { "color", Color },
       
   112     { "float", Float },
       
   113     { "font", Font },
       
   114     { "font-family", FontFamily },
       
   115     { "font-size", FontSize },
       
   116     { "font-style", FontStyle },
       
   117     { "font-variant", FontVariant },
       
   118     { "font-weight", FontWeight },
       
   119     { "height", Height },
       
   120     { "image", QtImage },
       
   121     { "image-position", QtImageAlignment },
       
   122     { "left", Left },
       
   123     { "list-style", ListStyle },
       
   124     { "list-style-type", ListStyleType },
       
   125     { "margin" , Margin },
       
   126     { "margin-bottom", MarginBottom },
       
   127     { "margin-left", MarginLeft },
       
   128     { "margin-right", MarginRight },
       
   129     { "margin-top", MarginTop },
       
   130     { "max-height", MaximumHeight },
       
   131     { "max-width", MaximumWidth },
       
   132     { "min-height", MinimumHeight },
       
   133     { "min-width", MinimumWidth },
       
   134     { "outline", Outline },
       
   135     { "outline-bottom-left-radius", OutlineBottomLeftRadius },
       
   136     { "outline-bottom-right-radius", OutlineBottomRightRadius },
       
   137     { "outline-color", OutlineColor },
       
   138     { "outline-offset", OutlineOffset },
       
   139     { "outline-radius", OutlineRadius },
       
   140     { "outline-style", OutlineStyle },
       
   141     { "outline-top-left-radius", OutlineTopLeftRadius },
       
   142     { "outline-top-right-radius", OutlineTopRightRadius },
       
   143     { "outline-width", OutlineWidth },
       
   144     { "padding", Padding },
       
   145     { "padding-bottom", PaddingBottom },
       
   146     { "padding-left", PaddingLeft },
       
   147     { "padding-right", PaddingRight },
       
   148     { "padding-top", PaddingTop },
       
   149     { "page-break-after", PageBreakAfter },
       
   150     { "page-break-before", PageBreakBefore },
       
   151     { "position", Position },
       
   152     { "right", Right },
       
   153     { "selection-background-color", QtSelectionBackground },
       
   154     { "selection-color", QtSelectionForeground },
       
   155     { "spacing", QtSpacing },
       
   156     { "subcontrol-origin", QtOrigin },
       
   157     { "subcontrol-position", QtPosition },
       
   158     { "text-align", TextAlignment },
       
   159     { "text-decoration", TextDecoration },
       
   160     { "text-indent", TextIndent },
       
   161     { "text-transform", TextTransform },
       
   162     { "text-underline-style", TextUnderlineStyle },
       
   163     { "top", Top },
       
   164     { "vertical-align", VerticalAlignment },
       
   165     { "white-space", Whitespace },
       
   166     { "width", Width }
       
   167 };
       
   168 
       
   169 static const QCssKnownValue values[NumKnownValues - 1] = {
       
   170     { "active", Value_Active },
       
   171     { "alternate-base", Value_AlternateBase },
       
   172     { "always", Value_Always },
       
   173     { "auto", Value_Auto },
       
   174     { "base", Value_Base },
       
   175     { "bold", Value_Bold },
       
   176     { "bottom", Value_Bottom },
       
   177     { "bright-text", Value_BrightText },
       
   178     { "button", Value_Button },
       
   179     { "button-text", Value_ButtonText },
       
   180     { "center", Value_Center },
       
   181     { "circle", Value_Circle },
       
   182     { "dark", Value_Dark },
       
   183     { "dashed", Value_Dashed },
       
   184     { "decimal", Value_Decimal },
       
   185     { "disabled", Value_Disabled },
       
   186     { "disc", Value_Disc },
       
   187     { "dot-dash", Value_DotDash },
       
   188     { "dot-dot-dash", Value_DotDotDash },
       
   189     { "dotted", Value_Dotted },
       
   190     { "double", Value_Double },
       
   191     { "groove", Value_Groove },
       
   192     { "highlight", Value_Highlight },
       
   193     { "highlighted-text", Value_HighlightedText },
       
   194     { "inset", Value_Inset },
       
   195     { "italic", Value_Italic },
       
   196     { "large", Value_Large },
       
   197     { "left", Value_Left },
       
   198     { "light", Value_Light },
       
   199     { "line-through", Value_LineThrough },
       
   200     { "link", Value_Link },
       
   201     { "link-visited", Value_LinkVisited },
       
   202     { "lower-alpha", Value_LowerAlpha },
       
   203     { "lower-roman", Value_LowerRoman },
       
   204     { "lowercase", Value_Lowercase },
       
   205     { "medium", Value_Medium },
       
   206     { "mid", Value_Mid },
       
   207     { "middle", Value_Middle },
       
   208     { "midlight", Value_Midlight },
       
   209     { "native", Value_Native },
       
   210     { "none", Value_None },
       
   211     { "normal", Value_Normal },
       
   212     { "nowrap", Value_NoWrap },
       
   213     { "oblique", Value_Oblique },
       
   214     { "off", Value_Off },
       
   215     { "on", Value_On },
       
   216     { "outset", Value_Outset },
       
   217     { "overline", Value_Overline },
       
   218     { "pre", Value_Pre },
       
   219     { "pre-wrap", Value_PreWrap },
       
   220     { "ridge", Value_Ridge },
       
   221     { "right", Value_Right },
       
   222     { "selected", Value_Selected },
       
   223     { "shadow", Value_Shadow },
       
   224     { "small" , Value_Small },
       
   225     { "small-caps", Value_SmallCaps },
       
   226     { "solid", Value_Solid },
       
   227     { "square", Value_Square },
       
   228     { "sub", Value_Sub },
       
   229     { "super", Value_Super },
       
   230     { "text", Value_Text },
       
   231     { "top", Value_Top },
       
   232     { "transparent", Value_Transparent },
       
   233     { "underline", Value_Underline },
       
   234     { "upper-alpha", Value_UpperAlpha },
       
   235     { "upper-roman", Value_UpperRoman },
       
   236     { "uppercase", Value_Uppercase },
       
   237     { "wave", Value_Wave },
       
   238     { "window", Value_Window },
       
   239     { "window-text", Value_WindowText },
       
   240     { "x-large", Value_XLarge },
       
   241     { "xx-large", Value_XXLarge }
       
   242 };
       
   243 
       
   244 //Map id to strings as they appears in the 'values' array above
       
   245 static const short indexOfId[NumKnownValues] = { 0, 41, 48, 42, 49, 54, 35, 26, 70, 71, 25, 43, 5, 63, 47,
       
   246     29, 58, 59, 27, 51, 61, 6, 10, 39, 56, 19, 13, 17, 18, 20, 21, 50, 24, 46, 67, 37, 3, 2, 40, 62, 16,
       
   247     11, 57, 14, 32, 64, 33, 65, 55, 66, 34, 69, 8, 28, 38, 12, 36, 60, 7, 9, 4, 68, 53, 22, 23, 30, 31,
       
   248     1, 15, 0, 52, 45, 44 };
       
   249 
       
   250 QString Value::toString() const
       
   251 {
       
   252     if (type == KnownIdentifier) {
       
   253         return QLatin1String(values[indexOfId[variant.toInt()]].name);
       
   254     } else {
       
   255         return variant.toString();
       
   256     }
       
   257 }
       
   258 
       
   259 static const QCssKnownValue pseudos[NumPseudos - 1] = {
       
   260     { "active", PseudoClass_Active },
       
   261     { "adjoins-item", PseudoClass_Item },
       
   262     { "alternate", PseudoClass_Alternate },
       
   263     { "bottom", PseudoClass_Bottom },
       
   264     { "checked", PseudoClass_Checked },
       
   265     { "closable", PseudoClass_Closable },
       
   266     { "closed", PseudoClass_Closed },
       
   267     { "default", PseudoClass_Default },
       
   268     { "disabled", PseudoClass_Disabled },
       
   269     { "edit-focus", PseudoClass_EditFocus },
       
   270     { "editable", PseudoClass_Editable },
       
   271     { "enabled", PseudoClass_Enabled },
       
   272     { "exclusive", PseudoClass_Exclusive },
       
   273     { "first", PseudoClass_First },
       
   274     { "flat", PseudoClass_Flat },
       
   275     { "floatable", PseudoClass_Floatable },
       
   276     { "focus", PseudoClass_Focus },
       
   277     { "has-children", PseudoClass_Children },
       
   278     { "has-siblings", PseudoClass_Sibling },
       
   279     { "horizontal", PseudoClass_Horizontal },
       
   280     { "hover", PseudoClass_Hover },
       
   281     { "indeterminate" , PseudoClass_Indeterminate },
       
   282     { "last", PseudoClass_Last },
       
   283     { "left", PseudoClass_Left },
       
   284     { "maximized", PseudoClass_Maximized },
       
   285     { "middle", PseudoClass_Middle },
       
   286     { "minimized", PseudoClass_Minimized },
       
   287     { "movable", PseudoClass_Movable },
       
   288     { "next-selected", PseudoClass_NextSelected },
       
   289     { "no-frame", PseudoClass_Frameless },
       
   290     { "non-exclusive", PseudoClass_NonExclusive },
       
   291     { "off", PseudoClass_Unchecked },
       
   292     { "on", PseudoClass_Checked },
       
   293     { "only-one", PseudoClass_OnlyOne },
       
   294     { "open", PseudoClass_Open },
       
   295     { "pressed", PseudoClass_Pressed },
       
   296     { "previous-selected", PseudoClass_PreviousSelected },
       
   297     { "read-only", PseudoClass_ReadOnly },
       
   298     { "right", PseudoClass_Right },
       
   299     { "selected", PseudoClass_Selected },
       
   300     { "top", PseudoClass_Top },
       
   301     { "unchecked" , PseudoClass_Unchecked },
       
   302     { "vertical", PseudoClass_Vertical },
       
   303     { "window", PseudoClass_Window }
       
   304 };
       
   305 
       
   306 static const QCssKnownValue origins[NumKnownOrigins - 1] = {
       
   307     { "border", Origin_Border },
       
   308     { "content", Origin_Content },
       
   309     { "margin", Origin_Margin }, // not in css
       
   310     { "padding", Origin_Padding }
       
   311 };
       
   312 
       
   313 static const QCssKnownValue repeats[NumKnownRepeats - 1] = {
       
   314     { "no-repeat", Repeat_None },
       
   315     { "repeat-x", Repeat_X },
       
   316     { "repeat-xy", Repeat_XY },
       
   317     { "repeat-y", Repeat_Y }
       
   318 };
       
   319 
       
   320 static const QCssKnownValue tileModes[NumKnownTileModes - 1] = {
       
   321     { "repeat", TileMode_Repeat },
       
   322     { "round", TileMode_Round },
       
   323     { "stretch", TileMode_Stretch },
       
   324 };
       
   325 
       
   326 static const QCssKnownValue positions[NumKnownPositionModes - 1] = {
       
   327     { "absolute", PositionMode_Absolute },
       
   328     { "fixed", PositionMode_Fixed },
       
   329     { "relative", PositionMode_Relative },
       
   330     { "static", PositionMode_Static }
       
   331 };
       
   332 
       
   333 static const QCssKnownValue attachments[NumKnownAttachments - 1] = {
       
   334     { "fixed", Attachment_Fixed },
       
   335     { "scroll", Attachment_Scroll }
       
   336 };
       
   337 
       
   338 static const QCssKnownValue styleFeatures[NumKnownStyleFeatures - 1] = {
       
   339     { "background-color", StyleFeature_BackgroundColor },
       
   340     { "background-gradient", StyleFeature_BackgroundGradient },
       
   341     { "none", StyleFeature_None }
       
   342 };
       
   343 
       
   344 Q_STATIC_GLOBAL_OPERATOR bool operator<(const QString &name, const QCssKnownValue &prop)
       
   345 {
       
   346     return QString::compare(name, QLatin1String(prop.name), Qt::CaseInsensitive) < 0;
       
   347 }
       
   348 
       
   349 Q_STATIC_GLOBAL_OPERATOR bool operator<(const QCssKnownValue &prop, const QString &name)
       
   350 {
       
   351     return QString::compare(QLatin1String(prop.name), name, Qt::CaseInsensitive) < 0;
       
   352 }
       
   353 
       
   354 static quint64 findKnownValue(const QString &name, const QCssKnownValue *start, int numValues)
       
   355 {
       
   356     const QCssKnownValue *end = &start[numValues - 1];
       
   357     const QCssKnownValue *prop = qBinaryFind(start, end, name);
       
   358     if (prop == end)
       
   359         return 0;
       
   360     return prop->id;
       
   361 }
       
   362 
       
   363 ///////////////////////////////////////////////////////////////////////////////
       
   364 // Value Extractor
       
   365 ValueExtractor::ValueExtractor(const QVector<Declaration> &decls, const QPalette &pal)
       
   366 : declarations(decls), adjustment(0), fontExtracted(false), pal(pal)
       
   367 {
       
   368 }
       
   369 
       
   370 LengthData ValueExtractor::lengthValue(const Value& v)
       
   371 {
       
   372     QString s = v.variant.toString();
       
   373     s.reserve(s.length());
       
   374     LengthData data;
       
   375     data.unit = LengthData::None;
       
   376     if (s.endsWith(QLatin1String("px"), Qt::CaseInsensitive))
       
   377         data.unit = LengthData::Px;
       
   378     else if (s.endsWith(QLatin1String("ex"), Qt::CaseInsensitive))
       
   379         data.unit = LengthData::Ex;
       
   380     else if (s.endsWith(QLatin1String("em"), Qt::CaseInsensitive))
       
   381         data.unit = LengthData::Em;
       
   382 
       
   383     if (data.unit != LengthData::None)
       
   384         s.chop(2);
       
   385 
       
   386     data.number = s.toDouble();
       
   387     return data;
       
   388 }
       
   389 
       
   390 static int lengthValueFromData(const LengthData& data, const QFont& f)
       
   391 {
       
   392     if (data.unit == LengthData::Ex)
       
   393         return qRound(QFontMetrics(f).xHeight() * data.number);
       
   394     else if (data.unit == LengthData::Em)
       
   395         return qRound(QFontMetrics(f).height() * data.number);
       
   396     return qRound(data.number);
       
   397 }
       
   398 
       
   399 int ValueExtractor::lengthValue(const Declaration &decl)
       
   400 {
       
   401     if (decl.d->parsed.isValid())
       
   402         return  lengthValueFromData(qvariant_cast<LengthData>(decl.d->parsed), f);
       
   403     if (decl.d->values.count() < 1)
       
   404         return 0;
       
   405     LengthData data = lengthValue(decl.d->values.at(0));
       
   406     decl.d->parsed = qVariantFromValue<LengthData>(data);
       
   407     return lengthValueFromData(data,f);
       
   408 }
       
   409 
       
   410 void ValueExtractor::lengthValues(const Declaration &decl, int *m)
       
   411 {
       
   412     if (decl.d->parsed.isValid()) {
       
   413         QList<QVariant> v = decl.d->parsed.toList();
       
   414         for (int i = 0; i < 4; i++)
       
   415             m[i] = lengthValueFromData(qvariant_cast<LengthData>(v.at(i)), f);
       
   416         return;
       
   417     }
       
   418 
       
   419     LengthData datas[4];
       
   420     int i;
       
   421     for (i = 0; i < qMin(decl.d->values.count(), 4); i++)
       
   422         datas[i] = lengthValue(decl.d->values[i]);
       
   423 
       
   424     if (i == 0) {
       
   425         LengthData zero = {0.0, LengthData::None};
       
   426         datas[0] = datas[1] = datas[2] = datas[3] = zero;
       
   427     } else if (i == 1) {
       
   428         datas[3] = datas[2] = datas[1] = datas[0];
       
   429     } else if (i == 2) {
       
   430         datas[2] = datas[0];
       
   431         datas[3] = datas[1];
       
   432     } else if (i == 3) {
       
   433         datas[3] = datas[1];
       
   434     }
       
   435 
       
   436     QList<QVariant> v;
       
   437     for (i = 0; i < 4; i++) {
       
   438         v += qVariantFromValue<LengthData>(datas[i]);
       
   439         m[i] = lengthValueFromData(datas[i], f);
       
   440     }
       
   441     decl.d->parsed = v;
       
   442 }
       
   443 
       
   444 bool ValueExtractor::extractGeometry(int *w, int *h, int *minw, int *minh, int *maxw, int *maxh)
       
   445 {
       
   446     extractFont();
       
   447     bool hit = false;
       
   448     for (int i = 0; i < declarations.count(); i++) {
       
   449         const Declaration &decl = declarations.at(i);
       
   450         switch (decl.d->propertyId) {
       
   451         case Width: *w = lengthValue(decl); break;
       
   452         case Height: *h = lengthValue(decl); break;
       
   453         case MinimumWidth: *minw = lengthValue(decl); break;
       
   454         case MinimumHeight: *minh = lengthValue(decl); break;
       
   455         case MaximumWidth: *maxw = lengthValue(decl); break;
       
   456         case MaximumHeight: *maxh = lengthValue(decl); break;
       
   457         default: continue;
       
   458         }
       
   459         hit = true;
       
   460     }
       
   461 
       
   462     return hit;
       
   463 }
       
   464 
       
   465 bool ValueExtractor::extractPosition(int *left, int *top, int *right, int *bottom, QCss::Origin *origin,
       
   466                                      Qt::Alignment *position, QCss::PositionMode *mode, Qt::Alignment *textAlignment)
       
   467 {
       
   468     extractFont();
       
   469     bool hit = false;
       
   470     for (int i = 0; i < declarations.count(); i++) {
       
   471         const Declaration &decl = declarations.at(i);
       
   472         switch (decl.d->propertyId) {
       
   473         case Left: *left = lengthValue(decl); break;
       
   474         case Top: *top = lengthValue(decl); break;
       
   475         case Right: *right = lengthValue(decl); break;
       
   476         case Bottom: *bottom = lengthValue(decl); break;
       
   477         case QtOrigin: *origin = decl.originValue(); break;
       
   478         case QtPosition: *position = decl.alignmentValue(); break;
       
   479         case TextAlignment: *textAlignment = decl.alignmentValue(); break;
       
   480         case Position: *mode = decl.positionValue(); break;
       
   481         default: continue;
       
   482         }
       
   483         hit = true;
       
   484     }
       
   485 
       
   486     return hit;
       
   487 }
       
   488 
       
   489 bool ValueExtractor::extractBox(int *margins, int *paddings, int *spacing)
       
   490 {
       
   491     extractFont();
       
   492     bool hit = false;
       
   493     for (int i = 0; i < declarations.count(); i++) {
       
   494         const Declaration &decl = declarations.at(i);
       
   495         switch (decl.d->propertyId) {
       
   496         case PaddingLeft: paddings[LeftEdge] = lengthValue(decl); break;
       
   497         case PaddingRight: paddings[RightEdge] = lengthValue(decl); break;
       
   498         case PaddingTop: paddings[TopEdge] = lengthValue(decl); break;
       
   499         case PaddingBottom: paddings[BottomEdge] = lengthValue(decl); break;
       
   500         case Padding: lengthValues(decl, paddings); break;
       
   501 
       
   502         case MarginLeft: margins[LeftEdge] = lengthValue(decl); break;
       
   503         case MarginRight: margins[RightEdge] = lengthValue(decl); break;
       
   504         case MarginTop: margins[TopEdge] = lengthValue(decl); break;
       
   505         case MarginBottom: margins[BottomEdge] = lengthValue(decl); break;
       
   506         case Margin: lengthValues(decl, margins); break;
       
   507         case QtSpacing: if (spacing) *spacing = lengthValue(decl); break;
       
   508 
       
   509         default: continue;
       
   510         }
       
   511         hit = true;
       
   512     }
       
   513 
       
   514     return hit;
       
   515 }
       
   516 
       
   517 int ValueExtractor::extractStyleFeatures()
       
   518 {
       
   519     int features = StyleFeature_None;
       
   520     for (int i = 0; i < declarations.count(); i++) {
       
   521         const Declaration &decl = declarations.at(i);
       
   522         if (decl.d->propertyId == QtStyleFeatures)
       
   523             features = decl.styleFeaturesValue();
       
   524     }
       
   525     return features;
       
   526 }
       
   527 
       
   528 QSize ValueExtractor::sizeValue(const Declaration &decl)
       
   529 {
       
   530     if (decl.d->parsed.isValid()) {
       
   531         QList<QVariant> v = decl.d->parsed.toList();
       
   532         return QSize(lengthValueFromData(qvariant_cast<LengthData>(v.at(0)), f),
       
   533                      lengthValueFromData(qvariant_cast<LengthData>(v.at(1)), f));
       
   534     }
       
   535 
       
   536     LengthData x[2] = { {0, LengthData::None }, {0, LengthData::None} };   
       
   537     if (decl.d->values.count() > 0)
       
   538         x[0] = lengthValue(decl.d->values.at(0));
       
   539     if (decl.d->values.count() > 1)
       
   540         x[1] = lengthValue(decl.d->values.at(1));
       
   541     else
       
   542         x[1] = x[0];
       
   543     QList<QVariant> v;
       
   544     v << qVariantFromValue<LengthData>(x[0]) << qVariantFromValue<LengthData>(x[1]);
       
   545     decl.d->parsed = v;
       
   546     return QSize(lengthValueFromData(x[0], f), lengthValueFromData(x[1], f));
       
   547 }
       
   548 
       
   549 void ValueExtractor::sizeValues(const Declaration &decl, QSize *radii)
       
   550 {
       
   551     radii[0] = sizeValue(decl);
       
   552     for (int i = 1; i < 4; i++)
       
   553         radii[i] = radii[0];
       
   554 }
       
   555 
       
   556 bool ValueExtractor::extractBorder(int *borders, QBrush *colors, BorderStyle *styles,
       
   557                                    QSize *radii)
       
   558 {
       
   559     extractFont();
       
   560     bool hit = false;
       
   561     for (int i = 0; i < declarations.count(); i++) {
       
   562         const Declaration &decl = declarations.at(i);
       
   563         switch (decl.d->propertyId) {
       
   564         case BorderLeftWidth: borders[LeftEdge] = lengthValue(decl); break;
       
   565         case BorderRightWidth: borders[RightEdge] = lengthValue(decl); break;
       
   566         case BorderTopWidth: borders[TopEdge] = lengthValue(decl); break;
       
   567         case BorderBottomWidth: borders[BottomEdge] = lengthValue(decl); break;
       
   568         case BorderWidth: lengthValues(decl, borders); break;
       
   569 
       
   570         case BorderLeftColor: colors[LeftEdge] = decl.brushValue(pal); break;
       
   571         case BorderRightColor: colors[RightEdge] = decl.brushValue(pal); break;
       
   572         case BorderTopColor: colors[TopEdge] = decl.brushValue(pal); break;
       
   573         case BorderBottomColor: colors[BottomEdge] = decl.brushValue(pal); break;
       
   574         case BorderColor: decl.brushValues(colors, pal); break;
       
   575 
       
   576         case BorderTopStyle: styles[TopEdge] = decl.styleValue(); break;
       
   577         case BorderBottomStyle: styles[BottomEdge] = decl.styleValue(); break;
       
   578         case BorderLeftStyle: styles[LeftEdge] = decl.styleValue(); break;
       
   579         case BorderRightStyle: styles[RightEdge] = decl.styleValue(); break;
       
   580         case BorderStyles:  decl.styleValues(styles); break;
       
   581 
       
   582         case BorderTopLeftRadius: radii[0] = sizeValue(decl); break;
       
   583         case BorderTopRightRadius: radii[1] = sizeValue(decl); break;
       
   584         case BorderBottomLeftRadius: radii[2] = sizeValue(decl); break;
       
   585         case BorderBottomRightRadius: radii[3] = sizeValue(decl); break;
       
   586         case BorderRadius: sizeValues(decl, radii); break;
       
   587 
       
   588         case BorderLeft:
       
   589             borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
       
   590             break;
       
   591         case BorderTop:
       
   592             borderValue(decl, &borders[TopEdge], &styles[TopEdge], &colors[TopEdge]);
       
   593             break;
       
   594         case BorderRight:
       
   595             borderValue(decl, &borders[RightEdge], &styles[RightEdge], &colors[RightEdge]);
       
   596             break;
       
   597         case BorderBottom:
       
   598             borderValue(decl, &borders[BottomEdge], &styles[BottomEdge], &colors[BottomEdge]);
       
   599             break;
       
   600         case Border:
       
   601             borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
       
   602             borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
       
   603             styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
       
   604             colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
       
   605             break;
       
   606 
       
   607         default: continue;
       
   608         }
       
   609         hit = true;
       
   610     }
       
   611 
       
   612     return hit;
       
   613 }
       
   614 
       
   615 bool ValueExtractor::extractOutline(int *borders, QBrush *colors, BorderStyle *styles,
       
   616                                    QSize *radii, int *offsets)
       
   617 {
       
   618     extractFont();
       
   619     bool hit = false;
       
   620     for (int i = 0; i < declarations.count(); i++) {
       
   621         const Declaration &decl = declarations.at(i);
       
   622         switch (decl.d->propertyId) {
       
   623         case OutlineWidth: lengthValues(decl, borders); break;
       
   624         case OutlineColor: decl.brushValues(colors, pal); break;
       
   625         case OutlineStyle:  decl.styleValues(styles); break;
       
   626 
       
   627         case OutlineTopLeftRadius: radii[0] = sizeValue(decl); break;
       
   628         case OutlineTopRightRadius: radii[1] = sizeValue(decl); break;
       
   629         case OutlineBottomLeftRadius: radii[2] = sizeValue(decl); break;
       
   630         case OutlineBottomRightRadius: radii[3] = sizeValue(decl); break;
       
   631         case OutlineRadius: sizeValues(decl, radii); break;
       
   632         case OutlineOffset: lengthValues(decl, offsets); break;
       
   633 
       
   634         case Outline:
       
   635             borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
       
   636             borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
       
   637             styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
       
   638             colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
       
   639             break;
       
   640 
       
   641         default: continue;
       
   642         }
       
   643         hit = true;
       
   644     }
       
   645 
       
   646     return hit;
       
   647 }
       
   648 
       
   649 static Qt::Alignment parseAlignment(const Value *values, int count)
       
   650 {
       
   651     Qt::Alignment a[2] = { 0, 0 };
       
   652     for (int i = 0; i < qMin(2, count); i++) {
       
   653         if (values[i].type != Value::KnownIdentifier)
       
   654             break;
       
   655         switch (values[i].variant.toInt()) {
       
   656         case Value_Left: a[i] = Qt::AlignLeft; break;
       
   657         case Value_Right: a[i] = Qt::AlignRight; break;
       
   658         case Value_Top: a[i] = Qt::AlignTop; break;
       
   659         case Value_Bottom: a[i] = Qt::AlignBottom; break;
       
   660         case Value_Center: a[i] = Qt::AlignCenter; break;
       
   661         default: break;
       
   662         }
       
   663     }
       
   664 
       
   665     if (a[0] == Qt::AlignCenter && a[1] != 0 && a[1] != Qt::AlignCenter)
       
   666         a[0] = (a[1] == Qt::AlignLeft || a[1] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
       
   667     if ((a[1] == 0 || a[1] == Qt::AlignCenter) && a[0] != Qt::AlignCenter)
       
   668         a[1] = (a[0] == Qt::AlignLeft || a[0] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
       
   669     return a[0] | a[1];
       
   670 }
       
   671 
       
   672 static ColorData parseColorValue(Value v)
       
   673 {
       
   674     if (v.type == Value::Identifier || v.type == Value::String) {
       
   675         v.variant.convert(QVariant::Color);
       
   676         v.type = Value::Color;
       
   677     }
       
   678 
       
   679     if (v.type == Value::Color)
       
   680         return qvariant_cast<QColor>(v.variant);
       
   681 
       
   682     if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent)
       
   683         return QColor(Qt::transparent);
       
   684 
       
   685     if (v.type != Value::Function)
       
   686         return ColorData();
       
   687 
       
   688     QStringList lst = v.variant.toStringList();
       
   689     if (lst.count() != 2)
       
   690         return ColorData();
       
   691 
       
   692     if ((lst.at(0).compare(QLatin1String("palette"), Qt::CaseInsensitive)) == 0) {
       
   693         int role = findKnownValue(lst.at(1).trimmed(), values, NumKnownValues);
       
   694         if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
       
   695             return (QPalette::ColorRole)(role-Value_FirstColorRole);
       
   696 
       
   697         return ColorData();
       
   698     }
       
   699 
       
   700     bool rgb = lst.at(0).startsWith(QLatin1String("rgb"));
       
   701 
       
   702     Parser p(lst.at(1));
       
   703     if (!p.testExpr())
       
   704         return ColorData();
       
   705 
       
   706     QVector<Value> colorDigits;
       
   707     if (!p.parseExpr(&colorDigits))
       
   708         return ColorData();
       
   709 
       
   710     for (int i = 0; i < qMin(colorDigits.count(), 7); i += 2) {
       
   711         if (colorDigits.at(i).type == Value::Percentage) {
       
   712             colorDigits[i].variant = colorDigits.at(i).variant.toReal() * (255. / 100.);
       
   713             colorDigits[i].type = Value::Number;
       
   714         } else if (colorDigits.at(i).type != Value::Number) {
       
   715             return ColorData();
       
   716         }
       
   717     }
       
   718 
       
   719     int v1 = colorDigits.at(0).variant.toInt();
       
   720     int v2 = colorDigits.at(2).variant.toInt();
       
   721     int v3 = colorDigits.at(4).variant.toInt();
       
   722     int alpha = colorDigits.count() >= 7 ? colorDigits.at(6).variant.toInt() : 255;
       
   723 
       
   724     return rgb ? QColor::fromRgb(v1, v2, v3, alpha)
       
   725                : QColor::fromHsv(v1, v2, v3, alpha);
       
   726 }
       
   727 
       
   728 static QColor colorFromData(const ColorData& c, const QPalette &pal)
       
   729 {
       
   730     if (c.type == ColorData::Color) {
       
   731         return c.color;
       
   732     } else if (c.type == ColorData::Role) {
       
   733         return pal.color(c.role);
       
   734     }
       
   735     return QColor();
       
   736 }
       
   737 
       
   738 static BrushData parseBrushValue(const Value &v, const QPalette &pal)
       
   739 {
       
   740     ColorData c = parseColorValue(v);
       
   741     if (c.type == ColorData::Color) {
       
   742         return QBrush(c.color);
       
   743     } else if (c.type == ColorData::Role) {
       
   744         return c.role;
       
   745     }
       
   746 
       
   747     if (v.type != Value::Function)
       
   748         return BrushData();
       
   749 
       
   750     QStringList lst = v.variant.toStringList();
       
   751     if (lst.count() != 2)
       
   752         return BrushData();
       
   753 
       
   754     QStringList gradFuncs;
       
   755     gradFuncs << QLatin1String("qlineargradient") << QLatin1String("qradialgradient") << QLatin1String("qconicalgradient") << QLatin1String("qgradient");
       
   756     int gradType = -1;
       
   757 
       
   758     if ((gradType = gradFuncs.indexOf(lst.at(0).toLower())) == -1)
       
   759         return BrushData();
       
   760 
       
   761     QHash<QString, qreal> vars;
       
   762     QVector<QGradientStop> stops;
       
   763 
       
   764     int spread = -1;
       
   765     QStringList spreads;
       
   766     spreads << QLatin1String("pad") << QLatin1String("reflect") << QLatin1String("repeat");
       
   767 
       
   768     bool dependsOnThePalette = false;
       
   769     Parser parser(lst.at(1));
       
   770     while (parser.hasNext()) {
       
   771         parser.skipSpace();
       
   772         if (!parser.test(IDENT))
       
   773             return BrushData();
       
   774         QString attr = parser.lexem();
       
   775         parser.skipSpace();
       
   776         if (!parser.test(COLON))
       
   777             return BrushData();
       
   778         parser.skipSpace();
       
   779         if (attr.compare(QLatin1String("stop"), Qt::CaseInsensitive) == 0) {
       
   780             Value stop, color;
       
   781             parser.next();
       
   782             if (!parser.parseTerm(&stop)) return BrushData();
       
   783             parser.skipSpace();
       
   784             parser.next();
       
   785             if (!parser.parseTerm(&color)) return BrushData();
       
   786             ColorData cd = parseColorValue(color);
       
   787             if(cd.type == ColorData::Role)
       
   788                 dependsOnThePalette = true;
       
   789             stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal)));
       
   790         } else {
       
   791             parser.next();
       
   792             Value value;
       
   793             (void)parser.parseTerm(&value);
       
   794             if (attr.compare(QLatin1String("spread"), Qt::CaseInsensitive) == 0) {
       
   795                 spread = spreads.indexOf(value.variant.toString());
       
   796             } else {
       
   797                 vars[attr] = value.variant.toReal();
       
   798             }
       
   799         }
       
   800         parser.skipSpace();
       
   801         (void)parser.test(COMMA);
       
   802     }
       
   803 
       
   804     if (gradType == 0) {
       
   805         QLinearGradient lg(vars.value(QLatin1String("x1")), vars.value(QLatin1String("y1")),
       
   806                            vars.value(QLatin1String("x2")), vars.value(QLatin1String("y2")));
       
   807         lg.setCoordinateMode(QGradient::ObjectBoundingMode);
       
   808         lg.setStops(stops);
       
   809         if (spread != -1)
       
   810             lg.setSpread(QGradient::Spread(spread));
       
   811         BrushData bd = QBrush(lg);
       
   812         if (dependsOnThePalette)
       
   813             bd.type = BrushData::DependsOnThePalette;
       
   814         return bd;
       
   815     }
       
   816 
       
   817     if (gradType == 1) {
       
   818         QRadialGradient rg(vars.value(QLatin1String("cx")), vars.value(QLatin1String("cy")),
       
   819                            vars.value(QLatin1String("radius")), vars.value(QLatin1String("fx")),
       
   820                            vars.value(QLatin1String("fy")));
       
   821         rg.setCoordinateMode(QGradient::ObjectBoundingMode);
       
   822         rg.setStops(stops);
       
   823         if (spread != -1)
       
   824             rg.setSpread(QGradient::Spread(spread));
       
   825         BrushData bd = QBrush(rg);
       
   826         if (dependsOnThePalette)
       
   827             bd.type = BrushData::DependsOnThePalette;
       
   828         return bd;
       
   829     }
       
   830 
       
   831     if (gradType == 2) {
       
   832         QConicalGradient cg(vars.value(QLatin1String("cx")), vars.value(QLatin1String("cy")),
       
   833                             vars.value(QLatin1String("angle")));
       
   834         cg.setCoordinateMode(QGradient::ObjectBoundingMode);
       
   835         cg.setStops(stops);
       
   836         if (spread != -1)
       
   837             cg.setSpread(QGradient::Spread(spread));
       
   838         BrushData bd = QBrush(cg);
       
   839         if (dependsOnThePalette)
       
   840             bd.type = BrushData::DependsOnThePalette;
       
   841         return bd;
       
   842     }
       
   843 
       
   844     return BrushData();
       
   845 }
       
   846 
       
   847 static QBrush brushFromData(const BrushData& c, const QPalette &pal)
       
   848 {
       
   849     if (c.type == BrushData::Role) {
       
   850         return pal.color(c.role);
       
   851     } else {
       
   852         return c.brush;
       
   853     }
       
   854 }
       
   855 
       
   856 static BorderStyle parseStyleValue(Value v)
       
   857 {
       
   858     if (v.type == Value::KnownIdentifier) {
       
   859         switch (v.variant.toInt()) {
       
   860         case Value_None:
       
   861             return BorderStyle_None;
       
   862         case Value_Dotted:
       
   863             return BorderStyle_Dotted;
       
   864         case Value_Dashed:
       
   865             return BorderStyle_Dashed;
       
   866         case Value_Solid:
       
   867             return BorderStyle_Solid;
       
   868         case Value_Double:
       
   869             return BorderStyle_Double;
       
   870         case Value_DotDash:
       
   871             return BorderStyle_DotDash;
       
   872         case Value_DotDotDash:
       
   873             return BorderStyle_DotDotDash;
       
   874         case Value_Groove:
       
   875             return BorderStyle_Groove;
       
   876         case Value_Ridge:
       
   877             return BorderStyle_Ridge;
       
   878         case Value_Inset:
       
   879             return BorderStyle_Inset;
       
   880         case Value_Outset:
       
   881             return BorderStyle_Outset;
       
   882         case Value_Native:
       
   883             return BorderStyle_Native;
       
   884         default:
       
   885             break;
       
   886         }
       
   887     }
       
   888 
       
   889     return BorderStyle_Unknown;
       
   890 }
       
   891 
       
   892 void ValueExtractor::borderValue(const Declaration &decl, int *width, QCss::BorderStyle *style, QBrush *color)
       
   893 {
       
   894     if (decl.d->parsed.isValid()) {
       
   895         BorderData data = qvariant_cast<BorderData>(decl.d->parsed);
       
   896         *width = lengthValueFromData(data.width, f);
       
   897         *style = data.style;
       
   898         *color = brushFromData(data.color, pal);
       
   899         return;
       
   900     }
       
   901 
       
   902     *width = 0;
       
   903     *style = BorderStyle_None;
       
   904     *color = QColor();
       
   905 
       
   906     if (decl.d->values.isEmpty())
       
   907         return;
       
   908     
       
   909     BorderData data;
       
   910     data.width.number = 0;
       
   911     data.width.unit = LengthData::None;
       
   912     data.style = BorderStyle_None;
       
   913 
       
   914     int i = 0;
       
   915     if (decl.d->values.at(i).type == Value::Length || decl.d->values.at(i).type == Value::Number) {
       
   916         data.width = lengthValue(decl.d->values.at(i));
       
   917         *width = lengthValueFromData(data.width, f);
       
   918         if (++i >= decl.d->values.count()) {
       
   919             decl.d->parsed = qVariantFromValue<BorderData>(data);
       
   920             return;
       
   921         }
       
   922     }
       
   923 
       
   924     data.style = parseStyleValue(decl.d->values.at(i));
       
   925     if (data.style != BorderStyle_Unknown) {
       
   926         *style = data.style;
       
   927         if (++i >= decl.d->values.count()) {
       
   928             decl.d->parsed = qVariantFromValue<BorderData>(data);
       
   929             return;
       
   930         }
       
   931     } else {
       
   932         data.style = BorderStyle_None;
       
   933     }
       
   934 
       
   935      data.color = parseBrushValue(decl.d->values.at(i), pal);
       
   936      *color = brushFromData(data.color, pal);
       
   937      if (data.color.type != BrushData::DependsOnThePalette)
       
   938          decl.d->parsed = qVariantFromValue<BorderData>(data);
       
   939 }
       
   940 
       
   941 static void parseShorthandBackgroundProperty(const QVector<Value> &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal)
       
   942 {
       
   943     *brush = BrushData();
       
   944     *image = QString();
       
   945     *repeat = Repeat_XY;
       
   946     *alignment = Qt::AlignTop | Qt::AlignLeft;
       
   947 
       
   948     for (int i = 0; i < values.count(); ++i) {
       
   949         const Value &v = values.at(i);
       
   950         if (v.type == Value::Uri) {
       
   951             *image = v.variant.toString();
       
   952             continue;
       
   953         } else if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_None) {
       
   954             *image = QString();
       
   955             continue;
       
   956         } else if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent) {
       
   957             *brush = QBrush(Qt::transparent);
       
   958         }
       
   959 
       
   960         Repeat repeatAttempt = static_cast<Repeat>(findKnownValue(v.variant.toString(),
       
   961                                                    repeats, NumKnownRepeats));
       
   962         if (repeatAttempt != Repeat_Unknown) {
       
   963             *repeat = repeatAttempt;
       
   964             continue;
       
   965         }
       
   966 
       
   967         if (v.type == Value::KnownIdentifier) {
       
   968             const int start = i;
       
   969             int count = 1;
       
   970             if (i < values.count() - 1
       
   971                 && values.at(i + 1).type == Value::KnownIdentifier) {
       
   972                 ++i;
       
   973                 ++count;
       
   974             }
       
   975             Qt::Alignment a = parseAlignment(values.constData() + start, count);
       
   976             if (int(a) != 0) {
       
   977                 *alignment = a;
       
   978                 continue;
       
   979             }
       
   980             i -= count - 1;
       
   981         }
       
   982 
       
   983         *brush = parseBrushValue(v, pal);
       
   984     }
       
   985 }
       
   986 
       
   987 bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *repeat,
       
   988                                        Qt::Alignment *alignment, Origin *origin, Attachment *attachment,
       
   989                                        Origin *clip)
       
   990 {
       
   991     bool hit = false;
       
   992     for (int i = 0; i < declarations.count(); ++i) {
       
   993         const Declaration &decl = declarations.at(i);
       
   994         if (decl.d->values.isEmpty())
       
   995             continue;
       
   996         const Value &val = decl.d->values.at(0);
       
   997         switch (decl.d->propertyId) {
       
   998             case BackgroundColor:
       
   999                     *brush = decl.brushValue();
       
  1000                 break;
       
  1001             case BackgroundImage:
       
  1002                 if (val.type == Value::Uri)
       
  1003                     *image = val.variant.toString();
       
  1004                 break;
       
  1005             case BackgroundRepeat:
       
  1006                 if (decl.d->parsed.isValid()) {
       
  1007                     *repeat = static_cast<Repeat>(decl.d->parsed.toInt());
       
  1008                 } else {
       
  1009                     *repeat = static_cast<Repeat>(findKnownValue(val.variant.toString(),
       
  1010                                                   repeats, NumKnownRepeats));
       
  1011                     decl.d->parsed = *repeat;
       
  1012                 }
       
  1013                 break;
       
  1014             case BackgroundPosition:
       
  1015                 *alignment = decl.alignmentValue();
       
  1016                 break;
       
  1017             case BackgroundOrigin:
       
  1018                 *origin = decl.originValue();
       
  1019                 break;
       
  1020             case BackgroundClip:
       
  1021                 *clip = decl.originValue();
       
  1022                 break;
       
  1023             case Background:
       
  1024                 if (decl.d->parsed.isValid()) {
       
  1025                     BackgroundData data = qvariant_cast<BackgroundData>(decl.d->parsed);
       
  1026                     *brush = brushFromData(data.brush, pal);
       
  1027                     *image = data.image;
       
  1028                     *repeat = data.repeat;
       
  1029                     *alignment = data.alignment;
       
  1030                 } else {
       
  1031                     BrushData brushData;
       
  1032                     parseShorthandBackgroundProperty(decl.d->values, &brushData, image, repeat, alignment, pal);
       
  1033                     *brush = brushFromData(brushData, pal);
       
  1034                     if (brushData.type != BrushData::DependsOnThePalette) {
       
  1035 #if defined Q_CC_MSVC && _MSC_VER <= 1300
       
  1036                         BackgroundData data;
       
  1037                         data.brush = brushData;
       
  1038                         data.image = *image;
       
  1039                         data.repeat = *repeat;
       
  1040                         data.alignment = *alignment;
       
  1041 #else
       
  1042                         BackgroundData data = { brushData, *image, *repeat, *alignment };
       
  1043 #endif
       
  1044                         decl.d->parsed = qVariantFromValue<BackgroundData>(data);
       
  1045                     }
       
  1046                 }
       
  1047                 break;
       
  1048             case BackgroundAttachment:
       
  1049                 *attachment = decl.attachmentValue();
       
  1050                 break;
       
  1051             default: continue;
       
  1052         }
       
  1053         hit = true;
       
  1054     }
       
  1055     return hit;
       
  1056 }
       
  1057 
       
  1058 static bool setFontSizeFromValue(Value value, QFont *font, int *fontSizeAdjustment)
       
  1059 {
       
  1060     if (value.type == Value::KnownIdentifier) {
       
  1061         bool valid = true;
       
  1062         switch (value.variant.toInt()) {
       
  1063             case Value_Small: *fontSizeAdjustment = -1; break;
       
  1064             case Value_Medium: *fontSizeAdjustment = 0; break;
       
  1065             case Value_Large: *fontSizeAdjustment = 1; break;
       
  1066             case Value_XLarge: *fontSizeAdjustment = 2; break;
       
  1067             case Value_XXLarge: *fontSizeAdjustment = 3; break;
       
  1068             default: valid = false; break;
       
  1069         }
       
  1070         return valid;
       
  1071     }
       
  1072     if (value.type != Value::Length)
       
  1073         return false;
       
  1074 
       
  1075     bool valid = false;
       
  1076     QString s = value.variant.toString();
       
  1077     if (s.endsWith(QLatin1String("pt"), Qt::CaseInsensitive)) {
       
  1078         s.chop(2);
       
  1079         value.variant = s;
       
  1080         if (value.variant.convert((QVariant::Type)qMetaTypeId<qreal>())) {
       
  1081             font->setPointSizeF(value.variant.toReal());
       
  1082             valid = true;
       
  1083         }
       
  1084     } else if (s.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) {
       
  1085         s.chop(2);
       
  1086         value.variant = s;
       
  1087         if (value.variant.convert(QVariant::Int)) {
       
  1088             font->setPixelSize(value.variant.toInt());
       
  1089             valid = true;
       
  1090         }
       
  1091     }
       
  1092     return valid;
       
  1093 }
       
  1094 
       
  1095 static bool setFontStyleFromValue(const Value &value, QFont *font)
       
  1096 {
       
  1097     if (value.type != Value::KnownIdentifier)
       
  1098         return false ;
       
  1099     switch (value.variant.toInt()) {
       
  1100         case Value_Normal: font->setStyle(QFont::StyleNormal); return true;
       
  1101         case Value_Italic: font->setStyle(QFont::StyleItalic); return true;
       
  1102         case Value_Oblique: font->setStyle(QFont::StyleOblique); return true;
       
  1103         default: break;
       
  1104     }
       
  1105     return false;
       
  1106 }
       
  1107 
       
  1108 static bool setFontWeightFromValue(const Value &value, QFont *font)
       
  1109 {
       
  1110     if (value.type == Value::KnownIdentifier) {
       
  1111         switch (value.variant.toInt()) {
       
  1112             case Value_Normal: font->setWeight(QFont::Normal); return true;
       
  1113             case Value_Bold: font->setWeight(QFont::Bold); return true;
       
  1114             default: break;
       
  1115         }
       
  1116         return false;
       
  1117     }
       
  1118     if (value.type != Value::Number)
       
  1119         return false;
       
  1120     font->setWeight(qMin(value.variant.toInt() / 8, 99));
       
  1121     return true;
       
  1122 }
       
  1123 
       
  1124 /** \internal
       
  1125  * parse the font family from the values (starting from index \a start)
       
  1126  * and set it the \a font
       
  1127  * \returns true if a family was extracted.
       
  1128  */
       
  1129 static bool setFontFamilyFromValues(const QVector<Value> &values, QFont *font, int start = 0)
       
  1130 {
       
  1131     QString family;
       
  1132     bool shouldAddSpace = false;
       
  1133     for (int i = start; i < values.count(); ++i) {
       
  1134         const Value &v = values.at(i);
       
  1135         if (v.type == Value::TermOperatorComma) {
       
  1136             family += QLatin1Char(',');
       
  1137             shouldAddSpace = false;
       
  1138             continue;
       
  1139         }
       
  1140         const QString str = v.variant.toString();
       
  1141         if (str.isEmpty())
       
  1142             break;
       
  1143         if (shouldAddSpace)
       
  1144             family += QLatin1Char(' ');
       
  1145         family += str;
       
  1146         shouldAddSpace = true;
       
  1147     }
       
  1148     if (family.isEmpty())
       
  1149         return false;
       
  1150     font->setFamily(family);
       
  1151     return true;
       
  1152 }
       
  1153 
       
  1154 static void setTextDecorationFromValues(const QVector<Value> &values, QFont *font)
       
  1155 {
       
  1156     for (int i = 0; i < values.count(); ++i) {
       
  1157         if (values.at(i).type != Value::KnownIdentifier)
       
  1158             continue;
       
  1159         switch (values.at(i).variant.toInt()) {
       
  1160             case Value_Underline: font->setUnderline(true); break;
       
  1161             case Value_Overline: font->setOverline(true); break;
       
  1162             case Value_LineThrough: font->setStrikeOut(true); break;
       
  1163             case Value_None:
       
  1164                 font->setUnderline(false);
       
  1165                 font->setOverline(false);
       
  1166                 font->setStrikeOut(false);
       
  1167                 break;
       
  1168             default: break;
       
  1169         }
       
  1170     }
       
  1171 }
       
  1172 
       
  1173 static void parseShorthandFontProperty(const QVector<Value> &values, QFont *font, int *fontSizeAdjustment)
       
  1174 {
       
  1175     font->setStyle(QFont::StyleNormal);
       
  1176     font->setWeight(QFont::Normal);
       
  1177     *fontSizeAdjustment = -255;
       
  1178 
       
  1179     int i = 0;
       
  1180     while (i < values.count()) {
       
  1181         if (setFontStyleFromValue(values.at(i), font)
       
  1182             || setFontWeightFromValue(values.at(i), font))
       
  1183             ++i;
       
  1184         else
       
  1185             break;
       
  1186     }
       
  1187 
       
  1188     if (i < values.count()) {
       
  1189         setFontSizeFromValue(values.at(i), font, fontSizeAdjustment);
       
  1190         ++i;
       
  1191     }
       
  1192 
       
  1193     if (i < values.count()) {
       
  1194         setFontFamilyFromValues(values, font, i);
       
  1195     }
       
  1196 }
       
  1197 
       
  1198 static void setFontVariantFromValue(const Value &value, QFont *font)
       
  1199 {
       
  1200     if (value.type == Value::KnownIdentifier) {
       
  1201         switch (value.variant.toInt()) {
       
  1202             case Value_Normal: font->setCapitalization(QFont::MixedCase); break;
       
  1203             case Value_SmallCaps: font->setCapitalization(QFont::SmallCaps); break;
       
  1204             default: break;
       
  1205         }
       
  1206     }
       
  1207 }
       
  1208 
       
  1209 static void setTextTransformFromValue(const Value &value, QFont *font)
       
  1210 {
       
  1211     if (value.type == Value::KnownIdentifier) {
       
  1212         switch (value.variant.toInt()) {
       
  1213             case Value_None: font->setCapitalization(QFont::MixedCase); break;
       
  1214             case Value_Uppercase: font->setCapitalization(QFont::AllUppercase); break;
       
  1215             case Value_Lowercase: font->setCapitalization(QFont::AllLowercase); break;
       
  1216             default: break;
       
  1217         }
       
  1218     }
       
  1219 }
       
  1220 
       
  1221 bool ValueExtractor::extractFont(QFont *font, int *fontSizeAdjustment)
       
  1222 {
       
  1223     if (fontExtracted) {
       
  1224         *font = f;
       
  1225         *fontSizeAdjustment = adjustment;
       
  1226         return fontExtracted == 1;
       
  1227     }
       
  1228 
       
  1229     bool hit = false;
       
  1230     for (int i = 0; i < declarations.count(); ++i) {
       
  1231         const Declaration &decl = declarations.at(i);
       
  1232         if (decl.d->values.isEmpty())
       
  1233             continue;
       
  1234         const Value &val = decl.d->values.at(0);
       
  1235         switch (decl.d->propertyId) {
       
  1236             case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment); break;
       
  1237             case FontStyle: setFontStyleFromValue(val, font); break;
       
  1238             case FontWeight: setFontWeightFromValue(val, font); break;
       
  1239             case FontFamily: setFontFamilyFromValues(decl.d->values, font); break;
       
  1240             case TextDecoration: setTextDecorationFromValues(decl.d->values, font); break;
       
  1241             case Font: parseShorthandFontProperty(decl.d->values, font, fontSizeAdjustment); break;
       
  1242             case FontVariant: setFontVariantFromValue(val, font); break;
       
  1243             case TextTransform: setTextTransformFromValue(val, font); break;
       
  1244             default: continue;
       
  1245         }
       
  1246         hit = true;
       
  1247     }
       
  1248 
       
  1249     f = *font;
       
  1250     adjustment = *fontSizeAdjustment;
       
  1251     fontExtracted = hit ? 1 : 2;
       
  1252     return hit;
       
  1253 }
       
  1254 
       
  1255 bool ValueExtractor::extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg)
       
  1256 {
       
  1257     bool hit = false;
       
  1258     for (int i = 0; i < declarations.count(); ++i) {
       
  1259         const Declaration &decl = declarations.at(i);
       
  1260         switch (decl.d->propertyId) {
       
  1261         case Color: *fg = decl.brushValue(pal); break;
       
  1262         case QtSelectionForeground: *sfg = decl.brushValue(pal); break;
       
  1263         case QtSelectionBackground: *sbg = decl.brushValue(pal); break;
       
  1264         case QtAlternateBackground: *abg = decl.brushValue(pal); break;
       
  1265         default: continue;
       
  1266         }
       
  1267         hit = true;
       
  1268     }
       
  1269     return hit;
       
  1270 }
       
  1271 
       
  1272 void ValueExtractor::extractFont()
       
  1273 {
       
  1274     if (fontExtracted)
       
  1275         return;
       
  1276     int dummy = -255;
       
  1277     extractFont(&f, &dummy);
       
  1278 }
       
  1279 
       
  1280 bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size)
       
  1281 {
       
  1282     bool hit = false;
       
  1283     for (int i = 0; i < declarations.count(); ++i) {
       
  1284         const Declaration &decl = declarations.at(i);
       
  1285         switch (decl.d->propertyId) {
       
  1286         case QtImage:
       
  1287             *icon = decl.iconValue();
       
  1288             if (decl.d->values.count() > 0 && decl.d->values.at(0).type == Value::Uri) {
       
  1289                 // try to pull just the size from the image...
       
  1290                 QImageReader imageReader(decl.d->values.at(0).variant.toString());
       
  1291                 if ((*size = imageReader.size()).isNull()) {
       
  1292                     // but we'll have to load the whole image if the
       
  1293                     // format doesn't support just reading the size
       
  1294                     *size = imageReader.read().size();
       
  1295                 }
       
  1296             }
       
  1297             break;
       
  1298         case QtImageAlignment: *a = decl.alignmentValue();  break;
       
  1299         default: continue;
       
  1300         }
       
  1301         hit = true;
       
  1302     }
       
  1303     return hit;
       
  1304 }
       
  1305 
       
  1306 ///////////////////////////////////////////////////////////////////////////////
       
  1307 // Declaration
       
  1308 QColor Declaration::colorValue(const QPalette &pal) const
       
  1309 {
       
  1310     if (d->values.count() != 1)
       
  1311         return QColor();
       
  1312 
       
  1313     if (d->parsed.isValid()) {
       
  1314         if (d->parsed.type() == QVariant::Color)
       
  1315             return qvariant_cast<QColor>(d->parsed);
       
  1316         if (d->parsed.type() == QVariant::Int)
       
  1317             return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
       
  1318     }
       
  1319 
       
  1320     ColorData color = parseColorValue(d->values.at(0));
       
  1321     if(color.type == ColorData::Role) {
       
  1322         d->parsed = qVariantFromValue<int>(color.role);
       
  1323         return pal.color((QPalette::ColorRole)(color.role));
       
  1324     } else {
       
  1325         d->parsed = qVariantFromValue<QColor>(color.color);
       
  1326         return color.color;
       
  1327     }
       
  1328 }
       
  1329 
       
  1330 QBrush Declaration::brushValue(const QPalette &pal) const
       
  1331 {
       
  1332     if (d->values.count() != 1)
       
  1333         return QBrush();
       
  1334 
       
  1335     if (d->parsed.isValid()) {
       
  1336         if (d->parsed.type() == QVariant::Brush)
       
  1337             return qvariant_cast<QBrush>(d->parsed);
       
  1338         if (d->parsed.type() == QVariant::Int)
       
  1339             return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
       
  1340     }
       
  1341 
       
  1342     BrushData data = parseBrushValue(d->values.at(0), pal);
       
  1343 
       
  1344     if(data.type == BrushData::Role) {
       
  1345         d->parsed = qVariantFromValue<int>(data.role);
       
  1346         return pal.color((QPalette::ColorRole)(data.role));
       
  1347     } else {
       
  1348         if (data.type != BrushData::DependsOnThePalette)
       
  1349             d->parsed = qVariantFromValue<QBrush>(data.brush);
       
  1350         return data.brush;
       
  1351     }
       
  1352 }
       
  1353 
       
  1354 void Declaration::brushValues(QBrush *c, const QPalette &pal) const
       
  1355 {
       
  1356     int needParse = 0x1f; // bits 0..3 say if we should parse the corresponding value.
       
  1357                           // the bit 4 say we need to update d->parsed
       
  1358     int i = 0;
       
  1359     if (d->parsed.isValid()) {
       
  1360         needParse = 0;
       
  1361         QList<QVariant> v = d->parsed.toList();
       
  1362         for (i = 0; i < qMin(v.count(), 4); i++) {
       
  1363             if (v.at(i).type() == QVariant::Brush) {
       
  1364                 c[i] = qvariant_cast<QBrush>(v.at(i));
       
  1365             } else if (v.at(i).type() == QVariant::Int) {
       
  1366                 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
       
  1367             } else {
       
  1368                 needParse |= (1<<i);
       
  1369             }
       
  1370         }
       
  1371     }
       
  1372     if (needParse != 0) {
       
  1373         QList<QVariant> v;
       
  1374         for (i = 0; i < qMin(d->values.count(), 4); i++) {
       
  1375             if (!(needParse & (1<<i)))
       
  1376                 continue;
       
  1377             BrushData data = parseBrushValue(d->values.at(i), pal);
       
  1378             if(data.type == BrushData::Role) {
       
  1379                 v += qVariantFromValue<int>(data.role);
       
  1380                 c[i] = pal.color((QPalette::ColorRole)(data.role));
       
  1381             } else {
       
  1382                 if (data.type != BrushData::DependsOnThePalette) {
       
  1383                     v += qVariantFromValue<QBrush>(data.brush);
       
  1384                 } else {
       
  1385                     v += QVariant();
       
  1386                 }
       
  1387                 c[i] = data.brush;
       
  1388             }
       
  1389         }
       
  1390         if (needParse & 0x10)
       
  1391             d->parsed = v;
       
  1392     }
       
  1393     if (i == 0) c[0] = c[1] = c[2] = c[3] = QBrush();
       
  1394     else if (i == 1) c[3] = c[2] = c[1] = c[0];
       
  1395     else if (i == 2) c[2] = c[0], c[3] = c[1];
       
  1396     else if (i == 3) c[3] = c[1];
       
  1397 }
       
  1398 
       
  1399 bool Declaration::realValue(qreal *real, const char *unit) const
       
  1400 {
       
  1401     if (d->values.count() != 1)
       
  1402         return false;
       
  1403     const Value &v = d->values.at(0);
       
  1404     if (unit && v.type != Value::Length)
       
  1405         return false;
       
  1406     QString s = v.variant.toString();
       
  1407     if (unit) {
       
  1408         if (!s.endsWith(QLatin1String(unit), Qt::CaseInsensitive))
       
  1409             return false;
       
  1410         s.chop(qstrlen(unit));
       
  1411     }
       
  1412     bool ok = false;
       
  1413     qreal val = s.toDouble(&ok);
       
  1414     if (ok)
       
  1415         *real = val;
       
  1416     return ok;
       
  1417 }
       
  1418 
       
  1419 static bool intValueHelper(const Value &v, int *i, const char *unit)
       
  1420 {
       
  1421     if (unit && v.type != Value::Length)
       
  1422         return false;
       
  1423     QString s = v.variant.toString();
       
  1424     if (unit) {
       
  1425         if (!s.endsWith(QLatin1String(unit), Qt::CaseInsensitive))
       
  1426             return false;
       
  1427         s.chop(qstrlen(unit));
       
  1428     }
       
  1429     bool ok = false;
       
  1430     int val = s.toInt(&ok);
       
  1431     if (ok)
       
  1432         *i = val;
       
  1433     return ok;
       
  1434 }
       
  1435 
       
  1436 bool Declaration::intValue(int *i, const char *unit) const
       
  1437 {
       
  1438     if (d->values.count() != 1)
       
  1439         return false;
       
  1440     return intValueHelper(d->values.at(0), i, unit);
       
  1441 }
       
  1442 
       
  1443 QSize Declaration::sizeValue() const
       
  1444 {
       
  1445     if (d->parsed.isValid())
       
  1446         return qvariant_cast<QSize>(d->parsed);
       
  1447 
       
  1448     int x[2] = { 0, 0 };
       
  1449     if (d->values.count() > 0)
       
  1450         intValueHelper(d->values.at(0), &x[0], "px");
       
  1451     if (d->values.count() > 1)
       
  1452         intValueHelper(d->values.at(1), &x[1], "px");
       
  1453     else
       
  1454         x[1] = x[0];
       
  1455     QSize size(x[0], x[1]);
       
  1456     d->parsed = qVariantFromValue<QSize>(size);
       
  1457     return size;
       
  1458 }
       
  1459 
       
  1460 QRect Declaration::rectValue() const
       
  1461 {
       
  1462     if (d->values.count() != 1)
       
  1463         return QRect();
       
  1464     
       
  1465     if (d->parsed.isValid())
       
  1466         return qvariant_cast<QRect>(d->parsed);
       
  1467 
       
  1468     const Value &v = d->values.at(0);
       
  1469     if (v.type != Value::Function)
       
  1470         return QRect();
       
  1471     QStringList func = v.variant.toStringList();
       
  1472     if (func.count() != 2 || func.at(0).compare(QLatin1String("rect")) != 0)
       
  1473         return QRect();
       
  1474     QStringList args = func[1].split(QLatin1Char(' '), QString::SkipEmptyParts);
       
  1475     if (args.count() != 4)
       
  1476         return QRect();
       
  1477     QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
       
  1478     d->parsed = qVariantFromValue<QRect>(rect);
       
  1479     return rect;
       
  1480 }
       
  1481 
       
  1482 void Declaration::colorValues(QColor *c, const QPalette &pal) const
       
  1483 {
       
  1484     int i;
       
  1485     if (d->parsed.isValid()) {
       
  1486         QList<QVariant> v = d->parsed.toList();
       
  1487         for (i = 0; i < qMin(d->values.count(), 4); i++) {
       
  1488             if (v.at(i).type() == QVariant::Color) {
       
  1489                 c[i] = qvariant_cast<QColor>(v.at(i));
       
  1490             } else {
       
  1491                 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
       
  1492             }
       
  1493         }
       
  1494     } else {
       
  1495         QList<QVariant> v;
       
  1496         for (i = 0; i < qMin(d->values.count(), 4); i++) {
       
  1497             ColorData color = parseColorValue(d->values.at(i));
       
  1498             if(color.type == ColorData::Role) {
       
  1499                 v += qVariantFromValue<int>(color.role);
       
  1500                 c[i] = pal.color((QPalette::ColorRole)(color.role));
       
  1501             } else {
       
  1502                 v += qVariantFromValue<QColor>(color.color);
       
  1503                 c[i] = color.color;
       
  1504             }
       
  1505         }
       
  1506         d->parsed = v;
       
  1507     }
       
  1508 
       
  1509     if (i == 0) c[0] = c[1] = c[2] = c[3] = QColor();
       
  1510     else if (i == 1) c[3] = c[2] = c[1] = c[0];
       
  1511     else if (i == 2) c[2] = c[0], c[3] = c[1];
       
  1512     else if (i == 3) c[3] = c[1];
       
  1513 }
       
  1514 
       
  1515 BorderStyle Declaration::styleValue() const
       
  1516 {
       
  1517     if (d->values.count() != 1)
       
  1518         return BorderStyle_None;
       
  1519     return parseStyleValue(d->values.at(0));
       
  1520 }
       
  1521 
       
  1522 void Declaration::styleValues(BorderStyle *s) const
       
  1523 {
       
  1524     int i;
       
  1525     for (i = 0; i < qMin(d->values.count(), 4); i++)
       
  1526         s[i] = parseStyleValue(d->values.at(i));
       
  1527     if (i == 0) s[0] = s[1] = s[2] = s[3] = BorderStyle_None;
       
  1528     else if (i == 1) s[3] = s[2] = s[1] = s[0];
       
  1529     else if (i == 2) s[2] = s[0], s[3] = s[1];
       
  1530     else if (i == 3) s[3] = s[1];
       
  1531 }
       
  1532 
       
  1533 Repeat Declaration::repeatValue() const
       
  1534 {
       
  1535     if (d->parsed.isValid())
       
  1536         return static_cast<Repeat>(d->parsed.toInt());
       
  1537     if (d->values.count() != 1)
       
  1538         return Repeat_Unknown;
       
  1539     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1540                    repeats, NumKnownRepeats);
       
  1541     d->parsed = v;
       
  1542     return static_cast<Repeat>(v);
       
  1543 }
       
  1544 
       
  1545 Origin Declaration::originValue() const
       
  1546 {
       
  1547     if (d->parsed.isValid())
       
  1548         return static_cast<Origin>(d->parsed.toInt());
       
  1549     if (d->values.count() != 1)
       
  1550         return Origin_Unknown;
       
  1551     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1552                                origins, NumKnownOrigins);
       
  1553     d->parsed = v;
       
  1554     return static_cast<Origin>(v);
       
  1555 }
       
  1556 
       
  1557 PositionMode Declaration::positionValue() const
       
  1558 {
       
  1559     if (d->parsed.isValid())
       
  1560         return static_cast<PositionMode>(d->parsed.toInt());
       
  1561     if (d->values.count() != 1)
       
  1562         return PositionMode_Unknown;
       
  1563     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1564                            positions, NumKnownPositionModes);
       
  1565     d->parsed = v;
       
  1566     return static_cast<PositionMode>(v);
       
  1567 }
       
  1568 
       
  1569 Attachment Declaration::attachmentValue() const
       
  1570 {
       
  1571     if (d->parsed.isValid())
       
  1572         return static_cast<Attachment>(d->parsed.toInt());
       
  1573     if (d->values.count() != 1)
       
  1574         return Attachment_Unknown;
       
  1575     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1576                            attachments, NumKnownAttachments);
       
  1577     d->parsed = v;
       
  1578     return static_cast<Attachment>(v);
       
  1579 }
       
  1580 
       
  1581 int Declaration::styleFeaturesValue() const
       
  1582 {
       
  1583     Q_ASSERT(d->propertyId == QtStyleFeatures);
       
  1584     if (d->parsed.isValid())
       
  1585         return d->parsed.toInt();
       
  1586     int features = StyleFeature_None;
       
  1587     for (int i = 0; i < d->values.count(); i++) {
       
  1588         features |= static_cast<int>(findKnownValue(d->values.value(i).variant.toString(),
       
  1589                                      styleFeatures, NumKnownStyleFeatures));
       
  1590     }
       
  1591     d->parsed = features;
       
  1592     return features;
       
  1593 }
       
  1594 
       
  1595 QString Declaration::uriValue() const
       
  1596 {
       
  1597     if (d->values.isEmpty() || d->values.at(0).type != Value::Uri)
       
  1598         return QString();
       
  1599     return d->values.at(0).variant.toString();
       
  1600 }
       
  1601 
       
  1602 Qt::Alignment Declaration::alignmentValue() const
       
  1603 {
       
  1604     if (d->parsed.isValid())
       
  1605         return Qt::Alignment(d->parsed.toInt());
       
  1606     if (d->values.isEmpty() || d->values.count() > 2)
       
  1607         return Qt::AlignLeft | Qt::AlignTop;
       
  1608 
       
  1609     Qt::Alignment v = parseAlignment(d->values.constData(), d->values.count());
       
  1610     d->parsed = int(v);
       
  1611     return v;
       
  1612 }
       
  1613 
       
  1614 void Declaration::borderImageValue(QString *image, int *cuts,
       
  1615                                    TileMode *h, TileMode *v) const
       
  1616 {
       
  1617     *image = uriValue();
       
  1618     for (int i = 0; i < 4; i++)
       
  1619         cuts[i] = -1;
       
  1620     *h = *v = TileMode_Stretch;
       
  1621 
       
  1622     if (d->values.count() < 2)
       
  1623         return;
       
  1624 
       
  1625     if (d->values.at(1).type == Value::Number) { // cuts!
       
  1626         int i;
       
  1627         for (i = 0; i < qMin(d->values.count()-1, 4); i++) {
       
  1628             const Value& v = d->values.at(i+1);
       
  1629             if (v.type != Value::Number)
       
  1630                 break;
       
  1631             cuts[i] = v.variant.toString().toInt();
       
  1632         }
       
  1633         if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
       
  1634         else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];
       
  1635         else if (i == 2) cuts[2] = cuts[0], cuts[3] = cuts[1];
       
  1636         else if (i == 3) cuts[3] = cuts[1];
       
  1637     }
       
  1638 
       
  1639     if (d->values.last().type == Value::Identifier) {
       
  1640         *v = static_cast<TileMode>(findKnownValue(d->values.last().variant.toString(),
       
  1641                                       tileModes, NumKnownTileModes));
       
  1642     }
       
  1643     if (d->values[d->values.count() - 2].type == Value::Identifier) {
       
  1644         *h = static_cast<TileMode>
       
  1645                 (findKnownValue(d->values[d->values.count()-2].variant.toString(),
       
  1646                                         tileModes, NumKnownTileModes));
       
  1647     } else
       
  1648         *h = *v;
       
  1649 }
       
  1650 
       
  1651 QIcon Declaration::iconValue() const
       
  1652 {
       
  1653     if (d->parsed.isValid())
       
  1654         return qvariant_cast<QIcon>(d->parsed);
       
  1655 
       
  1656     QIcon icon;
       
  1657     for (int i = 0; i < d->values.count();) {
       
  1658         const Value &value = d->values.at(i++);
       
  1659         if (value.type != Value::Uri)
       
  1660             break;
       
  1661         QString uri = value.variant.toString();
       
  1662         QIcon::Mode mode = QIcon::Normal;
       
  1663         QIcon::State state = QIcon::Off;
       
  1664         for (int j = 0; j < 2; j++) {
       
  1665             if (i != d->values.count() && d->values.at(i).type == Value::KnownIdentifier) {
       
  1666                 switch (d->values.at(i).variant.toInt()) {
       
  1667                 case Value_Disabled: mode = QIcon::Disabled; break;
       
  1668                 case Value_Active: mode = QIcon::Active; break;
       
  1669                 case Value_Selected: mode = QIcon::Selected; break;
       
  1670                 case Value_Normal: mode = QIcon::Normal; break;
       
  1671                 case Value_On: state = QIcon::On; break;
       
  1672                 case Value_Off: state = QIcon::Off; break;
       
  1673                 default: break;
       
  1674                 }
       
  1675                 ++i;
       
  1676             } else {
       
  1677                 break;
       
  1678             }
       
  1679         }
       
  1680 
       
  1681         // QIcon is soo broken
       
  1682         if (icon.isNull())
       
  1683             icon = QIcon(uri);
       
  1684         else
       
  1685             icon.addPixmap(uri, mode, state);
       
  1686 
       
  1687         if (i == d->values.count())
       
  1688             break;
       
  1689 
       
  1690         if (d->values.at(i).type == Value::TermOperatorComma)
       
  1691             i++;
       
  1692     }
       
  1693 
       
  1694     d->parsed = qVariantFromValue<QIcon>(icon);
       
  1695     return icon;
       
  1696 }
       
  1697 
       
  1698 ///////////////////////////////////////////////////////////////////////////////
       
  1699 // Selector
       
  1700 int Selector::specificity() const
       
  1701 {
       
  1702     int val = 0;
       
  1703     for (int i = 0; i < basicSelectors.count(); ++i) {
       
  1704         const BasicSelector &sel = basicSelectors.at(i);
       
  1705         if (!sel.elementName.isEmpty())
       
  1706             val += 1;
       
  1707 
       
  1708         val += (sel.pseudos.count() + sel.attributeSelectors.count()) * 0x10;
       
  1709         val += sel.ids.count() * 0x100;
       
  1710     }
       
  1711     return val;
       
  1712 }
       
  1713 
       
  1714 QString Selector::pseudoElement() const
       
  1715 {
       
  1716     const BasicSelector& bs = basicSelectors.last();
       
  1717     if (!bs.pseudos.isEmpty() && bs.pseudos.at(0).type == PseudoClass_Unknown)
       
  1718         return bs.pseudos.at(0).name;
       
  1719     return QString();
       
  1720 }
       
  1721 
       
  1722 quint64 Selector::pseudoClass(quint64 *negated) const
       
  1723 {
       
  1724     const BasicSelector& bs = basicSelectors.last();
       
  1725     if (bs.pseudos.isEmpty())
       
  1726         return PseudoClass_Unspecified;
       
  1727     quint64 pc = PseudoClass_Unknown;
       
  1728     for (int i = !pseudoElement().isEmpty(); i < bs.pseudos.count(); i++) {
       
  1729         const Pseudo &pseudo = bs.pseudos.at(i);
       
  1730         if (pseudo.type == PseudoClass_Unknown)
       
  1731             return PseudoClass_Unknown;
       
  1732         if (!pseudo.negated)
       
  1733             pc |= pseudo.type;
       
  1734         else if (negated)
       
  1735             *negated |= pseudo.type;
       
  1736     }
       
  1737     return pc;
       
  1738 }
       
  1739 
       
  1740 ///////////////////////////////////////////////////////////////////////////////
       
  1741 // StyleSheet
       
  1742 void StyleSheet::buildIndexes(Qt::CaseSensitivity nameCaseSensitivity)
       
  1743 {
       
  1744     QVector<StyleRule> universals;
       
  1745     for (int i = 0; i < styleRules.count(); ++i) {
       
  1746         const StyleRule &rule = styleRules.at(i);
       
  1747         QVector<Selector> universalsSelectors;
       
  1748         for (int j = 0; j < rule.selectors.count(); ++j) {
       
  1749             const Selector& selector = rule.selectors.at(j);
       
  1750 
       
  1751             if (selector.basicSelectors.isEmpty())
       
  1752                 continue;
       
  1753 
       
  1754             if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
       
  1755                 if (selector.basicSelectors.count() != 1)
       
  1756                     continue;
       
  1757             } else if (selector.basicSelectors.count() <= 1) {
       
  1758                 continue;
       
  1759             }
       
  1760 
       
  1761             const BasicSelector &sel = selector.basicSelectors.at(selector.basicSelectors.count() - 1);
       
  1762 
       
  1763             if (!sel.ids.isEmpty()) {
       
  1764                 StyleRule nr;
       
  1765                 nr.selectors += selector;
       
  1766                 nr.declarations = rule.declarations;
       
  1767                 nr.order = i;
       
  1768                 idIndex.insert(sel.ids.at(0), nr);
       
  1769             } else if (!sel.elementName.isEmpty()) {
       
  1770                 StyleRule nr;
       
  1771                 nr.selectors += selector;
       
  1772                 nr.declarations = rule.declarations;
       
  1773                 nr.order = i;
       
  1774                 QString name = sel.elementName;
       
  1775                 if (nameCaseSensitivity == Qt::CaseInsensitive)
       
  1776                     name=name.toLower();
       
  1777                 nameIndex.insert(name, nr);
       
  1778             } else {
       
  1779                 universalsSelectors += selector;
       
  1780             }
       
  1781         }
       
  1782         if (!universalsSelectors.isEmpty()) {
       
  1783             StyleRule nr;
       
  1784             nr.selectors = universalsSelectors;
       
  1785             nr.declarations = rule.declarations;
       
  1786             nr.order = i;
       
  1787             universals << nr;
       
  1788         }
       
  1789     }
       
  1790     styleRules = universals;
       
  1791 }
       
  1792 
       
  1793 ///////////////////////////////////////////////////////////////////////////////
       
  1794 // StyleSelector
       
  1795 StyleSelector::~StyleSelector()
       
  1796 {
       
  1797 }
       
  1798 
       
  1799 bool StyleSelector::nodeNameEquals(NodePtr node, const QString& nodeName) const
       
  1800 {
       
  1801     return nodeNames(node).contains(nodeName, nameCaseSensitivity);
       
  1802 }
       
  1803 
       
  1804 QStringList StyleSelector::nodeIds(NodePtr node) const
       
  1805 {
       
  1806     return QStringList(attribute(node, QLatin1String("id")));
       
  1807 }
       
  1808 
       
  1809 bool StyleSelector::selectorMatches(const Selector &selector, NodePtr node)
       
  1810 {
       
  1811     if (selector.basicSelectors.isEmpty())
       
  1812         return false;
       
  1813 
       
  1814     if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
       
  1815         if (selector.basicSelectors.count() != 1)
       
  1816             return false;
       
  1817         return basicSelectorMatches(selector.basicSelectors.at(0), node);
       
  1818     }
       
  1819     if (selector.basicSelectors.count() <= 1)
       
  1820         return false;
       
  1821 
       
  1822     int i = selector.basicSelectors.count() - 1;
       
  1823     node = duplicateNode(node);
       
  1824     bool match = true;
       
  1825 
       
  1826     BasicSelector sel = selector.basicSelectors.at(i);
       
  1827     do {
       
  1828         match = basicSelectorMatches(sel, node);
       
  1829         if (!match) {
       
  1830             if (sel.relationToNext == BasicSelector::MatchNextSelectorIfParent
       
  1831                 || i == selector.basicSelectors.count() - 1) // first element must always match!
       
  1832                 break;
       
  1833         }
       
  1834 
       
  1835         if (match || sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor)
       
  1836             --i;
       
  1837 
       
  1838         if (i < 0)
       
  1839             break;
       
  1840 
       
  1841         sel = selector.basicSelectors.at(i);
       
  1842         if (sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
       
  1843             || sel.relationToNext == BasicSelector::MatchNextSelectorIfParent) {
       
  1844 
       
  1845             NodePtr nextParent = parentNode(node);
       
  1846             freeNode(node);
       
  1847             node = nextParent;
       
  1848        } else if (sel.relationToNext == BasicSelector::MatchNextSelectorIfPreceeds) {
       
  1849             NodePtr previousSibling = previousSiblingNode(node);
       
  1850             freeNode(node);
       
  1851             node = previousSibling;
       
  1852        }
       
  1853         if (isNullNode(node)) {
       
  1854             match = false;
       
  1855             break;
       
  1856         }
       
  1857    } while (i >= 0 && (match || sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor));
       
  1858 
       
  1859     freeNode(node);
       
  1860 
       
  1861     return match;
       
  1862 }
       
  1863 
       
  1864 bool StyleSelector::basicSelectorMatches(const BasicSelector &sel, NodePtr node)
       
  1865 {
       
  1866     if (!sel.attributeSelectors.isEmpty()) {
       
  1867         if (!hasAttributes(node))
       
  1868             return false;
       
  1869 
       
  1870         for (int i = 0; i < sel.attributeSelectors.count(); ++i) {
       
  1871             const QCss::AttributeSelector &a = sel.attributeSelectors.at(i);
       
  1872 
       
  1873             const QString attrValue = attribute(node, a.name);
       
  1874             if (attrValue.isNull())
       
  1875                 return false;
       
  1876 
       
  1877             if (a.valueMatchCriterium == QCss::AttributeSelector::MatchContains) {
       
  1878 
       
  1879                 QStringList lst = attrValue.split(QLatin1Char(' '));
       
  1880                 if (!lst.contains(a.value))
       
  1881                     return false;
       
  1882             } else if (
       
  1883                 (a.valueMatchCriterium == QCss::AttributeSelector::MatchEqual
       
  1884                  && attrValue != a.value)
       
  1885                 ||
       
  1886                 (a.valueMatchCriterium == QCss::AttributeSelector::MatchBeginsWith
       
  1887                  && !attrValue.startsWith(a.value))
       
  1888                )
       
  1889                 return false;
       
  1890         }
       
  1891     }
       
  1892 
       
  1893     if (!sel.elementName.isEmpty()
       
  1894         && !nodeNameEquals(node, sel.elementName))
       
  1895             return false;
       
  1896 
       
  1897     if (!sel.ids.isEmpty()
       
  1898         && sel.ids != nodeIds(node))
       
  1899             return false;
       
  1900 
       
  1901     return true;
       
  1902 }
       
  1903 
       
  1904 void StyleSelector::matchRule(NodePtr node, const StyleRule &rule, StyleSheetOrigin origin,
       
  1905                                int depth, QMap<uint, StyleRule> *weightedRules)
       
  1906 {
       
  1907     for (int j = 0; j < rule.selectors.count(); ++j) {
       
  1908         const Selector& selector = rule.selectors.at(j);
       
  1909         if (selectorMatches(selector, node)) {
       
  1910             uint weight = rule.order
       
  1911                         + selector.specificity() *0x100
       
  1912                         + (uint(origin) + depth)*0x100000;
       
  1913             StyleRule newRule = rule;
       
  1914             if(rule.selectors.count() > 1) {
       
  1915                 newRule.selectors.resize(1);
       
  1916                 newRule.selectors[0] = selector;
       
  1917             }
       
  1918             //We might have rules with the same weight if they came from a rule with several selectors
       
  1919             weightedRules->insertMulti(weight, newRule);
       
  1920         }
       
  1921     }
       
  1922 }
       
  1923 
       
  1924 // Returns style rules that are in ascending order of specificity
       
  1925 // Each of the StyleRule returned will contain exactly one Selector
       
  1926 QVector<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
       
  1927 {
       
  1928     QVector<StyleRule> rules;
       
  1929     if (styleSheets.isEmpty())
       
  1930         return rules;
       
  1931 
       
  1932     QMap<uint, StyleRule> weightedRules; // (spec, rule) that will be sorted below
       
  1933     
       
  1934     //prune using indexed stylesheet
       
  1935     for (int sheetIdx = 0; sheetIdx < styleSheets.count(); ++sheetIdx) {
       
  1936         const StyleSheet &styleSheet = styleSheets.at(sheetIdx);
       
  1937         for (int i = 0; i < styleSheet.styleRules.count(); ++i) {
       
  1938             matchRule(node, styleSheet.styleRules.at(i), styleSheet.origin, styleSheet.depth, &weightedRules);
       
  1939         }
       
  1940 
       
  1941         if (!styleSheet.idIndex.isEmpty()) {
       
  1942             QStringList ids = nodeIds(node);
       
  1943             for (int i = 0; i < ids.count(); i++) {
       
  1944                 const QString &key = ids.at(i);
       
  1945                 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.idIndex.constFind(key);
       
  1946                 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
       
  1947                     matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
       
  1948                     ++it;
       
  1949                 }
       
  1950             }
       
  1951         }
       
  1952         if (!styleSheet.nameIndex.isEmpty()) {
       
  1953             QStringList names = nodeNames(node);
       
  1954             for (int i = 0; i < names.count(); i++) {
       
  1955                 QString name = names.at(i);
       
  1956                 if (nameCaseSensitivity == Qt::CaseInsensitive)
       
  1957                     name = name.toLower();
       
  1958                 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
       
  1959                 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
       
  1960                     matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
       
  1961                     ++it;
       
  1962                 }
       
  1963             }
       
  1964         }
       
  1965         if (!medium.isEmpty()) {
       
  1966             for (int i = 0; i < styleSheet.mediaRules.count(); ++i) {
       
  1967                 if (styleSheet.mediaRules.at(i).media.contains(medium, Qt::CaseInsensitive)) {
       
  1968                     for (int j = 0; j < styleSheet.mediaRules.at(i).styleRules.count(); ++j) {
       
  1969                         matchRule(node, styleSheet.mediaRules.at(i).styleRules.at(j), styleSheet.origin,
       
  1970                                styleSheet.depth, &weightedRules);
       
  1971                     }
       
  1972                 }
       
  1973             }
       
  1974         }
       
  1975     }
       
  1976 
       
  1977     rules.reserve(weightedRules.count());
       
  1978     QMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
       
  1979     for ( ; it != weightedRules.constEnd() ; ++it)
       
  1980         rules += *it;
       
  1981 
       
  1982     return rules;
       
  1983 }
       
  1984 
       
  1985 // for qtexthtmlparser which requires just the declarations with Enabled state
       
  1986 // and without pseudo elements
       
  1987 QVector<Declaration> StyleSelector::declarationsForNode(NodePtr node, const char *extraPseudo)
       
  1988 {
       
  1989     QVector<Declaration> decls;
       
  1990     QVector<StyleRule> rules = styleRulesForNode(node);
       
  1991     for (int i = 0; i < rules.count(); i++) {
       
  1992         const Selector& selector = rules.at(i).selectors.at(0);
       
  1993         const QString pseudoElement = selector.pseudoElement();
       
  1994 
       
  1995         if (extraPseudo && pseudoElement == QLatin1String(extraPseudo)) {
       
  1996             decls += rules.at(i).declarations;
       
  1997             continue;
       
  1998         }
       
  1999 
       
  2000         if (!pseudoElement.isEmpty()) // skip rules with pseudo elements
       
  2001             continue;
       
  2002         quint64 pseudoClass = selector.pseudoClass();
       
  2003         if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
       
  2004             decls += rules.at(i).declarations;
       
  2005     }
       
  2006     return decls;
       
  2007 }
       
  2008 
       
  2009 static inline bool isHexDigit(const char c)
       
  2010 {
       
  2011     return (c >= '0' && c <= '9')
       
  2012            || (c >= 'a' && c <= 'f')
       
  2013            || (c >= 'A' && c <= 'F')
       
  2014            ;
       
  2015 }
       
  2016 
       
  2017 QString Scanner::preprocess(const QString &input, bool *hasEscapeSequences)
       
  2018 {
       
  2019     QString output = input;
       
  2020 
       
  2021     if (hasEscapeSequences)
       
  2022         *hasEscapeSequences = false;
       
  2023 
       
  2024     int i = 0;
       
  2025     while (i < output.size()) {
       
  2026         if (output.at(i) == QLatin1Char('\\')) {
       
  2027 
       
  2028             ++i;
       
  2029             // test for unicode hex escape
       
  2030             int hexCount = 0;
       
  2031             const int hexStart = i;
       
  2032             while (i < output.size()
       
  2033                    && isHexDigit(output.at(i).toLatin1())
       
  2034                    && hexCount < 7) {
       
  2035                 ++hexCount;
       
  2036                 ++i;
       
  2037             }
       
  2038             if (hexCount == 0) {
       
  2039                 if (hasEscapeSequences)
       
  2040                     *hasEscapeSequences = true;
       
  2041                 continue;
       
  2042             }
       
  2043 
       
  2044             hexCount = qMin(hexCount, 6);
       
  2045             bool ok = false;
       
  2046             ushort code = output.mid(hexStart, hexCount).toUShort(&ok, 16);
       
  2047             if (ok) {
       
  2048                 output.replace(hexStart - 1, hexCount + 1, QChar(code));
       
  2049                 i = hexStart;
       
  2050             } else {
       
  2051                 i = hexStart;
       
  2052             }
       
  2053         } else {
       
  2054             ++i;
       
  2055         }
       
  2056     }
       
  2057     return output;
       
  2058 }
       
  2059 
       
  2060 int QCssScanner_Generated::handleCommentStart()
       
  2061 {
       
  2062     while (pos < input.size() - 1) {
       
  2063         if (input.at(pos) == QLatin1Char('*')
       
  2064             && input.at(pos + 1) == QLatin1Char('/')) {
       
  2065             pos += 2;
       
  2066             break;
       
  2067         }
       
  2068         ++pos;
       
  2069     }
       
  2070     return S;
       
  2071 }
       
  2072 
       
  2073 void Scanner::scan(const QString &preprocessedInput, QVector<Symbol> *symbols)
       
  2074 {
       
  2075     QCssScanner_Generated scanner(preprocessedInput);
       
  2076     Symbol sym;
       
  2077     int tok = scanner.lex();
       
  2078     while (tok != -1) {
       
  2079         sym.token = static_cast<QCss::TokenType>(tok);
       
  2080         sym.text = scanner.input;
       
  2081         sym.start = scanner.lexemStart;
       
  2082         sym.len = scanner.lexemLength;
       
  2083         symbols->append(sym);
       
  2084         tok = scanner.lex();
       
  2085     }
       
  2086 }
       
  2087 
       
  2088 QString Symbol::lexem() const
       
  2089 {
       
  2090     QString result;
       
  2091     if (len > 0)
       
  2092         result.reserve(len);
       
  2093     for (int i = 0; i < len; ++i) {
       
  2094         if (text.at(start + i) == QLatin1Char('\\') && i < len - 1)
       
  2095             ++i;
       
  2096         result += text.at(start + i);
       
  2097     }
       
  2098     return result;
       
  2099 }
       
  2100 
       
  2101 Parser::Parser(const QString &css, bool isFile)
       
  2102 {
       
  2103     init(css, isFile);
       
  2104 }
       
  2105 
       
  2106 Parser::Parser()
       
  2107 {
       
  2108     index = 0;
       
  2109     errorIndex = -1;
       
  2110     hasEscapeSequences = false;
       
  2111 }
       
  2112 
       
  2113 void Parser::init(const QString &css, bool isFile)
       
  2114 {
       
  2115     QString styleSheet = css;
       
  2116     if (isFile) {
       
  2117         QFile file(css);
       
  2118         if (file.open(QFile::ReadOnly)) {
       
  2119             sourcePath = QFileInfo(styleSheet).absolutePath() + QLatin1Char('/');
       
  2120             QTextStream stream(&file);
       
  2121             styleSheet = stream.readAll();
       
  2122         } else {
       
  2123             qWarning() << "QCss::Parser - Failed to load file " << css;
       
  2124             styleSheet.clear();
       
  2125         }
       
  2126     } else {
       
  2127         sourcePath.clear();
       
  2128     }
       
  2129 
       
  2130     hasEscapeSequences = false;
       
  2131     symbols.resize(0);
       
  2132     symbols.reserve(8);
       
  2133     Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
       
  2134     index = 0;
       
  2135     errorIndex = -1;
       
  2136 }
       
  2137 
       
  2138 bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
       
  2139 {
       
  2140     if (testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("charset"))) {
       
  2141         if (!next(STRING)) return false;
       
  2142         if (!next(SEMICOLON)) return false;
       
  2143     }
       
  2144 
       
  2145     while (test(S) || test(CDO) || test(CDC)) {}
       
  2146 
       
  2147     while (testImport()) {
       
  2148         ImportRule rule;
       
  2149         if (!parseImport(&rule)) return false;
       
  2150         styleSheet->importRules.append(rule);
       
  2151         while (test(S) || test(CDO) || test(CDC)) {}
       
  2152     }
       
  2153 
       
  2154     do {
       
  2155         if (testMedia()) {
       
  2156             MediaRule rule;
       
  2157             if (!parseMedia(&rule)) return false;
       
  2158             styleSheet->mediaRules.append(rule);
       
  2159         } else if (testPage()) {
       
  2160             PageRule rule;
       
  2161             if (!parsePage(&rule)) return false;
       
  2162             styleSheet->pageRules.append(rule);
       
  2163         } else if (testRuleset()) {
       
  2164             StyleRule rule;
       
  2165             if (!parseRuleset(&rule)) return false;
       
  2166             styleSheet->styleRules.append(rule);
       
  2167         } else if (test(ATKEYWORD_SYM)) {
       
  2168             if (!until(RBRACE)) return false;
       
  2169         } else if (hasNext()) {
       
  2170             return false;
       
  2171         }
       
  2172         while (test(S) || test(CDO) || test(CDC)) {}
       
  2173     } while (hasNext());
       
  2174     styleSheet->buildIndexes(nameCaseSensitivity);
       
  2175     return true;
       
  2176 }
       
  2177 
       
  2178 Symbol Parser::errorSymbol()
       
  2179 {
       
  2180     if (errorIndex == -1) return Symbol();
       
  2181     return symbols.at(errorIndex);
       
  2182 }
       
  2183 
       
  2184 static inline void removeOptionalQuotes(QString *str)
       
  2185 {
       
  2186     if (!str->startsWith(QLatin1Char('\''))
       
  2187         && !str->startsWith(QLatin1Char('\"')))
       
  2188         return;
       
  2189     str->remove(0, 1);
       
  2190     str->chop(1);
       
  2191 }
       
  2192 
       
  2193 bool Parser::parseImport(ImportRule *importRule)
       
  2194 {
       
  2195     skipSpace();
       
  2196 
       
  2197     if (test(STRING)) {
       
  2198         importRule->href = lexem();
       
  2199     } else {
       
  2200         if (!testAndParseUri(&importRule->href)) return false;
       
  2201     }
       
  2202     removeOptionalQuotes(&importRule->href);
       
  2203 
       
  2204     skipSpace();
       
  2205 
       
  2206     if (testMedium()) {
       
  2207         if (!parseMedium(&importRule->media)) return false;
       
  2208 
       
  2209         while (test(COMMA)) {
       
  2210             skipSpace();
       
  2211             if (!parseNextMedium(&importRule->media)) return false;
       
  2212         }
       
  2213     }
       
  2214 
       
  2215     if (!next(SEMICOLON)) return false;
       
  2216 
       
  2217     skipSpace();
       
  2218     return true;
       
  2219 }
       
  2220 
       
  2221 bool Parser::parseMedia(MediaRule *mediaRule)
       
  2222 {
       
  2223     do {
       
  2224         skipSpace();
       
  2225         if (!parseNextMedium(&mediaRule->media)) return false;
       
  2226     } while (test(COMMA));
       
  2227 
       
  2228     if (!next(LBRACE)) return false;
       
  2229     skipSpace();
       
  2230 
       
  2231     while (testRuleset()) {
       
  2232         StyleRule rule;
       
  2233         if (!parseRuleset(&rule)) return false;
       
  2234         mediaRule->styleRules.append(rule);
       
  2235     }
       
  2236 
       
  2237     if (!next(RBRACE)) return false;
       
  2238     skipSpace();
       
  2239     return true;
       
  2240 }
       
  2241 
       
  2242 bool Parser::parseMedium(QStringList *media)
       
  2243 {
       
  2244     media->append(lexem());
       
  2245     skipSpace();
       
  2246     return true;
       
  2247 }
       
  2248 
       
  2249 bool Parser::parsePage(PageRule *pageRule)
       
  2250 {
       
  2251     skipSpace();
       
  2252 
       
  2253     if (testPseudoPage())
       
  2254         if (!parsePseudoPage(&pageRule->selector)) return false;
       
  2255 
       
  2256     skipSpace();
       
  2257     if (!next(LBRACE)) return false;
       
  2258 
       
  2259     do {
       
  2260         skipSpace();
       
  2261         Declaration decl;
       
  2262         if (!parseNextDeclaration(&decl)) return false;
       
  2263         if (!decl.isEmpty())
       
  2264             pageRule->declarations.append(decl);
       
  2265     } while (test(SEMICOLON));
       
  2266 
       
  2267     if (!next(RBRACE)) return false;
       
  2268     skipSpace();
       
  2269     return true;
       
  2270 }
       
  2271 
       
  2272 bool Parser::parsePseudoPage(QString *selector)
       
  2273 {
       
  2274     if (!next(IDENT)) return false;
       
  2275     *selector = lexem();
       
  2276     return true;
       
  2277 }
       
  2278 
       
  2279 bool Parser::parseNextOperator(Value *value)
       
  2280 {
       
  2281     if (!hasNext()) return true;
       
  2282     switch (next()) {
       
  2283         case SLASH: value->type = Value::TermOperatorSlash; skipSpace(); break;
       
  2284         case COMMA: value->type = Value::TermOperatorComma; skipSpace(); break;
       
  2285         default: prev(); break;
       
  2286     }
       
  2287     return true;
       
  2288 }
       
  2289 
       
  2290 bool Parser::parseCombinator(BasicSelector::Relation *relation)
       
  2291 {
       
  2292     *relation = BasicSelector::NoRelation;
       
  2293     if (lookup() == S) {
       
  2294         *relation = BasicSelector::MatchNextSelectorIfAncestor;
       
  2295         skipSpace();
       
  2296     } else {
       
  2297         prev();
       
  2298     }
       
  2299     if (test(PLUS)) {
       
  2300         *relation = BasicSelector::MatchNextSelectorIfPreceeds;
       
  2301     } else if (test(GREATER)) {
       
  2302         *relation = BasicSelector::MatchNextSelectorIfParent;
       
  2303     }
       
  2304     skipSpace();
       
  2305     return true;
       
  2306 }
       
  2307 
       
  2308 bool Parser::parseProperty(Declaration *decl)
       
  2309 {
       
  2310     decl->d->property = lexem();
       
  2311     decl->d->propertyId = static_cast<Property>(findKnownValue(decl->d->property, properties, NumProperties));
       
  2312     skipSpace();
       
  2313     return true;
       
  2314 }
       
  2315 
       
  2316 bool Parser::parseRuleset(StyleRule *styleRule)
       
  2317 {
       
  2318     Selector sel;
       
  2319     if (!parseSelector(&sel)) return false;
       
  2320     styleRule->selectors.append(sel);
       
  2321 
       
  2322     while (test(COMMA)) {
       
  2323         skipSpace();
       
  2324         Selector sel;
       
  2325         if (!parseNextSelector(&sel)) return false;
       
  2326         styleRule->selectors.append(sel);
       
  2327     }
       
  2328 
       
  2329     skipSpace();
       
  2330     if (!next(LBRACE)) return false;
       
  2331     const int declarationStart = index;
       
  2332 
       
  2333     do {
       
  2334         skipSpace();
       
  2335         Declaration decl;
       
  2336         const int rewind = index;
       
  2337         if (!parseNextDeclaration(&decl)) {
       
  2338             index = rewind;
       
  2339             const bool foundSemicolon = until(SEMICOLON);
       
  2340             const int semicolonIndex = index;
       
  2341 
       
  2342             index = declarationStart;
       
  2343             const bool foundRBrace = until(RBRACE);
       
  2344 
       
  2345             if (foundSemicolon && semicolonIndex < index) {
       
  2346                 decl = Declaration();
       
  2347                 index = semicolonIndex - 1;
       
  2348             } else {
       
  2349                 skipSpace();
       
  2350                 return foundRBrace;
       
  2351             }
       
  2352         }
       
  2353         if (!decl.isEmpty())
       
  2354             styleRule->declarations.append(decl);
       
  2355     } while (test(SEMICOLON));
       
  2356 
       
  2357     if (!next(RBRACE)) return false;
       
  2358     skipSpace();
       
  2359     return true;
       
  2360 }
       
  2361 
       
  2362 bool Parser::parseSelector(Selector *sel)
       
  2363 {
       
  2364     BasicSelector basicSel;
       
  2365     if (!parseSimpleSelector(&basicSel)) return false;
       
  2366     while (testCombinator()) {
       
  2367         if (!parseCombinator(&basicSel.relationToNext)) return false;
       
  2368 
       
  2369         if (!testSimpleSelector()) break;
       
  2370         sel->basicSelectors.append(basicSel);
       
  2371 
       
  2372         basicSel = BasicSelector();
       
  2373         if (!parseSimpleSelector(&basicSel)) return false;
       
  2374     }
       
  2375     sel->basicSelectors.append(basicSel);
       
  2376     return true;
       
  2377 }
       
  2378 
       
  2379 bool Parser::parseSimpleSelector(BasicSelector *basicSel)
       
  2380 {
       
  2381     int minCount = 0;
       
  2382     if (lookupElementName()) {
       
  2383         if (!parseElementName(&basicSel->elementName)) return false;
       
  2384     } else {
       
  2385         prev();
       
  2386         minCount = 1;
       
  2387     }
       
  2388     bool onceMore;
       
  2389     int count = 0;
       
  2390     do {
       
  2391         onceMore = false;
       
  2392         if (test(HASH)) {
       
  2393             QString theid = lexem();
       
  2394             // chop off leading #
       
  2395             theid.remove(0, 1);
       
  2396             basicSel->ids.append(theid);
       
  2397             onceMore = true;
       
  2398         } else if (testClass()) {
       
  2399             onceMore = true;
       
  2400             AttributeSelector a;
       
  2401             a.name = QLatin1String("class");
       
  2402             a.valueMatchCriterium = AttributeSelector::MatchContains;
       
  2403             if (!parseClass(&a.value)) return false;
       
  2404             basicSel->attributeSelectors.append(a);
       
  2405         } else if (testAttrib()) {
       
  2406             onceMore = true;
       
  2407             AttributeSelector a;
       
  2408             if (!parseAttrib(&a)) return false;
       
  2409             basicSel->attributeSelectors.append(a);
       
  2410         } else if (testPseudo()) {
       
  2411             onceMore = true;
       
  2412             Pseudo ps;
       
  2413             if (!parsePseudo(&ps)) return false;
       
  2414             basicSel->pseudos.append(ps);
       
  2415         }
       
  2416         if (onceMore) ++count;
       
  2417     } while (onceMore);
       
  2418     return count >= minCount;
       
  2419 }
       
  2420 
       
  2421 bool Parser::parseClass(QString *name)
       
  2422 {
       
  2423     if (!next(IDENT)) return false;
       
  2424     *name = lexem();
       
  2425     return true;
       
  2426 }
       
  2427 
       
  2428 bool Parser::parseElementName(QString *name)
       
  2429 {
       
  2430     switch (lookup()) {
       
  2431         case STAR: name->clear(); break;
       
  2432         case IDENT: *name = lexem(); break;
       
  2433         default: return false;
       
  2434     }
       
  2435     return true;
       
  2436 }
       
  2437 
       
  2438 bool Parser::parseAttrib(AttributeSelector *attr)
       
  2439 {
       
  2440     skipSpace();
       
  2441     if (!next(IDENT)) return false;
       
  2442     attr->name = lexem();
       
  2443     skipSpace();
       
  2444 
       
  2445     if (test(EQUAL)) {
       
  2446         attr->valueMatchCriterium = AttributeSelector::MatchEqual;
       
  2447     } else if (test(INCLUDES)) {
       
  2448         attr->valueMatchCriterium = AttributeSelector::MatchContains;
       
  2449     } else if (test(DASHMATCH)) {
       
  2450         attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
       
  2451     } else {
       
  2452         return next(RBRACKET);
       
  2453     }
       
  2454 
       
  2455     skipSpace();
       
  2456 
       
  2457     if (!test(IDENT) && !test(STRING)) return false;
       
  2458     attr->value = unquotedLexem();
       
  2459 
       
  2460     skipSpace();
       
  2461     return next(RBRACKET);
       
  2462 }
       
  2463 
       
  2464 bool Parser::parsePseudo(Pseudo *pseudo)
       
  2465 {
       
  2466     (void)test(COLON);
       
  2467     pseudo->negated = test(EXCLAMATION_SYM);
       
  2468     if (test(IDENT)) {
       
  2469         pseudo->name = lexem();
       
  2470         pseudo->type = static_cast<quint64>(findKnownValue(pseudo->name, pseudos, NumPseudos));
       
  2471         return true;
       
  2472     }
       
  2473     if (!next(FUNCTION)) return false;
       
  2474     pseudo->function = lexem();
       
  2475     // chop off trailing parenthesis
       
  2476     pseudo->function.chop(1);
       
  2477     skipSpace();
       
  2478     if (!test(IDENT)) return false;
       
  2479     pseudo->name = lexem();
       
  2480     skipSpace();
       
  2481     return next(RPAREN);
       
  2482 }
       
  2483 
       
  2484 bool Parser::parseNextDeclaration(Declaration *decl)
       
  2485 {
       
  2486     if (!testProperty())
       
  2487         return true; // not an error!
       
  2488     if (!parseProperty(decl)) return false;
       
  2489     if (!next(COLON)) return false;
       
  2490     skipSpace();
       
  2491     if (!parseNextExpr(&decl->d->values)) return false;
       
  2492     if (testPrio())
       
  2493         if (!parsePrio(decl)) return false;
       
  2494     return true;
       
  2495 }
       
  2496 
       
  2497 bool Parser::testPrio()
       
  2498 {
       
  2499     const int rewind = index;
       
  2500     if (!test(EXCLAMATION_SYM)) return false;
       
  2501     skipSpace();
       
  2502     if (!test(IDENT)) {
       
  2503         index = rewind;
       
  2504         return false;
       
  2505     }
       
  2506     if (lexem().compare(QLatin1String("important"), Qt::CaseInsensitive) != 0) {
       
  2507         index = rewind;
       
  2508         return false;
       
  2509     }
       
  2510     return true;
       
  2511 }
       
  2512 
       
  2513 bool Parser::parsePrio(Declaration *declaration)
       
  2514 {
       
  2515     declaration->d->important = true;
       
  2516     skipSpace();
       
  2517     return true;
       
  2518 }
       
  2519 
       
  2520 bool Parser::parseExpr(QVector<Value> *values)
       
  2521 {
       
  2522     Value val;
       
  2523     if (!parseTerm(&val)) return false;
       
  2524     values->append(val);
       
  2525     bool onceMore;
       
  2526     do {
       
  2527         onceMore = false;
       
  2528         val = Value();
       
  2529         if (!parseNextOperator(&val)) return false;
       
  2530         if (val.type != QCss::Value::Unknown)
       
  2531             values->append(val);
       
  2532         if (testTerm()) {
       
  2533             onceMore = true;
       
  2534             val = Value();
       
  2535             if (!parseTerm(&val)) return false;
       
  2536             values->append(val);
       
  2537         }
       
  2538     } while (onceMore);
       
  2539     return true;
       
  2540 }
       
  2541 
       
  2542 bool Parser::testTerm()
       
  2543 {
       
  2544     return test(PLUS) || test(MINUS)
       
  2545            || test(NUMBER)
       
  2546            || test(PERCENTAGE)
       
  2547            || test(LENGTH)
       
  2548            || test(STRING)
       
  2549            || test(IDENT)
       
  2550            || testHexColor()
       
  2551            || testFunction();
       
  2552 }
       
  2553 
       
  2554 bool Parser::parseTerm(Value *value)
       
  2555 {
       
  2556     QString str = lexem();
       
  2557     bool haveUnary = false;
       
  2558     if (lookup() == PLUS || lookup() == MINUS) {
       
  2559         haveUnary = true;
       
  2560         if (!hasNext()) return false;
       
  2561         next();
       
  2562         str += lexem();
       
  2563     }
       
  2564 
       
  2565     value->variant = str;
       
  2566     value->type = QCss::Value::String;
       
  2567     switch (lookup()) {
       
  2568         case NUMBER:
       
  2569             value->type = Value::Number;
       
  2570             value->variant.convert(QVariant::Double);
       
  2571             break;
       
  2572         case PERCENTAGE:
       
  2573             value->type = Value::Percentage;
       
  2574             str.chop(1); // strip off %
       
  2575             value->variant = str;
       
  2576             break;
       
  2577         case LENGTH:
       
  2578             value->type = Value::Length;
       
  2579             break;
       
  2580 
       
  2581         case STRING:
       
  2582             if (haveUnary) return false;
       
  2583             value->type = Value::String;
       
  2584             str.chop(1);
       
  2585             str.remove(0, 1);
       
  2586             value->variant = str;
       
  2587             break;
       
  2588         case IDENT: {
       
  2589             if (haveUnary) return false;
       
  2590             value->type = Value::Identifier;
       
  2591             const int theid = findKnownValue(str, values, NumKnownValues);
       
  2592             if (theid != 0) {
       
  2593                 value->type = Value::KnownIdentifier;
       
  2594                 value->variant = theid;
       
  2595             }
       
  2596             break;
       
  2597         }
       
  2598         default: {
       
  2599             if (haveUnary) return false;
       
  2600             prev();
       
  2601             if (testHexColor()) {
       
  2602                 QColor col;
       
  2603                 if (!parseHexColor(&col)) return false;
       
  2604                 value->type = Value::Color;
       
  2605                 value->variant = col;
       
  2606             } else if (testFunction()) {
       
  2607                 QString name, args;
       
  2608                 if (!parseFunction(&name, &args)) return false;
       
  2609                 if (name == QLatin1String("url")) {
       
  2610                     value->type = Value::Uri;
       
  2611                     removeOptionalQuotes(&args);
       
  2612                     if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
       
  2613                         args.prepend(sourcePath);
       
  2614                     }
       
  2615                     value->variant = args;
       
  2616                 } else {
       
  2617                     value->type = Value::Function;
       
  2618                     value->variant = QStringList() << name << args;
       
  2619                 }
       
  2620             } else {
       
  2621                 return recordError();
       
  2622             }
       
  2623             return true;
       
  2624         }
       
  2625     }
       
  2626     skipSpace();
       
  2627     return true;
       
  2628 }
       
  2629 
       
  2630 bool Parser::parseFunction(QString *name, QString *args)
       
  2631 {
       
  2632     *name = lexem();
       
  2633     name->chop(1);
       
  2634     skipSpace();
       
  2635     const int start = index;
       
  2636     if (!until(RPAREN)) return false;
       
  2637     for (int i = start; i < index - 1; ++i)
       
  2638         args->append(symbols.at(i).lexem());
       
  2639     /*
       
  2640     if (!nextExpr(&arguments)) return false;
       
  2641     if (!next(RPAREN)) return false;
       
  2642     */
       
  2643     skipSpace();
       
  2644     return true;
       
  2645 }
       
  2646 
       
  2647 bool Parser::parseHexColor(QColor *col)
       
  2648 {
       
  2649     col->setNamedColor(lexem());
       
  2650     if (!col->isValid()) {
       
  2651         qWarning("QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
       
  2652         return false;
       
  2653     }
       
  2654     skipSpace();
       
  2655     return true;
       
  2656 }
       
  2657 
       
  2658 bool Parser::testAndParseUri(QString *uri)
       
  2659 {
       
  2660     const int rewind = index;
       
  2661     if (!testFunction()) return false;
       
  2662 
       
  2663     QString name, args;
       
  2664     if (!parseFunction(&name, &args)) {
       
  2665         index = rewind;
       
  2666         return false;
       
  2667     }
       
  2668     if (name.toLower() != QLatin1String("url")) {
       
  2669         index = rewind;
       
  2670         return false;
       
  2671     }
       
  2672     *uri = args;
       
  2673     removeOptionalQuotes(uri);
       
  2674     return true;
       
  2675 }
       
  2676 
       
  2677 bool Parser::testSimpleSelector()
       
  2678 {
       
  2679     return testElementName()
       
  2680            || (test(HASH))
       
  2681            || testClass()
       
  2682            || testAttrib()
       
  2683            || testPseudo();
       
  2684 }
       
  2685 
       
  2686 bool Parser::next(QCss::TokenType t)
       
  2687 {
       
  2688     if (hasNext() && next() == t)
       
  2689         return true;
       
  2690     return recordError();
       
  2691 }
       
  2692 
       
  2693 bool Parser::test(QCss::TokenType t)
       
  2694 {
       
  2695     if (index >= symbols.count())
       
  2696         return false;
       
  2697     if (symbols.at(index).token == t) {
       
  2698         ++index;
       
  2699         return true;
       
  2700     }
       
  2701     return false;
       
  2702 }
       
  2703 
       
  2704 QString Parser::unquotedLexem() const
       
  2705 {
       
  2706     QString s = lexem();
       
  2707     if (lookup() == STRING) {
       
  2708         s.chop(1);
       
  2709         s.remove(0, 1);
       
  2710     }
       
  2711     return s;
       
  2712 }
       
  2713 
       
  2714 QString Parser::lexemUntil(QCss::TokenType t)
       
  2715 {
       
  2716     QString lexem;
       
  2717     while (hasNext() && next() != t)
       
  2718         lexem += symbol().lexem();
       
  2719     return lexem;
       
  2720 }
       
  2721 
       
  2722 bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
       
  2723 {
       
  2724     int braceCount = 0;
       
  2725     int brackCount = 0;
       
  2726     int parenCount = 0;
       
  2727     if (index) {
       
  2728         switch(symbols.at(index-1).token) {
       
  2729         case LBRACE: ++braceCount; break;
       
  2730         case LBRACKET: ++brackCount; break;
       
  2731         case FUNCTION:
       
  2732         case LPAREN: ++parenCount; break;
       
  2733         default: ;
       
  2734         }
       
  2735     }
       
  2736     while (index < symbols.size()) {
       
  2737         QCss::TokenType t = symbols.at(index++).token;
       
  2738         switch (t) {
       
  2739         case LBRACE: ++braceCount; break;
       
  2740         case RBRACE: --braceCount; break;
       
  2741         case LBRACKET: ++brackCount; break;
       
  2742         case RBRACKET: --brackCount; break;
       
  2743         case FUNCTION:
       
  2744         case LPAREN: ++parenCount; break;
       
  2745         case RPAREN: --parenCount; break;
       
  2746         default: break;
       
  2747         }
       
  2748         if ((t == target || (target2 != NONE && t == target2))
       
  2749             && braceCount <= 0
       
  2750             && brackCount <= 0
       
  2751             && parenCount <= 0)
       
  2752             return true;
       
  2753 
       
  2754         if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
       
  2755             --index;
       
  2756             break;
       
  2757         }
       
  2758     }
       
  2759     return false;
       
  2760 }
       
  2761 
       
  2762 bool Parser::testTokenAndEndsWith(QCss::TokenType t, const QLatin1String &str)
       
  2763 {
       
  2764     if (!test(t)) return false;
       
  2765     if (!lexem().endsWith(str, Qt::CaseInsensitive)) {
       
  2766         prev();
       
  2767         return false;
       
  2768     }
       
  2769     return true;
       
  2770 }
       
  2771 
       
  2772 QT_END_NAMESPACE
       
  2773 #endif // QT_NO_CSSPARSER