src/gui/text/qcssparser.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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     for (int i = start; i < values.count(); ++i) {
       
  1133         const Value &v = values.at(i);
       
  1134         if (v.type == Value::TermOperatorComma) {
       
  1135             family += QLatin1Char(',');
       
  1136             continue;
       
  1137         }
       
  1138         const QString str = v.variant.toString();
       
  1139         if (str.isEmpty())
       
  1140             break;
       
  1141         family += str;
       
  1142         family += QLatin1Char(' ');
       
  1143     }
       
  1144     family = family.simplified();
       
  1145     if (family.isEmpty())
       
  1146         return false;
       
  1147     font->setFamily(family);
       
  1148     return true;
       
  1149 }
       
  1150 
       
  1151 static void setTextDecorationFromValues(const QVector<Value> &values, QFont *font)
       
  1152 {
       
  1153     for (int i = 0; i < values.count(); ++i) {
       
  1154         if (values.at(i).type != Value::KnownIdentifier)
       
  1155             continue;
       
  1156         switch (values.at(i).variant.toInt()) {
       
  1157             case Value_Underline: font->setUnderline(true); break;
       
  1158             case Value_Overline: font->setOverline(true); break;
       
  1159             case Value_LineThrough: font->setStrikeOut(true); break;
       
  1160             case Value_None:
       
  1161                 font->setUnderline(false);
       
  1162                 font->setOverline(false);
       
  1163                 font->setStrikeOut(false);
       
  1164                 break;
       
  1165             default: break;
       
  1166         }
       
  1167     }
       
  1168 }
       
  1169 
       
  1170 static void parseShorthandFontProperty(const QVector<Value> &values, QFont *font, int *fontSizeAdjustment)
       
  1171 {
       
  1172     font->setStyle(QFont::StyleNormal);
       
  1173     font->setWeight(QFont::Normal);
       
  1174     *fontSizeAdjustment = -255;
       
  1175 
       
  1176     int i = 0;
       
  1177     while (i < values.count()) {
       
  1178         if (setFontStyleFromValue(values.at(i), font)
       
  1179             || setFontWeightFromValue(values.at(i), font))
       
  1180             ++i;
       
  1181         else
       
  1182             break;
       
  1183     }
       
  1184 
       
  1185     if (i < values.count()) {
       
  1186         setFontSizeFromValue(values.at(i), font, fontSizeAdjustment);
       
  1187         ++i;
       
  1188     }
       
  1189 
       
  1190     if (i < values.count()) {
       
  1191         setFontFamilyFromValues(values, font, i);
       
  1192     }
       
  1193 }
       
  1194 
       
  1195 static void setFontVariantFromValue(const Value &value, QFont *font)
       
  1196 {
       
  1197     if (value.type == Value::KnownIdentifier) {
       
  1198         switch (value.variant.toInt()) {
       
  1199             case Value_Normal: font->setCapitalization(QFont::MixedCase); break;
       
  1200             case Value_SmallCaps: font->setCapitalization(QFont::SmallCaps); break;
       
  1201             default: break;
       
  1202         }
       
  1203     }
       
  1204 }
       
  1205 
       
  1206 static void setTextTransformFromValue(const Value &value, QFont *font)
       
  1207 {
       
  1208     if (value.type == Value::KnownIdentifier) {
       
  1209         switch (value.variant.toInt()) {
       
  1210             case Value_None: font->setCapitalization(QFont::MixedCase); break;
       
  1211             case Value_Uppercase: font->setCapitalization(QFont::AllUppercase); break;
       
  1212             case Value_Lowercase: font->setCapitalization(QFont::AllLowercase); break;
       
  1213             default: break;
       
  1214         }
       
  1215     }
       
  1216 }
       
  1217 
       
  1218 bool ValueExtractor::extractFont(QFont *font, int *fontSizeAdjustment)
       
  1219 {
       
  1220     if (fontExtracted) {
       
  1221         *font = f;
       
  1222         *fontSizeAdjustment = adjustment;
       
  1223         return fontExtracted == 1;
       
  1224     }
       
  1225 
       
  1226     bool hit = false;
       
  1227     for (int i = 0; i < declarations.count(); ++i) {
       
  1228         const Declaration &decl = declarations.at(i);
       
  1229         if (decl.d->values.isEmpty())
       
  1230             continue;
       
  1231         const Value &val = decl.d->values.at(0);
       
  1232         switch (decl.d->propertyId) {
       
  1233             case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment); break;
       
  1234             case FontStyle: setFontStyleFromValue(val, font); break;
       
  1235             case FontWeight: setFontWeightFromValue(val, font); break;
       
  1236             case FontFamily: setFontFamilyFromValues(decl.d->values, font); break;
       
  1237             case TextDecoration: setTextDecorationFromValues(decl.d->values, font); break;
       
  1238             case Font: parseShorthandFontProperty(decl.d->values, font, fontSizeAdjustment); break;
       
  1239             case FontVariant: setFontVariantFromValue(val, font); break;
       
  1240             case TextTransform: setTextTransformFromValue(val, font); break;
       
  1241             default: continue;
       
  1242         }
       
  1243         hit = true;
       
  1244     }
       
  1245 
       
  1246     f = *font;
       
  1247     adjustment = *fontSizeAdjustment;
       
  1248     fontExtracted = hit ? 1 : 2;
       
  1249     return hit;
       
  1250 }
       
  1251 
       
  1252 bool ValueExtractor::extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg)
       
  1253 {
       
  1254     bool hit = false;
       
  1255     for (int i = 0; i < declarations.count(); ++i) {
       
  1256         const Declaration &decl = declarations.at(i);
       
  1257         switch (decl.d->propertyId) {
       
  1258         case Color: *fg = decl.brushValue(pal); break;
       
  1259         case QtSelectionForeground: *sfg = decl.brushValue(pal); break;
       
  1260         case QtSelectionBackground: *sbg = decl.brushValue(pal); break;
       
  1261         case QtAlternateBackground: *abg = decl.brushValue(pal); break;
       
  1262         default: continue;
       
  1263         }
       
  1264         hit = true;
       
  1265     }
       
  1266     return hit;
       
  1267 }
       
  1268 
       
  1269 void ValueExtractor::extractFont()
       
  1270 {
       
  1271     if (fontExtracted)
       
  1272         return;
       
  1273     int dummy = -255;
       
  1274     extractFont(&f, &dummy);
       
  1275 }
       
  1276 
       
  1277 bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size)
       
  1278 {
       
  1279     bool hit = false;
       
  1280     for (int i = 0; i < declarations.count(); ++i) {
       
  1281         const Declaration &decl = declarations.at(i);
       
  1282         switch (decl.d->propertyId) {
       
  1283         case QtImage:
       
  1284             *icon = decl.iconValue();
       
  1285             if (decl.d->values.count() > 0 && decl.d->values.at(0).type == Value::Uri) {
       
  1286                 // try to pull just the size from the image...
       
  1287                 QImageReader imageReader(decl.d->values.at(0).variant.toString());
       
  1288                 if ((*size = imageReader.size()).isNull()) {
       
  1289                     // but we'll have to load the whole image if the
       
  1290                     // format doesn't support just reading the size
       
  1291                     *size = imageReader.read().size();
       
  1292                 }
       
  1293             }
       
  1294             break;
       
  1295         case QtImageAlignment: *a = decl.alignmentValue();  break;
       
  1296         default: continue;
       
  1297         }
       
  1298         hit = true;
       
  1299     }
       
  1300     return hit;
       
  1301 }
       
  1302 
       
  1303 ///////////////////////////////////////////////////////////////////////////////
       
  1304 // Declaration
       
  1305 QColor Declaration::colorValue(const QPalette &pal) const
       
  1306 {
       
  1307     if (d->values.count() != 1)
       
  1308         return QColor();
       
  1309 
       
  1310     if (d->parsed.isValid()) {
       
  1311         if (d->parsed.type() == QVariant::Color)
       
  1312             return qvariant_cast<QColor>(d->parsed);
       
  1313         if (d->parsed.type() == QVariant::Int)
       
  1314             return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
       
  1315     }
       
  1316 
       
  1317     ColorData color = parseColorValue(d->values.at(0));
       
  1318     if(color.type == ColorData::Role) {
       
  1319         d->parsed = qVariantFromValue<int>(color.role);
       
  1320         return pal.color((QPalette::ColorRole)(color.role));
       
  1321     } else {
       
  1322         d->parsed = qVariantFromValue<QColor>(color.color);
       
  1323         return color.color;
       
  1324     }
       
  1325 }
       
  1326 
       
  1327 QBrush Declaration::brushValue(const QPalette &pal) const
       
  1328 {
       
  1329     if (d->values.count() != 1)
       
  1330         return QBrush();
       
  1331 
       
  1332     if (d->parsed.isValid()) {
       
  1333         if (d->parsed.type() == QVariant::Brush)
       
  1334             return qvariant_cast<QBrush>(d->parsed);
       
  1335         if (d->parsed.type() == QVariant::Int)
       
  1336             return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
       
  1337     }
       
  1338 
       
  1339     BrushData data = parseBrushValue(d->values.at(0), pal);
       
  1340 
       
  1341     if(data.type == BrushData::Role) {
       
  1342         d->parsed = qVariantFromValue<int>(data.role);
       
  1343         return pal.color((QPalette::ColorRole)(data.role));
       
  1344     } else {
       
  1345         if (data.type != BrushData::DependsOnThePalette)
       
  1346             d->parsed = qVariantFromValue<QBrush>(data.brush);
       
  1347         return data.brush;
       
  1348     }
       
  1349 }
       
  1350 
       
  1351 void Declaration::brushValues(QBrush *c, const QPalette &pal) const
       
  1352 {
       
  1353     int needParse = 0x1f; // bits 0..3 say if we should parse the corresponding value.
       
  1354                           // the bit 4 say we need to update d->parsed
       
  1355     int i = 0;
       
  1356     if (d->parsed.isValid()) {
       
  1357         needParse = 0;
       
  1358         QList<QVariant> v = d->parsed.toList();
       
  1359         for (i = 0; i < qMin(v.count(), 4); i++) {
       
  1360             if (v.at(i).type() == QVariant::Brush) {
       
  1361                 c[i] = qvariant_cast<QBrush>(v.at(i));
       
  1362             } else if (v.at(i).type() == QVariant::Int) {
       
  1363                 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
       
  1364             } else {
       
  1365                 needParse |= (1<<i);
       
  1366             }
       
  1367         }
       
  1368     }
       
  1369     if (needParse != 0) {
       
  1370         QList<QVariant> v;
       
  1371         for (i = 0; i < qMin(d->values.count(), 4); i++) {
       
  1372             if (!(needParse & (1<<i)))
       
  1373                 continue;
       
  1374             BrushData data = parseBrushValue(d->values.at(i), pal);
       
  1375             if(data.type == BrushData::Role) {
       
  1376                 v += qVariantFromValue<int>(data.role);
       
  1377                 c[i] = pal.color((QPalette::ColorRole)(data.role));
       
  1378             } else {
       
  1379                 if (data.type != BrushData::DependsOnThePalette) {
       
  1380                     v += qVariantFromValue<QBrush>(data.brush);
       
  1381                 } else {
       
  1382                     v += QVariant();
       
  1383                 }
       
  1384                 c[i] = data.brush;
       
  1385             }
       
  1386         }
       
  1387         if (needParse & 0x10)
       
  1388             d->parsed = v;
       
  1389     }
       
  1390     if (i == 0) c[0] = c[1] = c[2] = c[3] = QBrush();
       
  1391     else if (i == 1) c[3] = c[2] = c[1] = c[0];
       
  1392     else if (i == 2) c[2] = c[0], c[3] = c[1];
       
  1393     else if (i == 3) c[3] = c[1];
       
  1394 }
       
  1395 
       
  1396 bool Declaration::realValue(qreal *real, const char *unit) const
       
  1397 {
       
  1398     if (d->values.count() != 1)
       
  1399         return false;
       
  1400     const Value &v = d->values.at(0);
       
  1401     if (unit && v.type != Value::Length)
       
  1402         return false;
       
  1403     QString s = v.variant.toString();
       
  1404     if (unit) {
       
  1405         if (!s.endsWith(QLatin1String(unit), Qt::CaseInsensitive))
       
  1406             return false;
       
  1407         s.chop(qstrlen(unit));
       
  1408     }
       
  1409     bool ok = false;
       
  1410     qreal val = s.toDouble(&ok);
       
  1411     if (ok)
       
  1412         *real = val;
       
  1413     return ok;
       
  1414 }
       
  1415 
       
  1416 static bool intValueHelper(const Value &v, int *i, const char *unit)
       
  1417 {
       
  1418     if (unit && v.type != Value::Length)
       
  1419         return false;
       
  1420     QString s = v.variant.toString();
       
  1421     if (unit) {
       
  1422         if (!s.endsWith(QLatin1String(unit), Qt::CaseInsensitive))
       
  1423             return false;
       
  1424         s.chop(qstrlen(unit));
       
  1425     }
       
  1426     bool ok = false;
       
  1427     int val = s.toInt(&ok);
       
  1428     if (ok)
       
  1429         *i = val;
       
  1430     return ok;
       
  1431 }
       
  1432 
       
  1433 bool Declaration::intValue(int *i, const char *unit) const
       
  1434 {
       
  1435     if (d->values.count() != 1)
       
  1436         return false;
       
  1437     return intValueHelper(d->values.at(0), i, unit);
       
  1438 }
       
  1439 
       
  1440 QSize Declaration::sizeValue() const
       
  1441 {
       
  1442     if (d->parsed.isValid())
       
  1443         return qvariant_cast<QSize>(d->parsed);
       
  1444 
       
  1445     int x[2] = { 0, 0 };
       
  1446     if (d->values.count() > 0)
       
  1447         intValueHelper(d->values.at(0), &x[0], "px");
       
  1448     if (d->values.count() > 1)
       
  1449         intValueHelper(d->values.at(1), &x[1], "px");
       
  1450     else
       
  1451         x[1] = x[0];
       
  1452     QSize size(x[0], x[1]);
       
  1453     d->parsed = qVariantFromValue<QSize>(size);
       
  1454     return size;
       
  1455 }
       
  1456 
       
  1457 QRect Declaration::rectValue() const
       
  1458 {
       
  1459     if (d->values.count() != 1)
       
  1460         return QRect();
       
  1461     
       
  1462     if (d->parsed.isValid())
       
  1463         return qvariant_cast<QRect>(d->parsed);
       
  1464 
       
  1465     const Value &v = d->values.at(0);
       
  1466     if (v.type != Value::Function)
       
  1467         return QRect();
       
  1468     QStringList func = v.variant.toStringList();
       
  1469     if (func.count() != 2 || func.at(0).compare(QLatin1String("rect")) != 0)
       
  1470         return QRect();
       
  1471     QStringList args = func[1].split(QLatin1Char(' '), QString::SkipEmptyParts);
       
  1472     if (args.count() != 4)
       
  1473         return QRect();
       
  1474     QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
       
  1475     d->parsed = qVariantFromValue<QRect>(rect);
       
  1476     return rect;
       
  1477 }
       
  1478 
       
  1479 void Declaration::colorValues(QColor *c, const QPalette &pal) const
       
  1480 {
       
  1481     int i;
       
  1482     if (d->parsed.isValid()) {
       
  1483         QList<QVariant> v = d->parsed.toList();
       
  1484         for (i = 0; i < qMin(d->values.count(), 4); i++) {
       
  1485             if (v.at(i).type() == QVariant::Color) {
       
  1486                 c[i] = qvariant_cast<QColor>(v.at(i));
       
  1487             } else {
       
  1488                 c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
       
  1489             }
       
  1490         }
       
  1491     } else {
       
  1492         QList<QVariant> v;
       
  1493         for (i = 0; i < qMin(d->values.count(), 4); i++) {
       
  1494             ColorData color = parseColorValue(d->values.at(i));
       
  1495             if(color.type == ColorData::Role) {
       
  1496                 v += qVariantFromValue<int>(color.role);
       
  1497                 c[i] = pal.color((QPalette::ColorRole)(color.role));
       
  1498             } else {
       
  1499                 v += qVariantFromValue<QColor>(color.color);
       
  1500                 c[i] = color.color;
       
  1501             }
       
  1502         }
       
  1503         d->parsed = v;
       
  1504     }
       
  1505 
       
  1506     if (i == 0) c[0] = c[1] = c[2] = c[3] = QColor();
       
  1507     else if (i == 1) c[3] = c[2] = c[1] = c[0];
       
  1508     else if (i == 2) c[2] = c[0], c[3] = c[1];
       
  1509     else if (i == 3) c[3] = c[1];
       
  1510 }
       
  1511 
       
  1512 BorderStyle Declaration::styleValue() const
       
  1513 {
       
  1514     if (d->values.count() != 1)
       
  1515         return BorderStyle_None;
       
  1516     return parseStyleValue(d->values.at(0));
       
  1517 }
       
  1518 
       
  1519 void Declaration::styleValues(BorderStyle *s) const
       
  1520 {
       
  1521     int i;
       
  1522     for (i = 0; i < qMin(d->values.count(), 4); i++)
       
  1523         s[i] = parseStyleValue(d->values.at(i));
       
  1524     if (i == 0) s[0] = s[1] = s[2] = s[3] = BorderStyle_None;
       
  1525     else if (i == 1) s[3] = s[2] = s[1] = s[0];
       
  1526     else if (i == 2) s[2] = s[0], s[3] = s[1];
       
  1527     else if (i == 3) s[3] = s[1];
       
  1528 }
       
  1529 
       
  1530 Repeat Declaration::repeatValue() const
       
  1531 {
       
  1532     if (d->parsed.isValid())
       
  1533         return static_cast<Repeat>(d->parsed.toInt());
       
  1534     if (d->values.count() != 1)
       
  1535         return Repeat_Unknown;
       
  1536     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1537                    repeats, NumKnownRepeats);
       
  1538     d->parsed = v;
       
  1539     return static_cast<Repeat>(v);
       
  1540 }
       
  1541 
       
  1542 Origin Declaration::originValue() const
       
  1543 {
       
  1544     if (d->parsed.isValid())
       
  1545         return static_cast<Origin>(d->parsed.toInt());
       
  1546     if (d->values.count() != 1)
       
  1547         return Origin_Unknown;
       
  1548     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1549                                origins, NumKnownOrigins);
       
  1550     d->parsed = v;
       
  1551     return static_cast<Origin>(v);
       
  1552 }
       
  1553 
       
  1554 PositionMode Declaration::positionValue() const
       
  1555 {
       
  1556     if (d->parsed.isValid())
       
  1557         return static_cast<PositionMode>(d->parsed.toInt());
       
  1558     if (d->values.count() != 1)
       
  1559         return PositionMode_Unknown;
       
  1560     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1561                            positions, NumKnownPositionModes);
       
  1562     d->parsed = v;
       
  1563     return static_cast<PositionMode>(v);
       
  1564 }
       
  1565 
       
  1566 Attachment Declaration::attachmentValue() const
       
  1567 {
       
  1568     if (d->parsed.isValid())
       
  1569         return static_cast<Attachment>(d->parsed.toInt());
       
  1570     if (d->values.count() != 1)
       
  1571         return Attachment_Unknown;
       
  1572     int v = findKnownValue(d->values.at(0).variant.toString(),
       
  1573                            attachments, NumKnownAttachments);
       
  1574     d->parsed = v;
       
  1575     return static_cast<Attachment>(v);
       
  1576 }
       
  1577 
       
  1578 int Declaration::styleFeaturesValue() const
       
  1579 {
       
  1580     Q_ASSERT(d->propertyId == QtStyleFeatures);
       
  1581     if (d->parsed.isValid())
       
  1582         return d->parsed.toInt();
       
  1583     int features = StyleFeature_None;
       
  1584     for (int i = 0; i < d->values.count(); i++) {
       
  1585         features |= static_cast<int>(findKnownValue(d->values.value(i).variant.toString(),
       
  1586                                      styleFeatures, NumKnownStyleFeatures));
       
  1587     }
       
  1588     d->parsed = features;
       
  1589     return features;
       
  1590 }
       
  1591 
       
  1592 QString Declaration::uriValue() const
       
  1593 {
       
  1594     if (d->values.isEmpty() || d->values.at(0).type != Value::Uri)
       
  1595         return QString();
       
  1596     return d->values.at(0).variant.toString();
       
  1597 }
       
  1598 
       
  1599 Qt::Alignment Declaration::alignmentValue() const
       
  1600 {
       
  1601     if (d->parsed.isValid())
       
  1602         return Qt::Alignment(d->parsed.toInt());
       
  1603     if (d->values.isEmpty() || d->values.count() > 2)
       
  1604         return Qt::AlignLeft | Qt::AlignTop;
       
  1605 
       
  1606     Qt::Alignment v = parseAlignment(d->values.constData(), d->values.count());
       
  1607     d->parsed = int(v);
       
  1608     return v;
       
  1609 }
       
  1610 
       
  1611 void Declaration::borderImageValue(QString *image, int *cuts,
       
  1612                                    TileMode *h, TileMode *v) const
       
  1613 {
       
  1614     *image = uriValue();
       
  1615     for (int i = 0; i < 4; i++)
       
  1616         cuts[i] = -1;
       
  1617     *h = *v = TileMode_Stretch;
       
  1618 
       
  1619     if (d->values.count() < 2)
       
  1620         return;
       
  1621 
       
  1622     if (d->values.at(1).type == Value::Number) { // cuts!
       
  1623         int i;
       
  1624         for (i = 0; i < qMin(d->values.count()-1, 4); i++) {
       
  1625             const Value& v = d->values.at(i+1);
       
  1626             if (v.type != Value::Number)
       
  1627                 break;
       
  1628             cuts[i] = v.variant.toString().toInt();
       
  1629         }
       
  1630         if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
       
  1631         else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];
       
  1632         else if (i == 2) cuts[2] = cuts[0], cuts[3] = cuts[1];
       
  1633         else if (i == 3) cuts[3] = cuts[1];
       
  1634     }
       
  1635 
       
  1636     if (d->values.last().type == Value::Identifier) {
       
  1637         *v = static_cast<TileMode>(findKnownValue(d->values.last().variant.toString(),
       
  1638                                       tileModes, NumKnownTileModes));
       
  1639     }
       
  1640     if (d->values[d->values.count() - 2].type == Value::Identifier) {
       
  1641         *h = static_cast<TileMode>
       
  1642                 (findKnownValue(d->values[d->values.count()-2].variant.toString(),
       
  1643                                         tileModes, NumKnownTileModes));
       
  1644     } else
       
  1645         *h = *v;
       
  1646 }
       
  1647 
       
  1648 QIcon Declaration::iconValue() const
       
  1649 {
       
  1650     if (d->parsed.isValid())
       
  1651         return qvariant_cast<QIcon>(d->parsed);
       
  1652 
       
  1653     QIcon icon;
       
  1654     for (int i = 0; i < d->values.count();) {
       
  1655         const Value &value = d->values.at(i++);
       
  1656         if (value.type != Value::Uri)
       
  1657             break;
       
  1658         QString uri = value.variant.toString();
       
  1659         QIcon::Mode mode = QIcon::Normal;
       
  1660         QIcon::State state = QIcon::Off;
       
  1661         for (int j = 0; j < 2; j++) {
       
  1662             if (i != d->values.count() && d->values.at(i).type == Value::KnownIdentifier) {
       
  1663                 switch (d->values.at(i).variant.toInt()) {
       
  1664                 case Value_Disabled: mode = QIcon::Disabled; break;
       
  1665                 case Value_Active: mode = QIcon::Active; break;
       
  1666                 case Value_Selected: mode = QIcon::Selected; break;
       
  1667                 case Value_Normal: mode = QIcon::Normal; break;
       
  1668                 case Value_On: state = QIcon::On; break;
       
  1669                 case Value_Off: state = QIcon::Off; break;
       
  1670                 default: break;
       
  1671                 }
       
  1672                 ++i;
       
  1673             } else {
       
  1674                 break;
       
  1675             }
       
  1676         }
       
  1677 
       
  1678         // QIcon is soo broken
       
  1679         if (icon.isNull())
       
  1680             icon = QIcon(uri);
       
  1681         else
       
  1682             icon.addPixmap(uri, mode, state);
       
  1683 
       
  1684         if (i == d->values.count())
       
  1685             break;
       
  1686 
       
  1687         if (d->values.at(i).type == Value::TermOperatorComma)
       
  1688             i++;
       
  1689     }
       
  1690 
       
  1691     d->parsed = qVariantFromValue<QIcon>(icon);
       
  1692     return icon;
       
  1693 }
       
  1694 
       
  1695 ///////////////////////////////////////////////////////////////////////////////
       
  1696 // Selector
       
  1697 int Selector::specificity() const
       
  1698 {
       
  1699     int val = 0;
       
  1700     for (int i = 0; i < basicSelectors.count(); ++i) {
       
  1701         const BasicSelector &sel = basicSelectors.at(i);
       
  1702         if (!sel.elementName.isEmpty())
       
  1703             val += 1;
       
  1704 
       
  1705         val += (sel.pseudos.count() + sel.attributeSelectors.count()) * 0x10;
       
  1706         val += sel.ids.count() * 0x100;
       
  1707     }
       
  1708     return val;
       
  1709 }
       
  1710 
       
  1711 QString Selector::pseudoElement() const
       
  1712 {
       
  1713     const BasicSelector& bs = basicSelectors.last();
       
  1714     if (!bs.pseudos.isEmpty() && bs.pseudos.at(0).type == PseudoClass_Unknown)
       
  1715         return bs.pseudos.at(0).name;
       
  1716     return QString();
       
  1717 }
       
  1718 
       
  1719 quint64 Selector::pseudoClass(quint64 *negated) const
       
  1720 {
       
  1721     const BasicSelector& bs = basicSelectors.last();
       
  1722     if (bs.pseudos.isEmpty())
       
  1723         return PseudoClass_Unspecified;
       
  1724     quint64 pc = PseudoClass_Unknown;
       
  1725     for (int i = !pseudoElement().isEmpty(); i < bs.pseudos.count(); i++) {
       
  1726         const Pseudo &pseudo = bs.pseudos.at(i);
       
  1727         if (pseudo.type == PseudoClass_Unknown)
       
  1728             return PseudoClass_Unknown;
       
  1729         if (!pseudo.negated)
       
  1730             pc |= pseudo.type;
       
  1731         else if (negated)
       
  1732             *negated |= pseudo.type;
       
  1733     }
       
  1734     return pc;
       
  1735 }
       
  1736 
       
  1737 ///////////////////////////////////////////////////////////////////////////////
       
  1738 // StyleSheet
       
  1739 void StyleSheet::buildIndexes(Qt::CaseSensitivity nameCaseSensitivity)
       
  1740 {
       
  1741     QVector<StyleRule> universals;
       
  1742     for (int i = 0; i < styleRules.count(); ++i) {
       
  1743         const StyleRule &rule = styleRules.at(i);
       
  1744         QVector<Selector> universalsSelectors;
       
  1745         for (int j = 0; j < rule.selectors.count(); ++j) {
       
  1746             const Selector& selector = rule.selectors.at(j);
       
  1747 
       
  1748             if (selector.basicSelectors.isEmpty())
       
  1749                 continue;
       
  1750 
       
  1751             if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
       
  1752                 if (selector.basicSelectors.count() != 1)
       
  1753                     continue;
       
  1754             } else if (selector.basicSelectors.count() <= 1) {
       
  1755                 continue;
       
  1756             }
       
  1757 
       
  1758             const BasicSelector &sel = selector.basicSelectors.at(selector.basicSelectors.count() - 1);
       
  1759 
       
  1760             if (!sel.ids.isEmpty()) {
       
  1761                 StyleRule nr;
       
  1762                 nr.selectors += selector;
       
  1763                 nr.declarations = rule.declarations;
       
  1764                 nr.order = i;
       
  1765                 idIndex.insert(sel.ids.at(0), nr);
       
  1766             } else if (!sel.elementName.isEmpty()) {
       
  1767                 StyleRule nr;
       
  1768                 nr.selectors += selector;
       
  1769                 nr.declarations = rule.declarations;
       
  1770                 nr.order = i;
       
  1771                 QString name = sel.elementName;
       
  1772                 if (nameCaseSensitivity == Qt::CaseInsensitive)
       
  1773                     name=name.toLower();
       
  1774                 nameIndex.insert(name, nr);
       
  1775             } else {
       
  1776                 universalsSelectors += selector;
       
  1777             }
       
  1778         }
       
  1779         if (!universalsSelectors.isEmpty()) {
       
  1780             StyleRule nr;
       
  1781             nr.selectors = universalsSelectors;
       
  1782             nr.declarations = rule.declarations;
       
  1783             nr.order = i;
       
  1784             universals << nr;
       
  1785         }
       
  1786     }
       
  1787     styleRules = universals;
       
  1788 }
       
  1789 
       
  1790 ///////////////////////////////////////////////////////////////////////////////
       
  1791 // StyleSelector
       
  1792 StyleSelector::~StyleSelector()
       
  1793 {
       
  1794 }
       
  1795 
       
  1796 bool StyleSelector::nodeNameEquals(NodePtr node, const QString& nodeName) const
       
  1797 {
       
  1798     return nodeNames(node).contains(nodeName, nameCaseSensitivity);
       
  1799 }
       
  1800 
       
  1801 QStringList StyleSelector::nodeIds(NodePtr node) const
       
  1802 {
       
  1803     return QStringList(attribute(node, QLatin1String("id")));
       
  1804 }
       
  1805 
       
  1806 bool StyleSelector::selectorMatches(const Selector &selector, NodePtr node)
       
  1807 {
       
  1808     if (selector.basicSelectors.isEmpty())
       
  1809         return false;
       
  1810 
       
  1811     if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
       
  1812         if (selector.basicSelectors.count() != 1)
       
  1813             return false;
       
  1814         return basicSelectorMatches(selector.basicSelectors.at(0), node);
       
  1815     }
       
  1816     if (selector.basicSelectors.count() <= 1)
       
  1817         return false;
       
  1818 
       
  1819     int i = selector.basicSelectors.count() - 1;
       
  1820     node = duplicateNode(node);
       
  1821     bool match = true;
       
  1822 
       
  1823     BasicSelector sel = selector.basicSelectors.at(i);
       
  1824     do {
       
  1825         match = basicSelectorMatches(sel, node);
       
  1826         if (!match) {
       
  1827             if (sel.relationToNext == BasicSelector::MatchNextSelectorIfParent
       
  1828                 || i == selector.basicSelectors.count() - 1) // first element must always match!
       
  1829                 break;
       
  1830         }
       
  1831 
       
  1832         if (match || sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor)
       
  1833             --i;
       
  1834 
       
  1835         if (i < 0)
       
  1836             break;
       
  1837 
       
  1838         sel = selector.basicSelectors.at(i);
       
  1839         if (sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
       
  1840             || sel.relationToNext == BasicSelector::MatchNextSelectorIfParent) {
       
  1841 
       
  1842             NodePtr nextParent = parentNode(node);
       
  1843             freeNode(node);
       
  1844             node = nextParent;
       
  1845        } else if (sel.relationToNext == BasicSelector::MatchNextSelectorIfPreceeds) {
       
  1846             NodePtr previousSibling = previousSiblingNode(node);
       
  1847             freeNode(node);
       
  1848             node = previousSibling;
       
  1849        }
       
  1850         if (isNullNode(node)) {
       
  1851             match = false;
       
  1852             break;
       
  1853         }
       
  1854    } while (i >= 0 && (match || sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor));
       
  1855 
       
  1856     freeNode(node);
       
  1857 
       
  1858     return match;
       
  1859 }
       
  1860 
       
  1861 bool StyleSelector::basicSelectorMatches(const BasicSelector &sel, NodePtr node)
       
  1862 {
       
  1863     if (!sel.attributeSelectors.isEmpty()) {
       
  1864         if (!hasAttributes(node))
       
  1865             return false;
       
  1866 
       
  1867         for (int i = 0; i < sel.attributeSelectors.count(); ++i) {
       
  1868             const QCss::AttributeSelector &a = sel.attributeSelectors.at(i);
       
  1869 
       
  1870             const QString attrValue = attribute(node, a.name);
       
  1871             if (attrValue.isNull())
       
  1872                 return false;
       
  1873 
       
  1874             if (a.valueMatchCriterium == QCss::AttributeSelector::MatchContains) {
       
  1875 
       
  1876                 QStringList lst = attrValue.split(QLatin1Char(' '));
       
  1877                 if (!lst.contains(a.value))
       
  1878                     return false;
       
  1879             } else if (
       
  1880                 (a.valueMatchCriterium == QCss::AttributeSelector::MatchEqual
       
  1881                  && attrValue != a.value)
       
  1882                 ||
       
  1883                 (a.valueMatchCriterium == QCss::AttributeSelector::MatchBeginsWith
       
  1884                  && !attrValue.startsWith(a.value))
       
  1885                )
       
  1886                 return false;
       
  1887         }
       
  1888     }
       
  1889 
       
  1890     if (!sel.elementName.isEmpty()
       
  1891         && !nodeNameEquals(node, sel.elementName))
       
  1892             return false;
       
  1893 
       
  1894     if (!sel.ids.isEmpty()
       
  1895         && sel.ids != nodeIds(node))
       
  1896             return false;
       
  1897 
       
  1898     return true;
       
  1899 }
       
  1900 
       
  1901 void StyleSelector::matchRule(NodePtr node, const StyleRule &rule, StyleSheetOrigin origin,
       
  1902                                int depth, QMap<uint, StyleRule> *weightedRules)
       
  1903 {
       
  1904     for (int j = 0; j < rule.selectors.count(); ++j) {
       
  1905         const Selector& selector = rule.selectors.at(j);
       
  1906         if (selectorMatches(selector, node)) {
       
  1907             uint weight = rule.order
       
  1908                         + selector.specificity() *0x100
       
  1909                         + (uint(origin) + depth)*0x100000;
       
  1910             StyleRule newRule = rule;
       
  1911             if(rule.selectors.count() > 1) {
       
  1912                 newRule.selectors.resize(1);
       
  1913                 newRule.selectors[0] = selector;
       
  1914             }
       
  1915             //We might have rules with the same weight if they came from a rule with several selectors
       
  1916             weightedRules->insertMulti(weight, newRule);
       
  1917         }
       
  1918     }
       
  1919 }
       
  1920 
       
  1921 // Returns style rules that are in ascending order of specificity
       
  1922 // Each of the StyleRule returned will contain exactly one Selector
       
  1923 QVector<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
       
  1924 {
       
  1925     QVector<StyleRule> rules;
       
  1926     if (styleSheets.isEmpty())
       
  1927         return rules;
       
  1928 
       
  1929     QMap<uint, StyleRule> weightedRules; // (spec, rule) that will be sorted below
       
  1930     
       
  1931     //prune using indexed stylesheet
       
  1932     for (int sheetIdx = 0; sheetIdx < styleSheets.count(); ++sheetIdx) {
       
  1933         const StyleSheet &styleSheet = styleSheets.at(sheetIdx);
       
  1934         for (int i = 0; i < styleSheet.styleRules.count(); ++i) {
       
  1935             matchRule(node, styleSheet.styleRules.at(i), styleSheet.origin, styleSheet.depth, &weightedRules);
       
  1936         }
       
  1937 
       
  1938         if (!styleSheet.idIndex.isEmpty()) {
       
  1939             QStringList ids = nodeIds(node);
       
  1940             for (int i = 0; i < ids.count(); i++) {
       
  1941                 const QString &key = ids.at(i);
       
  1942                 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.idIndex.constFind(key);
       
  1943                 while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
       
  1944                     matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
       
  1945                     ++it;
       
  1946                 }
       
  1947             }
       
  1948         }
       
  1949         if (!styleSheet.nameIndex.isEmpty()) {
       
  1950             QStringList names = nodeNames(node);
       
  1951             for (int i = 0; i < names.count(); i++) {
       
  1952                 QString name = names.at(i);
       
  1953                 if (nameCaseSensitivity == Qt::CaseInsensitive)
       
  1954                     name = name.toLower();
       
  1955                 QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
       
  1956                 while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
       
  1957                     matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
       
  1958                     ++it;
       
  1959                 }
       
  1960             }
       
  1961         }
       
  1962         if (!medium.isEmpty()) {
       
  1963             for (int i = 0; i < styleSheet.mediaRules.count(); ++i) {
       
  1964                 if (styleSheet.mediaRules.at(i).media.contains(medium, Qt::CaseInsensitive)) {
       
  1965                     for (int j = 0; j < styleSheet.mediaRules.at(i).styleRules.count(); ++j) {
       
  1966                         matchRule(node, styleSheet.mediaRules.at(i).styleRules.at(j), styleSheet.origin,
       
  1967                                styleSheet.depth, &weightedRules);
       
  1968                     }
       
  1969                 }
       
  1970             }
       
  1971         }
       
  1972     }
       
  1973 
       
  1974     rules.reserve(weightedRules.count());
       
  1975     QMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
       
  1976     for ( ; it != weightedRules.constEnd() ; ++it)
       
  1977         rules += *it;
       
  1978 
       
  1979     return rules;
       
  1980 }
       
  1981 
       
  1982 // for qtexthtmlparser which requires just the declarations with Enabled state
       
  1983 // and without pseudo elements
       
  1984 QVector<Declaration> StyleSelector::declarationsForNode(NodePtr node, const char *extraPseudo)
       
  1985 {
       
  1986     QVector<Declaration> decls;
       
  1987     QVector<StyleRule> rules = styleRulesForNode(node);
       
  1988     for (int i = 0; i < rules.count(); i++) {
       
  1989         const Selector& selector = rules.at(i).selectors.at(0);
       
  1990         const QString pseudoElement = selector.pseudoElement();
       
  1991 
       
  1992         if (extraPseudo && pseudoElement == QLatin1String(extraPseudo)) {
       
  1993             decls += rules.at(i).declarations;
       
  1994             continue;
       
  1995         }
       
  1996 
       
  1997         if (!pseudoElement.isEmpty()) // skip rules with pseudo elements
       
  1998             continue;
       
  1999         quint64 pseudoClass = selector.pseudoClass();
       
  2000         if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
       
  2001             decls += rules.at(i).declarations;
       
  2002     }
       
  2003     return decls;
       
  2004 }
       
  2005 
       
  2006 static inline bool isHexDigit(const char c)
       
  2007 {
       
  2008     return (c >= '0' && c <= '9')
       
  2009            || (c >= 'a' && c <= 'f')
       
  2010            || (c >= 'A' && c <= 'F')
       
  2011            ;
       
  2012 }
       
  2013 
       
  2014 QString Scanner::preprocess(const QString &input, bool *hasEscapeSequences)
       
  2015 {
       
  2016     QString output = input;
       
  2017 
       
  2018     if (hasEscapeSequences)
       
  2019         *hasEscapeSequences = false;
       
  2020 
       
  2021     int i = 0;
       
  2022     while (i < output.size()) {
       
  2023         if (output.at(i) == QLatin1Char('\\')) {
       
  2024 
       
  2025             ++i;
       
  2026             // test for unicode hex escape
       
  2027             int hexCount = 0;
       
  2028             const int hexStart = i;
       
  2029             while (i < output.size()
       
  2030                    && isHexDigit(output.at(i).toLatin1())
       
  2031                    && hexCount < 7) {
       
  2032                 ++hexCount;
       
  2033                 ++i;
       
  2034             }
       
  2035             if (hexCount == 0) {
       
  2036                 if (hasEscapeSequences)
       
  2037                     *hasEscapeSequences = true;
       
  2038                 continue;
       
  2039             }
       
  2040 
       
  2041             hexCount = qMin(hexCount, 6);
       
  2042             bool ok = false;
       
  2043             ushort code = output.mid(hexStart, hexCount).toUShort(&ok, 16);
       
  2044             if (ok) {
       
  2045                 output.replace(hexStart - 1, hexCount + 1, QChar(code));
       
  2046                 i = hexStart;
       
  2047             } else {
       
  2048                 i = hexStart;
       
  2049             }
       
  2050         } else {
       
  2051             ++i;
       
  2052         }
       
  2053     }
       
  2054     return output;
       
  2055 }
       
  2056 
       
  2057 int QCssScanner_Generated::handleCommentStart()
       
  2058 {
       
  2059     while (pos < input.size() - 1) {
       
  2060         if (input.at(pos) == QLatin1Char('*')
       
  2061             && input.at(pos + 1) == QLatin1Char('/')) {
       
  2062             pos += 2;
       
  2063             break;
       
  2064         }
       
  2065         ++pos;
       
  2066     }
       
  2067     return S;
       
  2068 }
       
  2069 
       
  2070 void Scanner::scan(const QString &preprocessedInput, QVector<Symbol> *symbols)
       
  2071 {
       
  2072     QCssScanner_Generated scanner(preprocessedInput);
       
  2073     Symbol sym;
       
  2074     int tok = scanner.lex();
       
  2075     while (tok != -1) {
       
  2076         sym.token = static_cast<QCss::TokenType>(tok);
       
  2077         sym.text = scanner.input;
       
  2078         sym.start = scanner.lexemStart;
       
  2079         sym.len = scanner.lexemLength;
       
  2080         symbols->append(sym);
       
  2081         tok = scanner.lex();
       
  2082     }
       
  2083 }
       
  2084 
       
  2085 QString Symbol::lexem() const
       
  2086 {
       
  2087     QString result;
       
  2088     if (len > 0)
       
  2089         result.reserve(len);
       
  2090     for (int i = 0; i < len; ++i) {
       
  2091         if (text.at(start + i) == QLatin1Char('\\') && i < len - 1)
       
  2092             ++i;
       
  2093         result += text.at(start + i);
       
  2094     }
       
  2095     return result;
       
  2096 }
       
  2097 
       
  2098 Parser::Parser(const QString &css, bool isFile)
       
  2099 {
       
  2100     init(css, isFile);
       
  2101 }
       
  2102 
       
  2103 Parser::Parser()
       
  2104 {
       
  2105     index = 0;
       
  2106     errorIndex = -1;
       
  2107     hasEscapeSequences = false;
       
  2108 }
       
  2109 
       
  2110 void Parser::init(const QString &css, bool isFile)
       
  2111 {
       
  2112     QString styleSheet = css;
       
  2113     if (isFile) {
       
  2114         QFile file(css);
       
  2115         if (file.open(QFile::ReadOnly)) {
       
  2116             sourcePath = QFileInfo(styleSheet).absolutePath() + QLatin1Char('/');
       
  2117             QTextStream stream(&file);
       
  2118             styleSheet = stream.readAll();
       
  2119         } else {
       
  2120             qWarning() << "QCss::Parser - Failed to load file " << css;
       
  2121             styleSheet.clear();
       
  2122         }
       
  2123     } else {
       
  2124         sourcePath.clear();
       
  2125     }
       
  2126 
       
  2127     hasEscapeSequences = false;
       
  2128     symbols.resize(0);
       
  2129     symbols.reserve(8);
       
  2130     Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
       
  2131     index = 0;
       
  2132     errorIndex = -1;
       
  2133 }
       
  2134 
       
  2135 bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
       
  2136 {
       
  2137     if (testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("charset"))) {
       
  2138         if (!next(STRING)) return false;
       
  2139         if (!next(SEMICOLON)) return false;
       
  2140     }
       
  2141 
       
  2142     while (test(S) || test(CDO) || test(CDC)) {}
       
  2143 
       
  2144     while (testImport()) {
       
  2145         ImportRule rule;
       
  2146         if (!parseImport(&rule)) return false;
       
  2147         styleSheet->importRules.append(rule);
       
  2148         while (test(S) || test(CDO) || test(CDC)) {}
       
  2149     }
       
  2150 
       
  2151     do {
       
  2152         if (testMedia()) {
       
  2153             MediaRule rule;
       
  2154             if (!parseMedia(&rule)) return false;
       
  2155             styleSheet->mediaRules.append(rule);
       
  2156         } else if (testPage()) {
       
  2157             PageRule rule;
       
  2158             if (!parsePage(&rule)) return false;
       
  2159             styleSheet->pageRules.append(rule);
       
  2160         } else if (testRuleset()) {
       
  2161             StyleRule rule;
       
  2162             if (!parseRuleset(&rule)) return false;
       
  2163             styleSheet->styleRules.append(rule);
       
  2164         } else if (test(ATKEYWORD_SYM)) {
       
  2165             if (!until(RBRACE)) return false;
       
  2166         } else if (hasNext()) {
       
  2167             return false;
       
  2168         }
       
  2169         while (test(S) || test(CDO) || test(CDC)) {}
       
  2170     } while (hasNext());
       
  2171     styleSheet->buildIndexes(nameCaseSensitivity);
       
  2172     return true;
       
  2173 }
       
  2174 
       
  2175 Symbol Parser::errorSymbol()
       
  2176 {
       
  2177     if (errorIndex == -1) return Symbol();
       
  2178     return symbols.at(errorIndex);
       
  2179 }
       
  2180 
       
  2181 static inline void removeOptionalQuotes(QString *str)
       
  2182 {
       
  2183     if (!str->startsWith(QLatin1Char('\''))
       
  2184         && !str->startsWith(QLatin1Char('\"')))
       
  2185         return;
       
  2186     str->remove(0, 1);
       
  2187     str->chop(1);
       
  2188 }
       
  2189 
       
  2190 bool Parser::parseImport(ImportRule *importRule)
       
  2191 {
       
  2192     skipSpace();
       
  2193 
       
  2194     if (test(STRING)) {
       
  2195         importRule->href = lexem();
       
  2196     } else {
       
  2197         if (!testAndParseUri(&importRule->href)) return false;
       
  2198     }
       
  2199     removeOptionalQuotes(&importRule->href);
       
  2200 
       
  2201     skipSpace();
       
  2202 
       
  2203     if (testMedium()) {
       
  2204         if (!parseMedium(&importRule->media)) return false;
       
  2205 
       
  2206         while (test(COMMA)) {
       
  2207             skipSpace();
       
  2208             if (!parseNextMedium(&importRule->media)) return false;
       
  2209         }
       
  2210     }
       
  2211 
       
  2212     if (!next(SEMICOLON)) return false;
       
  2213 
       
  2214     skipSpace();
       
  2215     return true;
       
  2216 }
       
  2217 
       
  2218 bool Parser::parseMedia(MediaRule *mediaRule)
       
  2219 {
       
  2220     do {
       
  2221         skipSpace();
       
  2222         if (!parseNextMedium(&mediaRule->media)) return false;
       
  2223     } while (test(COMMA));
       
  2224 
       
  2225     if (!next(LBRACE)) return false;
       
  2226     skipSpace();
       
  2227 
       
  2228     while (testRuleset()) {
       
  2229         StyleRule rule;
       
  2230         if (!parseRuleset(&rule)) return false;
       
  2231         mediaRule->styleRules.append(rule);
       
  2232     }
       
  2233 
       
  2234     if (!next(RBRACE)) return false;
       
  2235     skipSpace();
       
  2236     return true;
       
  2237 }
       
  2238 
       
  2239 bool Parser::parseMedium(QStringList *media)
       
  2240 {
       
  2241     media->append(lexem());
       
  2242     skipSpace();
       
  2243     return true;
       
  2244 }
       
  2245 
       
  2246 bool Parser::parsePage(PageRule *pageRule)
       
  2247 {
       
  2248     skipSpace();
       
  2249 
       
  2250     if (testPseudoPage())
       
  2251         if (!parsePseudoPage(&pageRule->selector)) return false;
       
  2252 
       
  2253     skipSpace();
       
  2254     if (!next(LBRACE)) return false;
       
  2255 
       
  2256     do {
       
  2257         skipSpace();
       
  2258         Declaration decl;
       
  2259         if (!parseNextDeclaration(&decl)) return false;
       
  2260         if (!decl.isEmpty())
       
  2261             pageRule->declarations.append(decl);
       
  2262     } while (test(SEMICOLON));
       
  2263 
       
  2264     if (!next(RBRACE)) return false;
       
  2265     skipSpace();
       
  2266     return true;
       
  2267 }
       
  2268 
       
  2269 bool Parser::parsePseudoPage(QString *selector)
       
  2270 {
       
  2271     if (!next(IDENT)) return false;
       
  2272     *selector = lexem();
       
  2273     return true;
       
  2274 }
       
  2275 
       
  2276 bool Parser::parseNextOperator(Value *value)
       
  2277 {
       
  2278     if (!hasNext()) return true;
       
  2279     switch (next()) {
       
  2280         case SLASH: value->type = Value::TermOperatorSlash; skipSpace(); break;
       
  2281         case COMMA: value->type = Value::TermOperatorComma; skipSpace(); break;
       
  2282         default: prev(); break;
       
  2283     }
       
  2284     return true;
       
  2285 }
       
  2286 
       
  2287 bool Parser::parseCombinator(BasicSelector::Relation *relation)
       
  2288 {
       
  2289     *relation = BasicSelector::NoRelation;
       
  2290     if (lookup() == S) {
       
  2291         *relation = BasicSelector::MatchNextSelectorIfAncestor;
       
  2292         skipSpace();
       
  2293     } else {
       
  2294         prev();
       
  2295     }
       
  2296     if (test(PLUS)) {
       
  2297         *relation = BasicSelector::MatchNextSelectorIfPreceeds;
       
  2298     } else if (test(GREATER)) {
       
  2299         *relation = BasicSelector::MatchNextSelectorIfParent;
       
  2300     }
       
  2301     skipSpace();
       
  2302     return true;
       
  2303 }
       
  2304 
       
  2305 bool Parser::parseProperty(Declaration *decl)
       
  2306 {
       
  2307     decl->d->property = lexem();
       
  2308     decl->d->propertyId = static_cast<Property>(findKnownValue(decl->d->property, properties, NumProperties));
       
  2309     skipSpace();
       
  2310     return true;
       
  2311 }
       
  2312 
       
  2313 bool Parser::parseRuleset(StyleRule *styleRule)
       
  2314 {
       
  2315     Selector sel;
       
  2316     if (!parseSelector(&sel)) return false;
       
  2317     styleRule->selectors.append(sel);
       
  2318 
       
  2319     while (test(COMMA)) {
       
  2320         skipSpace();
       
  2321         Selector sel;
       
  2322         if (!parseNextSelector(&sel)) return false;
       
  2323         styleRule->selectors.append(sel);
       
  2324     }
       
  2325 
       
  2326     skipSpace();
       
  2327     if (!next(LBRACE)) return false;
       
  2328     const int declarationStart = index;
       
  2329 
       
  2330     do {
       
  2331         skipSpace();
       
  2332         Declaration decl;
       
  2333         const int rewind = index;
       
  2334         if (!parseNextDeclaration(&decl)) {
       
  2335             index = rewind;
       
  2336             const bool foundSemicolon = until(SEMICOLON);
       
  2337             const int semicolonIndex = index;
       
  2338 
       
  2339             index = declarationStart;
       
  2340             const bool foundRBrace = until(RBRACE);
       
  2341 
       
  2342             if (foundSemicolon && semicolonIndex < index) {
       
  2343                 decl = Declaration();
       
  2344                 index = semicolonIndex - 1;
       
  2345             } else {
       
  2346                 skipSpace();
       
  2347                 return foundRBrace;
       
  2348             }
       
  2349         }
       
  2350         if (!decl.isEmpty())
       
  2351             styleRule->declarations.append(decl);
       
  2352     } while (test(SEMICOLON));
       
  2353 
       
  2354     if (!next(RBRACE)) return false;
       
  2355     skipSpace();
       
  2356     return true;
       
  2357 }
       
  2358 
       
  2359 bool Parser::parseSelector(Selector *sel)
       
  2360 {
       
  2361     BasicSelector basicSel;
       
  2362     if (!parseSimpleSelector(&basicSel)) return false;
       
  2363     while (testCombinator()) {
       
  2364         if (!parseCombinator(&basicSel.relationToNext)) return false;
       
  2365 
       
  2366         if (!testSimpleSelector()) break;
       
  2367         sel->basicSelectors.append(basicSel);
       
  2368 
       
  2369         basicSel = BasicSelector();
       
  2370         if (!parseSimpleSelector(&basicSel)) return false;
       
  2371     }
       
  2372     sel->basicSelectors.append(basicSel);
       
  2373     return true;
       
  2374 }
       
  2375 
       
  2376 bool Parser::parseSimpleSelector(BasicSelector *basicSel)
       
  2377 {
       
  2378     int minCount = 0;
       
  2379     if (lookupElementName()) {
       
  2380         if (!parseElementName(&basicSel->elementName)) return false;
       
  2381     } else {
       
  2382         prev();
       
  2383         minCount = 1;
       
  2384     }
       
  2385     bool onceMore;
       
  2386     int count = 0;
       
  2387     do {
       
  2388         onceMore = false;
       
  2389         if (test(HASH)) {
       
  2390             QString theid = lexem();
       
  2391             // chop off leading #
       
  2392             theid.remove(0, 1);
       
  2393             basicSel->ids.append(theid);
       
  2394             onceMore = true;
       
  2395         } else if (testClass()) {
       
  2396             onceMore = true;
       
  2397             AttributeSelector a;
       
  2398             a.name = QLatin1String("class");
       
  2399             a.valueMatchCriterium = AttributeSelector::MatchContains;
       
  2400             if (!parseClass(&a.value)) return false;
       
  2401             basicSel->attributeSelectors.append(a);
       
  2402         } else if (testAttrib()) {
       
  2403             onceMore = true;
       
  2404             AttributeSelector a;
       
  2405             if (!parseAttrib(&a)) return false;
       
  2406             basicSel->attributeSelectors.append(a);
       
  2407         } else if (testPseudo()) {
       
  2408             onceMore = true;
       
  2409             Pseudo ps;
       
  2410             if (!parsePseudo(&ps)) return false;
       
  2411             basicSel->pseudos.append(ps);
       
  2412         }
       
  2413         if (onceMore) ++count;
       
  2414     } while (onceMore);
       
  2415     return count >= minCount;
       
  2416 }
       
  2417 
       
  2418 bool Parser::parseClass(QString *name)
       
  2419 {
       
  2420     if (!next(IDENT)) return false;
       
  2421     *name = lexem();
       
  2422     return true;
       
  2423 }
       
  2424 
       
  2425 bool Parser::parseElementName(QString *name)
       
  2426 {
       
  2427     switch (lookup()) {
       
  2428         case STAR: name->clear(); break;
       
  2429         case IDENT: *name = lexem(); break;
       
  2430         default: return false;
       
  2431     }
       
  2432     return true;
       
  2433 }
       
  2434 
       
  2435 bool Parser::parseAttrib(AttributeSelector *attr)
       
  2436 {
       
  2437     skipSpace();
       
  2438     if (!next(IDENT)) return false;
       
  2439     attr->name = lexem();
       
  2440     skipSpace();
       
  2441 
       
  2442     if (test(EQUAL)) {
       
  2443         attr->valueMatchCriterium = AttributeSelector::MatchEqual;
       
  2444     } else if (test(INCLUDES)) {
       
  2445         attr->valueMatchCriterium = AttributeSelector::MatchContains;
       
  2446     } else if (test(DASHMATCH)) {
       
  2447         attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
       
  2448     } else {
       
  2449         return next(RBRACKET);
       
  2450     }
       
  2451 
       
  2452     skipSpace();
       
  2453 
       
  2454     if (!test(IDENT) && !test(STRING)) return false;
       
  2455     attr->value = unquotedLexem();
       
  2456 
       
  2457     skipSpace();
       
  2458     return next(RBRACKET);
       
  2459 }
       
  2460 
       
  2461 bool Parser::parsePseudo(Pseudo *pseudo)
       
  2462 {
       
  2463     (void)test(COLON);
       
  2464     pseudo->negated = test(EXCLAMATION_SYM);
       
  2465     if (test(IDENT)) {
       
  2466         pseudo->name = lexem();
       
  2467         pseudo->type = static_cast<quint64>(findKnownValue(pseudo->name, pseudos, NumPseudos));
       
  2468         return true;
       
  2469     }
       
  2470     if (!next(FUNCTION)) return false;
       
  2471     pseudo->function = lexem();
       
  2472     // chop off trailing parenthesis
       
  2473     pseudo->function.chop(1);
       
  2474     skipSpace();
       
  2475     if (!test(IDENT)) return false;
       
  2476     pseudo->name = lexem();
       
  2477     skipSpace();
       
  2478     return next(RPAREN);
       
  2479 }
       
  2480 
       
  2481 bool Parser::parseNextDeclaration(Declaration *decl)
       
  2482 {
       
  2483     if (!testProperty())
       
  2484         return true; // not an error!
       
  2485     if (!parseProperty(decl)) return false;
       
  2486     if (!next(COLON)) return false;
       
  2487     skipSpace();
       
  2488     if (!parseNextExpr(&decl->d->values)) return false;
       
  2489     if (testPrio())
       
  2490         if (!parsePrio(decl)) return false;
       
  2491     return true;
       
  2492 }
       
  2493 
       
  2494 bool Parser::testPrio()
       
  2495 {
       
  2496     const int rewind = index;
       
  2497     if (!test(EXCLAMATION_SYM)) return false;
       
  2498     skipSpace();
       
  2499     if (!test(IDENT)) {
       
  2500         index = rewind;
       
  2501         return false;
       
  2502     }
       
  2503     if (lexem().compare(QLatin1String("important"), Qt::CaseInsensitive) != 0) {
       
  2504         index = rewind;
       
  2505         return false;
       
  2506     }
       
  2507     return true;
       
  2508 }
       
  2509 
       
  2510 bool Parser::parsePrio(Declaration *declaration)
       
  2511 {
       
  2512     declaration->d->important = true;
       
  2513     skipSpace();
       
  2514     return true;
       
  2515 }
       
  2516 
       
  2517 bool Parser::parseExpr(QVector<Value> *values)
       
  2518 {
       
  2519     Value val;
       
  2520     if (!parseTerm(&val)) return false;
       
  2521     values->append(val);
       
  2522     bool onceMore;
       
  2523     do {
       
  2524         onceMore = false;
       
  2525         val = Value();
       
  2526         if (!parseNextOperator(&val)) return false;
       
  2527         if (val.type != QCss::Value::Unknown)
       
  2528             values->append(val);
       
  2529         if (testTerm()) {
       
  2530             onceMore = true;
       
  2531             val = Value();
       
  2532             if (!parseTerm(&val)) return false;
       
  2533             values->append(val);
       
  2534         }
       
  2535     } while (onceMore);
       
  2536     return true;
       
  2537 }
       
  2538 
       
  2539 bool Parser::testTerm()
       
  2540 {
       
  2541     return test(PLUS) || test(MINUS)
       
  2542            || test(NUMBER)
       
  2543            || test(PERCENTAGE)
       
  2544            || test(LENGTH)
       
  2545            || test(STRING)
       
  2546            || test(IDENT)
       
  2547            || testHexColor()
       
  2548            || testFunction();
       
  2549 }
       
  2550 
       
  2551 bool Parser::parseTerm(Value *value)
       
  2552 {
       
  2553     QString str = lexem();
       
  2554     bool haveUnary = false;
       
  2555     if (lookup() == PLUS || lookup() == MINUS) {
       
  2556         haveUnary = true;
       
  2557         if (!hasNext()) return false;
       
  2558         next();
       
  2559         str += lexem();
       
  2560     }
       
  2561 
       
  2562     value->variant = str;
       
  2563     value->type = QCss::Value::String;
       
  2564     switch (lookup()) {
       
  2565         case NUMBER:
       
  2566             value->type = Value::Number;
       
  2567             value->variant.convert(QVariant::Double);
       
  2568             break;
       
  2569         case PERCENTAGE:
       
  2570             value->type = Value::Percentage;
       
  2571             str.chop(1); // strip off %
       
  2572             value->variant = str;
       
  2573             break;
       
  2574         case LENGTH:
       
  2575             value->type = Value::Length;
       
  2576             break;
       
  2577 
       
  2578         case STRING:
       
  2579             if (haveUnary) return false;
       
  2580             value->type = Value::String;
       
  2581             str.chop(1);
       
  2582             str.remove(0, 1);
       
  2583             value->variant = str;
       
  2584             break;
       
  2585         case IDENT: {
       
  2586             if (haveUnary) return false;
       
  2587             value->type = Value::Identifier;
       
  2588             const int theid = findKnownValue(str, values, NumKnownValues);
       
  2589             if (theid != 0) {
       
  2590                 value->type = Value::KnownIdentifier;
       
  2591                 value->variant = theid;
       
  2592             }
       
  2593             break;
       
  2594         }
       
  2595         default: {
       
  2596             if (haveUnary) return false;
       
  2597             prev();
       
  2598             if (testHexColor()) {
       
  2599                 QColor col;
       
  2600                 if (!parseHexColor(&col)) return false;
       
  2601                 value->type = Value::Color;
       
  2602                 value->variant = col;
       
  2603             } else if (testFunction()) {
       
  2604                 QString name, args;
       
  2605                 if (!parseFunction(&name, &args)) return false;
       
  2606                 if (name == QLatin1String("url")) {
       
  2607                     value->type = Value::Uri;
       
  2608                     removeOptionalQuotes(&args);
       
  2609                     if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
       
  2610                         args.prepend(sourcePath);
       
  2611                     }
       
  2612                     value->variant = args;
       
  2613                 } else {
       
  2614                     value->type = Value::Function;
       
  2615                     value->variant = QStringList() << name << args;
       
  2616                 }
       
  2617             } else {
       
  2618                 return recordError();
       
  2619             }
       
  2620             return true;
       
  2621         }
       
  2622     }
       
  2623     skipSpace();
       
  2624     return true;
       
  2625 }
       
  2626 
       
  2627 bool Parser::parseFunction(QString *name, QString *args)
       
  2628 {
       
  2629     *name = lexem();
       
  2630     name->chop(1);
       
  2631     skipSpace();
       
  2632     const int start = index;
       
  2633     if (!until(RPAREN)) return false;
       
  2634     for (int i = start; i < index - 1; ++i)
       
  2635         args->append(symbols.at(i).lexem());
       
  2636     /*
       
  2637     if (!nextExpr(&arguments)) return false;
       
  2638     if (!next(RPAREN)) return false;
       
  2639     */
       
  2640     skipSpace();
       
  2641     return true;
       
  2642 }
       
  2643 
       
  2644 bool Parser::parseHexColor(QColor *col)
       
  2645 {
       
  2646     col->setNamedColor(lexem());
       
  2647     if (!col->isValid()) {
       
  2648         qWarning("QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
       
  2649         return false;
       
  2650     }
       
  2651     skipSpace();
       
  2652     return true;
       
  2653 }
       
  2654 
       
  2655 bool Parser::testAndParseUri(QString *uri)
       
  2656 {
       
  2657     const int rewind = index;
       
  2658     if (!testFunction()) return false;
       
  2659 
       
  2660     QString name, args;
       
  2661     if (!parseFunction(&name, &args)) {
       
  2662         index = rewind;
       
  2663         return false;
       
  2664     }
       
  2665     if (name.toLower() != QLatin1String("url")) {
       
  2666         index = rewind;
       
  2667         return false;
       
  2668     }
       
  2669     *uri = args;
       
  2670     removeOptionalQuotes(uri);
       
  2671     return true;
       
  2672 }
       
  2673 
       
  2674 bool Parser::testSimpleSelector()
       
  2675 {
       
  2676     return testElementName()
       
  2677            || (test(HASH))
       
  2678            || testClass()
       
  2679            || testAttrib()
       
  2680            || testPseudo();
       
  2681 }
       
  2682 
       
  2683 bool Parser::next(QCss::TokenType t)
       
  2684 {
       
  2685     if (hasNext() && next() == t)
       
  2686         return true;
       
  2687     return recordError();
       
  2688 }
       
  2689 
       
  2690 bool Parser::test(QCss::TokenType t)
       
  2691 {
       
  2692     if (index >= symbols.count())
       
  2693         return false;
       
  2694     if (symbols.at(index).token == t) {
       
  2695         ++index;
       
  2696         return true;
       
  2697     }
       
  2698     return false;
       
  2699 }
       
  2700 
       
  2701 QString Parser::unquotedLexem() const
       
  2702 {
       
  2703     QString s = lexem();
       
  2704     if (lookup() == STRING) {
       
  2705         s.chop(1);
       
  2706         s.remove(0, 1);
       
  2707     }
       
  2708     return s;
       
  2709 }
       
  2710 
       
  2711 QString Parser::lexemUntil(QCss::TokenType t)
       
  2712 {
       
  2713     QString lexem;
       
  2714     while (hasNext() && next() != t)
       
  2715         lexem += symbol().lexem();
       
  2716     return lexem;
       
  2717 }
       
  2718 
       
  2719 bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
       
  2720 {
       
  2721     int braceCount = 0;
       
  2722     int brackCount = 0;
       
  2723     int parenCount = 0;
       
  2724     if (index) {
       
  2725         switch(symbols.at(index-1).token) {
       
  2726         case LBRACE: ++braceCount; break;
       
  2727         case LBRACKET: ++brackCount; break;
       
  2728         case FUNCTION:
       
  2729         case LPAREN: ++parenCount; break;
       
  2730         default: ;
       
  2731         }
       
  2732     }
       
  2733     while (index < symbols.size()) {
       
  2734         QCss::TokenType t = symbols.at(index++).token;
       
  2735         switch (t) {
       
  2736         case LBRACE: ++braceCount; break;
       
  2737         case RBRACE: --braceCount; break;
       
  2738         case LBRACKET: ++brackCount; break;
       
  2739         case RBRACKET: --brackCount; break;
       
  2740         case FUNCTION:
       
  2741         case LPAREN: ++parenCount; break;
       
  2742         case RPAREN: --parenCount; break;
       
  2743         default: break;
       
  2744         }
       
  2745         if ((t == target || (target2 != NONE && t == target2))
       
  2746             && braceCount <= 0
       
  2747             && brackCount <= 0
       
  2748             && parenCount <= 0)
       
  2749             return true;
       
  2750 
       
  2751         if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
       
  2752             --index;
       
  2753             break;
       
  2754         }
       
  2755     }
       
  2756     return false;
       
  2757 }
       
  2758 
       
  2759 bool Parser::testTokenAndEndsWith(QCss::TokenType t, const QLatin1String &str)
       
  2760 {
       
  2761     if (!test(t)) return false;
       
  2762     if (!lexem().endsWith(str, Qt::CaseInsensitive)) {
       
  2763         prev();
       
  2764         return false;
       
  2765     }
       
  2766     return true;
       
  2767 }
       
  2768 
       
  2769 QT_END_NAMESPACE
       
  2770 #endif // QT_NO_CSSPARSER