qcssparser.cpp

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

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9