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