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 QtWidgets 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 <qglobal.h>
41 #include "qstylesheetstyle_p.h"
42 
43 #if QT_CONFIG(style_stylesheet)
44 
45 #include "private/qcssutil_p.h"
46 #include <qdebug.h>
47 #include <qdir.h>
48 #include <qapplication.h>
49 #if QT_CONFIG(menu)
50 #include <qmenu.h>
51 #endif
52 #if QT_CONFIG(menubar)
53 #include <qmenubar.h>
54 #endif
55 #include <qpainter.h>
56 #include <qstyleoption.h>
57 #if QT_CONFIG(lineedit)
58 #include <qlineedit.h>
59 #endif
60 #include <private/qwindowsstyle_p.h>
61 #if QT_CONFIG(combobox)
62 #include <qcombobox.h>
63 #endif
64 #include "private/qcssparser_p.h"
65 #include "private/qmath_p.h"
66 #include <qabstractscrollarea.h>
67 #include "private/qabstractscrollarea_p.h"
68 #include <qtooltip.h>
69 #include <qshareddata.h>
70 #if QT_CONFIG(toolbutton)
71 #include <qtoolbutton.h>
72 #endif
73 #if QT_CONFIG(scrollbar)
74 #include <qscrollbar.h>
75 #endif
76 #if QT_CONFIG(abstractslider)
77 #include <qabstractslider.h>
78 #endif
79 #include <qstring.h>
80 #include <qfile.h>
81 #if QT_CONFIG(checkbox)
82 #include <qcheckbox.h>
83 #endif
84 #if QT_CONFIG(itemviews)
85 #include <qheaderview.h>
86 #endif
87 #include <private/qwindowsstyle_p_p.h>
88 #if QT_CONFIG(animation)
89 #include <private/qstyleanimation_p.h>
90 #endif
91 #if QT_CONFIG(tabbar)
92 #include <qtabbar.h>
93 #endif
94 #include <QMetaProperty>
95 #if QT_CONFIG(mainwindow)
96 #include <qmainwindow.h>
97 #endif
98 #if QT_CONFIG(dockwidget)
99 #include <qdockwidget.h>
100 #endif
101 #if QT_CONFIG(mdiarea)
102 #include <qmdisubwindow.h>
103 #endif
104 #if QT_CONFIG(dialog)
105 #include <qdialog.h>
106 #endif
107 #include <private/qwidget_p.h>
108 #if QT_CONFIG(spinbox)
109 #include <QAbstractSpinBox>
110 #endif
111 #if QT_CONFIG(label)
112 #include <QLabel>
113 #endif
114 #include "qdrawutil.h"
115 
116 #include <limits.h>
117 #if QT_CONFIG(toolbar)
118 #include <QtWidgets/qtoolbar.h>
119 #endif
120 
121 #include <QtGui/qpainterpath.h>
122 #include <QtGui/qscreen.h>
123 
124 QT_BEGIN_NAMESPACE
125 
126 using namespace QCss;
127 
128 
129 class QStyleSheetStylePrivate : public QWindowsStylePrivate
130 {
131     Q_DECLARE_PUBLIC(QStyleSheetStyle)
132 public:
QStyleSheetStylePrivate()133     QStyleSheetStylePrivate() { }
134 };
135 
136 
137 static QStyleSheetStyleCaches *styleSheetCaches = nullptr;
138 
139 /* RECURSION_GUARD:
140  * the QStyleSheetStyle is a proxy. If used with others proxy style, we may end up with something like:
141  * QStyleSheetStyle -> ProxyStyle -> QStyleSheetStyle -> OriginalStyle
142  * Recursion may happen if the style call the widget()->style() again.
143  * Not to mention the performence penalty of having two lookup of rules.
144  *
145  * The first instance of QStyleSheetStyle will set globalStyleSheetStyle to itself. The second one
146  * will notice the globalStyleSheetStyle is not istelf and call its base style directly.
147  */
148 static const QStyleSheetStyle *globalStyleSheetStyle = nullptr;
149 class QStyleSheetStyleRecursionGuard
150 {
151     public:
QStyleSheetStyleRecursionGuard(const QStyleSheetStyle * that)152         QStyleSheetStyleRecursionGuard(const QStyleSheetStyle *that)
153             :  guarded(globalStyleSheetStyle == nullptr)
154             {
155                 if (guarded) globalStyleSheetStyle = that;
156             }
~QStyleSheetStyleRecursionGuard()157         ~QStyleSheetStyleRecursionGuard() { if (guarded) globalStyleSheetStyle = nullptr; }
158         bool guarded;
159 };
160 #define RECURSION_GUARD(RETURN) \
161     if (globalStyleSheetStyle != 0 && globalStyleSheetStyle != this) { RETURN; } \
162     QStyleSheetStyleRecursionGuard recursion_guard(this);
163 
164 #define ceil(x) ((int)(x) + ((x) > 0 && (x) != (int)(x)))
165 
166 enum PseudoElement {
167     PseudoElement_None,
168     PseudoElement_DownArrow,
169     PseudoElement_UpArrow,
170     PseudoElement_LeftArrow,
171     PseudoElement_RightArrow,
172     PseudoElement_Indicator,
173     PseudoElement_ExclusiveIndicator,
174     PseudoElement_PushButtonMenuIndicator,
175     PseudoElement_ComboBoxDropDown,
176     PseudoElement_ComboBoxArrow,
177     PseudoElement_Item,
178     PseudoElement_SpinBoxUpButton,
179     PseudoElement_SpinBoxUpArrow,
180     PseudoElement_SpinBoxDownButton,
181     PseudoElement_SpinBoxDownArrow,
182     PseudoElement_GroupBoxTitle,
183     PseudoElement_GroupBoxIndicator,
184     PseudoElement_ToolButtonMenu,
185     PseudoElement_ToolButtonMenuArrow,
186     PseudoElement_ToolButtonDownArrow,
187     PseudoElement_ToolBoxTab,
188     PseudoElement_ScrollBarSlider,
189     PseudoElement_ScrollBarAddPage,
190     PseudoElement_ScrollBarSubPage,
191     PseudoElement_ScrollBarAddLine,
192     PseudoElement_ScrollBarSubLine,
193     PseudoElement_ScrollBarFirst,
194     PseudoElement_ScrollBarLast,
195     PseudoElement_ScrollBarUpArrow,
196     PseudoElement_ScrollBarDownArrow,
197     PseudoElement_ScrollBarLeftArrow,
198     PseudoElement_ScrollBarRightArrow,
199     PseudoElement_SplitterHandle,
200     PseudoElement_ToolBarHandle,
201     PseudoElement_ToolBarSeparator,
202     PseudoElement_MenuScroller,
203     PseudoElement_MenuTearoff,
204     PseudoElement_MenuCheckMark,
205     PseudoElement_MenuSeparator,
206     PseudoElement_MenuIcon,
207     PseudoElement_MenuRightArrow,
208     PseudoElement_TreeViewBranch,
209     PseudoElement_HeaderViewSection,
210     PseudoElement_HeaderViewUpArrow,
211     PseudoElement_HeaderViewDownArrow,
212     PseudoElement_ProgressBarChunk,
213     PseudoElement_TabBarTab,
214     PseudoElement_TabBarScroller,
215     PseudoElement_TabBarTear,
216     PseudoElement_SliderGroove,
217     PseudoElement_SliderHandle,
218     PseudoElement_SliderAddPage,
219     PseudoElement_SliderSubPage,
220     PseudoElement_SliderTickmark,
221     PseudoElement_TabWidgetPane,
222     PseudoElement_TabWidgetTabBar,
223     PseudoElement_TabWidgetLeftCorner,
224     PseudoElement_TabWidgetRightCorner,
225     PseudoElement_DockWidgetTitle,
226     PseudoElement_DockWidgetCloseButton,
227     PseudoElement_DockWidgetFloatButton,
228     PseudoElement_DockWidgetSeparator,
229     PseudoElement_MdiCloseButton,
230     PseudoElement_MdiMinButton,
231     PseudoElement_MdiNormalButton,
232     PseudoElement_TitleBar,
233     PseudoElement_TitleBarCloseButton,
234     PseudoElement_TitleBarMinButton,
235     PseudoElement_TitleBarMaxButton,
236     PseudoElement_TitleBarShadeButton,
237     PseudoElement_TitleBarUnshadeButton,
238     PseudoElement_TitleBarNormalButton,
239     PseudoElement_TitleBarContextHelpButton,
240     PseudoElement_TitleBarSysMenu,
241     PseudoElement_ViewItem,
242     PseudoElement_ViewItemIcon,
243     PseudoElement_ViewItemText,
244     PseudoElement_ViewItemIndicator,
245     PseudoElement_ScrollAreaCorner,
246     PseudoElement_TabBarTabCloseButton,
247     NumPseudoElements
248 };
249 
250 struct PseudoElementInfo {
251     QStyle::SubControl subControl;
252     const char name[19];
253 };
254 
255 static const PseudoElementInfo knownPseudoElements[NumPseudoElements] = {
256     { QStyle::SC_None, "" },
257     { QStyle::SC_None, "down-arrow" },
258     { QStyle::SC_None, "up-arrow" },
259     { QStyle::SC_None, "left-arrow" },
260     { QStyle::SC_None, "right-arrow" },
261     { QStyle::SC_None, "indicator" },
262     { QStyle::SC_None, "indicator" },
263     { QStyle::SC_None, "menu-indicator" },
264     { QStyle::SC_ComboBoxArrow, "drop-down" },
265     { QStyle::SC_ComboBoxArrow, "down-arrow" },
266     { QStyle::SC_None, "item" },
267     { QStyle::SC_SpinBoxUp, "up-button" },
268     { QStyle::SC_SpinBoxUp, "up-arrow" },
269     { QStyle::SC_SpinBoxDown, "down-button" },
270     { QStyle::SC_SpinBoxDown, "down-arrow" },
271     { QStyle::SC_GroupBoxLabel, "title" },
272     { QStyle::SC_GroupBoxCheckBox, "indicator" },
273     { QStyle::SC_ToolButtonMenu, "menu-button" },
274     { QStyle::SC_ToolButtonMenu, "menu-arrow" },
275     { QStyle::SC_None, "menu-indicator" },
276     { QStyle::SC_None, "tab" },
277     { QStyle::SC_ScrollBarSlider, "handle" },
278     { QStyle::SC_ScrollBarAddPage, "add-page" },
279     { QStyle::SC_ScrollBarSubPage, "sub-page" },
280     { QStyle::SC_ScrollBarAddLine, "add-line" },
281     { QStyle::SC_ScrollBarSubLine, "sub-line" },
282     { QStyle::SC_ScrollBarFirst, "first" },
283     { QStyle::SC_ScrollBarLast, "last" },
284     { QStyle::SC_ScrollBarSubLine, "up-arrow" },
285     { QStyle::SC_ScrollBarAddLine, "down-arrow" },
286     { QStyle::SC_ScrollBarSubLine, "left-arrow" },
287     { QStyle::SC_ScrollBarAddLine, "right-arrow" },
288     { QStyle::SC_None, "handle" },
289     { QStyle::SC_None, "handle" },
290     { QStyle::SC_None, "separator" },
291     { QStyle::SC_None, "scroller" },
292     { QStyle::SC_None, "tearoff" },
293     { QStyle::SC_None, "indicator" },
294     { QStyle::SC_None, "separator" },
295     { QStyle::SC_None, "icon" },
296     { QStyle::SC_None, "right-arrow" },
297     { QStyle::SC_None, "branch" },
298     { QStyle::SC_None, "section" },
299     { QStyle::SC_None, "down-arrow" },
300     { QStyle::SC_None, "up-arrow" },
301     { QStyle::SC_None, "chunk" },
302     { QStyle::SC_None, "tab" },
303     { QStyle::SC_None, "scroller" },
304     { QStyle::SC_None, "tear" },
305     { QStyle::SC_SliderGroove, "groove" },
306     { QStyle::SC_SliderHandle, "handle" },
307     { QStyle::SC_None, "add-page" },
308     { QStyle::SC_None, "sub-page"},
309     { QStyle::SC_SliderTickmarks, "tick-mark" },
310     { QStyle::SC_None, "pane" },
311     { QStyle::SC_None, "tab-bar" },
312     { QStyle::SC_None, "left-corner" },
313     { QStyle::SC_None, "right-corner" },
314     { QStyle::SC_None, "title" },
315     { QStyle::SC_None, "close-button" },
316     { QStyle::SC_None, "float-button" },
317     { QStyle::SC_None, "separator" },
318     { QStyle::SC_MdiCloseButton, "close-button" },
319     { QStyle::SC_MdiMinButton, "minimize-button" },
320     { QStyle::SC_MdiNormalButton, "normal-button" },
321     { QStyle::SC_TitleBarLabel, "title" },
322     { QStyle::SC_TitleBarCloseButton, "close-button" },
323     { QStyle::SC_TitleBarMinButton, "minimize-button" },
324     { QStyle::SC_TitleBarMaxButton, "maximize-button" },
325     { QStyle::SC_TitleBarShadeButton, "shade-button" },
326     { QStyle::SC_TitleBarUnshadeButton, "unshade-button" },
327     { QStyle::SC_TitleBarNormalButton, "normal-button" },
328     { QStyle::SC_TitleBarContextHelpButton, "contexthelp-button" },
329     { QStyle::SC_TitleBarSysMenu, "sys-menu" },
330     { QStyle::SC_None, "item" },
331     { QStyle::SC_None, "icon" },
332     { QStyle::SC_None, "text" },
333     { QStyle::SC_None, "indicator" },
334     { QStyle::SC_None, "corner" },
335     { QStyle::SC_None, "close-button" },
336 };
337 
338 
339 struct QStyleSheetBorderImageData : public QSharedData
340 {
QStyleSheetBorderImageDataQStyleSheetBorderImageData341     QStyleSheetBorderImageData()
342         : horizStretch(QCss::TileMode_Unknown), vertStretch(QCss::TileMode_Unknown)
343     {
344         for (int i = 0; i < 4; i++)
345             cuts[i] = -1;
346     }
347     int cuts[4];
348     QPixmap pixmap;
349     QImage image;
350     QCss::TileMode horizStretch, vertStretch;
351 };
352 
353 struct QStyleSheetBackgroundData : public QSharedData
354 {
QStyleSheetBackgroundDataQStyleSheetBackgroundData355     QStyleSheetBackgroundData(const QBrush& b, const QPixmap& p, QCss::Repeat r,
356                               Qt::Alignment a, QCss::Origin o, Attachment t, QCss::Origin c)
357         : brush(b), pixmap(p), repeat(r), position(a), origin(o), attachment(t), clip(c) { }
358 
isTransparentQStyleSheetBackgroundData359     bool isTransparent() const {
360         if (brush.style() != Qt::NoBrush)
361             return !brush.isOpaque();
362         return pixmap.isNull() ? false : pixmap.hasAlpha();
363     }
364     QBrush brush;
365     QPixmap pixmap;
366     QCss::Repeat repeat;
367     Qt::Alignment position;
368     QCss::Origin origin;
369     QCss::Attachment attachment;
370     QCss::Origin clip;
371 };
372 
373 struct QStyleSheetBorderData : public QSharedData
374 {
QStyleSheetBorderDataQStyleSheetBorderData375     QStyleSheetBorderData() : bi(nullptr)
376     {
377         for (int i = 0; i < 4; i++) {
378             borders[i] = 0;
379             styles[i] = QCss::BorderStyle_None;
380         }
381     }
382 
QStyleSheetBorderDataQStyleSheetBorderData383     QStyleSheetBorderData(int *b, QBrush *c, QCss::BorderStyle *s, QSize *r) : bi(nullptr)
384     {
385         for (int i = 0; i < 4; i++) {
386             borders[i] = b[i];
387             styles[i] = s[i];
388             colors[i] = c[i];
389             radii[i] = r[i];
390         }
391     }
392 
393     int borders[4];
394     QBrush colors[4];
395     QCss::BorderStyle styles[4];
396     QSize radii[4]; // topleft, topright, bottomleft, bottomright
397 
borderImageQStyleSheetBorderData398     const QStyleSheetBorderImageData *borderImage() const
399     { return bi; }
hasBorderImageQStyleSheetBorderData400     bool hasBorderImage() const { return bi!=nullptr; }
401 
402     QSharedDataPointer<QStyleSheetBorderImageData> bi;
403 
isOpaqueQStyleSheetBorderData404     bool isOpaque() const
405     {
406         for (int i = 0; i < 4; i++) {
407             if (styles[i] == QCss::BorderStyle_Native || styles[i] == QCss::BorderStyle_None)
408                 continue;
409             if (styles[i] >= QCss::BorderStyle_Dotted && styles[i] <= QCss::BorderStyle_DotDotDash
410                 && styles[i] != BorderStyle_Solid)
411                 return false;
412             if (!colors[i].isOpaque())
413                 return false;
414             if (!radii[i].isEmpty())
415                 return false;
416         }
417         if (bi != nullptr && bi->pixmap.hasAlpha())
418             return false;
419         return true;
420     }
421 };
422 
423 
424 struct QStyleSheetOutlineData : public QStyleSheetBorderData
425 {
QStyleSheetOutlineDataQStyleSheetOutlineData426     QStyleSheetOutlineData()
427     {
428         for (int i = 0; i < 4; i++) {
429             offsets[i] = 0;
430         }
431     }
432 
QStyleSheetOutlineDataQStyleSheetOutlineData433     QStyleSheetOutlineData(int *b, QBrush *c, QCss::BorderStyle *s, QSize *r, int *o)
434             : QStyleSheetBorderData(b, c, s, r)
435     {
436         for (int i = 0; i < 4; i++) {
437             offsets[i] = o[i];
438         }
439     }
440 
441     int offsets[4];
442 };
443 
444 struct QStyleSheetBoxData : public QSharedData
445 {
QStyleSheetBoxDataQStyleSheetBoxData446     QStyleSheetBoxData(int *m, int *p, int s) : spacing(s)
447     {
448         for (int i = 0; i < 4; i++) {
449             margins[i] = m[i];
450             paddings[i] = p[i];
451         }
452     }
453 
454     int margins[4];
455     int paddings[4];
456 
457     int spacing;
458 };
459 
460 struct QStyleSheetPaletteData : public QSharedData
461 {
QStyleSheetPaletteDataQStyleSheetPaletteData462     QStyleSheetPaletteData(const QBrush &fg, const QBrush &sfg, const QBrush &sbg,
463                            const QBrush &abg)
464         : foreground(fg), selectionForeground(sfg), selectionBackground(sbg),
465           alternateBackground(abg) { }
466 
467     QBrush foreground;
468     QBrush selectionForeground;
469     QBrush selectionBackground;
470     QBrush alternateBackground;
471 };
472 
473 struct QStyleSheetGeometryData : public QSharedData
474 {
QStyleSheetGeometryDataQStyleSheetGeometryData475     QStyleSheetGeometryData(int w, int h, int minw, int minh, int maxw, int maxh)
476         : minWidth(minw), minHeight(minh), width(w), height(h), maxWidth(maxw), maxHeight(maxh) { }
477 
478     int minWidth, minHeight, width, height, maxWidth, maxHeight;
479 };
480 
481 struct QStyleSheetPositionData : public QSharedData
482 {
QStyleSheetPositionDataQStyleSheetPositionData483     QStyleSheetPositionData(int l, int t, int r, int b, Origin o, Qt::Alignment p, QCss::PositionMode m, Qt::Alignment a = { })
484         : left(l), top(t), bottom(b), right(r), origin(o), position(p), mode(m), textAlignment(a) { }
485 
486     int left, top, bottom, right;
487     Origin origin;
488     Qt::Alignment position;
489     QCss::PositionMode mode;
490     Qt::Alignment textAlignment;
491 };
492 
493 struct QStyleSheetImageData : public QSharedData
494 {
QStyleSheetImageDataQStyleSheetImageData495     QStyleSheetImageData(const QIcon &i, Qt::Alignment a, const QSize &sz)
496         : icon(i), alignment(a), size(sz) { }
497 
498     QIcon icon;
499     Qt::Alignment alignment;
500     QSize size;
501 };
502 
503 class QRenderRule
504 {
505 public:
QRenderRule()506     QRenderRule() : features(0), hasFont(false), pal(nullptr), b(nullptr), bg(nullptr), bd(nullptr), ou(nullptr), geo(nullptr), p(nullptr), img(nullptr), clipset(0) { }
507     QRenderRule(const QVector<QCss::Declaration> &, const QObject *);
508 
509     QRect borderRect(const QRect &r) const;
510     QRect outlineRect(const QRect &r) const;
511     QRect paddingRect(const QRect &r) const;
512     QRect contentsRect(const QRect &r) const;
513 
514     enum { Margin = 1, Border = 2, Padding = 4, All=Margin|Border|Padding };
515     QRect boxRect(const QRect &r, int flags = All) const;
516     QSize boxSize(const QSize &s, int flags = All) const;
517     QRect originRect(const QRect &rect, Origin origin) const;
518 
519     QPainterPath borderClip(QRect rect);
520     void drawBorder(QPainter *, const QRect&);
521     void drawOutline(QPainter *, const QRect&);
522     void drawBorderImage(QPainter *, const QRect&);
523     void drawBackground(QPainter *, const QRect&, const QPoint& = QPoint(0, 0));
524     void drawBackgroundImage(QPainter *, const QRect&, QPoint = QPoint(0, 0));
525     void drawFrame(QPainter *, const QRect&);
526     void drawImage(QPainter *p, const QRect &rect);
527     void drawRule(QPainter *, const QRect&);
528     void configurePalette(QPalette *, QPalette::ColorGroup, const QWidget *, bool);
529     void configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette::ColorRole br);
530 
palette() const531     const QStyleSheetPaletteData *palette() const { return pal; }
box() const532     const QStyleSheetBoxData *box() const { return b; }
background() const533     const QStyleSheetBackgroundData *background() const { return bg; }
border() const534     const QStyleSheetBorderData *border() const { return bd; }
outline() const535     const QStyleSheetOutlineData *outline() const { return ou; }
geometry() const536     const QStyleSheetGeometryData *geometry() const { return geo; }
position() const537     const QStyleSheetPositionData *position() const { return p; }
icon() const538     const QStyleSheetImageData *icon() const { return iconPtr; }
539 
540     bool hasModification() const;
541 
hasPalette() const542     bool hasPalette() const { return pal != nullptr; }
hasBackground() const543     bool hasBackground() const { return bg != nullptr && (!bg->pixmap.isNull() || bg->brush.style() != Qt::NoBrush); }
hasGradientBackground() const544     bool hasGradientBackground() const { return bg && bg->brush.style() >= Qt::LinearGradientPattern
545                                                    && bg->brush.style() <= Qt::ConicalGradientPattern; }
546 
hasNativeBorder() const547     bool hasNativeBorder() const {
548         return bd == nullptr
549                || (!bd->hasBorderImage() && bd->styles[0] == BorderStyle_Native);
550     }
551 
hasNativeOutline() const552     bool hasNativeOutline() const {
553         return (ou == nullptr
554                 || (!ou->hasBorderImage() && ou->styles[0] == BorderStyle_Native));
555     }
556 
baseStyleCanDraw() const557     bool baseStyleCanDraw() const {
558         if (!hasBackground() || (background()->brush.style() == Qt::NoBrush && bg->pixmap.isNull()))
559             return true;
560         if (bg && !bg->pixmap.isNull())
561             return false;
562         if (hasGradientBackground())
563             return features & StyleFeature_BackgroundGradient;
564         return features & StyleFeature_BackgroundColor;
565     }
566 
hasBox() const567     bool hasBox() const { return b != nullptr; }
hasBorder() const568     bool hasBorder() const { return bd != nullptr; }
hasOutline() const569     bool hasOutline() const { return ou != nullptr; }
hasPosition() const570     bool hasPosition() const { return p != nullptr; }
hasGeometry() const571     bool hasGeometry() const { return geo != nullptr; }
hasDrawable() const572     bool hasDrawable() const { return !hasNativeBorder() || hasBackground() || hasImage(); }
hasImage() const573     bool hasImage() const { return img != nullptr; }
hasIcon() const574     bool hasIcon() const { return iconPtr != nullptr; }
575 
minimumContentsSize() const576     QSize minimumContentsSize() const
577     { return geo ? QSize(geo->minWidth, geo->minHeight) : QSize(0, 0); }
minimumSize() const578     QSize minimumSize() const
579     { return boxSize(minimumContentsSize()); }
580 
contentsSize() const581     QSize contentsSize() const
582     { return geo ? QSize(geo->width, geo->height)
583                  : ((img && img->size.isValid()) ? img->size : QSize()); }
contentsSize(const QSize & sz) const584     QSize contentsSize(const QSize &sz) const
585     {
586         QSize csz = contentsSize();
587         if (csz.width() == -1) csz.setWidth(sz.width());
588         if (csz.height() == -1) csz.setHeight(sz.height());
589         return csz;
590     }
hasContentsSize() const591     bool hasContentsSize() const
592     { return (geo && (geo->width != -1 || geo->height != -1)) || (img && img->size.isValid()); }
593 
size() const594     QSize size() const { return boxSize(contentsSize()); }
size(const QSize & sz) const595     QSize size(const QSize &sz) const { return boxSize(contentsSize(sz)); }
adjustSize(const QSize & sz)596     QSize adjustSize(const QSize &sz)
597     {
598         if (!geo)
599             return sz;
600         QSize csz = contentsSize();
601         if (csz.width() == -1) csz.setWidth(sz.width());
602         if (csz.height() == -1) csz.setHeight(sz.height());
603         if (geo->maxWidth != -1 && csz.width() > geo->maxWidth) csz.setWidth(geo->maxWidth);
604         if (geo->maxHeight != -1 && csz.height() > geo->maxHeight) csz.setHeight(geo->maxHeight);
605         csz=csz.expandedTo(QSize(geo->minWidth, geo->minHeight));
606         return csz;
607     }
608 
hasStyleHint(const QString & sh) const609     bool hasStyleHint(const QString &sh) const { return styleHints.contains(sh); }
styleHint(const QString & sh) const610     QVariant styleHint(const QString &sh) const { return styleHints.value(sh); }
611 
612     void fixupBorder(int);
613 
614     // Shouldn't be here
615     void setClip(QPainter *p, const QRect &rect);
616     void unsetClip(QPainter *);
617 
618 public:
619     int features;
620     QBrush defaultBackground;
621     QFont font; // Be careful using this font directly. Prefer using font.resolve( )
622     bool hasFont;
623 
624     QHash<QString, QVariant> styleHints;
625 
626     QSharedDataPointer<QStyleSheetPaletteData> pal;
627     QSharedDataPointer<QStyleSheetBoxData> b;
628     QSharedDataPointer<QStyleSheetBackgroundData> bg;
629     QSharedDataPointer<QStyleSheetBorderData> bd;
630     QSharedDataPointer<QStyleSheetOutlineData> ou;
631     QSharedDataPointer<QStyleSheetGeometryData> geo;
632     QSharedDataPointer<QStyleSheetPositionData> p;
633     QSharedDataPointer<QStyleSheetImageData> img;
634     QSharedDataPointer<QStyleSheetImageData> iconPtr;
635 
636     int clipset;
637     QPainterPath clipPath;
638 };
639 Q_DECLARE_TYPEINFO(QRenderRule, Q_MOVABLE_TYPE);
640 
641 ///////////////////////////////////////////////////////////////////////////////////////////
642 static const char knownStyleHints[][45] = {
643     "activate-on-singleclick",
644     "alignment",
645     "arrow-keys-navigate-into-children",
646     "backward-icon",
647     "button-layout",
648     "cd-icon",
649     "combobox-list-mousetracking",
650     "combobox-popup",
651     "computer-icon",
652     "desktop-icon",
653     "dialog-apply-icon",
654     "dialog-cancel-icon",
655     "dialog-close-icon",
656     "dialog-discard-icon",
657     "dialog-help-icon",
658     "dialog-no-icon",
659     "dialog-ok-icon",
660     "dialog-open-icon",
661     "dialog-reset-icon",
662     "dialog-save-icon",
663     "dialog-yes-icon",
664     "dialogbuttonbox-buttons-have-icons",
665     "directory-closed-icon",
666     "directory-icon",
667     "directory-link-icon",
668     "directory-open-icon",
669     "dither-disable-text",
670     "dockwidget-close-icon",
671     "downarrow-icon",
672     "dvd-icon",
673     "etch-disabled-text",
674     "file-icon",
675     "file-link-icon",
676     "filedialog-backward-icon", // unused
677     "filedialog-contentsview-icon",
678     "filedialog-detailedview-icon",
679     "filedialog-end-icon",
680     "filedialog-infoview-icon",
681     "filedialog-listview-icon",
682     "filedialog-new-directory-icon",
683     "filedialog-parent-directory-icon",
684     "filedialog-start-icon",
685     "floppy-icon",
686     "forward-icon",
687     "gridline-color",
688     "harddisk-icon",
689     "home-icon",
690     "icon-size",
691     "leftarrow-icon",
692     "lineedit-password-character",
693     "lineedit-password-mask-delay",
694     "mdi-fill-space-on-maximize",
695     "menu-scrollable",
696     "menubar-altkey-navigation",
697     "menubar-separator",
698     "messagebox-critical-icon",
699     "messagebox-information-icon",
700     "messagebox-question-icon",
701     "messagebox-text-interaction-flags",
702     "messagebox-warning-icon",
703     "mouse-tracking",
704     "network-icon",
705     "opacity",
706     "paint-alternating-row-colors-for-empty-area",
707     "rightarrow-icon",
708     "scrollbar-contextmenu",
709     "scrollbar-leftclick-absolute-position",
710     "scrollbar-middleclick-absolute-position",
711     "scrollbar-roll-between-buttons",
712     "scrollbar-scroll-when-pointer-leaves-control",
713     "scrollview-frame-around-contents",
714     "show-decoration-selected",
715     "spinbox-click-autorepeat-rate",
716     "spincontrol-disable-on-bounds",
717     "tabbar-elide-mode",
718     "tabbar-prefer-no-arrows",
719     "titlebar-close-icon",
720     "titlebar-contexthelp-icon",
721     "titlebar-maximize-icon",
722     "titlebar-menu-icon",
723     "titlebar-minimize-icon",
724     "titlebar-normal-icon",
725     "titlebar-shade-icon",
726     "titlebar-show-tooltips-on-buttons",
727     "titlebar-unshade-icon",
728     "toolbutton-popup-delay",
729     "trash-icon",
730     "uparrow-icon",
731     "widget-animation-duration"
732 };
733 
734 static const int numKnownStyleHints = sizeof(knownStyleHints)/sizeof(knownStyleHints[0]);
735 
subControlLayout(const QString & layout)736 static QList<QVariant> subControlLayout(const QString& layout)
737 {
738     QList<QVariant> buttons;
739     for (int i = 0; i < layout.count(); i++) {
740         int button = layout[i].toLatin1();
741         switch (button) {
742         case 'm':
743             buttons.append(PseudoElement_MdiMinButton);
744             buttons.append(PseudoElement_TitleBarMinButton);
745             break;
746         case 'M':
747             buttons.append(PseudoElement_TitleBarMaxButton);
748             break;
749         case 'X':
750             buttons.append(PseudoElement_MdiCloseButton);
751             buttons.append(PseudoElement_TitleBarCloseButton);
752             break;
753         case 'N':
754             buttons.append(PseudoElement_MdiNormalButton);
755             buttons.append(PseudoElement_TitleBarNormalButton);
756             break;
757         case 'I':
758             buttons.append(PseudoElement_TitleBarSysMenu);
759             break;
760         case 'T':
761             buttons.append(PseudoElement_TitleBar);
762             break;
763         case 'H':
764             buttons.append(PseudoElement_TitleBarContextHelpButton);
765             break;
766         case 'S':
767             buttons.append(PseudoElement_TitleBarShadeButton);
768             break;
769         default:
770             buttons.append(button);
771             break;
772         }
773     }
774     return buttons;
775 }
776 
777 namespace {
778     struct ButtonInfo {
779         QRenderRule rule;
780         int element;
781         int offset;
782         int where;
783         int width;
784     };
785 }
786 template <> class QTypeInfo<ButtonInfo> : public QTypeInfoMerger<ButtonInfo, QRenderRule, int> {};
787 
titleBarLayout(const QWidget * w,const QStyleOptionTitleBar * tb) const788 QHash<QStyle::SubControl, QRect> QStyleSheetStyle::titleBarLayout(const QWidget *w, const QStyleOptionTitleBar *tb) const
789 {
790     QHash<QStyle::SubControl, QRect> layoutRects;
791     const bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
792     const bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
793     QRenderRule subRule = renderRule(w, tb);
794     QRect cr = subRule.contentsRect(tb->rect);
795     QList<QVariant> layout = subRule.styleHint(QLatin1String("button-layout")).toList();
796     if (layout.isEmpty())
797         layout = subControlLayout(QLatin1String("I(T)HSmMX"));
798 
799     int offsets[3] = { 0, 0, 0 };
800     enum Where { Left, Right, Center, NoWhere } where = Left;
801     QVector<ButtonInfo> infos;
802     const int numLayouts = layout.size();
803     infos.reserve(numLayouts);
804     for (int i = 0; i < numLayouts; i++) {
805         const int element = layout[i].toInt();
806         if (element == '(') {
807             where = Center;
808         } else if (element == ')') {
809             where = Right;
810         } else {
811             ButtonInfo info;
812             info.element = element;
813             switch (element) {
814             case PseudoElement_TitleBar:
815                 if (!(tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)))
816                     continue;
817                 break;
818             case PseudoElement_TitleBarContextHelpButton:
819                 if (!(tb->titleBarFlags & Qt::WindowContextHelpButtonHint))
820                     continue;
821                 break;
822             case PseudoElement_TitleBarMinButton:
823                 if (!(tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
824                     continue;
825                 if (isMinimized)
826                     info.element = PseudoElement_TitleBarNormalButton;
827                 break;
828             case PseudoElement_TitleBarMaxButton:
829                 if (!(tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
830                     continue;
831                 if (isMaximized)
832                     info.element = PseudoElement_TitleBarNormalButton;
833                 break;
834             case PseudoElement_TitleBarShadeButton:
835                 if (!(tb->titleBarFlags & Qt::WindowShadeButtonHint))
836                     continue;
837                 if (isMinimized)
838                     info.element = PseudoElement_TitleBarUnshadeButton;
839                 break;
840             case PseudoElement_TitleBarCloseButton:
841             case PseudoElement_TitleBarSysMenu:
842                 if (!(tb->titleBarFlags & Qt::WindowSystemMenuHint))
843                     continue;
844                 break;
845             default:
846                 continue;
847             }
848             if (info.element == PseudoElement_TitleBar) {
849                 info.width = tb->fontMetrics.horizontalAdvance(tb->text) + 6;
850                 subRule.geo = new QStyleSheetGeometryData(info.width, tb->fontMetrics.height(), -1, -1, -1, -1);
851             } else {
852                 subRule = renderRule(w, tb, info.element);
853                 info.width = subRule.size().width();
854             }
855             info.rule = subRule;
856             info.offset = offsets[where];
857             info.where = where;
858             infos.append(std::move(info));
859 
860             offsets[where] += info.width;
861         }
862     }
863 
864     for (int i = 0; i < infos.size(); i++) {
865         const ButtonInfo &info = infos[i];
866         QRect lr = cr;
867         switch (info.where) {
868         case Center: {
869             lr.setLeft(cr.left() + offsets[Left]);
870             lr.setRight(cr.right() - offsets[Right]);
871             QRect r(0, 0, offsets[Center], lr.height());
872             r.moveCenter(lr.center());
873             r.setLeft(r.left()+info.offset);
874             r.setWidth(info.width);
875             lr = r;
876             break; }
877         case Left:
878             lr.translate(info.offset, 0);
879             lr.setWidth(info.width);
880             break;
881         case Right:
882             lr.moveLeft(cr.right() + 1 - offsets[Right] + info.offset);
883             lr.setWidth(info.width);
884             break;
885         default:
886             break;
887         }
888         QStyle::SubControl control = knownPseudoElements[info.element].subControl;
889         layoutRects[control] = positionRect(w, info.rule, info.element, lr, tb->direction);
890     }
891 
892     return layoutRects;
893 }
894 
subControlIcon(int pe)895 static QStyle::StandardPixmap subControlIcon(int pe)
896 {
897     switch (pe) {
898     case PseudoElement_MdiCloseButton: return QStyle::SP_TitleBarCloseButton;
899     case PseudoElement_MdiMinButton: return QStyle::SP_TitleBarMinButton;
900     case PseudoElement_MdiNormalButton: return QStyle::SP_TitleBarNormalButton;
901     case PseudoElement_TitleBarCloseButton: return QStyle::SP_TitleBarCloseButton;
902     case PseudoElement_TitleBarMinButton: return QStyle::SP_TitleBarMinButton;
903     case PseudoElement_TitleBarMaxButton: return QStyle::SP_TitleBarMaxButton;
904     case PseudoElement_TitleBarShadeButton: return QStyle::SP_TitleBarShadeButton;
905     case PseudoElement_TitleBarUnshadeButton: return QStyle::SP_TitleBarUnshadeButton;
906     case PseudoElement_TitleBarNormalButton: return QStyle::SP_TitleBarNormalButton;
907     case PseudoElement_TitleBarContextHelpButton: return QStyle::SP_TitleBarContextHelpButton;
908     default: break;
909     }
910     return QStyle::SP_CustomBase;
911 }
912 
QRenderRule(const QVector<Declaration> & declarations,const QObject * object)913 QRenderRule::QRenderRule(const QVector<Declaration> &declarations, const QObject *object)
914 : features(0), hasFont(false), pal(nullptr), b(nullptr), bg(nullptr), bd(nullptr), ou(nullptr), geo(nullptr), p(nullptr), img(nullptr), clipset(0)
915 {
916     QPalette palette = QGuiApplication::palette(); // ###: ideally widget's palette
917     ValueExtractor v(declarations, palette);
918     features = v.extractStyleFeatures();
919 
920     int w = -1, h = -1, minw = -1, minh = -1, maxw = -1, maxh = -1;
921     if (v.extractGeometry(&w, &h, &minw, &minh, &maxw, &maxh))
922         geo = new QStyleSheetGeometryData(w, h, minw, minh, maxw, maxh);
923 
924     int left = 0, top = 0, right = 0, bottom = 0;
925     Origin origin = Origin_Unknown;
926     Qt::Alignment position;
927     QCss::PositionMode mode = PositionMode_Unknown;
928     Qt::Alignment textAlignment;
929     if (v.extractPosition(&left, &top, &right, &bottom, &origin, &position, &mode, &textAlignment))
930         p = new QStyleSheetPositionData(left, top, right, bottom, origin, position, mode, textAlignment);
931 
932     int margins[4], paddings[4], spacing = -1;
933     for (int i = 0; i < 4; i++)
934         margins[i] = paddings[i] = 0;
935     if (v.extractBox(margins, paddings, &spacing))
936         b = new QStyleSheetBoxData(margins, paddings, spacing);
937 
938     int borders[4];
939     QBrush colors[4];
940     QCss::BorderStyle styles[4];
941     QSize radii[4];
942     for (int i = 0; i < 4; i++) {
943         borders[i] = 0;
944         styles[i] = BorderStyle_None;
945     }
946     if (v.extractBorder(borders, colors, styles, radii))
947         bd = new QStyleSheetBorderData(borders, colors, styles, radii);
948 
949     int offsets[4];
950     for (int i = 0; i < 4; i++) {
951         borders[i] = offsets[i] = 0;
952         styles[i] = BorderStyle_None;
953     }
954     if (v.extractOutline(borders, colors, styles, radii, offsets))
955         ou = new QStyleSheetOutlineData(borders, colors, styles, radii, offsets);
956 
957     QBrush brush;
958     QString uri;
959     Repeat repeat = Repeat_XY;
960     Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft;
961     Attachment attachment = Attachment_Scroll;
962     origin = Origin_Padding;
963     Origin clip = Origin_Border;
964     if (v.extractBackground(&brush, &uri, &repeat, &alignment, &origin, &attachment, &clip)) {
965         QPixmap pixmap = QStyleSheetStyle::loadPixmap(uri, object);
966         if (!uri.isEmpty() && pixmap.isNull())
967             qWarning("Could not create pixmap from %s", qPrintable(QDir::toNativeSeparators(uri)));
968         bg = new QStyleSheetBackgroundData(brush, pixmap, repeat, alignment, origin, attachment, clip);
969     }
970 
971     QBrush sfg, fg;
972     QBrush sbg, abg;
973     if (v.extractPalette(&fg, &sfg, &sbg, &abg))
974         pal = new QStyleSheetPaletteData(fg, sfg, sbg, abg);
975 
976     QIcon imgIcon;
977     alignment = Qt::AlignCenter;
978     QSize imgSize;
979     if (v.extractImage(&imgIcon, &alignment, &imgSize))
980         img = new QStyleSheetImageData(imgIcon, alignment, imgSize);
981 
982     QIcon icon;
983     QSize size;
984     if (v.extractIcon(&icon, &size))
985         iconPtr = new QStyleSheetImageData(icon, Qt::AlignCenter, size);
986 
987     int adj = -255;
988     hasFont = v.extractFont(&font, &adj);
989 
990 #ifndef QT_NO_TOOLTIP
991     if (object && qstrcmp(object->metaObject()->className(), "QTipLabel") == 0)
992         palette = QToolTip::palette();
993 #endif
994 
995     for (int i = 0; i < declarations.count(); i++) {
996         const Declaration& decl = declarations.at(i);
997         if (decl.d->propertyId == BorderImage) {
998             QString uri;
999             QCss::TileMode horizStretch, vertStretch;
1000             int cuts[4];
1001 
1002             decl.borderImageValue(&uri, cuts, &horizStretch, &vertStretch);
1003             if (uri.isEmpty() || uri == QLatin1String("none")) {
1004                 if (bd && bd->bi)
1005                     bd->bi->pixmap = QPixmap();
1006             } else {
1007                 if (!bd)
1008                     bd = new QStyleSheetBorderData;
1009                 if (!bd->bi)
1010                     bd->bi = new QStyleSheetBorderImageData;
1011 
1012                 QStyleSheetBorderImageData *bi = bd->bi;
1013                 bi->pixmap = QStyleSheetStyle::loadPixmap(uri, object);
1014                 for (int i = 0; i < 4; i++)
1015                     bi->cuts[i] = cuts[i];
1016                 bi->horizStretch = horizStretch;
1017                 bi->vertStretch = vertStretch;
1018             }
1019         } else if (decl.d->propertyId == QtBackgroundRole) {
1020             if (bg && bg->brush.style() != Qt::NoBrush)
1021                 continue;
1022             int role = decl.d->values.at(0).variant.toInt();
1023             if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
1024                 defaultBackground = palette.color((QPalette::ColorRole)(role-Value_FirstColorRole));
1025         } else if (decl.d->property.startsWith(QLatin1String("qproperty-"), Qt::CaseInsensitive)) {
1026             // intentionally left blank...
1027         } else if (decl.d->propertyId == UnknownProperty) {
1028             bool knownStyleHint = false;
1029             for (int i = 0; i < numKnownStyleHints; i++) {
1030                 QLatin1String styleHint(knownStyleHints[i]);
1031                 if (decl.d->property.compare(styleHint) == 0) {
1032                    QString hintName = QString(styleHint);
1033                    QVariant hintValue;
1034                    if (hintName.endsWith(QLatin1String("alignment"))) {
1035                        hintValue = (int) decl.alignmentValue();
1036                    } else if (hintName.endsWith(QLatin1String("color"))) {
1037                        hintValue = (int) decl.colorValue().rgba();
1038                    } else if (hintName.endsWith(QLatin1String("size"))) {
1039                        hintValue = decl.sizeValue();
1040                    } else if (hintName.endsWith(QLatin1String("icon"))) {
1041                        hintValue = decl.iconValue();
1042                    } else if (hintName == QLatin1String("button-layout")
1043                               && decl.d->values.count() != 0 && decl.d->values.at(0).type == Value::String) {
1044                        hintValue = subControlLayout(decl.d->values.at(0).variant.toString());
1045                    } else {
1046                        int integer;
1047                        decl.intValue(&integer);
1048                        hintValue = integer;
1049                    }
1050                    styleHints[decl.d->property] = hintValue;
1051                    knownStyleHint = true;
1052                    break;
1053                 }
1054             }
1055             if (!knownStyleHint)
1056                 qDebug("Unknown property %s", qPrintable(decl.d->property));
1057         }
1058     }
1059 
1060     if (hasBorder()) {
1061         if (const QWidget *widget = qobject_cast<const QWidget *>(object)) {
1062             QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle);
1063             if (!style)
1064                 style = qt_styleSheet(widget->style());
1065             if (style)
1066                 fixupBorder(style->nativeFrameWidth(widget));
1067         }
1068         if (border()->hasBorderImage())
1069             defaultBackground = QBrush();
1070     }
1071 }
1072 
borderRect(const QRect & r) const1073 QRect QRenderRule::borderRect(const QRect& r) const
1074 {
1075     if (!hasBox())
1076         return r;
1077     const int* m = box()->margins;
1078     return r.adjusted(m[LeftEdge], m[TopEdge], -m[RightEdge], -m[BottomEdge]);
1079 }
1080 
outlineRect(const QRect & r) const1081 QRect QRenderRule::outlineRect(const QRect& r) const
1082 {
1083     QRect br = borderRect(r);
1084     if (!hasOutline())
1085         return br;
1086     const int *b = outline()->borders;
1087     return r.adjusted(b[LeftEdge], b[TopEdge], -b[RightEdge], -b[BottomEdge]);
1088 }
1089 
paddingRect(const QRect & r) const1090 QRect QRenderRule::paddingRect(const QRect& r) const
1091 {
1092     QRect br = borderRect(r);
1093     if (!hasBorder())
1094         return br;
1095     const int *b = border()->borders;
1096     return br.adjusted(b[LeftEdge], b[TopEdge], -b[RightEdge], -b[BottomEdge]);
1097 }
1098 
contentsRect(const QRect & r) const1099 QRect QRenderRule::contentsRect(const QRect& r) const
1100 {
1101     QRect pr = paddingRect(r);
1102     if (!hasBox())
1103         return pr;
1104     const int *p = box()->paddings;
1105     return pr.adjusted(p[LeftEdge], p[TopEdge], -p[RightEdge], -p[BottomEdge]);
1106 }
1107 
boxRect(const QRect & cr,int flags) const1108 QRect QRenderRule::boxRect(const QRect& cr, int flags) const
1109 {
1110     QRect r = cr;
1111     if (hasBox()) {
1112         if (flags & Margin) {
1113             const int *m = box()->margins;
1114             r.adjust(-m[LeftEdge], -m[TopEdge], m[RightEdge], m[BottomEdge]);
1115         }
1116         if (flags & Padding) {
1117             const int *p = box()->paddings;
1118             r.adjust(-p[LeftEdge], -p[TopEdge], p[RightEdge], p[BottomEdge]);
1119         }
1120     }
1121     if (hasBorder() && (flags & Border)) {
1122         const int *b = border()->borders;
1123         r.adjust(-b[LeftEdge], -b[TopEdge], b[RightEdge], b[BottomEdge]);
1124     }
1125     return r;
1126 }
1127 
boxSize(const QSize & cs,int flags) const1128 QSize QRenderRule::boxSize(const QSize &cs, int flags) const
1129 {
1130     QSize bs = boxRect(QRect(QPoint(0, 0), cs), flags).size();
1131     if (cs.width() < 0) bs.setWidth(-1);
1132     if (cs.height() < 0) bs.setHeight(-1);
1133     return bs;
1134 }
1135 
fixupBorder(int nativeWidth)1136 void QRenderRule::fixupBorder(int nativeWidth)
1137 {
1138     if (bd == nullptr)
1139         return;
1140 
1141     if (!bd->hasBorderImage() || bd->bi->pixmap.isNull()) {
1142         bd->bi = nullptr;
1143         // ignore the color, border of edges that have none border-style
1144         QBrush color = pal ? pal->foreground : QBrush();
1145         const bool hasRadius = bd->radii[0].isValid() || bd->radii[1].isValid()
1146                                || bd->radii[2].isValid() || bd->radii[3].isValid();
1147         for (int i = 0; i < 4; i++) {
1148             if ((bd->styles[i] == BorderStyle_Native) && hasRadius)
1149                 bd->styles[i] = BorderStyle_None;
1150 
1151             switch (bd->styles[i]) {
1152             case BorderStyle_None:
1153                 // border-style: none forces width to be 0
1154                 bd->colors[i] = QBrush();
1155                 bd->borders[i] = 0;
1156                 break;
1157             case BorderStyle_Native:
1158                 if (bd->borders[i] == 0)
1159                     bd->borders[i] = nativeWidth;
1160                 Q_FALLTHROUGH();
1161             default:
1162                 if (bd->colors[i].style() == Qt::NoBrush) // auto-acquire 'color'
1163                     bd->colors[i] = color;
1164                 break;
1165             }
1166         }
1167 
1168         return;
1169     }
1170 
1171     // inspect the border image
1172     QStyleSheetBorderImageData *bi = bd->bi;
1173     if (bi->cuts[0] == -1) {
1174         for (int i = 0; i < 4; i++) // assume, cut = border
1175             bi->cuts[i] = int(border()->borders[i]);
1176     }
1177 }
1178 
drawBorderImage(QPainter * p,const QRect & rect)1179 void QRenderRule::drawBorderImage(QPainter *p, const QRect& rect)
1180 {
1181     setClip(p, rect);
1182     static const Qt::TileRule tileMode2TileRule[] = {
1183         Qt::StretchTile, Qt::RoundTile, Qt::StretchTile, Qt::RepeatTile, Qt::StretchTile };
1184 
1185     const QStyleSheetBorderImageData *borderImageData = border()->borderImage();
1186     const int *targetBorders = border()->borders;
1187     const int *sourceBorders = borderImageData->cuts;
1188     QMargins sourceMargins(sourceBorders[LeftEdge], sourceBorders[TopEdge],
1189                            sourceBorders[RightEdge], sourceBorders[BottomEdge]);
1190     QMargins targetMargins(targetBorders[LeftEdge], targetBorders[TopEdge],
1191                            targetBorders[RightEdge], targetBorders[BottomEdge]);
1192 
1193     bool wasSmoothPixmapTransform = p->renderHints() & QPainter::SmoothPixmapTransform;
1194     p->setRenderHint(QPainter::SmoothPixmapTransform);
1195     qDrawBorderPixmap(p, rect, targetMargins, borderImageData->pixmap,
1196                       QRect(QPoint(), borderImageData->pixmap.size()), sourceMargins,
1197                       QTileRules(tileMode2TileRule[borderImageData->horizStretch], tileMode2TileRule[borderImageData->vertStretch]));
1198     p->setRenderHint(QPainter::SmoothPixmapTransform, wasSmoothPixmapTransform);
1199     unsetClip(p);
1200 }
1201 
originRect(const QRect & rect,Origin origin) const1202 QRect QRenderRule::originRect(const QRect &rect, Origin origin) const
1203 {
1204     switch (origin) {
1205     case Origin_Padding:
1206         return paddingRect(rect);
1207     case Origin_Border:
1208         return borderRect(rect);
1209     case Origin_Content:
1210         return contentsRect(rect);
1211     case Origin_Margin:
1212     default:
1213         return rect;
1214     }
1215 }
1216 
drawBackgroundImage(QPainter * p,const QRect & rect,QPoint off)1217 void QRenderRule::drawBackgroundImage(QPainter *p, const QRect &rect, QPoint off)
1218 {
1219     if (!hasBackground())
1220         return;
1221 
1222     const QPixmap& bgp = background()->pixmap;
1223     if (bgp.isNull())
1224         return;
1225 
1226     setClip(p, borderRect(rect));
1227 
1228     if (background()->origin != background()->clip) {
1229         p->save();
1230         p->setClipRect(originRect(rect, background()->clip), Qt::IntersectClip);
1231     }
1232 
1233     if (background()->attachment == Attachment_Fixed)
1234         off = QPoint(0, 0);
1235 
1236     QSize bgpSize = bgp.size() / bgp.devicePixelRatio();
1237     int bgpHeight = bgpSize.height();
1238     int bgpWidth = bgpSize.width();
1239     QRect r = originRect(rect, background()->origin);
1240     QRect aligned = QStyle::alignedRect(Qt::LeftToRight, background()->position, bgpSize, r);
1241     QRect inter = aligned.translated(-off).intersected(r);
1242 
1243     switch (background()->repeat) {
1244     case Repeat_Y:
1245         p->drawTiledPixmap(inter.x(), r.y(), inter.width(), r.height(), bgp,
1246                            inter.x() - aligned.x() + off.x(),
1247                            bgpHeight - int(aligned.y() - r.y()) % bgpHeight + off.y());
1248         break;
1249     case Repeat_X:
1250         p->drawTiledPixmap(r.x(), inter.y(), r.width(), inter.height(), bgp,
1251                            bgpWidth - int(aligned.x() - r.x())%bgpWidth + off.x(),
1252                            inter.y() - aligned.y() + off.y());
1253         break;
1254     case Repeat_XY:
1255         p->drawTiledPixmap(r, bgp,
1256                             QPoint(bgpWidth - int(aligned.x() - r.x())% bgpWidth + off.x(),
1257                                    bgpHeight - int(aligned.y() - r.y())%bgpHeight + off.y()));
1258         break;
1259     case Repeat_None:
1260     default:
1261         p->drawPixmap(inter.x(), inter.y(), bgp, inter.x() - aligned.x() + off.x(),
1262                       inter.y() - aligned.y() + off.y(), bgp.width() , bgp.height());
1263         break;
1264     }
1265 
1266 
1267     if (background()->origin != background()->clip)
1268         p->restore();
1269 
1270     unsetClip(p);
1271 }
1272 
drawOutline(QPainter * p,const QRect & rect)1273 void QRenderRule::drawOutline(QPainter *p, const QRect &rect)
1274 {
1275     if (!hasOutline())
1276         return;
1277 
1278     bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1279     p->setRenderHint(QPainter::Antialiasing);
1280     qDrawBorder(p, rect, ou->styles, ou->borders, ou->colors, ou->radii);
1281     p->setRenderHint(QPainter::Antialiasing, wasAntialiased);
1282 }
1283 
drawBorder(QPainter * p,const QRect & rect)1284 void QRenderRule::drawBorder(QPainter *p, const QRect& rect)
1285 {
1286     if (!hasBorder())
1287         return;
1288 
1289     if (border()->hasBorderImage()) {
1290         drawBorderImage(p, rect);
1291         return;
1292     }
1293 
1294     bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1295     p->setRenderHint(QPainter::Antialiasing);
1296     qDrawBorder(p, rect, bd->styles, bd->borders, bd->colors, bd->radii);
1297     p->setRenderHint(QPainter::Antialiasing, wasAntialiased);
1298 }
1299 
borderClip(QRect r)1300 QPainterPath QRenderRule::borderClip(QRect r)
1301 {
1302     if (!hasBorder())
1303         return QPainterPath();
1304 
1305     QSize tlr, trr, blr, brr;
1306     qNormalizeRadii(r, bd->radii, &tlr, &trr, &blr, &brr);
1307     if (tlr.isNull() && trr.isNull() && blr.isNull() && brr.isNull())
1308         return QPainterPath();
1309 
1310     const QRectF rect(r);
1311     const int *borders = border()->borders;
1312     QPainterPath path;
1313     qreal curY = rect.y() + borders[TopEdge]/2.0;
1314     path.moveTo(rect.x() + tlr.width(), curY);
1315     path.lineTo(rect.right() - trr.width(), curY);
1316     qreal curX = rect.right() - borders[RightEdge]/2.0;
1317     path.arcTo(curX - 2*trr.width() + borders[RightEdge], curY,
1318                trr.width()*2 - borders[RightEdge], trr.height()*2 - borders[TopEdge], 90, -90);
1319 
1320     path.lineTo(curX, rect.bottom() - brr.height());
1321     curY = rect.bottom() - borders[BottomEdge]/2.0;
1322     path.arcTo(curX - 2*brr.width() + borders[RightEdge], curY - 2*brr.height() + borders[BottomEdge],
1323                brr.width()*2 - borders[RightEdge], brr.height()*2 - borders[BottomEdge], 0, -90);
1324 
1325     path.lineTo(rect.x() + blr.width(), curY);
1326     curX = rect.left() + borders[LeftEdge]/2.0;
1327     path.arcTo(curX, rect.bottom() - 2*blr.height() + borders[BottomEdge]/2.0,
1328                blr.width()*2 - borders[LeftEdge], blr.height()*2 - borders[BottomEdge], 270, -90);
1329 
1330     path.lineTo(curX, rect.top() + tlr.height());
1331     path.arcTo(curX, rect.top() + borders[TopEdge]/2.0,
1332                tlr.width()*2 - borders[LeftEdge], tlr.height()*2 - borders[TopEdge], 180, -90);
1333 
1334     path.closeSubpath();
1335     return path;
1336 }
1337 
1338 /*! \internal
1339   Clip the painter to the border (in case we are using radius border)
1340  */
setClip(QPainter * p,const QRect & rect)1341 void QRenderRule::setClip(QPainter *p, const QRect &rect)
1342 {
1343     if (clipset++)
1344         return;
1345     clipPath = borderClip(rect);
1346     if (!clipPath.isEmpty()) {
1347         p->save();
1348         p->setClipPath(clipPath, Qt::IntersectClip);
1349     }
1350 }
1351 
unsetClip(QPainter * p)1352 void QRenderRule::unsetClip(QPainter *p)
1353 {
1354     if (--clipset)
1355         return;
1356     if (!clipPath.isEmpty())
1357         p->restore();
1358 }
1359 
drawBackground(QPainter * p,const QRect & rect,const QPoint & off)1360 void QRenderRule::drawBackground(QPainter *p, const QRect& rect, const QPoint& off)
1361 {
1362     QBrush brush = hasBackground() ? background()->brush : QBrush();
1363     if (brush.style() == Qt::NoBrush)
1364         brush = defaultBackground;
1365 
1366     if (brush.style() != Qt::NoBrush) {
1367         Origin origin = hasBackground() ? background()->clip : Origin_Border;
1368         // ### fix for  gradients
1369         const QPainterPath &borderPath = borderClip(originRect(rect, origin));
1370         if (!borderPath.isEmpty()) {
1371             // Drawn intead of being used as clipping path for better visual quality
1372             bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1373             p->setRenderHint(QPainter::Antialiasing);
1374             p->fillPath(borderPath, brush);
1375             p->setRenderHint(QPainter::Antialiasing, wasAntialiased);
1376         } else {
1377             p->fillRect(originRect(rect, origin), brush);
1378         }
1379     }
1380 
1381     drawBackgroundImage(p, rect, off);
1382 }
1383 
drawFrame(QPainter * p,const QRect & rect)1384 void QRenderRule::drawFrame(QPainter *p, const QRect& rect)
1385 {
1386     drawBackground(p, rect);
1387     if (hasBorder())
1388         drawBorder(p, borderRect(rect));
1389 }
1390 
drawImage(QPainter * p,const QRect & rect)1391 void QRenderRule::drawImage(QPainter *p, const QRect &rect)
1392 {
1393     if (!hasImage())
1394         return;
1395     img->icon.paint(p, rect, img->alignment);
1396 }
1397 
drawRule(QPainter * p,const QRect & rect)1398 void QRenderRule::drawRule(QPainter *p, const QRect& rect)
1399 {
1400     drawFrame(p, rect);
1401     drawImage(p, contentsRect(rect));
1402 }
1403 
1404 // *shudder* , *horror*, *whoa* <-- what you might feel when you see the functions below
configurePalette(QPalette * p,QPalette::ColorRole fr,QPalette::ColorRole br)1405 void QRenderRule::configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette::ColorRole br)
1406 {
1407     if (bg && bg->brush.style() != Qt::NoBrush) {
1408         if (br != QPalette::NoRole)
1409             p->setBrush(br, bg->brush);
1410         p->setBrush(QPalette::Window, bg->brush);
1411         if (bg->brush.style() == Qt::SolidPattern) {
1412             p->setBrush(QPalette::Light, bg->brush.color().lighter(115));
1413             p->setBrush(QPalette::Midlight, bg->brush.color().lighter(107));
1414             p->setBrush(QPalette::Dark, bg->brush.color().darker(150));
1415             p->setBrush(QPalette::Shadow, bg->brush.color().darker(300));
1416         }
1417     }
1418 
1419     if (!hasPalette())
1420         return;
1421 
1422     if (pal->foreground.style() != Qt::NoBrush) {
1423         if (fr != QPalette::NoRole)
1424             p->setBrush(fr, pal->foreground);
1425         p->setBrush(QPalette::WindowText, pal->foreground);
1426         p->setBrush(QPalette::Text, pal->foreground);
1427     }
1428     if (pal->selectionBackground.style() != Qt::NoBrush)
1429         p->setBrush(QPalette::Highlight, pal->selectionBackground);
1430     if (pal->selectionForeground.style() != Qt::NoBrush)
1431         p->setBrush(QPalette::HighlightedText, pal->selectionForeground);
1432     if (pal->alternateBackground.style() != Qt::NoBrush)
1433         p->setBrush(QPalette::AlternateBase, pal->alternateBackground);
1434 }
1435 
configurePalette(QPalette * p,QPalette::ColorGroup cg,const QWidget * w,bool embedded)1436 void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const QWidget *w, bool embedded)
1437 {
1438     if (bg && bg->brush.style() != Qt::NoBrush) {
1439         p->setBrush(cg, QPalette::Base, bg->brush); // for windows, windowxp
1440         p->setBrush(cg, QPalette::Button, bg->brush); // for plastique
1441         p->setBrush(cg, w->backgroundRole(), bg->brush);
1442         p->setBrush(cg, QPalette::Window, bg->brush);
1443     }
1444 
1445     if (embedded) {
1446         /* For embedded widgets (ComboBox, SpinBox and ScrollArea) we want the embedded widget
1447          * to be transparent when we have a transparent background or border image */
1448         if ((hasBackground() && background()->isTransparent())
1449             || (hasBorder() && border()->hasBorderImage() && !border()->borderImage()->pixmap.isNull()))
1450             p->setBrush(cg, w->backgroundRole(), Qt::NoBrush);
1451     }
1452 
1453     if (!hasPalette())
1454         return;
1455 
1456     if (pal->foreground.style() != Qt::NoBrush) {
1457         p->setBrush(cg, QPalette::ButtonText, pal->foreground);
1458         p->setBrush(cg, w->foregroundRole(), pal->foreground);
1459         p->setBrush(cg, QPalette::WindowText, pal->foreground);
1460         p->setBrush(cg, QPalette::Text, pal->foreground);
1461     }
1462     if (pal->selectionBackground.style() != Qt::NoBrush)
1463         p->setBrush(cg, QPalette::Highlight, pal->selectionBackground);
1464     if (pal->selectionForeground.style() != Qt::NoBrush)
1465         p->setBrush(cg, QPalette::HighlightedText, pal->selectionForeground);
1466     if (pal->alternateBackground.style() != Qt::NoBrush)
1467         p->setBrush(cg, QPalette::AlternateBase, pal->alternateBackground);
1468 }
1469 
hasModification() const1470 bool QRenderRule::hasModification() const
1471 {
1472     return hasPalette() ||
1473            hasBackground() ||
1474            hasGradientBackground() ||
1475            !hasNativeBorder() ||
1476            !hasNativeOutline() ||
1477            hasBox() ||
1478            hasPosition() ||
1479            hasGeometry() ||
1480            hasImage() ||
1481            hasFont ||
1482            !styleHints.isEmpty();
1483 }
1484 
1485 ///////////////////////////////////////////////////////////////////////////////
1486 // Style rules
1487 #define OBJECT_PTR(x) (static_cast<QObject *>(x.ptr))
1488 
parentObject(const QObject * obj)1489 static inline QObject *parentObject(const QObject *obj)
1490 {
1491 #if QT_CONFIG(tooltip)
1492     if (qobject_cast<const QLabel *>(obj) && qstrcmp(obj->metaObject()->className(), "QTipLabel") == 0) {
1493         QObject *p = qvariant_cast<QObject *>(obj->property("_q_stylesheet_parent"));
1494         if (p)
1495             return p;
1496     }
1497 #endif
1498     return obj->parent();
1499 }
1500 
1501 class QStyleSheetStyleSelector : public StyleSelector
1502 {
1503 public:
QStyleSheetStyleSelector()1504     QStyleSheetStyleSelector() { }
1505 
nodeNames(NodePtr node) const1506     QStringList nodeNames(NodePtr node) const override
1507     {
1508         if (isNullNode(node))
1509             return QStringList();
1510         const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject();
1511 #ifndef QT_NO_TOOLTIP
1512         if (qstrcmp(metaObject->className(), "QTipLabel") == 0)
1513             return QStringList(QLatin1String("QToolTip"));
1514 #endif
1515         QStringList result;
1516         do {
1517             result += QString::fromLatin1(metaObject->className()).replace(QLatin1Char(':'), QLatin1Char('-'));
1518             metaObject = metaObject->superClass();
1519         } while (metaObject != nullptr);
1520         return result;
1521     }
attribute(NodePtr node,const QString & name) const1522     QString attribute(NodePtr node, const QString& name) const override
1523     {
1524         if (isNullNode(node))
1525             return QString();
1526 
1527         QHash<QString, QString> &cache = m_attributeCache[OBJECT_PTR(node)];
1528         QHash<QString, QString>::const_iterator cacheIt = cache.constFind(name);
1529         if (cacheIt != cache.constEnd())
1530             return cacheIt.value();
1531 
1532         QObject *obj = OBJECT_PTR(node);
1533         QVariant value = obj->property(name.toLatin1());
1534         if (!value.isValid()) {
1535             if (name == QLatin1String("class")) {
1536                 QString className = QString::fromLatin1(obj->metaObject()->className());
1537                 if (className.contains(QLatin1Char(':')))
1538                     className.replace(QLatin1Char(':'), QLatin1Char('-'));
1539                 cache[name] = className;
1540                 return className;
1541             } else if (name == QLatin1String("style")) {
1542                 QWidget *w = qobject_cast<QWidget *>(obj);
1543                 QStyleSheetStyle *proxy = w ? qt_styleSheet(w->style()) : nullptr;
1544                 if (proxy) {
1545                     QString styleName = QString::fromLatin1(proxy->baseStyle()->metaObject()->className());
1546                     cache[name] = styleName;
1547                     return styleName;
1548                 }
1549             }
1550         }
1551         QString valueStr = (value.userType() == QMetaType::QStringList
1552             || value.userType() == QMetaType::QVariantList)
1553             ? value.toStringList().join(QLatin1Char(' '))
1554             : value.toString();
1555         cache[name] = valueStr;
1556         return valueStr;
1557     }
nodeNameEquals(NodePtr node,const QString & nodeName) const1558     bool nodeNameEquals(NodePtr node, const QString& nodeName) const override
1559     {
1560         if (isNullNode(node))
1561             return false;
1562         const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject();
1563 #ifndef QT_NO_TOOLTIP
1564         if (qstrcmp(metaObject->className(), "QTipLabel") == 0)
1565             return nodeName == QLatin1String("QToolTip");
1566 #endif
1567         do {
1568             const ushort *uc = (const ushort *)nodeName.constData();
1569             const ushort *e = uc + nodeName.length();
1570             const uchar *c = (const uchar *)metaObject->className();
1571             while (*c && uc != e && (*uc == *c || (*c == ':' && *uc == '-'))) {
1572                 ++uc;
1573                 ++c;
1574             }
1575             if (uc == e && !*c)
1576                 return true;
1577             metaObject = metaObject->superClass();
1578         } while (metaObject != nullptr);
1579         return false;
1580     }
hasAttributes(NodePtr) const1581     bool hasAttributes(NodePtr) const override
1582     { return true; }
nodeIds(NodePtr node) const1583     QStringList nodeIds(NodePtr node) const override
1584     { return isNullNode(node) ? QStringList() : QStringList(OBJECT_PTR(node)->objectName()); }
isNullNode(NodePtr node) const1585     bool isNullNode(NodePtr node) const override
1586     { return node.ptr == nullptr; }
parentNode(NodePtr node) const1587     NodePtr parentNode(NodePtr node) const override
1588     { NodePtr n; n.ptr = isNullNode(node) ? nullptr : parentObject(OBJECT_PTR(node)); return n; }
previousSiblingNode(NodePtr) const1589     NodePtr previousSiblingNode(NodePtr) const override
1590     { NodePtr n; n.ptr = nullptr; return n; }
duplicateNode(NodePtr node) const1591     NodePtr duplicateNode(NodePtr node) const override
1592     { return node; }
freeNode(NodePtr) const1593     void freeNode(NodePtr) const override
1594     { }
1595 
1596 private:
1597     mutable QHash<const QObject *, QHash<QString, QString> > m_attributeCache;
1598 };
1599 
styleRules(const QObject * obj) const1600 QVector<QCss::StyleRule> QStyleSheetStyle::styleRules(const QObject *obj) const
1601 {
1602     QHash<const QObject *, QVector<StyleRule> >::const_iterator cacheIt = styleSheetCaches->styleRulesCache.constFind(obj);
1603     if (cacheIt != styleSheetCaches->styleRulesCache.constEnd())
1604         return cacheIt.value();
1605 
1606     if (!initObject(obj)) {
1607         return QVector<StyleRule>();
1608     }
1609 
1610     QStyleSheetStyleSelector styleSelector;
1611 
1612     StyleSheet defaultSs;
1613     QHash<const void *, StyleSheet>::const_iterator defaultCacheIt = styleSheetCaches->styleSheetCache.constFind(baseStyle());
1614     if (defaultCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1615         defaultSs = getDefaultStyleSheet();
1616         QStyle *bs = baseStyle();
1617         styleSheetCaches->styleSheetCache.insert(bs, defaultSs);
1618         QObject::connect(bs, SIGNAL(destroyed(QObject*)), styleSheetCaches, SLOT(styleDestroyed(QObject*)), Qt::UniqueConnection);
1619     } else {
1620         defaultSs = defaultCacheIt.value();
1621     }
1622     styleSelector.styleSheets += defaultSs;
1623 
1624     if (!qApp->styleSheet().isEmpty()) {
1625         StyleSheet appSs;
1626         QHash<const void *, StyleSheet>::const_iterator appCacheIt = styleSheetCaches->styleSheetCache.constFind(qApp);
1627         if (appCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1628             QString ss = qApp->styleSheet();
1629             if (ss.startsWith(QLatin1String("file:///")))
1630                 ss.remove(0, 8);
1631             parser.init(ss, qApp->styleSheet() != ss);
1632             if (Q_UNLIKELY(!parser.parse(&appSs)))
1633                 qWarning("Could not parse application stylesheet");
1634             appSs.origin = StyleSheetOrigin_Inline;
1635             appSs.depth = 1;
1636             styleSheetCaches->styleSheetCache.insert(qApp, appSs);
1637         } else {
1638             appSs = appCacheIt.value();
1639         }
1640         styleSelector.styleSheets += appSs;
1641     }
1642 
1643     QVector<QCss::StyleSheet> objectSs;
1644     for (const QObject *o = obj; o; o = parentObject(o)) {
1645         QString styleSheet = o->property("styleSheet").toString();
1646         if (styleSheet.isEmpty())
1647             continue;
1648         StyleSheet ss;
1649         QHash<const void *, StyleSheet>::const_iterator objCacheIt = styleSheetCaches->styleSheetCache.constFind(o);
1650         if (objCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1651             parser.init(styleSheet);
1652             if (!parser.parse(&ss)) {
1653                 parser.init(QLatin1String("* {") + styleSheet + QLatin1Char('}'));
1654                 if (Q_UNLIKELY(!parser.parse(&ss)))
1655                    qWarning() << "Could not parse stylesheet of object" << o;
1656             }
1657             ss.origin = StyleSheetOrigin_Inline;
1658             styleSheetCaches->styleSheetCache.insert(o, ss);
1659         } else {
1660             ss = objCacheIt.value();
1661         }
1662         objectSs.append(ss);
1663     }
1664 
1665     for (int i = 0; i < objectSs.count(); i++)
1666         objectSs[i].depth = objectSs.count() - i + 2;
1667 
1668     styleSelector.styleSheets += objectSs;
1669 
1670     StyleSelector::NodePtr n;
1671     n.ptr = const_cast<QObject *>(obj);
1672     QVector<QCss::StyleRule> rules = styleSelector.styleRulesForNode(n);
1673     styleSheetCaches->styleRulesCache.insert(obj, rules);
1674     return rules;
1675 }
1676 
1677 /////////////////////////////////////////////////////////////////////////////////////////
1678 // Rendering rules
declarations(const QVector<StyleRule> & styleRules,const QString & part,quint64 pseudoClass=PseudoClass_Unspecified)1679 static QVector<Declaration> declarations(const QVector<StyleRule> &styleRules, const QString &part, quint64 pseudoClass = PseudoClass_Unspecified)
1680 {
1681     QVector<Declaration> decls;
1682     for (int i = 0; i < styleRules.count(); i++) {
1683         const Selector& selector = styleRules.at(i).selectors.at(0);
1684         // Rules with pseudo elements don't cascade. This is an intentional
1685         // diversion for CSS
1686         if (part.compare(selector.pseudoElement(), Qt::CaseInsensitive) != 0)
1687             continue;
1688         quint64 negated = 0;
1689         quint64 cssClass = selector.pseudoClass(&negated);
1690         if ((pseudoClass == PseudoClass_Any) || (cssClass == PseudoClass_Unspecified)
1691             || ((((cssClass & pseudoClass) == cssClass)) && ((negated & pseudoClass) == 0)))
1692             decls += styleRules.at(i).declarations;
1693     }
1694     return decls;
1695 }
1696 
nativeFrameWidth(const QWidget * w)1697 int QStyleSheetStyle::nativeFrameWidth(const QWidget *w)
1698 {
1699     QStyle *base = baseStyle();
1700 
1701 #if QT_CONFIG(spinbox)
1702     if (qobject_cast<const QAbstractSpinBox *>(w))
1703         return base->pixelMetric(QStyle::PM_SpinBoxFrameWidth, nullptr, w);
1704 #endif
1705 
1706 #if QT_CONFIG(combobox)
1707     if (qobject_cast<const QComboBox *>(w))
1708         return base->pixelMetric(QStyle::PM_ComboBoxFrameWidth, nullptr, w);
1709 #endif
1710 
1711 #if QT_CONFIG(menu)
1712     if (qobject_cast<const QMenu *>(w))
1713         return base->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, w);
1714 #endif
1715 
1716 #if QT_CONFIG(menubar)
1717     if (qobject_cast<const QMenuBar *>(w))
1718         return base->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, w);
1719 #endif
1720 #ifndef QT_NO_FRAME
1721     if (const QFrame *frame = qobject_cast<const QFrame *>(w)) {
1722         if (frame->frameShape() == QFrame::NoFrame)
1723             return 0;
1724     }
1725 #endif
1726 
1727     if (qstrcmp(w->metaObject()->className(), "QTipLabel") == 0)
1728         return base->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, nullptr, w);
1729 
1730     return base->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, w);
1731 }
1732 
pseudoClass(QStyle::State state)1733 static quint64 pseudoClass(QStyle::State state)
1734 {
1735     quint64 pc = 0;
1736     if (state & QStyle::State_Enabled) {
1737         pc |= PseudoClass_Enabled;
1738         if (state & QStyle::State_MouseOver)
1739             pc |= PseudoClass_Hover;
1740     } else {
1741         pc |= PseudoClass_Disabled;
1742     }
1743     if (state & QStyle::State_Active)
1744         pc |= PseudoClass_Active;
1745     if (state & QStyle::State_Window)
1746         pc |= PseudoClass_Window;
1747     if (state & QStyle::State_Sunken)
1748         pc |= PseudoClass_Pressed;
1749     if (state & QStyle::State_HasFocus)
1750         pc |= PseudoClass_Focus;
1751     if (state & QStyle::State_On)
1752         pc |= (PseudoClass_On | PseudoClass_Checked);
1753     if (state & QStyle::State_Off)
1754         pc |= (PseudoClass_Off | PseudoClass_Unchecked);
1755     if (state & QStyle::State_NoChange)
1756         pc |= PseudoClass_Indeterminate;
1757     if (state & QStyle::State_Selected)
1758         pc |= PseudoClass_Selected;
1759     if (state & QStyle::State_Horizontal)
1760         pc |= PseudoClass_Horizontal;
1761     else
1762         pc |= PseudoClass_Vertical;
1763     if (state & (QStyle::State_Open | QStyle::State_On | QStyle::State_Sunken))
1764         pc |= PseudoClass_Open;
1765     else
1766         pc |= PseudoClass_Closed;
1767     if (state & QStyle::State_Children)
1768         pc |= PseudoClass_Children;
1769     if (state & QStyle::State_Sibling)
1770         pc |= PseudoClass_Sibling;
1771     if (state & QStyle::State_ReadOnly)
1772         pc |= PseudoClass_ReadOnly;
1773     if (state & QStyle::State_Item)
1774         pc |= PseudoClass_Item;
1775 #ifdef QT_KEYPAD_NAVIGATION
1776     if (state & QStyle::State_HasEditFocus)
1777         pc |= PseudoClass_EditFocus;
1778 #endif
1779     return pc;
1780 }
1781 
qt_check_if_internal_object(const QObject ** obj,int * element)1782 static void qt_check_if_internal_object(const QObject **obj, int *element)
1783 {
1784 #if !QT_CONFIG(dockwidget)
1785     Q_UNUSED(obj);
1786     Q_UNUSED(element);
1787 #else
1788     if (*obj && qstrcmp((*obj)->metaObject()->className(), "QDockWidgetTitleButton") == 0) {
1789         if ((*obj)->objectName() == QLatin1String("qt_dockwidget_closebutton")) {
1790             *element = PseudoElement_DockWidgetCloseButton;
1791         } else if ((*obj)->objectName() == QLatin1String("qt_dockwidget_floatbutton")) {
1792             *element = PseudoElement_DockWidgetFloatButton;
1793         }
1794         *obj = (*obj)->parent();
1795     }
1796 #endif
1797 }
1798 
renderRule(const QObject * obj,int element,quint64 state) const1799 QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, int element, quint64 state) const
1800 {
1801     qt_check_if_internal_object(&obj, &element);
1802     QHash<quint64, QRenderRule> &cache = styleSheetCaches->renderRulesCache[obj][element];
1803     QHash<quint64, QRenderRule>::const_iterator cacheIt = cache.constFind(state);
1804     if (cacheIt != cache.constEnd())
1805         return cacheIt.value();
1806 
1807     if (!initObject(obj))
1808         return QRenderRule();
1809 
1810     quint64 stateMask = 0;
1811     const QVector<StyleRule> rules = styleRules(obj);
1812     for (int i = 0; i < rules.count(); i++) {
1813         const Selector& selector = rules.at(i).selectors.at(0);
1814         quint64 negated = 0;
1815         stateMask |= selector.pseudoClass(&negated);
1816         stateMask |= negated;
1817     }
1818 
1819     cacheIt = cache.constFind(state & stateMask);
1820     if (cacheIt != cache.constEnd()) {
1821         const QRenderRule &newRule = cacheIt.value();
1822         cache[state] = newRule;
1823         return newRule;
1824     }
1825 
1826 
1827     const QString part = QLatin1String(knownPseudoElements[element].name);
1828     QVector<Declaration> decls = declarations(rules, part, state);
1829     QRenderRule newRule(decls, obj);
1830     cache[state] = newRule;
1831     if ((state & stateMask) != state)
1832         cache[state&stateMask] = newRule;
1833     return newRule;
1834 }
1835 
renderRule(const QObject * obj,const QStyleOption * opt,int pseudoElement) const1836 QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption *opt, int pseudoElement) const
1837 {
1838     quint64 extraClass = 0;
1839     QStyle::State state = opt ? opt->state : QStyle::State(QStyle::State_None);
1840 
1841     if (const QStyleOptionComplex *complex = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
1842         if (pseudoElement != PseudoElement_None) {
1843             // if not an active subcontrol, just pass enabled/disabled
1844             QStyle::SubControl subControl = knownPseudoElements[pseudoElement].subControl;
1845 
1846             if (!(complex->activeSubControls & subControl))
1847                 state &= (QStyle::State_Enabled | QStyle::State_Horizontal | QStyle::State_HasFocus);
1848         }
1849 
1850         switch (pseudoElement) {
1851         case PseudoElement_ComboBoxDropDown:
1852         case PseudoElement_ComboBoxArrow:
1853             state |= (complex->state & (QStyle::State_On|QStyle::State_ReadOnly));
1854             break;
1855         case PseudoElement_SpinBoxUpButton:
1856         case PseudoElement_SpinBoxDownButton:
1857         case PseudoElement_SpinBoxUpArrow:
1858         case PseudoElement_SpinBoxDownArrow:
1859 #if QT_CONFIG(spinbox)
1860             if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
1861                 bool on = false;
1862                 bool up = pseudoElement == PseudoElement_SpinBoxUpButton
1863                           || pseudoElement == PseudoElement_SpinBoxUpArrow;
1864                 if ((sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) && up)
1865                     on = true;
1866                 else if ((sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) && !up)
1867                     on = true;
1868                 state |= (on ? QStyle::State_On : QStyle::State_Off);
1869             }
1870 #endif // QT_CONFIG(spinbox)
1871             break;
1872         case PseudoElement_GroupBoxTitle:
1873             state |= (complex->state & (QStyle::State_MouseOver | QStyle::State_Sunken));
1874             break;
1875         case PseudoElement_ToolButtonMenu:
1876         case PseudoElement_ToolButtonMenuArrow:
1877         case PseudoElement_ToolButtonDownArrow:
1878             state |= complex->state & QStyle::State_MouseOver;
1879             if (complex->state & QStyle::State_Sunken ||
1880                 complex->activeSubControls & QStyle::SC_ToolButtonMenu)
1881                 state |= QStyle::State_Sunken;
1882             break;
1883         case PseudoElement_SliderGroove:
1884             state |= complex->state & QStyle::State_MouseOver;
1885             break;
1886         default:
1887             break;
1888         }
1889 
1890         if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
1891             // QStyle::State_On is set when the popup is being shown
1892             // Propagate EditField Pressed state
1893             if (pseudoElement == PseudoElement_None
1894                 && (complex->activeSubControls & QStyle::SC_ComboBoxEditField)
1895                 && (!(state & QStyle::State_MouseOver))) {
1896                 state |= QStyle::State_Sunken;
1897             }
1898 
1899             if (!combo->frame)
1900                 extraClass |= PseudoClass_Frameless;
1901             if (!combo->editable)
1902                 extraClass |= PseudoClass_ReadOnly;
1903             else
1904                 extraClass |= PseudoClass_Editable;
1905 #if QT_CONFIG(spinbox)
1906         } else if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
1907             if (!spin->frame)
1908                 extraClass |= PseudoClass_Frameless;
1909 #endif // QT_CONFIG(spinbox)
1910         } else if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
1911             if (gb->features & QStyleOptionFrame::Flat)
1912                 extraClass |= PseudoClass_Flat;
1913             if (gb->lineWidth == 0)
1914                 extraClass |= PseudoClass_Frameless;
1915         } else if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
1916             if (tb->titleBarState & Qt::WindowMinimized) {
1917                 extraClass |= PseudoClass_Minimized;
1918             }
1919             else if (tb->titleBarState & Qt::WindowMaximized)
1920                 extraClass |= PseudoClass_Maximized;
1921         }
1922     } else {
1923         // handle simple style options
1924         if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
1925             if (mi->menuItemType == QStyleOptionMenuItem::DefaultItem)
1926                 extraClass |= PseudoClass_Default;
1927             if (mi->checkType == QStyleOptionMenuItem::Exclusive)
1928                 extraClass |= PseudoClass_Exclusive;
1929             else if (mi->checkType == QStyleOptionMenuItem::NonExclusive)
1930                 extraClass |= PseudoClass_NonExclusive;
1931             if (mi->checkType != QStyleOptionMenuItem::NotCheckable)
1932                 extraClass |= (mi->checked) ? (PseudoClass_On|PseudoClass_Checked)
1933                                             : (PseudoClass_Off|PseudoClass_Unchecked);
1934         } else if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
1935             if (hdr->position == QStyleOptionHeader::OnlyOneSection)
1936                 extraClass |= PseudoClass_OnlyOne;
1937             else if (hdr->position == QStyleOptionHeader::Beginning)
1938                 extraClass |= PseudoClass_First;
1939             else if (hdr->position == QStyleOptionHeader::End)
1940                 extraClass |= PseudoClass_Last;
1941             else if (hdr->position == QStyleOptionHeader::Middle)
1942                 extraClass |= PseudoClass_Middle;
1943 
1944             if (hdr->selectedPosition == QStyleOptionHeader::NextAndPreviousAreSelected)
1945                 extraClass |= (PseudoClass_NextSelected | PseudoClass_PreviousSelected);
1946             else if (hdr->selectedPosition == QStyleOptionHeader::NextIsSelected)
1947                 extraClass |= PseudoClass_NextSelected;
1948             else if (hdr->selectedPosition == QStyleOptionHeader::PreviousIsSelected)
1949                 extraClass |= PseudoClass_PreviousSelected;
1950 #if QT_CONFIG(tabwidget)
1951         } else if (const QStyleOptionTabWidgetFrame *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
1952             switch (tab->shape) {
1953                 case QTabBar::RoundedNorth:
1954                 case QTabBar::TriangularNorth:
1955                     extraClass |= PseudoClass_Top;
1956                     break;
1957                 case QTabBar::RoundedSouth:
1958                 case QTabBar::TriangularSouth:
1959                     extraClass |= PseudoClass_Bottom;
1960                     break;
1961                 case QTabBar::RoundedEast:
1962                 case QTabBar::TriangularEast:
1963                     extraClass |= PseudoClass_Right;
1964                     break;
1965                 case QTabBar::RoundedWest:
1966                 case QTabBar::TriangularWest:
1967                     extraClass |= PseudoClass_Left;
1968                     break;
1969                 default:
1970                     break;
1971             }
1972 #endif
1973 #if QT_CONFIG(tabbar)
1974         } else if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
1975             if (tab->position == QStyleOptionTab::OnlyOneTab)
1976                 extraClass |= PseudoClass_OnlyOne;
1977             else if (tab->position == QStyleOptionTab::Beginning)
1978                 extraClass |= PseudoClass_First;
1979             else if (tab->position == QStyleOptionTab::End)
1980                 extraClass |= PseudoClass_Last;
1981             else if (tab->position == QStyleOptionTab::Middle)
1982                 extraClass |= PseudoClass_Middle;
1983 
1984             if (tab->selectedPosition == QStyleOptionTab::NextIsSelected)
1985                 extraClass |= PseudoClass_NextSelected;
1986             else if (tab->selectedPosition == QStyleOptionTab::PreviousIsSelected)
1987                 extraClass |= PseudoClass_PreviousSelected;
1988 
1989             switch (tab->shape) {
1990                 case QTabBar::RoundedNorth:
1991                 case QTabBar::TriangularNorth:
1992                     extraClass |= PseudoClass_Top;
1993                     break;
1994                 case QTabBar::RoundedSouth:
1995                 case QTabBar::TriangularSouth:
1996                     extraClass |= PseudoClass_Bottom;
1997                     break;
1998                 case QTabBar::RoundedEast:
1999                 case QTabBar::TriangularEast:
2000                     extraClass |= PseudoClass_Right;
2001                     break;
2002                 case QTabBar::RoundedWest:
2003                 case QTabBar::TriangularWest:
2004                     extraClass |= PseudoClass_Left;
2005                     break;
2006                 default:
2007                     break;
2008             }
2009 #endif // QT_CONFIG(tabbar)
2010         } else if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2011             if (btn->features & QStyleOptionButton::Flat)
2012                 extraClass |= PseudoClass_Flat;
2013             if (btn->features & QStyleOptionButton::DefaultButton)
2014                 extraClass |= PseudoClass_Default;
2015         } else if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2016             if (frm->lineWidth == 0)
2017                 extraClass |= PseudoClass_Frameless;
2018             if (frm->features & QStyleOptionFrame::Flat)
2019                 extraClass |= PseudoClass_Flat;
2020         }
2021 #if QT_CONFIG(toolbar)
2022         else if (const QStyleOptionToolBar *tb = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
2023             if (tb->toolBarArea == Qt::LeftToolBarArea)
2024                 extraClass |= PseudoClass_Left;
2025             else if (tb->toolBarArea == Qt::RightToolBarArea)
2026                 extraClass |= PseudoClass_Right;
2027             else if (tb->toolBarArea == Qt::TopToolBarArea)
2028                 extraClass |= PseudoClass_Top;
2029             else if (tb->toolBarArea == Qt::BottomToolBarArea)
2030                 extraClass |= PseudoClass_Bottom;
2031 
2032             if (tb->positionWithinLine == QStyleOptionToolBar::Beginning)
2033                 extraClass |= PseudoClass_First;
2034             else if (tb->positionWithinLine == QStyleOptionToolBar::Middle)
2035                 extraClass |= PseudoClass_Middle;
2036             else if (tb->positionWithinLine == QStyleOptionToolBar::End)
2037                 extraClass |= PseudoClass_Last;
2038             else if (tb->positionWithinLine == QStyleOptionToolBar::OnlyOne)
2039                 extraClass |= PseudoClass_OnlyOne;
2040         }
2041 #endif // QT_CONFIG(toolbar)
2042 #if QT_CONFIG(toolbox)
2043         else if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
2044             if (tb->position == QStyleOptionToolBox::OnlyOneTab)
2045                 extraClass |= PseudoClass_OnlyOne;
2046             else if (tb->position == QStyleOptionToolBox::Beginning)
2047                 extraClass |= PseudoClass_First;
2048             else if (tb->position == QStyleOptionToolBox::End)
2049                 extraClass |= PseudoClass_Last;
2050             else if (tb->position == QStyleOptionToolBox::Middle)
2051                 extraClass |= PseudoClass_Middle;
2052 
2053             if (tb->selectedPosition == QStyleOptionToolBox::NextIsSelected)
2054                 extraClass |= PseudoClass_NextSelected;
2055             else if (tb->selectedPosition == QStyleOptionToolBox::PreviousIsSelected)
2056                 extraClass |= PseudoClass_PreviousSelected;
2057         }
2058 #endif // QT_CONFIG(toolbox)
2059 #if QT_CONFIG(dockwidget)
2060         else if (const QStyleOptionDockWidget *dw = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
2061             if (dw->verticalTitleBar)
2062                 extraClass |= PseudoClass_Vertical;
2063             else
2064                 extraClass |= PseudoClass_Horizontal;
2065             if (dw->closable)
2066                 extraClass |= PseudoClass_Closable;
2067             if (dw->floatable)
2068                 extraClass |= PseudoClass_Floatable;
2069             if (dw->movable)
2070                 extraClass |= PseudoClass_Movable;
2071         }
2072 #endif // QT_CONFIG(dockwidget)
2073 #if QT_CONFIG(itemviews)
2074         else if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
2075             if (vopt->features & QStyleOptionViewItem::Alternate)
2076                 extraClass |= PseudoClass_Alternate;
2077             if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne)
2078                 extraClass |= PseudoClass_OnlyOne;
2079             else if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning)
2080                 extraClass |= PseudoClass_First;
2081             else if (vopt->viewItemPosition == QStyleOptionViewItem::End)
2082                 extraClass |= PseudoClass_Last;
2083             else if (vopt->viewItemPosition == QStyleOptionViewItem::Middle)
2084                 extraClass |= PseudoClass_Middle;
2085 
2086         }
2087 #endif
2088 #if QT_CONFIG(lineedit)
2089         // LineEdit sets Sunken flag to indicate Sunken frame (argh)
2090         if (const QLineEdit *lineEdit = qobject_cast<const QLineEdit *>(obj)) {
2091             state &= ~QStyle::State_Sunken;
2092             if (lineEdit->hasFrame()) {
2093                 extraClass &= ~PseudoClass_Frameless;
2094             } else {
2095                 extraClass |= PseudoClass_Frameless;
2096             }
2097         } else
2098 #endif
2099         if (const QFrame *frm = qobject_cast<const QFrame *>(obj)) {
2100             if (frm->lineWidth() == 0)
2101                 extraClass |= PseudoClass_Frameless;
2102         }
2103     }
2104 
2105     return renderRule(obj, pseudoElement, pseudoClass(state) | extraClass);
2106 }
2107 
hasStyleRule(const QObject * obj,int part) const2108 bool QStyleSheetStyle::hasStyleRule(const QObject *obj, int part) const
2109 {
2110     QHash<int, bool> &cache = styleSheetCaches->hasStyleRuleCache[obj];
2111     QHash<int, bool>::const_iterator cacheIt = cache.constFind(part);
2112     if (cacheIt != cache.constEnd())
2113         return cacheIt.value();
2114 
2115     if (!initObject(obj))
2116         return false;
2117 
2118 
2119     const QVector<StyleRule> &rules = styleRules(obj);
2120     if (part == PseudoElement_None) {
2121         bool result = obj && !rules.isEmpty();
2122         cache[part] = result;
2123         return result;
2124     }
2125 
2126     QString pseudoElement = QLatin1String(knownPseudoElements[part].name);
2127     for (int i = 0; i < rules.count(); i++) {
2128         const Selector& selector = rules.at(i).selectors.at(0);
2129         if (pseudoElement.compare(selector.pseudoElement(), Qt::CaseInsensitive) == 0) {
2130             cache[part] = true;
2131             return true;
2132         }
2133     }
2134 
2135     cache[part] = false;
2136     return false;
2137 }
2138 
defaultOrigin(int pe)2139 static Origin defaultOrigin(int pe)
2140 {
2141     switch (pe) {
2142     case PseudoElement_ScrollBarAddPage:
2143     case PseudoElement_ScrollBarSubPage:
2144     case PseudoElement_ScrollBarAddLine:
2145     case PseudoElement_ScrollBarSubLine:
2146     case PseudoElement_ScrollBarFirst:
2147     case PseudoElement_ScrollBarLast:
2148     case PseudoElement_GroupBoxTitle:
2149     case PseudoElement_GroupBoxIndicator: // never used
2150     case PseudoElement_ToolButtonMenu:
2151     case PseudoElement_SliderAddPage:
2152     case PseudoElement_SliderSubPage:
2153         return Origin_Border;
2154 
2155     case PseudoElement_SpinBoxUpButton:
2156     case PseudoElement_SpinBoxDownButton:
2157     case PseudoElement_PushButtonMenuIndicator:
2158     case PseudoElement_ComboBoxDropDown:
2159     case PseudoElement_ToolButtonDownArrow:
2160     case PseudoElement_MenuCheckMark:
2161     case PseudoElement_MenuIcon:
2162     case PseudoElement_MenuRightArrow:
2163         return Origin_Padding;
2164 
2165     case PseudoElement_Indicator:
2166     case PseudoElement_ExclusiveIndicator:
2167     case PseudoElement_ComboBoxArrow:
2168     case PseudoElement_ScrollBarSlider:
2169     case PseudoElement_ScrollBarUpArrow:
2170     case PseudoElement_ScrollBarDownArrow:
2171     case PseudoElement_ScrollBarLeftArrow:
2172     case PseudoElement_ScrollBarRightArrow:
2173     case PseudoElement_SpinBoxUpArrow:
2174     case PseudoElement_SpinBoxDownArrow:
2175     case PseudoElement_ToolButtonMenuArrow:
2176     case PseudoElement_HeaderViewUpArrow:
2177     case PseudoElement_HeaderViewDownArrow:
2178     case PseudoElement_SliderGroove:
2179     case PseudoElement_SliderHandle:
2180         return Origin_Content;
2181 
2182     default:
2183         return Origin_Margin;
2184     }
2185 }
2186 
defaultPosition(int pe)2187 static Qt::Alignment defaultPosition(int pe)
2188 {
2189     switch (pe) {
2190     case PseudoElement_Indicator:
2191     case PseudoElement_ExclusiveIndicator:
2192     case PseudoElement_MenuCheckMark:
2193     case PseudoElement_MenuIcon:
2194         return Qt::AlignLeft | Qt::AlignVCenter;
2195 
2196     case PseudoElement_ScrollBarAddLine:
2197     case PseudoElement_ScrollBarLast:
2198     case PseudoElement_SpinBoxDownButton:
2199     case PseudoElement_PushButtonMenuIndicator:
2200     case PseudoElement_ToolButtonDownArrow:
2201         return Qt::AlignRight | Qt::AlignBottom;
2202 
2203     case PseudoElement_ScrollBarSubLine:
2204     case PseudoElement_ScrollBarFirst:
2205     case PseudoElement_SpinBoxUpButton:
2206     case PseudoElement_ComboBoxDropDown:
2207     case PseudoElement_ToolButtonMenu:
2208     case PseudoElement_DockWidgetCloseButton:
2209     case PseudoElement_DockWidgetFloatButton:
2210         return Qt::AlignRight | Qt::AlignTop;
2211 
2212     case PseudoElement_ScrollBarUpArrow:
2213     case PseudoElement_ScrollBarDownArrow:
2214     case PseudoElement_ScrollBarLeftArrow:
2215     case PseudoElement_ScrollBarRightArrow:
2216     case PseudoElement_SpinBoxUpArrow:
2217     case PseudoElement_SpinBoxDownArrow:
2218     case PseudoElement_ComboBoxArrow:
2219     case PseudoElement_DownArrow:
2220     case PseudoElement_ToolButtonMenuArrow:
2221     case PseudoElement_SliderGroove:
2222         return Qt::AlignCenter;
2223 
2224     case PseudoElement_GroupBoxTitle:
2225     case PseudoElement_GroupBoxIndicator: // never used
2226         return Qt::AlignLeft | Qt::AlignTop;
2227 
2228     case PseudoElement_HeaderViewUpArrow:
2229     case PseudoElement_HeaderViewDownArrow:
2230     case PseudoElement_MenuRightArrow:
2231         return Qt::AlignRight | Qt::AlignVCenter;
2232 
2233     default:
2234         return { };
2235     }
2236 }
2237 
defaultSize(const QWidget * w,QSize sz,const QRect & rect,int pe) const2238 QSize QStyleSheetStyle::defaultSize(const QWidget *w, QSize sz, const QRect& rect, int pe) const
2239 {
2240     QStyle *base = baseStyle();
2241 
2242     switch (pe) {
2243     case PseudoElement_Indicator:
2244     case PseudoElement_MenuCheckMark:
2245         if (sz.width() == -1)
2246             sz.setWidth(base->pixelMetric(PM_IndicatorWidth, nullptr, w));
2247         if (sz.height() == -1)
2248             sz.setHeight(base->pixelMetric(PM_IndicatorHeight, nullptr, w));
2249         break;
2250 
2251     case PseudoElement_ExclusiveIndicator:
2252     case PseudoElement_GroupBoxIndicator:
2253         if (sz.width() == -1)
2254             sz.setWidth(base->pixelMetric(PM_ExclusiveIndicatorWidth, nullptr, w));
2255         if (sz.height() == -1)
2256             sz.setHeight(base->pixelMetric(PM_ExclusiveIndicatorHeight, nullptr, w));
2257         break;
2258 
2259     case PseudoElement_PushButtonMenuIndicator: {
2260         int pm = base->pixelMetric(PM_MenuButtonIndicator, nullptr, w);
2261         if (sz.width() == -1)
2262             sz.setWidth(pm);
2263         if (sz.height() == -1)
2264             sz.setHeight(pm);
2265                                       }
2266         break;
2267 
2268     case PseudoElement_ComboBoxDropDown:
2269         if (sz.width() == -1)
2270             sz.setWidth(16);
2271         break;
2272 
2273     case PseudoElement_ComboBoxArrow:
2274     case PseudoElement_DownArrow:
2275     case PseudoElement_ToolButtonMenuArrow:
2276     case PseudoElement_ToolButtonDownArrow:
2277     case PseudoElement_MenuRightArrow:
2278         if (sz.width() == -1)
2279             sz.setWidth(13);
2280         if (sz.height() == -1)
2281             sz.setHeight(13);
2282         break;
2283 
2284     case PseudoElement_SpinBoxUpButton:
2285     case PseudoElement_SpinBoxDownButton:
2286         if (sz.width() == -1)
2287             sz.setWidth(16);
2288         if (sz.height() == -1)
2289             sz.setHeight(rect.height()/2);
2290         break;
2291 
2292     case PseudoElement_ToolButtonMenu:
2293         if (sz.width() == -1)
2294             sz.setWidth(base->pixelMetric(PM_MenuButtonIndicator, nullptr, w));
2295         break;
2296 
2297     case PseudoElement_HeaderViewUpArrow:
2298     case PseudoElement_HeaderViewDownArrow: {
2299         int pm = base->pixelMetric(PM_HeaderMargin, nullptr, w);
2300         if (sz.width() == -1)
2301             sz.setWidth(pm);
2302         if (sz.height() == 1)
2303             sz.setHeight(pm);
2304         break;
2305                                             }
2306 
2307     case PseudoElement_ScrollBarFirst:
2308     case PseudoElement_ScrollBarLast:
2309     case PseudoElement_ScrollBarAddLine:
2310     case PseudoElement_ScrollBarSubLine:
2311     case PseudoElement_ScrollBarSlider: {
2312         int pm = pixelMetric(QStyle::PM_ScrollBarExtent, nullptr, w);
2313         if (sz.width() == -1)
2314             sz.setWidth(pm);
2315         if (sz.height() == -1)
2316             sz.setHeight(pm);
2317         break;
2318                                         }
2319 
2320     case PseudoElement_DockWidgetCloseButton:
2321     case PseudoElement_DockWidgetFloatButton: {
2322         int iconSize = pixelMetric(PM_SmallIconSize, nullptr, w);
2323         return QSize(iconSize, iconSize);
2324                                               }
2325 
2326     default:
2327         break;
2328     }
2329 
2330     // expand to rectangle
2331     if (sz.height() == -1)
2332         sz.setHeight(rect.height());
2333     if (sz.width() == -1)
2334         sz.setWidth(rect.width());
2335 
2336     return sz;
2337 }
2338 
defaultPositionMode(int pe)2339 static PositionMode defaultPositionMode(int pe)
2340 {
2341     switch (pe) {
2342     case PseudoElement_ScrollBarFirst:
2343     case PseudoElement_ScrollBarLast:
2344     case PseudoElement_ScrollBarAddLine:
2345     case PseudoElement_ScrollBarSubLine:
2346     case PseudoElement_ScrollBarAddPage:
2347     case PseudoElement_ScrollBarSubPage:
2348     case PseudoElement_ScrollBarSlider:
2349     case PseudoElement_SliderGroove:
2350     case PseudoElement_SliderHandle:
2351     case PseudoElement_TabWidgetPane:
2352         return PositionMode_Absolute;
2353     default:
2354         return PositionMode_Static;
2355     }
2356 }
2357 
positionRect(const QWidget * w,const QRenderRule & rule2,int pe,const QRect & originRect,Qt::LayoutDirection dir) const2358 QRect QStyleSheetStyle::positionRect(const QWidget *w, const QRenderRule &rule2, int pe,
2359                                      const QRect &originRect, Qt::LayoutDirection dir) const
2360 {
2361     const QStyleSheetPositionData *p = rule2.position();
2362     PositionMode mode = (p && p->mode != PositionMode_Unknown) ? p->mode : defaultPositionMode(pe);
2363     Qt::Alignment position = (p && p->position != 0) ? p->position : defaultPosition(pe);
2364     QRect r;
2365 
2366     if (mode != PositionMode_Absolute) {
2367         QSize sz = defaultSize(w, rule2.size(), originRect, pe);
2368         sz = sz.expandedTo(rule2.minimumContentsSize());
2369         r = QStyle::alignedRect(dir, position, sz, originRect);
2370         if (p) {
2371             int left = p->left ? p->left : -p->right;
2372             int top = p->top ? p->top : -p->bottom;
2373             r.translate(dir == Qt::LeftToRight ? left : -left, top);
2374         }
2375     } else {
2376         r = p ? originRect.adjusted(dir == Qt::LeftToRight ? p->left : p->right, p->top,
2377                                    dir == Qt::LeftToRight ? -p->right : -p->left, -p->bottom)
2378               : originRect;
2379         if (rule2.hasContentsSize()) {
2380             QSize sz = rule2.size().expandedTo(rule2.minimumContentsSize());
2381             if (sz.width() == -1) sz.setWidth(r.width());
2382             if (sz.height() == -1) sz.setHeight(r.height());
2383             r = QStyle::alignedRect(dir, position, sz, r);
2384         }
2385     }
2386     return r;
2387 }
2388 
positionRect(const QWidget * w,const QRenderRule & rule1,const QRenderRule & rule2,int pe,const QRect & rect,Qt::LayoutDirection dir) const2389 QRect QStyleSheetStyle::positionRect(const QWidget *w, const QRenderRule& rule1, const QRenderRule& rule2, int pe,
2390                                      const QRect& rect, Qt::LayoutDirection dir) const
2391 {
2392     const QStyleSheetPositionData *p = rule2.position();
2393     Origin origin = (p && p->origin != Origin_Unknown) ? p->origin : defaultOrigin(pe);
2394     QRect originRect = rule1.originRect(rect, origin);
2395     return positionRect(w, rule2, pe, originRect, dir);
2396 }
2397 
2398 
2399 /** \internal
2400    For widget that have an embedded widget (such as combobox) return that embedded widget.
2401    otherwise return the widget itself
2402  */
embeddedWidget(QWidget * w)2403 static QWidget *embeddedWidget(QWidget *w)
2404 {
2405 #if QT_CONFIG(combobox)
2406     if (QComboBox *cmb = qobject_cast<QComboBox *>(w)) {
2407         if (cmb->isEditable())
2408             return cmb->lineEdit();
2409         else
2410             return cmb;
2411     }
2412 #endif
2413 
2414 #if QT_CONFIG(spinbox)
2415     if (QAbstractSpinBox *sb = qobject_cast<QAbstractSpinBox *>(w))
2416         return sb->findChild<QLineEdit *>();
2417 #endif
2418 
2419 #if QT_CONFIG(scrollarea)
2420     if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w))
2421         return sa->viewport();
2422 #endif
2423 
2424     return w;
2425 }
2426 
2427 /** \internal
2428   in case w is an embedded widget, return the container widget
2429   (i.e, the widget for which the rules actualy apply)
2430   (exemple, if w is a lineedit embedded in a combobox, return the combobox)
2431 
2432   if w is not embedded, return w itself
2433 */
containerWidget(const QWidget * w)2434 static QWidget *containerWidget(const QWidget *w)
2435 {
2436 #if QT_CONFIG(lineedit)
2437     if (qobject_cast<const QLineEdit *>(w)) {
2438         //if the QLineEdit is an embeddedWidget, we need the rule of the real widget
2439 #if QT_CONFIG(combobox)
2440         if (qobject_cast<const QComboBox *>(w->parentWidget()))
2441             return w->parentWidget();
2442 #endif
2443 #if QT_CONFIG(spinbox)
2444         if (qobject_cast<const QAbstractSpinBox *>(w->parentWidget()))
2445             return w->parentWidget();
2446 #endif
2447     }
2448 #endif // QT_CONFIG(lineedit)
2449 
2450 #if QT_CONFIG(scrollarea)
2451     if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(w->parentWidget())) {
2452         if (sa->viewport() == w)
2453             return w->parentWidget();
2454     }
2455 #endif
2456 
2457     return const_cast<QWidget *>(w);
2458 }
2459 
2460 /** \internal
2461     returns \c true if the widget can NOT be styled directly
2462  */
unstylable(const QWidget * w)2463 static bool unstylable(const QWidget *w)
2464 {
2465     if (w->windowType() == Qt::Desktop)
2466         return true;
2467 
2468     if (!w->styleSheet().isEmpty())
2469         return false;
2470 
2471     if (containerWidget(w) != w)
2472         return true;
2473 
2474 #ifndef QT_NO_FRAME
2475     // detect QComboBoxPrivateContainer
2476     else if (qobject_cast<const QFrame *>(w)) {
2477         if (0
2478 #if QT_CONFIG(combobox)
2479             || qobject_cast<const QComboBox *>(w->parentWidget())
2480 #endif
2481            )
2482             return true;
2483     }
2484 #endif
2485 
2486 #if QT_CONFIG(tabbar)
2487     if (w->metaObject() == &QWidget::staticMetaObject
2488             && qobject_cast<const QTabBar*>(w->parentWidget()))
2489         return true; // The moving tab of a QTabBar
2490 #endif
2491 
2492     return false;
2493 }
2494 
extendedPseudoClass(const QWidget * w)2495 static quint64 extendedPseudoClass(const QWidget *w)
2496 {
2497     quint64 pc = w->isWindow() ? quint64(PseudoClass_Window) : 0;
2498 #if QT_CONFIG(abstractslider)
2499     if (const QAbstractSlider *slider = qobject_cast<const QAbstractSlider *>(w)) {
2500         pc |= ((slider->orientation() == Qt::Vertical) ? PseudoClass_Vertical : PseudoClass_Horizontal);
2501     } else
2502 #endif
2503 #if QT_CONFIG(combobox)
2504     if (const QComboBox *combo = qobject_cast<const QComboBox *>(w)) {
2505         if (combo->isEditable())
2506         pc |= (combo->isEditable() ? PseudoClass_Editable : PseudoClass_ReadOnly);
2507     } else
2508 #endif
2509 #if QT_CONFIG(lineedit)
2510     if (const QLineEdit *edit = qobject_cast<const QLineEdit *>(w)) {
2511         pc |= (edit->isReadOnly() ? PseudoClass_ReadOnly : PseudoClass_Editable);
2512     } else
2513 #endif
2514     { } // required for the above ifdef'ery to work
2515     return pc;
2516 }
2517 
2518 // sets up the geometry of the widget. We set a dynamic property when
2519 // we modify the min/max size of the widget. The min/max size is restored
2520 // to their original value when a new stylesheet that does not contain
2521 // the CSS properties is set and when the widget has this dynamic property set.
2522 // This way we don't trample on users who had setup a min/max size in code and
2523 // don't use stylesheets at all.
setGeometry(QWidget * w)2524 void QStyleSheetStyle::setGeometry(QWidget *w)
2525 {
2526     QRenderRule rule = renderRule(w, PseudoElement_None, PseudoClass_Enabled | extendedPseudoClass(w));
2527     const QStyleSheetGeometryData *geo = rule.geometry();
2528     if (w->property("_q_stylesheet_minw").toBool()
2529         && ((!rule.hasGeometry() || geo->minWidth == -1))) {
2530             w->setMinimumWidth(0);
2531             w->setProperty("_q_stylesheet_minw", QVariant());
2532     }
2533     if (w->property("_q_stylesheet_minh").toBool()
2534         && ((!rule.hasGeometry() || geo->minHeight == -1))) {
2535             w->setMinimumHeight(0);
2536             w->setProperty("_q_stylesheet_minh", QVariant());
2537     }
2538     if (w->property("_q_stylesheet_maxw").toBool()
2539         && ((!rule.hasGeometry() || geo->maxWidth == -1))) {
2540             w->setMaximumWidth(QWIDGETSIZE_MAX);
2541             w->setProperty("_q_stylesheet_maxw", QVariant());
2542     }
2543    if (w->property("_q_stylesheet_maxh").toBool()
2544         && ((!rule.hasGeometry() || geo->maxHeight == -1))) {
2545             w->setMaximumHeight(QWIDGETSIZE_MAX);
2546             w->setProperty("_q_stylesheet_maxh", QVariant());
2547     }
2548 
2549 
2550     if (rule.hasGeometry()) {
2551         if (geo->minWidth != -1) {
2552             w->setProperty("_q_stylesheet_minw", true);
2553             w->setMinimumWidth(rule.boxSize(QSize(qMax(geo->width, geo->minWidth), 0)).width());
2554         }
2555         if (geo->minHeight != -1) {
2556             w->setProperty("_q_stylesheet_minh", true);
2557             w->setMinimumHeight(rule.boxSize(QSize(0, qMax(geo->height, geo->minHeight))).height());
2558         }
2559         if (geo->maxWidth != -1) {
2560             w->setProperty("_q_stylesheet_maxw", true);
2561             w->setMaximumWidth(rule.boxSize(QSize(qMin(geo->width == -1 ? QWIDGETSIZE_MAX : geo->width,
2562                                                        geo->maxWidth == -1 ? QWIDGETSIZE_MAX : geo->maxWidth), 0)).width());
2563         }
2564         if (geo->maxHeight != -1) {
2565             w->setProperty("_q_stylesheet_maxh", true);
2566             w->setMaximumHeight(rule.boxSize(QSize(0, qMin(geo->height == -1 ? QWIDGETSIZE_MAX : geo->height,
2567                                                        geo->maxHeight == -1 ? QWIDGETSIZE_MAX : geo->maxHeight))).height());
2568         }
2569     }
2570 }
2571 
setProperties(QWidget * w)2572 void QStyleSheetStyle::setProperties(QWidget *w)
2573 {
2574     // The final occurrence of each property is authoritative.
2575     // Set value for each property in the order of property final occurrence
2576     // since properties interact.
2577 
2578     const QVector<Declaration> decls = declarations(styleRules(w), QString());
2579     QVector<int> finals; // indices in reverse order of each property's final occurrence
2580 
2581     {
2582         // scan decls for final occurrence of each "qproperty"
2583         QSet<const QString> propertySet;
2584         for (int i = decls.count() - 1; i >= 0; --i) {
2585             const QString property = decls.at(i).d->property;
2586             if (!property.startsWith(QLatin1String("qproperty-"), Qt::CaseInsensitive))
2587                 continue;
2588             if (!propertySet.contains(property)) {
2589                 propertySet.insert(property);
2590                 finals.append(i);
2591             }
2592         }
2593     }
2594 
2595     for (int i = finals.count() - 1; i >= 0; --i) {
2596         const Declaration &decl = decls.at(finals[i]);
2597         QStringView property = decl.d->property;
2598         property = property.mid(10); // strip "qproperty-"
2599         const auto propertyL1 = property.toLatin1();
2600 
2601         const QMetaObject *metaObject = w->metaObject();
2602         int index = metaObject->indexOfProperty(propertyL1);
2603         if (Q_UNLIKELY(index == -1)) {
2604             qWarning() << w << " does not have a property named " << property;
2605             continue;
2606         }
2607         const QMetaProperty metaProperty = metaObject->property(index);
2608         if (Q_UNLIKELY(!metaProperty.isWritable() || !metaProperty.isDesignable())) {
2609             qWarning() << w << " cannot design property named " << property;
2610             continue;
2611         }
2612 
2613         QVariant v;
2614         const QVariant value = w->property(propertyL1);
2615         switch (value.userType()) {
2616         case QMetaType::QIcon: v = decl.iconValue(); break;
2617         case QMetaType::QImage: v = QImage(decl.uriValue()); break;
2618         case QMetaType::QPixmap: v = QPixmap(decl.uriValue()); break;
2619         case QMetaType::QRect: v = decl.rectValue(); break;
2620         case QMetaType::QSize: v = decl.sizeValue(); break;
2621         case QMetaType::QColor: v = decl.colorValue(); break;
2622         case QMetaType::QBrush: v = decl.brushValue(); break;
2623 #ifndef QT_NO_SHORTCUT
2624         case QMetaType::QKeySequence: v = QKeySequence(decl.d->values.at(0).variant.toString()); break;
2625 #endif
2626         default: v = decl.d->values.at(0).variant; break;
2627         }
2628 
2629         w->setProperty(propertyL1, v);
2630     }
2631 }
2632 
setPalette(QWidget * w)2633 void QStyleSheetStyle::setPalette(QWidget *w)
2634 {
2635     struct RuleRoleMap {
2636         int state;
2637         QPalette::ColorGroup group;
2638     } map[3] = {
2639         { int(PseudoClass_Active | PseudoClass_Enabled), QPalette::Active },
2640         { PseudoClass_Disabled, QPalette::Disabled },
2641         { PseudoClass_Enabled, QPalette::Inactive }
2642     };
2643 
2644     const bool useStyleSheetPropagationInWidgetStyles =
2645         QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles);
2646 
2647     QPalette p;
2648     if (!useStyleSheetPropagationInWidgetStyles)
2649         p = w->palette();
2650 
2651     QWidget *ew = embeddedWidget(w);
2652 
2653     for (int i = 0; i < 3; i++) {
2654         QRenderRule rule = renderRule(w, PseudoElement_None, map[i].state | extendedPseudoClass(w));
2655         if (i == 0) {
2656             if (!w->property("_q_styleSheetWidgetFont").isValid()) {
2657                 saveWidgetFont(w, w->d_func()->localFont());
2658             }
2659             updateStyleSheetFont(w);
2660             if (ew != w)
2661                 updateStyleSheetFont(ew);
2662         }
2663 
2664         rule.configurePalette(&p, map[i].group, ew, ew != w);
2665     }
2666 
2667     if (!useStyleSheetPropagationInWidgetStyles || p.resolve() != 0) {
2668         QPalette wp = w->palette();
2669         styleSheetCaches->customPaletteWidgets.insert(w, {wp, p.resolve()});
2670 
2671         if (useStyleSheetPropagationInWidgetStyles) {
2672             p = p.resolve(wp);
2673             p.resolve(p.resolve() | wp.resolve());
2674         }
2675 
2676         w->setPalette(p);
2677         if (ew != w)
2678             ew->setPalette(p);
2679     }
2680 }
2681 
unsetPalette(QWidget * w)2682 void QStyleSheetStyle::unsetPalette(QWidget *w)
2683 {
2684     const bool useStyleSheetPropagationInWidgetStyles =
2685         QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles);
2686 
2687     const auto it = styleSheetCaches->customPaletteWidgets.find(w);
2688     if (it != styleSheetCaches->customPaletteWidgets.end()) {
2689         auto customizedPalette = std::move(*it);
2690         styleSheetCaches->customPaletteWidgets.erase(it);
2691 
2692         QPalette original;
2693         if (useStyleSheetPropagationInWidgetStyles)
2694             original = std::move(customizedPalette).reverted(w->palette());
2695         else
2696             original = customizedPalette.oldWidgetValue;
2697 
2698         w->setPalette(original);
2699         QWidget *ew = embeddedWidget(w);
2700         if (ew != w)
2701             ew->setPalette(original);
2702     }
2703 
2704     if (useStyleSheetPropagationInWidgetStyles) {
2705         unsetStyleSheetFont(w);
2706         QWidget *ew = embeddedWidget(w);
2707         if (ew != w)
2708             unsetStyleSheetFont(ew);
2709     } else {
2710         QVariant oldFont = w->property("_q_styleSheetWidgetFont");
2711         if (oldFont.isValid()) {
2712             w->setFont(qvariant_cast<QFont>(oldFont));
2713         }
2714     }
2715 
2716     if (styleSheetCaches->autoFillDisabledWidgets.contains(w)) {
2717         embeddedWidget(w)->setAutoFillBackground(true);
2718         styleSheetCaches->autoFillDisabledWidgets.remove(w);
2719     }
2720 }
2721 
unsetStyleSheetFont(QWidget * w) const2722 void QStyleSheetStyle::unsetStyleSheetFont(QWidget *w) const
2723 {
2724     const auto it = styleSheetCaches->customFontWidgets.find(w);
2725     if (it != styleSheetCaches->customFontWidgets.end()) {
2726         auto customizedFont = std::move(*it);
2727         styleSheetCaches->customFontWidgets.erase(it);
2728         w->setFont(std::move(customizedFont).reverted(w->font()));
2729     }
2730 }
2731 
updateObjects(const QList<const QObject * > & objects)2732 static void updateObjects(const QList<const QObject *>& objects)
2733 {
2734     if (!styleSheetCaches->styleRulesCache.isEmpty() || !styleSheetCaches->hasStyleRuleCache.isEmpty() || !styleSheetCaches->renderRulesCache.isEmpty()) {
2735         for (const QObject *object : objects) {
2736             styleSheetCaches->styleRulesCache.remove(object);
2737             styleSheetCaches->hasStyleRuleCache.remove(object);
2738             styleSheetCaches->renderRulesCache.remove(object);
2739         }
2740     }
2741 
2742     QEvent event(QEvent::StyleChange);
2743     for (const QObject *object : objects) {
2744         if (auto widget = qobject_cast<QWidget*>(const_cast<QObject*>(object))) {
2745             widget->style()->polish(widget);
2746             QCoreApplication::sendEvent(widget, &event);
2747             QList<const QObject *> children;
2748             children.reserve(widget->children().size() + 1);
2749             for (auto child: qAsConst(widget->children()))
2750                 children.append(child);
2751             updateObjects(children);
2752         }
2753     }
2754 }
2755 
2756 /////////////////////////////////////////////////////////////////////////////////////////
2757 // The stylesheet style
2758 int QStyleSheetStyle::numinstances = 0;
2759 
QStyleSheetStyle(QStyle * base)2760 QStyleSheetStyle::QStyleSheetStyle(QStyle *base)
2761     : QWindowsStyle(*new QStyleSheetStylePrivate), base(base), refcount(1)
2762 {
2763     ++numinstances;
2764     if (numinstances == 1) {
2765         styleSheetCaches = new QStyleSheetStyleCaches;
2766     }
2767 }
2768 
~QStyleSheetStyle()2769 QStyleSheetStyle::~QStyleSheetStyle()
2770 {
2771     --numinstances;
2772     if (numinstances == 0) {
2773         delete styleSheetCaches;
2774     }
2775 }
baseStyle() const2776 QStyle *QStyleSheetStyle::baseStyle() const
2777 {
2778     if (base)
2779         return base;
2780     if (QStyleSheetStyle *me = qt_styleSheet(QApplication::style()))
2781         return me->base;
2782     return QApplication::style();
2783 }
2784 
objectDestroyed(QObject * o)2785 void QStyleSheetStyleCaches::objectDestroyed(QObject *o)
2786 {
2787     styleRulesCache.remove(o);
2788     hasStyleRuleCache.remove(o);
2789     renderRulesCache.remove(o);
2790     customPaletteWidgets.remove((const QWidget *)o);
2791     customFontWidgets.remove(static_cast<QWidget *>(o));
2792     styleSheetCache.remove(o);
2793     autoFillDisabledWidgets.remove((const QWidget *)o);
2794 }
2795 
styleDestroyed(QObject * o)2796 void QStyleSheetStyleCaches::styleDestroyed(QObject *o)
2797 {
2798     styleSheetCache.remove(o);
2799 }
2800 
2801 /*!
2802  *  Make sure that the cache will be clean by connecting destroyed if needed.
2803  *  return false if the widget is not stylable;
2804  */
initObject(const QObject * obj) const2805 bool QStyleSheetStyle::initObject(const QObject *obj) const
2806 {
2807     if (!obj)
2808         return false;
2809     if (const QWidget *w = qobject_cast<const QWidget*>(obj)) {
2810         if (w->testAttribute(Qt::WA_StyleSheet))
2811             return true;
2812         if (unstylable(w))
2813             return false;
2814         const_cast<QWidget *>(w)->setAttribute(Qt::WA_StyleSheet, true);
2815     }
2816 
2817     QObject::connect(obj, SIGNAL(destroyed(QObject*)), styleSheetCaches, SLOT(objectDestroyed(QObject*)), Qt::UniqueConnection);
2818     return true;
2819 }
2820 
polish(QWidget * w)2821 void QStyleSheetStyle::polish(QWidget *w)
2822 {
2823     baseStyle()->polish(w);
2824     RECURSION_GUARD(return)
2825 
2826     if (!initObject(w))
2827         return;
2828 
2829     if (styleSheetCaches->styleRulesCache.contains(w)) {
2830         // the widget accessed its style pointer before polish (or repolish)
2831         // (exemple: the QAbstractSpinBox constructor ask for the stylehint)
2832         styleSheetCaches->styleRulesCache.remove(w);
2833         styleSheetCaches->hasStyleRuleCache.remove(w);
2834         styleSheetCaches->renderRulesCache.remove(w);
2835         styleSheetCaches->styleSheetCache.remove(w);
2836     }
2837     setGeometry(w);
2838     setProperties(w);
2839     unsetPalette(w);
2840     setPalette(w);
2841 
2842     //set the WA_Hover attribute if one of the selector depends of the hover state
2843     QVector<StyleRule> rules = styleRules(w);
2844     for (int i = 0; i < rules.count(); i++) {
2845         const Selector& selector = rules.at(i).selectors.at(0);
2846         quint64 negated = 0;
2847         quint64 cssClass = selector.pseudoClass(&negated);
2848         if ( cssClass & PseudoClass_Hover || negated & PseudoClass_Hover) {
2849             w->setAttribute(Qt::WA_Hover);
2850             embeddedWidget(w)->setAttribute(Qt::WA_Hover);
2851             embeddedWidget(w)->setMouseTracking(true);
2852         }
2853     }
2854 
2855 
2856 #if QT_CONFIG(scrollarea)
2857     if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w)) {
2858         QRenderRule rule = renderRule(sa, PseudoElement_None, PseudoClass_Enabled);
2859         if ((rule.hasBorder() && rule.border()->hasBorderImage())
2860             || (rule.hasBackground() && !rule.background()->pixmap.isNull())) {
2861             QObject::connect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)),
2862                              sa, SLOT(update()), Qt::UniqueConnection);
2863             QObject::connect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)),
2864                              sa, SLOT(update()), Qt::UniqueConnection);
2865         }
2866     }
2867 #endif
2868 
2869     QRenderRule rule = renderRule(w, PseudoElement_None, PseudoClass_Any);
2870 
2871     w->setAttribute(Qt::WA_StyleSheetTarget, rule.hasModification());
2872 
2873     if (rule.hasDrawable() || rule.hasBox()) {
2874         if (w->metaObject() == &QWidget::staticMetaObject
2875 #if QT_CONFIG(itemviews)
2876               || qobject_cast<QHeaderView *>(w)
2877 #endif
2878 #if QT_CONFIG(tabbar)
2879               || qobject_cast<QTabBar *>(w)
2880 #endif
2881 #ifndef QT_NO_FRAME
2882               || qobject_cast<QFrame *>(w)
2883 #endif
2884 #if QT_CONFIG(mainwindow)
2885               || qobject_cast<QMainWindow *>(w)
2886 #endif
2887 #if QT_CONFIG(mdiarea)
2888               || qobject_cast<QMdiSubWindow *>(w)
2889 #endif
2890 #if QT_CONFIG(menubar)
2891               || qobject_cast<QMenuBar *>(w)
2892 #endif
2893 #if QT_CONFIG(dialog)
2894               || qobject_cast<QDialog *>(w)
2895 #endif
2896                                            ) {
2897             w->setAttribute(Qt::WA_StyledBackground, true);
2898         }
2899         QWidget *ew = embeddedWidget(w);
2900         if (ew->autoFillBackground()) {
2901             ew->setAutoFillBackground(false);
2902             styleSheetCaches->autoFillDisabledWidgets.insert(w);
2903             if (ew != w) { //eg. viewport of a scrollarea
2904                 //(in order to draw the background anyway in case we don't.)
2905                 ew->setAttribute(Qt::WA_StyledBackground, true);
2906             }
2907         }
2908         if (!rule.hasBackground() || rule.background()->isTransparent() || rule.hasBox()
2909             || (!rule.hasNativeBorder() && !rule.border()->isOpaque()))
2910             w->setAttribute(Qt::WA_OpaquePaintEvent, false);
2911     }
2912 }
2913 
polish(QApplication * app)2914 void QStyleSheetStyle::polish(QApplication *app)
2915 {
2916     baseStyle()->polish(app);
2917 }
2918 
polish(QPalette & pal)2919 void QStyleSheetStyle::polish(QPalette &pal)
2920 {
2921     baseStyle()->polish(pal);
2922 }
2923 
repolish(QWidget * w)2924 void QStyleSheetStyle::repolish(QWidget *w)
2925 {
2926     QList<const QObject *> children;
2927     children.reserve(w->children().size() + 1);
2928     for (auto child: qAsConst(w->children()))
2929         children.append(child);
2930     children.append(w);
2931     styleSheetCaches->styleSheetCache.remove(w);
2932     updateObjects(children);
2933 }
2934 
repolish(QApplication * app)2935 void QStyleSheetStyle::repolish(QApplication *app)
2936 {
2937     Q_UNUSED(app);
2938     const QList<const QObject*> allObjects = styleSheetCaches->styleRulesCache.keys();
2939     styleSheetCaches->styleSheetCache.remove(qApp);
2940     styleSheetCaches->styleRulesCache.clear();
2941     styleSheetCaches->hasStyleRuleCache.clear();
2942     styleSheetCaches->renderRulesCache.clear();
2943     updateObjects(allObjects);
2944 }
2945 
unpolish(QWidget * w)2946 void QStyleSheetStyle::unpolish(QWidget *w)
2947 {
2948     if (!w || !w->testAttribute(Qt::WA_StyleSheet)) {
2949         baseStyle()->unpolish(w);
2950         return;
2951     }
2952 
2953     styleSheetCaches->styleRulesCache.remove(w);
2954     styleSheetCaches->hasStyleRuleCache.remove(w);
2955     styleSheetCaches->renderRulesCache.remove(w);
2956     styleSheetCaches->styleSheetCache.remove(w);
2957     unsetPalette(w);
2958     setGeometry(w);
2959     w->setAttribute(Qt::WA_StyleSheetTarget, false);
2960     w->setAttribute(Qt::WA_StyleSheet, false);
2961     QObject::disconnect(w, nullptr, this, nullptr);
2962 #if QT_CONFIG(scrollarea)
2963     if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w)) {
2964         QObject::disconnect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)),
2965                             sa, SLOT(update()));
2966         QObject::disconnect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)),
2967                             sa, SLOT(update()));
2968     }
2969 #endif
2970     baseStyle()->unpolish(w);
2971 }
2972 
unpolish(QApplication * app)2973 void QStyleSheetStyle::unpolish(QApplication *app)
2974 {
2975     baseStyle()->unpolish(app);
2976     RECURSION_GUARD(return)
2977     styleSheetCaches->styleRulesCache.clear();
2978     styleSheetCaches->hasStyleRuleCache.clear();
2979     styleSheetCaches->renderRulesCache.clear();
2980     styleSheetCaches->styleSheetCache.remove(qApp);
2981 }
2982 
2983 #if QT_CONFIG(tabbar)
verticalTabs(QTabBar::Shape shape)2984 inline static bool verticalTabs(QTabBar::Shape shape)
2985 {
2986     return shape == QTabBar::RoundedWest
2987            || shape == QTabBar::RoundedEast
2988            || shape == QTabBar::TriangularWest
2989            || shape == QTabBar::TriangularEast;
2990 }
2991 #endif // QT_CONFIG(tabbar)
2992 
drawComplexControl(ComplexControl cc,const QStyleOptionComplex * opt,QPainter * p,const QWidget * w) const2993 void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
2994                                           const QWidget *w) const
2995 {
2996     RECURSION_GUARD(baseStyle()->drawComplexControl(cc, opt, p, w); return)
2997 
2998     QRenderRule rule = renderRule(w, opt);
2999 
3000     switch (cc) {
3001     case CC_ComboBox:
3002         if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3003             QStyleOptionComboBox cmbOpt(*cmb);
3004             cmbOpt.rect = rule.borderRect(opt->rect);
3005             if (rule.hasNativeBorder()) {
3006                 rule.drawBackgroundImage(p, cmbOpt.rect);
3007                 rule.configurePalette(&cmbOpt.palette, QPalette::ButtonText, QPalette::Button);
3008                 bool customDropDown = (opt->subControls & QStyle::SC_ComboBoxArrow)
3009                                 && (hasStyleRule(w, PseudoElement_ComboBoxDropDown) || hasStyleRule(w, PseudoElement_ComboBoxArrow));
3010                 if (customDropDown)
3011                     cmbOpt.subControls &= ~QStyle::SC_ComboBoxArrow;
3012                 if (rule.baseStyleCanDraw()) {
3013                     baseStyle()->drawComplexControl(cc, &cmbOpt, p, w);
3014                 } else {
3015                     QWindowsStyle::drawComplexControl(cc, &cmbOpt, p, w);
3016                 }
3017                 if (!customDropDown)
3018                     return;
3019             } else {
3020                 rule.drawRule(p, opt->rect);
3021             }
3022 
3023             if (opt->subControls & QStyle::SC_ComboBoxArrow) {
3024                 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
3025                 if (subRule.hasDrawable()) {
3026                     QRect r = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow, w);
3027                     subRule.drawRule(p, r);
3028                     QRenderRule subRule2 = renderRule(w, opt, PseudoElement_ComboBoxArrow);
3029                     r = positionRect(w, subRule, subRule2, PseudoElement_ComboBoxArrow, r, opt->direction);
3030                     subRule2.drawRule(p, r);
3031                 } else {
3032                     rule.configurePalette(&cmbOpt.palette, QPalette::ButtonText, QPalette::Button);
3033                     cmbOpt.subControls = QStyle::SC_ComboBoxArrow;
3034                     QWindowsStyle::drawComplexControl(cc, &cmbOpt, p, w);
3035                 }
3036             }
3037 
3038             return;
3039         }
3040         break;
3041 
3042 #if QT_CONFIG(spinbox)
3043     case CC_SpinBox:
3044         if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
3045             QStyleOptionSpinBox spinOpt(*spin);
3046             rule.configurePalette(&spinOpt.palette, QPalette::ButtonText, QPalette::Button);
3047             rule.configurePalette(&spinOpt.palette, QPalette::Text, QPalette::Base);
3048             spinOpt.rect = rule.borderRect(opt->rect);
3049             bool customUp = true, customDown = true;
3050             QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
3051             QRenderRule downRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
3052             bool upRuleMatch = upRule.hasGeometry() || upRule.hasPosition();
3053             bool downRuleMatch = downRule.hasGeometry() || downRule.hasPosition();
3054             if (rule.hasNativeBorder() && !upRuleMatch && !downRuleMatch) {
3055                 rule.drawBackgroundImage(p, spinOpt.rect);
3056                 customUp = (opt->subControls & QStyle::SC_SpinBoxUp)
3057                         && (hasStyleRule(w, PseudoElement_SpinBoxUpButton) || hasStyleRule(w, PseudoElement_UpArrow));
3058                 if (customUp)
3059                     spinOpt.subControls &= ~QStyle::SC_SpinBoxUp;
3060                 customDown = (opt->subControls & QStyle::SC_SpinBoxDown)
3061                         && (hasStyleRule(w, PseudoElement_SpinBoxDownButton) || hasStyleRule(w, PseudoElement_DownArrow));
3062                 if (customDown)
3063                     spinOpt.subControls &= ~QStyle::SC_SpinBoxDown;
3064                 if (rule.baseStyleCanDraw()) {
3065                     baseStyle()->drawComplexControl(cc, &spinOpt, p, w);
3066                 } else {
3067                     QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3068                 }
3069                 if (!customUp && !customDown)
3070                     return;
3071             } else {
3072                 rule.drawRule(p, opt->rect);
3073             }
3074 
3075             if ((opt->subControls & QStyle::SC_SpinBoxUp) && customUp) {
3076                 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
3077                 if (subRule.hasDrawable()) {
3078                     QRect r = subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w);
3079                     subRule.drawRule(p, r);
3080                     QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SpinBoxUpArrow);
3081                     r = positionRect(w, subRule, subRule2, PseudoElement_SpinBoxUpArrow, r, opt->direction);
3082                     subRule2.drawRule(p, r);
3083                 } else {
3084                     spinOpt.subControls = QStyle::SC_SpinBoxUp;
3085                     QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3086                 }
3087             }
3088 
3089             if ((opt->subControls & QStyle::SC_SpinBoxDown) && customDown) {
3090                 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
3091                 if (subRule.hasDrawable()) {
3092                     QRect r = subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w);
3093                     subRule.drawRule(p, r);
3094                     QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SpinBoxDownArrow);
3095                     r = positionRect(w, subRule, subRule2, PseudoElement_SpinBoxDownArrow, r, opt->direction);
3096                     subRule2.drawRule(p, r);
3097                 } else {
3098                     spinOpt.subControls = QStyle::SC_SpinBoxDown;
3099                     QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3100                 }
3101             }
3102             return;
3103         }
3104         break;
3105 #endif // QT_CONFIG(spinbox)
3106 
3107     case CC_GroupBox:
3108         if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
3109 
3110             QRect labelRect, checkBoxRect, titleRect, frameRect;
3111             bool hasTitle = (gb->subControls & QStyle::SC_GroupBoxCheckBox) || !gb->text.isEmpty();
3112 
3113             if (!rule.hasDrawable() && (!hasTitle || !hasStyleRule(w, PseudoElement_GroupBoxTitle))
3114                 && !hasStyleRule(w, PseudoElement_Indicator) && !rule.hasBox() && !rule.hasFont && !rule.hasPalette()) {
3115                 // let the native style draw the combobox if there is no style for it.
3116                 break;
3117             }
3118             rule.drawBackground(p, opt->rect);
3119 
3120             QRenderRule titleRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
3121             bool clipSet = false;
3122 
3123             if (hasTitle) {
3124                 labelRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, w);
3125                 //Some native style (such as mac) may return a too small rectangle (because they use smaller fonts),  so we may need to expand it a little bit.
3126                 labelRect.setSize(labelRect.size().expandedTo(ParentStyle::subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, w).size()));
3127                 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3128                     checkBoxRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxCheckBox, w);
3129                     titleRect = titleRule.boxRect(checkBoxRect.united(labelRect));
3130                 } else {
3131                     titleRect = titleRule.boxRect(labelRect);
3132                 }
3133                 if (!titleRule.hasBackground() || !titleRule.background()->isTransparent()) {
3134                     clipSet = true;
3135                     p->save();
3136                     p->setClipRegion(QRegion(opt->rect) - titleRect);
3137                 }
3138             }
3139 
3140             frameRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxFrame, w);
3141             QStyleOptionFrame frame;
3142             frame.QStyleOption::operator=(*gb);
3143             frame.features = gb->features;
3144             frame.lineWidth = gb->lineWidth;
3145             frame.midLineWidth = gb->midLineWidth;
3146             frame.rect = frameRect;
3147             drawPrimitive(PE_FrameGroupBox, &frame, p, w);
3148 
3149             if (clipSet)
3150                 p->restore();
3151 
3152             // draw background and frame of the title
3153             if (hasTitle)
3154                 titleRule.drawRule(p, titleRect);
3155 
3156             // draw the indicator
3157             if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3158                 QStyleOptionButton box;
3159                 box.QStyleOption::operator=(*gb);
3160                 box.rect = checkBoxRect;
3161                 drawPrimitive(PE_IndicatorCheckBox, &box, p, w);
3162             }
3163 
3164             // draw the text
3165             if (!gb->text.isEmpty()) {
3166                 int alignment = int(Qt::AlignCenter | Qt::TextShowMnemonic);
3167                 if (!styleHint(QStyle::SH_UnderlineShortcut, opt, w)) {
3168                     alignment |= Qt::TextHideMnemonic;
3169                 }
3170 
3171                 QPalette pal = gb->palette;
3172                 if (gb->textColor.isValid())
3173                     pal.setColor(QPalette::WindowText, gb->textColor);
3174                 titleRule.configurePalette(&pal, QPalette::WindowText, QPalette::Window);
3175                 drawItemText(p, labelRect,  alignment, pal, gb->state & State_Enabled,
3176                              gb->text, QPalette::WindowText);
3177 
3178                 if (gb->state & State_HasFocus) {
3179                     QStyleOptionFocusRect fropt;
3180                     fropt.QStyleOption::operator=(*gb);
3181                     fropt.rect = labelRect;
3182                     drawPrimitive(PE_FrameFocusRect, &fropt, p, w);
3183                 }
3184             }
3185 
3186                         return;
3187         }
3188         break;
3189 
3190     case CC_ToolButton:
3191         if (const QStyleOptionToolButton *tool = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3192             QStyleOptionToolButton toolOpt(*tool);
3193             rule.configurePalette(&toolOpt.palette, QPalette::ButtonText, QPalette::Button);
3194             toolOpt.font = rule.font.resolve(toolOpt.font);
3195             toolOpt.rect = rule.borderRect(opt->rect);
3196             bool customArrow = (tool->features & (QStyleOptionToolButton::HasMenu | QStyleOptionToolButton::MenuButtonPopup));
3197             bool customDropDown = tool->features & QStyleOptionToolButton::MenuButtonPopup;
3198             if (rule.hasNativeBorder()) {
3199                 if (tool->subControls & SC_ToolButton) {
3200                     //in some case (eg. the button is "auto raised") the style doesn't draw the background
3201                     //so we need to draw the background.
3202                     // use the same condition as in QCommonStyle
3203                     State bflags = tool->state & ~State_Sunken;
3204                     if (bflags & State_AutoRaise && (!(bflags & State_MouseOver) || !(bflags & State_Enabled)))
3205                             bflags &= ~State_Raised;
3206                     if (tool->state & State_Sunken && tool->activeSubControls & SC_ToolButton)
3207                             bflags |= State_Sunken;
3208                     if (!(bflags & (State_Sunken | State_On | State_Raised)))
3209                         rule.drawBackground(p, toolOpt.rect);
3210                 }
3211                 customArrow = customArrow && hasStyleRule(w, PseudoElement_ToolButtonDownArrow);
3212                 if (customArrow)
3213                     toolOpt.features &= ~QStyleOptionToolButton::HasMenu;
3214                 customDropDown = customDropDown && hasStyleRule(w, PseudoElement_ToolButtonMenu);
3215                 if (customDropDown)
3216                     toolOpt.subControls &= ~QStyle::SC_ToolButtonMenu;
3217 
3218                 if (rule.baseStyleCanDraw() && !(tool->features & QStyleOptionToolButton::Arrow)) {
3219                     baseStyle()->drawComplexControl(cc, &toolOpt, p, w);
3220                 } else {
3221                     QWindowsStyle::drawComplexControl(cc, &toolOpt, p, w);
3222                 }
3223 
3224                 if (!customArrow && !customDropDown)
3225                     return;
3226             } else {
3227                 rule.drawRule(p, opt->rect);
3228                 toolOpt.rect = rule.contentsRect(opt->rect);
3229                 if (rule.hasFont)
3230                     toolOpt.font = rule.font.resolve(toolOpt.font);
3231                 drawControl(CE_ToolButtonLabel, &toolOpt, p, w);
3232             }
3233 
3234             QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
3235             QRect r = subControlRect(CC_ToolButton, opt, QStyle::SC_ToolButtonMenu, w);
3236             if (customDropDown) {
3237                 if (opt->subControls & QStyle::SC_ToolButtonMenu) {
3238                     if (subRule.hasDrawable()) {
3239                         subRule.drawRule(p, r);
3240                     } else {
3241                         toolOpt.rect = r;
3242                         baseStyle()->drawPrimitive(PE_IndicatorButtonDropDown, &toolOpt, p, w);
3243                     }
3244                 }
3245             }
3246 
3247             if (customArrow) {
3248                 QRenderRule subRule2 = customDropDown ? renderRule(w, opt, PseudoElement_ToolButtonMenuArrow)
3249                                                       : renderRule(w, opt, PseudoElement_ToolButtonDownArrow);
3250                 QRect r2 = customDropDown
3251                           ? positionRect(w, subRule, subRule2, PseudoElement_ToolButtonMenuArrow, r, opt->direction)
3252                           : positionRect(w, rule, subRule2, PseudoElement_ToolButtonDownArrow, opt->rect, opt->direction);
3253                 if (subRule2.hasDrawable()) {
3254                     subRule2.drawRule(p, r2);
3255                 } else {
3256                     toolOpt.rect = r2;
3257                     baseStyle()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &toolOpt, p, w);
3258                 }
3259             }
3260 
3261             return;
3262         }
3263         break;
3264 
3265 #if QT_CONFIG(scrollbar)
3266     case CC_ScrollBar:
3267         if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3268             if (!rule.hasDrawable()) {
3269                 QStyleOptionSlider sbOpt(*sb);
3270                 sbOpt.rect = rule.borderRect(opt->rect);
3271                 rule.drawBackgroundImage(p, opt->rect);
3272                 baseStyle()->drawComplexControl(cc, &sbOpt, p, w);
3273             } else {
3274                 rule.drawRule(p, opt->rect);
3275                 QWindowsStyle::drawComplexControl(cc, opt, p, w);
3276             }
3277             return;
3278         }
3279         break;
3280 #endif // QT_CONFIG(scrollbar)
3281 
3282 #if QT_CONFIG(slider)
3283     case CC_Slider:
3284         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3285             rule.drawRule(p, opt->rect);
3286 
3287             QRenderRule grooveSubRule = renderRule(w, opt, PseudoElement_SliderGroove);
3288             QRenderRule handleSubRule = renderRule(w, opt, PseudoElement_SliderHandle);
3289             if (!grooveSubRule.hasDrawable()) {
3290                 QStyleOptionSlider slOpt(*slider);
3291                 bool handleHasRule = handleSubRule.hasDrawable();
3292                 // If the style specifies a different handler rule, draw the groove without the handler.
3293                 if (handleHasRule)
3294                     slOpt.subControls &= ~SC_SliderHandle;
3295                 baseStyle()->drawComplexControl(cc, &slOpt, p, w);
3296                 if (!handleHasRule)
3297                     return;
3298             }
3299 
3300             QRect gr = subControlRect(cc, opt, SC_SliderGroove, w);
3301             if (slider->subControls & SC_SliderGroove) {
3302                 grooveSubRule.drawRule(p, gr);
3303             }
3304 
3305             if (slider->subControls & SC_SliderHandle) {
3306                 QRect hr = subControlRect(cc, opt, SC_SliderHandle, w);
3307 
3308                 QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage);
3309                 if (subRule1.hasDrawable()) {
3310                     QRect r(gr.topLeft(),
3311                             slider->orientation == Qt::Horizontal
3312                                 ? QPoint(hr.x()+hr.width()/2, gr.y()+gr.height() - 1)
3313                                 : QPoint(gr.x()+gr.width() - 1, hr.y()+hr.height()/2));
3314                     subRule1.drawRule(p, r);
3315                 }
3316 
3317                 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderAddPage);
3318                 if (subRule2.hasDrawable()) {
3319                     QRect r(slider->orientation == Qt::Horizontal
3320                                 ? QPoint(hr.x()+hr.width()/2+1, gr.y())
3321                                 : QPoint(gr.x(), hr.y()+hr.height()/2+1),
3322                             gr.bottomRight());
3323                     subRule2.drawRule(p, r);
3324                 }
3325 
3326                 handleSubRule.drawRule(p, handleSubRule.boxRect(hr, Margin));
3327             }
3328 
3329             if (slider->subControls & SC_SliderTickmarks) {
3330                 // TODO...
3331             }
3332 
3333             return;
3334         }
3335         break;
3336 #endif // QT_CONFIG(slider)
3337 
3338     case CC_MdiControls:
3339         if (hasStyleRule(w, PseudoElement_MdiCloseButton)
3340             || hasStyleRule(w, PseudoElement_MdiNormalButton)
3341             || hasStyleRule(w, PseudoElement_MdiMinButton)) {
3342             QList<QVariant> layout = rule.styleHint(QLatin1String("button-layout")).toList();
3343             if (layout.isEmpty())
3344                 layout = subControlLayout(QLatin1String("mNX"));
3345 
3346             QStyleOptionComplex optCopy(*opt);
3347             optCopy.subControls = { };
3348             for (int i = 0; i < layout.count(); i++) {
3349                 int layoutButton = layout[i].toInt();
3350                 if (layoutButton < PseudoElement_MdiCloseButton
3351                     || layoutButton > PseudoElement_MdiNormalButton)
3352                     continue;
3353                 QStyle::SubControl control = knownPseudoElements[layoutButton].subControl;
3354                 if (!(opt->subControls & control))
3355                     continue;
3356                 QRenderRule subRule = renderRule(w, opt, layoutButton);
3357                 if (subRule.hasDrawable()) {
3358                     QRect rect = subRule.boxRect(subControlRect(CC_MdiControls, opt, control, w), Margin);
3359                     subRule.drawRule(p, rect);
3360                     QIcon icon = standardIcon(subControlIcon(layoutButton), opt);
3361                     icon.paint(p, subRule.contentsRect(rect), Qt::AlignCenter);
3362                 } else {
3363                     optCopy.subControls |= control;
3364                 }
3365             }
3366 
3367             if (optCopy.subControls)
3368                 baseStyle()->drawComplexControl(CC_MdiControls, &optCopy, p, w);
3369             return;
3370         }
3371         break;
3372 
3373     case CC_TitleBar:
3374         if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
3375             QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
3376             if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
3377                 break;
3378             subRule.drawRule(p, opt->rect);
3379             QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
3380 
3381             QRect ir;
3382             ir = layout[SC_TitleBarLabel];
3383             if (ir.isValid()) {
3384                 if (subRule.hasPalette())
3385                     p->setPen(subRule.palette()->foreground.color());
3386                 p->fillRect(ir, Qt::white);
3387                 p->drawText(ir.x(), ir.y(), ir.width(), ir.height(), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
3388             }
3389 
3390             QPixmap pm;
3391 
3392             ir = layout[SC_TitleBarSysMenu];
3393             if (ir.isValid()) {
3394                 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarSysMenu);
3395                 subSubRule.drawRule(p, ir);
3396                 ir = subSubRule.contentsRect(ir);
3397                 if (!tb->icon.isNull()) {
3398                     tb->icon.paint(p, ir);
3399                 } else {
3400                     int iconSize = pixelMetric(PM_SmallIconSize, tb, w);
3401                     pm = standardIcon(SP_TitleBarMenuButton, nullptr, w).pixmap(iconSize, iconSize);
3402                     drawItemPixmap(p, ir, Qt::AlignCenter, pm);
3403                 }
3404             }
3405 
3406             ir = layout[SC_TitleBarCloseButton];
3407             if (ir.isValid()) {
3408                 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarCloseButton);
3409                 subSubRule.drawRule(p, ir);
3410 
3411                 QSize sz = subSubRule.contentsRect(ir).size();
3412                 if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool)
3413                     pm = standardIcon(SP_DockWidgetCloseButton, nullptr, w).pixmap(sz);
3414                 else
3415                     pm = standardIcon(SP_TitleBarCloseButton, nullptr, w).pixmap(sz);
3416                 drawItemPixmap(p, ir, Qt::AlignCenter, pm);
3417             }
3418 
3419             int pes[] = {
3420                 PseudoElement_TitleBarMaxButton,
3421                 PseudoElement_TitleBarMinButton,
3422                 PseudoElement_TitleBarNormalButton,
3423                 PseudoElement_TitleBarShadeButton,
3424                 PseudoElement_TitleBarUnshadeButton,
3425                 PseudoElement_TitleBarContextHelpButton
3426             };
3427 
3428             for (unsigned int i = 0; i < sizeof(pes)/sizeof(int); i++) {
3429                 int pe = pes[i];
3430                 QStyle::SubControl sc = knownPseudoElements[pe].subControl;
3431                 ir = layout[sc];
3432                 if (!ir.isValid())
3433                     continue;
3434                 QRenderRule subSubRule = renderRule(w, opt, pe);
3435                 subSubRule.drawRule(p, ir);
3436                 pm = standardIcon(subControlIcon(pe), nullptr, w).pixmap(subSubRule.contentsRect(ir).size());
3437                 drawItemPixmap(p, ir, Qt::AlignCenter, pm);
3438             }
3439 
3440             return;
3441         }
3442         break;
3443 
3444 
3445     default:
3446         break;
3447     }
3448 
3449     baseStyle()->drawComplexControl(cc, opt, p, w);
3450 }
3451 
drawControl(ControlElement ce,const QStyleOption * opt,QPainter * p,const QWidget * w) const3452 void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3453                           const QWidget *w) const
3454 {
3455     RECURSION_GUARD(baseStyle()->drawControl(ce, opt, p, w); return)
3456 
3457     QRenderRule rule = renderRule(w, opt);
3458     int pe1 = PseudoElement_None, pe2 = PseudoElement_None;
3459     bool fallback = false;
3460 
3461     switch (ce) {
3462     case CE_ToolButtonLabel:
3463         if (const QStyleOptionToolButton *btn = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3464             if (rule.hasBox() || btn->features & QStyleOptionToolButton::Arrow) {
3465                 QWindowsStyle::drawControl(ce, opt, p, w);
3466             } else {
3467                 QStyleOptionToolButton butOpt(*btn);
3468                 rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3469                 baseStyle()->drawControl(ce, &butOpt, p, w);
3470             }
3471             return;
3472         }
3473         break;
3474 
3475     case CE_FocusFrame:
3476         if (!rule.hasNativeBorder()) {
3477             rule.drawBorder(p, opt->rect);
3478             return;
3479         }
3480         break;
3481 
3482     case CE_PushButton:
3483         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3484             if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() ||
3485                     ((btn->features & QStyleOptionButton::HasMenu) && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator))) {
3486                 ParentStyle::drawControl(ce, opt, p, w);
3487                 return;
3488             }
3489         }
3490         break;
3491     case CE_PushButtonBevel:
3492         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3493             QStyleOptionButton btnOpt(*btn);
3494             btnOpt.rect = rule.borderRect(opt->rect);
3495             if (rule.hasNativeBorder()) {
3496                 rule.drawBackgroundImage(p, btnOpt.rect);
3497                 rule.configurePalette(&btnOpt.palette, QPalette::ButtonText, QPalette::Button);
3498                 bool customMenu = (btn->features & QStyleOptionButton::HasMenu
3499                                    && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator));
3500                 if (customMenu)
3501                     btnOpt.features &= ~QStyleOptionButton::HasMenu;
3502                 if (rule.baseStyleCanDraw()) {
3503                     baseStyle()->drawControl(ce, &btnOpt, p, w);
3504                 } else {
3505                     QWindowsStyle::drawControl(ce, &btnOpt, p, w);
3506                 }
3507                 rule.drawImage(p, rule.contentsRect(opt->rect));
3508                 if (!customMenu)
3509                     return;
3510             } else {
3511                 rule.drawRule(p, opt->rect);
3512             }
3513 
3514             if (btn->features & QStyleOptionButton::HasMenu) {
3515                 QRenderRule subRule = renderRule(w, opt, PseudoElement_PushButtonMenuIndicator);
3516                 QRect ir = positionRect(w, rule, subRule, PseudoElement_PushButtonMenuIndicator, opt->rect, opt->direction);
3517                 if (subRule.hasDrawable()) {
3518                     subRule.drawRule(p, ir);
3519                 } else {
3520                     btnOpt.rect = ir;
3521                     baseStyle()->drawPrimitive(PE_IndicatorArrowDown, &btnOpt, p, w);
3522                 }
3523             }
3524         }
3525         return;
3526 
3527     case CE_PushButtonLabel:
3528         if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3529             QStyleOptionButton butOpt(*button);
3530             rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3531 
3532             const QFont oldFont = p->font();
3533             if (rule.hasFont)
3534                 p->setFont(rule.font.resolve(p->font()));
3535 
3536             if (rule.hasPosition() || rule.hasIcon()) {
3537                 uint tf = Qt::TextShowMnemonic;
3538                 QRect textRect = button->rect;
3539 
3540                 const uint horizontalAlignMask = Qt::AlignHCenter | Qt::AlignLeft | Qt::AlignRight;
3541                 const uint verticalAlignMask = Qt::AlignVCenter | Qt::AlignTop | Qt::AlignLeft;
3542 
3543                 if (rule.hasPosition() && rule.position()->textAlignment != 0) {
3544                     Qt::Alignment textAlignment = rule.position()->textAlignment;
3545                     tf |= (textAlignment & verticalAlignMask) ? (textAlignment & verticalAlignMask) : Qt::AlignVCenter;
3546                     tf |= (textAlignment & horizontalAlignMask) ? (textAlignment & horizontalAlignMask) : Qt::AlignHCenter;
3547                     if (!styleHint(SH_UnderlineShortcut, button, w))
3548                         tf |= Qt::TextHideMnemonic;
3549                 } else {
3550                     tf |= Qt::AlignVCenter | Qt::AlignHCenter;
3551                 }
3552 
3553                 QIcon icon = rule.hasIcon() ? rule.icon()->icon : button->icon;
3554                 if (!icon.isNull()) {
3555                     //Group both icon and text
3556                     QRect iconRect;
3557                     QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3558                     if (mode == QIcon::Normal && button->state & State_HasFocus)
3559                         mode = QIcon::Active;
3560                     QIcon::State state = QIcon::Off;
3561                     if (button->state & State_On)
3562                         state = QIcon::On;
3563 
3564                     QPixmap pixmap = icon.pixmap(button->iconSize, mode, state);
3565                     int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3566                     int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3567                     int labelWidth = pixmapWidth;
3568                     int labelHeight = pixmapHeight;
3569                     int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
3570                     int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width();
3571                     if (!button->text.isEmpty())
3572                         labelWidth += (textWidth + iconSpacing);
3573 
3574                     //Determine label alignment:
3575                     if (tf & Qt::AlignLeft) { /*left*/
3576                         iconRect = QRect(textRect.x(), textRect.y() + (textRect.height() - labelHeight) / 2,
3577                                          pixmapWidth, pixmapHeight);
3578                     } else if (tf & Qt::AlignHCenter) { /* center */
3579                         iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
3580                                          textRect.y() + (textRect.height() - labelHeight) / 2,
3581                                          pixmapWidth, pixmapHeight);
3582                     } else { /*right*/
3583                         iconRect = QRect(textRect.x() + textRect.width() - labelWidth,
3584                                          textRect.y() + (textRect.height() - labelHeight) / 2,
3585                                          pixmapWidth, pixmapHeight);
3586                     }
3587 
3588                     iconRect = visualRect(button->direction, textRect, iconRect);
3589 
3590                     // Left align, adjust the text-rect according to the icon instead
3591                     tf &= ~horizontalAlignMask;
3592                     tf |= Qt::AlignLeft;
3593 
3594                     if (button->direction == Qt::RightToLeft)
3595                         textRect.setRight(iconRect.left() - iconSpacing);
3596                     else
3597                         textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing);
3598 
3599                     if (button->state & (State_On | State_Sunken))
3600                         iconRect.translate(pixelMetric(PM_ButtonShiftHorizontal, opt, w),
3601                                            pixelMetric(PM_ButtonShiftVertical, opt, w));
3602                     p->drawPixmap(iconRect, pixmap);
3603                 }
3604 
3605                 if (button->state & (State_On | State_Sunken))
3606                     textRect.translate(pixelMetric(PM_ButtonShiftHorizontal, opt, w),
3607                                  pixelMetric(PM_ButtonShiftVertical, opt, w));
3608 
3609                 if (button->features & QStyleOptionButton::HasMenu) {
3610                     int indicatorSize = pixelMetric(PM_MenuButtonIndicator, button, w);
3611                     if (button->direction == Qt::LeftToRight)
3612                         textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
3613                     else
3614                         textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
3615                 }
3616                 drawItemText(p, textRect, tf, butOpt.palette, (button->state & State_Enabled),
3617                              button->text, QPalette::ButtonText);
3618             } else {
3619                 ParentStyle::drawControl(ce, &butOpt, p, w);
3620             }
3621 
3622             if (rule.hasFont)
3623                 p->setFont(oldFont);
3624         }
3625         return;
3626 
3627     case CE_RadioButton:
3628     case CE_CheckBox:
3629         if (rule.hasBox() || !rule.hasNativeBorder() || rule.hasDrawable() || hasStyleRule(w, PseudoElement_Indicator)) {
3630             rule.drawRule(p, opt->rect);
3631             ParentStyle::drawControl(ce, opt, p, w);
3632             return;
3633         } else if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3634             QStyleOptionButton butOpt(*btn);
3635             rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3636             baseStyle()->drawControl(ce, &butOpt, p, w);
3637             return;
3638         }
3639         break;
3640     case CE_RadioButtonLabel:
3641     case CE_CheckBoxLabel:
3642         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3643             QStyleOptionButton butOpt(*btn);
3644             rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3645             ParentStyle::drawControl(ce, &butOpt, p, w);
3646         }
3647         return;
3648 
3649     case CE_Splitter:
3650         pe1 = PseudoElement_SplitterHandle;
3651         break;
3652 
3653     case CE_ToolBar:
3654         if (rule.hasBackground()) {
3655             rule.drawBackground(p, opt->rect);
3656         }
3657         if (rule.hasBorder()) {
3658             rule.drawBorder(p, rule.borderRect(opt->rect));
3659         } else {
3660 #if QT_CONFIG(toolbar)
3661             if (const QStyleOptionToolBar *tb = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
3662                 QStyleOptionToolBar newTb(*tb);
3663                 newTb.rect = rule.borderRect(opt->rect);
3664                 baseStyle()->drawControl(ce, &newTb, p, w);
3665             }
3666 #endif // QT_CONFIG(toolbar)
3667         }
3668         return;
3669 
3670     case CE_MenuEmptyArea:
3671     case CE_MenuBarEmptyArea:
3672         if (rule.hasDrawable()) {
3673             // Drawn by PE_Widget
3674             return;
3675         }
3676         break;
3677 
3678     case CE_MenuTearoff:
3679     case CE_MenuScroller:
3680         if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3681             QStyleOptionMenuItem mi(*m);
3682             int pe = ce == CE_MenuTearoff ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
3683             QRenderRule subRule = renderRule(w, opt, pe);
3684             mi.rect = subRule.contentsRect(opt->rect);
3685             rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3686             subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3687 
3688             if (subRule.hasDrawable()) {
3689                 subRule.drawRule(p, opt->rect);
3690             } else {
3691                 baseStyle()->drawControl(ce, &mi, p, w);
3692             }
3693         }
3694         return;
3695 
3696     case CE_MenuItem:
3697         if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3698             QStyleOptionMenuItem mi(*m);
3699 
3700             int pseudo = (mi.menuItemType == QStyleOptionMenuItem::Separator) ? PseudoElement_MenuSeparator : PseudoElement_Item;
3701             QRenderRule subRule = renderRule(w, opt, pseudo);
3702             mi.rect = subRule.contentsRect(opt->rect);
3703             rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3704             rule.configurePalette(&mi.palette, QPalette::HighlightedText, QPalette::Highlight);
3705             subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3706             subRule.configurePalette(&mi.palette, QPalette::HighlightedText, QPalette::Highlight);
3707             QFont oldFont = p->font();
3708             if (subRule.hasFont)
3709                 p->setFont(subRule.font.resolve(mi.font));
3710             else
3711                 p->setFont(mi.font);
3712 
3713             // We fall back to drawing with the style sheet code whenever at least one of the
3714             // items are styled in an incompatible way, such as having a background image.
3715             QRenderRule allRules = renderRule(w, PseudoElement_Item, PseudoClass_Any);
3716 
3717             if ((pseudo == PseudoElement_MenuSeparator) && subRule.hasDrawable()) {
3718                 subRule.drawRule(p, opt->rect);
3719             } else if ((pseudo == PseudoElement_Item)
3720                         && (allRules.hasBox() || allRules.hasBorder() || subRule.hasFont
3721                             || (allRules.background() && !allRules.background()->pixmap.isNull()))) {
3722                 subRule.drawRule(p, opt->rect);
3723                 if (subRule.hasBackground()) {
3724                     mi.palette.setBrush(QPalette::Highlight, Qt::NoBrush);
3725                     mi.palette.setBrush(QPalette::Button, Qt::NoBrush);
3726                 } else {
3727                     mi.palette.setBrush(QPalette::Highlight, mi.palette.brush(QPalette::Button));
3728                 }
3729                 mi.palette.setBrush(QPalette::HighlightedText, mi.palette.brush(QPalette::ButtonText));
3730 
3731                 bool checkable = mi.checkType != QStyleOptionMenuItem::NotCheckable;
3732                 bool checked = checkable ? mi.checked : false;
3733 
3734                 bool dis = !(opt->state & QStyle::State_Enabled),
3735                      act = opt->state & QStyle::State_Selected;
3736 
3737                 int textRectOffset = m->maxIconWidth;
3738                 if (!mi.icon.isNull()) {
3739                     QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
3740                     if (act && !dis)
3741                         mode = QIcon::Active;
3742                     const QPixmap pixmap(mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode, checked ? QIcon::On : QIcon::Off));
3743                     const int pixw = pixmap.width() / pixmap.devicePixelRatio();
3744                     const int pixh = pixmap.height() / pixmap.devicePixelRatio();
3745                     QRenderRule iconRule = renderRule(w, opt, PseudoElement_MenuIcon);
3746                     if (!iconRule.hasGeometry()) {
3747                         iconRule.geo = new QStyleSheetGeometryData(pixw, pixh, pixw, pixh, -1, -1);
3748                     } else {
3749                         iconRule.geo->width = pixw;
3750                         iconRule.geo->height = pixh;
3751                     }
3752                     QRect iconRect = positionRect(w, subRule, iconRule, PseudoElement_MenuIcon, opt->rect, opt->direction);
3753                     if (opt->direction == Qt::LeftToRight)
3754                         iconRect.moveLeft(iconRect.left());
3755                     else
3756                         iconRect.moveRight(iconRect.right());
3757                     iconRule.drawRule(p, iconRect);
3758                     QRect pmr(0, 0, pixw, pixh);
3759                     pmr.moveCenter(iconRect.center());
3760                     p->drawPixmap(pmr.topLeft(), pixmap);
3761                 } else if (checkable) {
3762                     QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
3763                     const QRect cmRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction);
3764                     if (subSubRule.hasDrawable() || checked) {
3765                         QStyleOptionMenuItem newMi = mi;
3766                         if (!dis)
3767                             newMi.state |= State_Enabled;
3768                         if (mi.checked)
3769                             newMi.state |= State_On;
3770                         newMi.rect = cmRect;
3771                         drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w);
3772                     }
3773                     textRectOffset = std::max(textRectOffset, cmRect.width());
3774                 }
3775 
3776                 QRect textRect = subRule.contentsRect(opt->rect);
3777                 textRect.setLeft(textRect.left() + textRectOffset);
3778                 textRect.setWidth(textRect.width() - mi.tabWidth);
3779                 const QRect vTextRect = visualRect(opt->direction, m->rect, textRect);
3780 
3781                 QStringRef s(&mi.text);
3782                 p->setPen(mi.palette.buttonText().color());
3783                 if (!s.isEmpty()) {
3784                     int text_flags = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
3785                     if (!styleHint(SH_UnderlineShortcut, &mi, w))
3786                         text_flags |= Qt::TextHideMnemonic;
3787                     int t = s.indexOf(QLatin1Char('\t'));
3788                     if (t >= 0) {
3789                         QRect vShortcutRect = visualRect(opt->direction, mi.rect,
3790                             QRect(textRect.topRight(), QPoint(mi.rect.right(), textRect.bottom())));
3791                         p->drawText(vShortcutRect, text_flags, s.mid(t + 1).toString());
3792                         s = s.left(t);
3793                     }
3794                     p->drawText(vTextRect, text_flags, s.left(t).toString());
3795                 }
3796 
3797                 if (mi.menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
3798                     PrimitiveElement arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
3799                     QRenderRule subRule2 = renderRule(w, opt, PseudoElement_MenuRightArrow);
3800                     mi.rect = positionRect(w, subRule, subRule2, PseudoElement_MenuRightArrow, opt->rect, mi.direction);
3801                     drawPrimitive(arrow, &mi, p, w);
3802                 }
3803             } else if (hasStyleRule(w, PseudoElement_MenuCheckMark) || hasStyleRule(w, PseudoElement_MenuRightArrow)) {
3804                 QWindowsStyle::drawControl(ce, &mi, p, w);
3805                 if (mi.checkType != QStyleOptionMenuItem::NotCheckable && !mi.checked) {
3806                     // We have a style defined, but QWindowsStyle won't draw anything if not checked.
3807                     // So we mimick what QWindowsStyle would do.
3808                     int checkcol = qMax<int>(mi.maxIconWidth, QWindowsStylePrivate::windowsCheckMarkWidth);
3809                     QRect vCheckRect = visualRect(opt->direction, mi.rect, QRect(mi.rect.x(), mi.rect.y(), checkcol, mi.rect.height()));
3810                     if (mi.state.testFlag(State_Enabled) && mi.state.testFlag(State_Selected)) {
3811                         qDrawShadePanel(p, vCheckRect, mi.palette, true, 1, &mi.palette.brush(QPalette::Button));
3812                     } else {
3813                         QBrush fill(mi.palette.light().color(), Qt::Dense4Pattern);
3814                         qDrawShadePanel(p, vCheckRect, mi.palette, true, 1, &fill);
3815                     }
3816                     QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
3817                     if (subSubRule.hasDrawable()) {
3818                         QStyleOptionMenuItem newMi(mi);
3819                         newMi.rect = visualRect(opt->direction, mi.rect, QRect(mi.rect.x() + QWindowsStylePrivate::windowsItemFrame,
3820                                                                                mi.rect.y() + QWindowsStylePrivate::windowsItemFrame,
3821                                                                                checkcol - 2 * QWindowsStylePrivate::windowsItemFrame,
3822                                                                                mi.rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame));
3823                         drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w);
3824                     }
3825                 }
3826             } else {
3827                 if (rule.hasDrawable() && !subRule.hasDrawable() && !(opt->state & QStyle::State_Selected)) {
3828                     mi.palette.setColor(QPalette::Window, Qt::transparent);
3829                     mi.palette.setColor(QPalette::Button, Qt::transparent);
3830                 }
3831                 if (rule.baseStyleCanDraw() && subRule.baseStyleCanDraw()) {
3832                     baseStyle()->drawControl(ce, &mi, p, w);
3833                 } else {
3834                     ParentStyle::drawControl(ce, &mi, p, w);
3835                 }
3836             }
3837 
3838             p->setFont(oldFont);
3839 
3840             return;
3841         }
3842         return;
3843 
3844     case CE_MenuBarItem:
3845         if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3846             QStyleOptionMenuItem mi(*m);
3847             QRenderRule subRule = renderRule(w, opt, PseudoElement_Item);
3848             mi.rect = subRule.contentsRect(opt->rect);
3849             rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3850             subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3851 
3852             if (subRule.hasDrawable()) {
3853                 subRule.drawRule(p, opt->rect);
3854                 QCommonStyle::drawControl(ce, &mi, p, w); // deliberate bypass of the base
3855             } else {
3856                 if (rule.hasDrawable() && !(opt->state & QStyle::State_Selected)) {
3857                     // So that the menu bar background is not hidden by the items
3858                     mi.palette.setColor(QPalette::Window, Qt::transparent);
3859                     mi.palette.setColor(QPalette::Button, Qt::transparent);
3860                 }
3861                 baseStyle()->drawControl(ce, &mi, p, w);
3862             }
3863         }
3864         return;
3865 
3866 #if QT_CONFIG(combobox)
3867     case CE_ComboBoxLabel:
3868         if (!rule.hasBox())
3869             break;
3870         if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3871             QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, w);
3872             p->save();
3873             p->setClipRect(editRect);
3874             if (!cb->currentIcon.isNull()) {
3875                 int spacing = rule.hasBox() ? rule.box()->spacing : -1;
3876                 if (spacing == -1)
3877                     spacing = 6;
3878                 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3879                 QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode);
3880                 QRect iconRect(editRect);
3881                 iconRect.setWidth(cb->iconSize.width());
3882                 iconRect = alignedRect(cb->direction,
3883                                        Qt::AlignLeft | Qt::AlignVCenter,
3884                                        iconRect.size(), editRect);
3885                 drawItemPixmap(p, iconRect, Qt::AlignCenter, pixmap);
3886 
3887                 if (cb->direction == Qt::RightToLeft)
3888                         editRect.translate(-spacing - cb->iconSize.width(), 0);
3889                 else
3890                         editRect.translate(cb->iconSize.width() + spacing, 0);
3891             }
3892             if (!cb->currentText.isEmpty() && !cb->editable) {
3893                 QPalette styledPalette(cb->palette);
3894                 rule.configurePalette(&styledPalette, QPalette::Text, QPalette::Base);
3895                 drawItemText(p, editRect.adjusted(0, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, styledPalette,
3896                              cb->state & State_Enabled, cb->currentText, QPalette::Text);
3897             }
3898             p->restore();
3899             return;
3900         }
3901         break;
3902 #endif // QT_CONFIG(combobox)
3903 
3904     case CE_Header:
3905         if (hasStyleRule(w, PseudoElement_HeaderViewUpArrow)
3906             || hasStyleRule(w, PseudoElement_HeaderViewDownArrow)) {
3907             ParentStyle::drawControl(ce, opt, p, w);
3908             return;
3909         }
3910         if(hasStyleRule(w, PseudoElement_HeaderViewSection)) {
3911             QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
3912             if (!subRule.hasNativeBorder() || !subRule.baseStyleCanDraw()
3913                 || subRule.hasBackground() || subRule.hasPalette() || subRule.hasFont || subRule.hasBorder()) {
3914                 ParentStyle::drawControl(ce, opt, p, w);
3915                 return;
3916             }
3917         }
3918         break;
3919     case CE_HeaderSection:
3920         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3921             QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
3922             if (subRule.hasNativeBorder()) {
3923                 QStyleOptionHeader hdr(*header);
3924                 subRule.configurePalette(&hdr.palette, QPalette::ButtonText, QPalette::Button);
3925 
3926                 if (subRule.baseStyleCanDraw()) {
3927                     baseStyle()->drawControl(CE_HeaderSection, &hdr, p, w);
3928                 } else {
3929                     QWindowsStyle::drawControl(CE_HeaderSection, &hdr, p, w);
3930                 }
3931             } else {
3932                 subRule.drawRule(p, opt->rect);
3933             }
3934             return;
3935         }
3936         break;
3937 
3938     case CE_HeaderLabel:
3939         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3940             QStyleOptionHeader hdr(*header);
3941             QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
3942             subRule.configurePalette(&hdr.palette, QPalette::ButtonText, QPalette::Button);
3943             if (subRule.hasFont) {
3944                 QFont oldFont = p->font();
3945                 p->setFont(subRule.font.resolve(p->font()));
3946                 ParentStyle::drawControl(ce, &hdr, p, w);
3947                 p->setFont(oldFont);
3948             } else {
3949                 baseStyle()->drawControl(ce, &hdr, p, w);
3950             }
3951             return;
3952         }
3953         break;
3954 
3955     case CE_HeaderEmptyArea:
3956         if (rule.hasDrawable()) {
3957             return;
3958         }
3959         break;
3960 
3961     case CE_ProgressBar:
3962         QWindowsStyle::drawControl(ce, opt, p, w);
3963         return;
3964 
3965     case CE_ProgressBarGroove:
3966         if (!rule.hasNativeBorder()) {
3967             rule.drawRule(p, rule.boxRect(opt->rect, Margin));
3968             return;
3969         }
3970         break;
3971 
3972     case CE_ProgressBarContents: {
3973         QRenderRule subRule = renderRule(w, opt, PseudoElement_ProgressBarChunk);
3974         if (subRule.hasDrawable()) {
3975             if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
3976                 p->save();
3977                 p->setClipRect(pb->rect);
3978 
3979                 qint64 minimum = qint64(pb->minimum);
3980                 qint64 maximum = qint64(pb->maximum);
3981                 qint64 progress = qint64(pb->progress);
3982                 bool vertical = (pb->orientation == Qt::Vertical);
3983                 bool inverted = pb->invertedAppearance;
3984 
3985                 QTransform m;
3986                 QRect rect = pb->rect;
3987                 if (vertical) {
3988                     rect = QRect(rect.y(), rect.x(), rect.height(), rect.width());
3989                     m.rotate(90);
3990                     m.translate(0, -(rect.height() + rect.y()*2));
3991                 }
3992 
3993                 bool reverse = ((!vertical && (pb->direction == Qt::RightToLeft)) || vertical);
3994                 if (inverted)
3995                     reverse = !reverse;
3996                 const bool indeterminate = pb->minimum == pb->maximum;
3997                 const auto fillRatio = indeterminate ? 0.50 : double(progress - minimum) / (maximum - minimum);
3998                 const auto fillWidth = static_cast<int>(rect.width() * fillRatio);
3999                 int chunkWidth = fillWidth;
4000                 if (subRule.hasContentsSize()) {
4001                     QSize sz = subRule.size();
4002                     chunkWidth = (opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
4003                 }
4004 
4005                 QRect r = rect;
4006 #if QT_CONFIG(animation)
4007                 Q_D(const QWindowsStyle);
4008 #endif
4009                 if (pb->minimum == 0 && pb->maximum == 0) {
4010                     int chunkCount = fillWidth/chunkWidth;
4011                     int offset = 0;
4012 #if QT_CONFIG(animation)
4013                     if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject)))
4014                         offset = animation->animationStep() * 8 % rect.width();
4015                     else
4016                         d->startAnimation(new QProgressStyleAnimation(d->animationFps, opt->styleObject));
4017 #endif
4018                     int x = reverse ? r.left() + r.width() - offset - chunkWidth : r.x() + offset;
4019                     while (chunkCount > 0) {
4020                         r.setRect(x, rect.y(), chunkWidth, rect.height());
4021                         r = m.mapRect(QRectF(r)).toRect();
4022                         subRule.drawRule(p, r);
4023                         x += reverse ? -chunkWidth : chunkWidth;
4024                         if (reverse ? x < rect.left() : x > rect.right())
4025                             break;
4026                         --chunkCount;
4027                     }
4028 
4029                     r = rect;
4030                     x = reverse ? r.right() - (r.left() - x - chunkWidth)
4031                                 : r.left() + (x - r.right() - chunkWidth);
4032                     while (chunkCount > 0) {
4033                         r.setRect(x, rect.y(), chunkWidth, rect.height());
4034                         r = m.mapRect(QRectF(r)).toRect();
4035                         subRule.drawRule(p, r);
4036                         x += reverse ? -chunkWidth : chunkWidth;
4037                         --chunkCount;
4038                     };
4039                 } else if (chunkWidth > 0) {
4040                     const int chunkCount = ceil(qreal(fillWidth)/chunkWidth);
4041                     int x = reverse ? r.left() + r.width() - chunkWidth : r.x();
4042 
4043                     for (int i = 0; i < chunkCount; ++i) {
4044                         r.setRect(x, rect.y(), chunkWidth, rect.height());
4045                         r = m.mapRect(QRectF(r)).toRect();
4046                         subRule.drawRule(p, r);
4047                         x += reverse ? -chunkWidth : chunkWidth;
4048                     }
4049 #if QT_CONFIG(animation)
4050                     d->stopAnimation(opt->styleObject);
4051 #endif
4052                 }
4053 
4054                 p->restore();
4055                 return;
4056             }
4057         }
4058                                }
4059         break;
4060 
4061     case CE_ProgressBarLabel:
4062         if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4063             if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_ProgressBarChunk)) {
4064                 drawItemText(p, pb->rect, pb->textAlignment | Qt::TextSingleLine, pb->palette,
4065                              pb->state & State_Enabled, pb->text, QPalette::Text);
4066             } else {
4067                 QStyleOptionProgressBar pbCopy(*pb);
4068                 rule.configurePalette(&pbCopy.palette, QPalette::HighlightedText, QPalette::Highlight);
4069                 baseStyle()->drawControl(ce, &pbCopy, p, w);
4070             }
4071             return;
4072         }
4073         break;
4074 
4075     case CE_SizeGrip:
4076         if (const QStyleOptionSizeGrip *sgOpt = qstyleoption_cast<const QStyleOptionSizeGrip *>(opt)) {
4077             if (rule.hasDrawable()) {
4078                 rule.drawFrame(p, opt->rect);
4079                 p->save();
4080                 switch (sgOpt->corner) {
4081                 case Qt::BottomRightCorner: break;
4082                 case Qt::BottomLeftCorner: p->rotate(90); break;
4083                 case Qt::TopLeftCorner: p->rotate(180); break;
4084                 case Qt::TopRightCorner: p->rotate(270); break;
4085                 default: break;
4086                 }
4087                 rule.drawImage(p, opt->rect);
4088                 p->restore();
4089             } else {
4090                 QStyleOptionSizeGrip sg(*sgOpt);
4091                 sg.rect = rule.contentsRect(opt->rect);
4092                 baseStyle()->drawControl(CE_SizeGrip, &sg, p, w);
4093             }
4094             return;
4095         }
4096         break;
4097 
4098     case CE_ToolBoxTab:
4099         QWindowsStyle::drawControl(ce, opt, p, w);
4100         return;
4101 
4102     case CE_ToolBoxTabShape: {
4103             QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolBoxTab);
4104             if (subRule.hasDrawable()) {
4105                 subRule.drawRule(p, opt->rect);
4106                 return;
4107             }
4108                             }
4109         break;
4110 
4111     case CE_ToolBoxTabLabel:
4112         if (const QStyleOptionToolBox *box = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
4113             QStyleOptionToolBox boxCopy(*box);
4114             QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolBoxTab);
4115             subRule.configurePalette(&boxCopy.palette, QPalette::ButtonText, QPalette::Button);
4116             QFont oldFont = p->font();
4117             if (subRule.hasFont)
4118                 p->setFont(subRule.font.resolve(p->font()));
4119             boxCopy.rect = subRule.contentsRect(opt->rect);
4120             if (subRule.hasImage()) {
4121                 // the image is already drawn with CE_ToolBoxTabShape, adjust rect here
4122                 const int iconExtent = proxy()->pixelMetric(QStyle::PM_SmallIconSize, box, w);
4123                 boxCopy.rect.setLeft(boxCopy.rect.left() + iconExtent);
4124             }
4125             QWindowsStyle::drawControl(ce, &boxCopy, p , w);
4126             if (subRule.hasFont)
4127                 p->setFont(oldFont);
4128             return;
4129         }
4130         break;
4131 
4132     case CE_ScrollBarAddPage:
4133         pe1 = PseudoElement_ScrollBarAddPage;
4134         break;
4135 
4136     case CE_ScrollBarSubPage:
4137         pe1 = PseudoElement_ScrollBarSubPage;
4138         break;
4139 
4140     case CE_ScrollBarAddLine:
4141         pe1 = PseudoElement_ScrollBarAddLine;
4142         pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarRightArrow : PseudoElement_ScrollBarDownArrow;
4143         fallback = true;
4144         break;
4145 
4146     case CE_ScrollBarSubLine:
4147         pe1 = PseudoElement_ScrollBarSubLine;
4148         pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarLeftArrow : PseudoElement_ScrollBarUpArrow;
4149         fallback = true;
4150         break;
4151 
4152     case CE_ScrollBarFirst:
4153         pe1 = PseudoElement_ScrollBarFirst;
4154         break;
4155 
4156     case CE_ScrollBarLast:
4157         pe1 = PseudoElement_ScrollBarLast;
4158         break;
4159 
4160     case CE_ScrollBarSlider:
4161         pe1 = PseudoElement_ScrollBarSlider;
4162         fallback = true;
4163         break;
4164 
4165 #if QT_CONFIG(itemviews)
4166     case CE_ItemViewItem:
4167         if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4168             QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
4169             if (subRule.hasDrawable() || hasStyleRule(w, PseudoElement_Indicator)) {
4170                 QStyleOptionViewItem optCopy(*vopt);
4171                 subRule.configurePalette(&optCopy.palette, vopt->state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text,
4172                                                            vopt->state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base);
4173                 QWindowsStyle::drawControl(ce, &optCopy, p, w);
4174             } else {
4175                 QStyleOptionViewItem voptCopy(*vopt);
4176                 subRule.configurePalette(&voptCopy.palette, QPalette::Text, QPalette::NoRole);
4177                 baseStyle()->drawControl(ce, &voptCopy, p, w);
4178             }
4179             return;
4180         }
4181         break;
4182 #endif // QT_CONFIG(itemviews)
4183 
4184 #if QT_CONFIG(tabbar)
4185     case CE_TabBarTab:
4186         if (hasStyleRule(w, PseudoElement_TabBarTab)) {
4187             QWindowsStyle::drawControl(ce, opt, p, w);
4188             return;
4189         }
4190         break;
4191 
4192     case CE_TabBarTabLabel:
4193     case CE_TabBarTabShape:
4194         if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4195             QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
4196             QRect r = positionRect(w, subRule, PseudoElement_TabBarTab, opt->rect, opt->direction);
4197             if (ce == CE_TabBarTabShape && subRule.hasDrawable() && tab->shape < QTabBar::TriangularNorth) {
4198                 subRule.drawRule(p, r);
4199                 return;
4200             }
4201             QStyleOptionTab tabCopy(*tab);
4202             subRule.configurePalette(&tabCopy.palette, QPalette::WindowText, QPalette::Base);
4203             QFont oldFont = p->font();
4204             if (subRule.hasFont)
4205                 p->setFont(subRule.font.resolve(p->font()));
4206             if (subRule.hasBox() || !subRule.hasNativeBorder()) {
4207                 tabCopy.rect = ce == CE_TabBarTabShape ? subRule.borderRect(r)
4208                                                        : subRule.contentsRect(r);
4209                 QWindowsStyle::drawControl(ce, &tabCopy, p, w);
4210             } else {
4211                 baseStyle()->drawControl(ce, &tabCopy, p, w);
4212             }
4213             if (subRule.hasFont)
4214                 p->setFont(oldFont);
4215 
4216             return;
4217         }
4218        break;
4219 #endif // QT_CONFIG(tabbar)
4220 
4221     case CE_ColumnViewGrip:
4222        if (rule.hasDrawable()) {
4223            rule.drawRule(p, opt->rect);
4224            return;
4225        }
4226        break;
4227 
4228     case CE_DockWidgetTitle:
4229        if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
4230            QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
4231            if (!subRule.hasDrawable() && !subRule.hasPosition())
4232                break;
4233            if (subRule.hasDrawable()) {
4234                subRule.drawRule(p, opt->rect);
4235            } else {
4236                QStyleOptionDockWidget dwCopy(*dwOpt);
4237                dwCopy.title = QString();
4238                baseStyle()->drawControl(ce, &dwCopy, p, w);
4239            }
4240 
4241            if (!dwOpt->title.isEmpty()) {
4242                QRect r = subElementRect(SE_DockWidgetTitleBarText, opt, w);
4243                if (dwOpt->verticalTitleBar) {
4244                    r = r.transposed();
4245                    p->save();
4246                    p->translate(r.left(), r.top() + r.width());
4247                    p->rotate(-90);
4248                    p->translate(-r.left(), -r.top());
4249                 }
4250                 r = subRule.contentsRect(r);
4251 
4252                 Qt::Alignment alignment;
4253                 if (subRule.hasPosition())
4254                     alignment = subRule.position()->textAlignment;
4255                 if (alignment == 0)
4256                     alignment = Qt::AlignLeft;
4257 
4258                 QString titleText = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, r.width());
4259                 drawItemText(p, r,
4260                              alignment, dwOpt->palette,
4261                              dwOpt->state & State_Enabled, titleText,
4262                              QPalette::WindowText);
4263 
4264                 if (dwOpt->verticalTitleBar)
4265                     p->restore();
4266             }
4267 
4268            return;
4269         }
4270         break;
4271     case CE_ShapedFrame:
4272         if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4273             if (rule.hasNativeBorder()) {
4274                 QStyleOptionFrame frmOpt(*frm);
4275                 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4276                 frmOpt.rect = rule.borderRect(frmOpt.rect);
4277                 baseStyle()->drawControl(ce, &frmOpt, p, w);
4278             }
4279             // else, borders are already drawn in PE_Widget
4280         }
4281         return;
4282 
4283 
4284     default:
4285         break;
4286     }
4287 
4288     if (pe1 != PseudoElement_None) {
4289         QRenderRule subRule = renderRule(w, opt, pe1);
4290         if (subRule.bg != nullptr || subRule.hasDrawable()) {
4291             //We test subRule.bg directly because hasBackground() would return false for background:none.
4292             //But we still don't want the default drawning in that case (example for QScrollBar::add-page) (task 198926)
4293             subRule.drawRule(p, opt->rect);
4294         } else if (fallback) {
4295             QWindowsStyle::drawControl(ce, opt, p, w);
4296             pe2 = PseudoElement_None;
4297         } else {
4298             baseStyle()->drawControl(ce, opt, p, w);
4299         }
4300         if (pe2 != PseudoElement_None) {
4301             QRenderRule subSubRule = renderRule(w, opt, pe2);
4302             QRect r = positionRect(w, subRule, subSubRule, pe2, opt->rect, opt->direction);
4303             subSubRule.drawRule(p, r);
4304         }
4305         return;
4306     }
4307 
4308     baseStyle()->drawControl(ce, opt, p, w);
4309 }
4310 
drawItemPixmap(QPainter * p,const QRect & rect,int alignment,const QPixmap & pixmap) const4311 void QStyleSheetStyle::drawItemPixmap(QPainter *p, const QRect &rect, int alignment, const
4312                                   QPixmap &pixmap) const
4313 {
4314     baseStyle()->drawItemPixmap(p, rect, alignment, pixmap);
4315 }
4316 
drawItemText(QPainter * painter,const QRect & rect,int alignment,const QPalette & pal,bool enabled,const QString & text,QPalette::ColorRole textRole) const4317 void QStyleSheetStyle::drawItemText(QPainter *painter, const QRect& rect, int alignment, const QPalette &pal,
4318                                 bool enabled, const QString& text, QPalette::ColorRole textRole) const
4319 {
4320     baseStyle()->drawItemText(painter, rect, alignment, pal, enabled, text, textRole);
4321 }
4322 
drawPrimitive(PrimitiveElement pe,const QStyleOption * opt,QPainter * p,const QWidget * w) const4323 void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
4324                                      const QWidget *w) const
4325 {
4326     RECURSION_GUARD(baseStyle()->drawPrimitive(pe, opt, p, w); return)
4327 
4328     int pseudoElement = PseudoElement_None;
4329     QRenderRule rule = renderRule(w, opt);
4330     QRect rect = opt->rect;
4331 
4332     switch (pe) {
4333 
4334     case PE_FrameStatusBarItem: {
4335         QRenderRule subRule = renderRule(w ? w->parentWidget() : nullptr, opt, PseudoElement_Item);
4336         if (subRule.hasDrawable()) {
4337             subRule.drawRule(p, opt->rect);
4338             return;
4339         }
4340         break;
4341                             }
4342 
4343     case PE_IndicatorArrowDown:
4344         pseudoElement = PseudoElement_DownArrow;
4345         break;
4346 
4347     case PE_IndicatorArrowUp:
4348         pseudoElement = PseudoElement_UpArrow;
4349         break;
4350 
4351     case PE_IndicatorRadioButton:
4352         pseudoElement = PseudoElement_ExclusiveIndicator;
4353         break;
4354 
4355     case PE_IndicatorItemViewItemCheck:
4356         pseudoElement = PseudoElement_ViewItemIndicator;
4357         break;
4358 
4359     case PE_IndicatorCheckBox:
4360         pseudoElement = PseudoElement_Indicator;
4361         break;
4362 
4363     case PE_IndicatorHeaderArrow:
4364         if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4365             pseudoElement = hdr->sortIndicator == QStyleOptionHeader::SortUp
4366                 ? PseudoElement_HeaderViewUpArrow
4367                 : PseudoElement_HeaderViewDownArrow;
4368         }
4369         break;
4370 
4371     case PE_PanelButtonTool:
4372     case PE_PanelButtonCommand:
4373 #if QT_CONFIG(abstractbutton)
4374         if (qobject_cast<const QAbstractButton *>(w) && rule.hasBackground() && rule.hasNativeBorder()) {
4375             //the window style will draw the borders
4376             ParentStyle::drawPrimitive(pe, opt, p, w);
4377             if (!rule.background()->pixmap.isNull() || rule.hasImage()) {
4378                 rule.drawRule(p, rule.boxRect(opt->rect, QRenderRule::Margin).adjusted(1,1,-1,-1));
4379             }
4380             return;
4381         }
4382 #endif
4383         if (!rule.hasNativeBorder()) {
4384             rule.drawRule(p, rule.boxRect(opt->rect, QRenderRule::Margin));
4385             return;
4386         }
4387         break;
4388 
4389     case PE_IndicatorButtonDropDown: {
4390         QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
4391         if (!subRule.hasNativeBorder()) {
4392             rule.drawBorder(p, opt->rect);
4393             return;
4394         }
4395         break;
4396                                      }
4397 
4398     case PE_FrameDefaultButton:
4399         if (rule.hasNativeBorder()) {
4400             if (rule.baseStyleCanDraw())
4401                 break;
4402             QWindowsStyle::drawPrimitive(pe, opt, p, w);
4403         }
4404         return;
4405 
4406     case PE_FrameWindow:
4407     case PE_FrameDockWidget:
4408     case PE_Frame:
4409         if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4410             if (rule.hasNativeBorder()) {
4411                 QStyleOptionFrame frmOpt(*frm);
4412                 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4413                 baseStyle()->drawPrimitive(pe, &frmOpt, p, w);
4414             } else {
4415                 rule.drawBorder(p, rule.borderRect(opt->rect));
4416             }
4417         }
4418         return;
4419 
4420     case PE_PanelLineEdit:
4421         if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4422 #if QT_CONFIG(spinbox)
4423             if (w && qobject_cast<const QAbstractSpinBox *>(w->parentWidget())) {
4424                 QRenderRule spinboxRule = renderRule(w->parentWidget(), opt);
4425                 if (!spinboxRule.hasNativeBorder() || !spinboxRule.baseStyleCanDraw())
4426                     return;
4427                 rule = spinboxRule;
4428             }
4429 #endif
4430             if (rule.hasNativeBorder()) {
4431                 QStyleOptionFrame frmOpt(*frm);
4432                 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4433                 frmOpt.rect = rule.borderRect(frmOpt.rect);
4434                 if (rule.baseStyleCanDraw()) {
4435                     rule.drawBackgroundImage(p, opt->rect);
4436                     baseStyle()->drawPrimitive(pe, &frmOpt, p, w);
4437                 } else {
4438                     rule.drawBackground(p, opt->rect);
4439                     if (frmOpt.lineWidth > 0)
4440                         baseStyle()->drawPrimitive(PE_FrameLineEdit, &frmOpt, p, w);
4441                 }
4442             } else {
4443                 rule.drawRule(p, opt->rect);
4444             }
4445         }
4446         return;
4447 
4448     case PE_Widget:
4449         if (w && !rule.hasDrawable()) {
4450             QWidget *container = containerWidget(w);
4451             if (styleSheetCaches->autoFillDisabledWidgets.contains(container)
4452                 && (container == w || !renderRule(container, opt).hasBackground())) {
4453                 //we do not have a background, but we disabled the autofillbackground anyway. so fill the background now.
4454                 // (this may happen if we have rules like :focus)
4455                 p->fillRect(opt->rect, opt->palette.brush(w->backgroundRole()));
4456             }
4457             break;
4458         }
4459 #if QT_CONFIG(scrollarea)
4460         if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(w)) {
4461             const QAbstractScrollAreaPrivate *sap = sa->d_func();
4462             rule.drawBackground(p, opt->rect, sap->contentsOffset());
4463             if (rule.hasBorder()) {
4464                 QRect brect = rule.borderRect(opt->rect);
4465                 if (styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, opt, w)) {
4466                     QRect r = brect.adjusted(0, 0, sa->verticalScrollBar()->isVisible() ? -sa->verticalScrollBar()->width() : 0,
4467                                              sa->horizontalScrollBar()->isVisible() ? -sa->horizontalScrollBar()->height() : 0);
4468                     brect = QStyle::visualRect(opt->direction, brect, r);
4469                 }
4470                 rule.drawBorder(p, brect);
4471             }
4472             break;
4473         }
4474 #endif
4475         Q_FALLTHROUGH();
4476     case PE_PanelMenu:
4477     case PE_PanelStatusBar:
4478         if(rule.hasDrawable()) {
4479             rule.drawRule(p, opt->rect);
4480             return;
4481         }
4482     break;
4483 
4484     case PE_FrameMenu:
4485         if (rule.hasDrawable()) {
4486             // Drawn by PE_PanelMenu
4487             return;
4488         }
4489         break;
4490 
4491     case PE_PanelMenuBar:
4492     if (rule.hasDrawable()) {
4493         // Drawn by PE_Widget
4494         return;
4495     }
4496     break;
4497 
4498     case PE_IndicatorToolBarSeparator:
4499     case PE_IndicatorToolBarHandle: {
4500         PseudoElement ps = pe == PE_IndicatorToolBarHandle ? PseudoElement_ToolBarHandle : PseudoElement_ToolBarSeparator;
4501         QRenderRule subRule = renderRule(w, opt, ps);
4502         if (subRule.hasDrawable()) {
4503             subRule.drawRule(p, opt->rect);
4504             return;
4505         }
4506                                     }
4507         break;
4508 
4509     case PE_IndicatorMenuCheckMark:
4510         pseudoElement = PseudoElement_MenuCheckMark;
4511         break;
4512 
4513     case PE_IndicatorArrowLeft:
4514         pseudoElement = PseudoElement_LeftArrow;
4515         break;
4516 
4517     case PE_IndicatorArrowRight:
4518         pseudoElement = PseudoElement_RightArrow;
4519         break;
4520 
4521     case PE_IndicatorColumnViewArrow:
4522 #if QT_CONFIG(itemviews)
4523         if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4524             bool reverse = (viewOpt->direction == Qt::RightToLeft);
4525             pseudoElement = reverse ? PseudoElement_LeftArrow : PseudoElement_RightArrow;
4526         } else
4527 #endif
4528         {
4529             pseudoElement = PseudoElement_RightArrow;
4530         }
4531         break;
4532 
4533 #if QT_CONFIG(itemviews)
4534     case PE_IndicatorBranch:
4535         if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4536             QRenderRule subRule = renderRule(w, opt, PseudoElement_TreeViewBranch);
4537             if (subRule.hasDrawable()) {
4538                 if ((vopt->state & QStyle::State_Selected) && vopt->showDecorationSelected)
4539                     p->fillRect(vopt->rect, vopt->palette.highlight());
4540                 else if (vopt->features & QStyleOptionViewItem::Alternate)
4541                     p->fillRect(vopt->rect, vopt->palette.alternateBase());
4542                 subRule.drawRule(p, opt->rect);
4543             } else {
4544                 baseStyle()->drawPrimitive(pe, vopt, p, w);
4545             }
4546         }
4547         return;
4548 #endif // QT_CONFIG(itemviews)
4549 
4550     case PE_PanelTipLabel:
4551         if (!rule.hasDrawable())
4552             break;
4553 
4554         if (const QStyleOptionFrame *frmOpt = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4555             if (rule.hasNativeBorder()) {
4556                 rule.drawBackground(p, opt->rect);
4557                 QStyleOptionFrame optCopy(*frmOpt);
4558                 optCopy.rect = rule.borderRect(opt->rect);
4559                 optCopy.palette.setBrush(QPalette::Window, Qt::NoBrush); // oh dear
4560                 baseStyle()->drawPrimitive(pe, &optCopy, p, w);
4561             } else {
4562                 rule.drawRule(p, opt->rect);
4563             }
4564         }
4565         return;
4566 
4567     case PE_FrameGroupBox:
4568         if (rule.hasNativeBorder())
4569             break;
4570         rule.drawBorder(p, opt->rect);
4571         return;
4572 
4573 #if QT_CONFIG(tabwidget)
4574     case PE_FrameTabWidget:
4575         if (const QStyleOptionTabWidgetFrame *frm = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4576             QRenderRule subRule = renderRule(w, opt, PseudoElement_TabWidgetPane);
4577             if (subRule.hasNativeBorder()) {
4578                 subRule.drawBackground(p, opt->rect);
4579                 QStyleOptionTabWidgetFrame frmCopy(*frm);
4580                 subRule.configurePalette(&frmCopy.palette, QPalette::WindowText, QPalette::Window);
4581                 baseStyle()->drawPrimitive(pe, &frmCopy, p, w);
4582             } else {
4583                 subRule.drawRule(p, opt->rect);
4584             }
4585             return;
4586         }
4587         break;
4588 #endif // QT_CONFIG(tabwidget)
4589 
4590     case PE_IndicatorProgressChunk:
4591         pseudoElement = PseudoElement_ProgressBarChunk;
4592         break;
4593 
4594     case PE_IndicatorTabTear:
4595         pseudoElement = PseudoElement_TabBarTear;
4596         break;
4597 
4598     case PE_FrameFocusRect:
4599         if (!rule.hasNativeOutline()) {
4600             rule.drawOutline(p, opt->rect);
4601             return;
4602         }
4603         break;
4604 
4605     case PE_IndicatorDockWidgetResizeHandle:
4606         pseudoElement = PseudoElement_DockWidgetSeparator;
4607         break;
4608 
4609     case PE_PanelItemViewItem:
4610         pseudoElement = PseudoElement_ViewItem;
4611         break;
4612 
4613     case PE_PanelScrollAreaCorner:
4614         pseudoElement = PseudoElement_ScrollAreaCorner;
4615         break;
4616 
4617     case PE_IndicatorSpinDown:
4618     case PE_IndicatorSpinMinus:
4619         pseudoElement = PseudoElement_SpinBoxDownArrow;
4620         break;
4621 
4622     case PE_IndicatorSpinUp:
4623     case PE_IndicatorSpinPlus:
4624         pseudoElement = PseudoElement_SpinBoxUpArrow;
4625         break;
4626 #if QT_CONFIG(tabbar)
4627     case PE_IndicatorTabClose:
4628         if (w) {
4629             // QMacStyle needs a real widget, not its parent - to implement
4630             // 'document mode' properly, drawing nothing if a tab is not hovered.
4631             baseStyle()->setProperty("_q_styleSheetRealCloseButton", QVariant::fromValue((void *)w));
4632             w = w->parentWidget(); //match on the QTabBar instead of the CloseButton
4633         }
4634         pseudoElement = PseudoElement_TabBarTabCloseButton;
4635 #endif
4636 
4637     default:
4638         break;
4639     }
4640 
4641     if (pseudoElement != PseudoElement_None) {
4642         QRenderRule subRule = renderRule(w, opt, pseudoElement);
4643         if (subRule.hasDrawable()) {
4644             subRule.drawRule(p, rect);
4645         } else {
4646             baseStyle()->drawPrimitive(pe, opt, p, w);
4647         }
4648     } else {
4649         baseStyle()->drawPrimitive(pe, opt, p, w);
4650     }
4651 
4652     if (baseStyle()->property("_q_styleSheetRealCloseButton").toBool())
4653         baseStyle()->setProperty("_q_styleSheetRealCloseButton", QVariant());
4654 }
4655 
generatedIconPixmap(QIcon::Mode iconMode,const QPixmap & pixmap,const QStyleOption * option) const4656 QPixmap QStyleSheetStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap,
4657                                           const QStyleOption *option) const
4658 {
4659     return baseStyle()->generatedIconPixmap(iconMode, pixmap, option);
4660 }
4661 
hitTestComplexControl(ComplexControl cc,const QStyleOptionComplex * opt,const QPoint & pt,const QWidget * w) const4662 QStyle::SubControl QStyleSheetStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
4663                                  const QPoint &pt, const QWidget *w) const
4664 {
4665     RECURSION_GUARD(return baseStyle()->hitTestComplexControl(cc, opt, pt, w))
4666     switch (cc) {
4667     case CC_TitleBar:
4668         if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4669             QRenderRule rule = renderRule(w, opt, PseudoElement_TitleBar);
4670             if (rule.hasDrawable() || rule.hasBox() || rule.hasBorder()) {
4671                 QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
4672                 QRect r;
4673                 QStyle::SubControl sc = QStyle::SC_None;
4674                 uint ctrl = SC_TitleBarSysMenu;
4675                 while (ctrl <= SC_TitleBarLabel) {
4676                     r = layout[QStyle::SubControl(ctrl)];
4677                     if (r.isValid() && r.contains(pt)) {
4678                         sc = QStyle::SubControl(ctrl);
4679                         break;
4680                     }
4681                     ctrl <<= 1;
4682                 }
4683                 return sc;
4684             }
4685         }
4686         break;
4687 
4688     case CC_MdiControls:
4689         if (hasStyleRule(w, PseudoElement_MdiCloseButton)
4690             || hasStyleRule(w, PseudoElement_MdiNormalButton)
4691             || hasStyleRule(w, PseudoElement_MdiMinButton))
4692             return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4693         break;
4694 
4695     case CC_ScrollBar: {
4696         QRenderRule rule = renderRule(w, opt);
4697         if (!rule.hasDrawable() && !rule.hasBox())
4698             break;
4699                        }
4700         Q_FALLTHROUGH();
4701     case CC_SpinBox:
4702     case CC_GroupBox:
4703     case CC_ComboBox:
4704     case CC_Slider:
4705     case CC_ToolButton:
4706         return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4707     default:
4708         break;
4709     }
4710 
4711     return baseStyle()->hitTestComplexControl(cc, opt, pt, w);
4712 }
4713 
itemPixmapRect(const QRect & rect,int alignment,const QPixmap & pixmap) const4714 QRect QStyleSheetStyle::itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pixmap) const
4715 {
4716     return baseStyle()->itemPixmapRect(rect, alignment, pixmap);
4717 }
4718 
itemTextRect(const QFontMetrics & metrics,const QRect & rect,int alignment,bool enabled,const QString & text) const4719 QRect QStyleSheetStyle::itemTextRect(const QFontMetrics &metrics, const QRect& rect, int alignment,
4720                                  bool enabled, const QString& text) const
4721 {
4722     return baseStyle()->itemTextRect(metrics, rect, alignment, enabled, text);
4723 }
4724 
pixelMetric(PixelMetric m,const QStyleOption * opt,const QWidget * w) const4725 int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *w) const
4726 {
4727     RECURSION_GUARD(return baseStyle()->pixelMetric(m, opt, w))
4728 
4729     QRenderRule rule = renderRule(w, opt);
4730     QRenderRule subRule;
4731 
4732     switch (m) {
4733     case PM_MenuButtonIndicator:
4734 #if QT_CONFIG(toolbutton)
4735         // QToolButton adds this directly to the width
4736         if (qobject_cast<const QToolButton *>(w) && (rule.hasBox() || !rule.hasNativeBorder()))
4737             return 0;
4738 #endif
4739         subRule = renderRule(w, opt, PseudoElement_PushButtonMenuIndicator);
4740         if (subRule.hasContentsSize())
4741             return subRule.size().width();
4742         break;
4743 
4744     case PM_ButtonShiftHorizontal:
4745     case PM_ButtonShiftVertical:
4746     case PM_ButtonMargin:
4747     case PM_ButtonDefaultIndicator:
4748         if (rule.hasBox())
4749             return 0;
4750         break;
4751 
4752     case PM_DefaultFrameWidth:
4753         if (!rule.hasNativeBorder())
4754             return rule.border()->borders[LeftEdge];
4755         break;
4756 
4757     case PM_ExclusiveIndicatorWidth:
4758     case PM_IndicatorWidth:
4759     case PM_ExclusiveIndicatorHeight:
4760     case PM_IndicatorHeight:
4761         subRule = renderRule(w, opt, PseudoElement_Indicator);
4762         if (subRule.hasContentsSize()) {
4763             return (m == PM_ExclusiveIndicatorWidth) || (m == PM_IndicatorWidth)
4764                         ? subRule.size().width() : subRule.size().height();
4765         }
4766         break;
4767 
4768     case PM_DockWidgetFrameWidth:
4769     case PM_ToolTipLabelFrameWidth: // border + margin + padding (support only one width)
4770         if (!rule.hasDrawable())
4771             break;
4772 
4773         return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4774                 + (rule.hasBox() ? rule.box()->margins[LeftEdge] + rule.box()->paddings[LeftEdge]: 0);
4775 
4776     case PM_ToolBarFrameWidth:
4777         if (rule.hasBorder() || rule.hasBox())
4778             return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4779                    + (rule.hasBox() ? rule.box()->paddings[LeftEdge]: 0);
4780         break;
4781 
4782     case PM_MenuPanelWidth:
4783     case PM_MenuBarPanelWidth:
4784         if (rule.hasBorder() || rule.hasBox())
4785             return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4786                    + (rule.hasBox() ? rule.box()->margins[LeftEdge]: 0);
4787         break;
4788 
4789 
4790     case PM_MenuHMargin:
4791     case PM_MenuBarHMargin:
4792         if (rule.hasBox())
4793             return rule.box()->paddings[LeftEdge];
4794         break;
4795 
4796     case PM_MenuVMargin:
4797     case PM_MenuBarVMargin:
4798         if (rule.hasBox())
4799             return rule.box()->paddings[TopEdge];
4800         break;
4801 
4802     case PM_DockWidgetTitleBarButtonMargin:
4803     case PM_ToolBarItemMargin:
4804         if (rule.hasBox())
4805             return rule.box()->margins[TopEdge];
4806         break;
4807 
4808     case PM_ToolBarItemSpacing:
4809     case PM_MenuBarItemSpacing:
4810         if (rule.hasBox() && rule.box()->spacing != -1)
4811             return rule.box()->spacing;
4812         break;
4813 
4814     case PM_MenuTearoffHeight:
4815     case PM_MenuScrollerHeight: {
4816         PseudoElement ps = m == PM_MenuTearoffHeight ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
4817         subRule = renderRule(w, opt, ps);
4818         if (subRule.hasContentsSize())
4819             return subRule.size().height();
4820         break;
4821                                 }
4822 
4823     case PM_ToolBarExtensionExtent:
4824         break;
4825 
4826     case PM_SplitterWidth:
4827     case PM_ToolBarSeparatorExtent:
4828     case PM_ToolBarHandleExtent: {
4829         PseudoElement ps;
4830         if (m == PM_ToolBarHandleExtent) ps = PseudoElement_ToolBarHandle;
4831         else if (m == PM_SplitterWidth) ps = PseudoElement_SplitterHandle;
4832         else ps = PseudoElement_ToolBarSeparator;
4833         subRule = renderRule(w, opt, ps);
4834         if (subRule.hasContentsSize()) {
4835             QSize sz = subRule.size();
4836             return (opt && opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
4837         }
4838         break;
4839                                  }
4840 
4841     case PM_RadioButtonLabelSpacing:
4842         if (rule.hasBox() && rule.box()->spacing != -1)
4843             return rule.box()->spacing;
4844         break;
4845     case PM_CheckBoxLabelSpacing:
4846 #if QT_CONFIG(checkbox)
4847         if (qobject_cast<const QCheckBox *>(w)) {
4848             if (rule.hasBox() && rule.box()->spacing != -1)
4849                 return rule.box()->spacing;
4850         }
4851 #endif
4852         // assume group box
4853         subRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
4854         if (subRule.hasBox() && subRule.box()->spacing != -1)
4855             return subRule.box()->spacing;
4856         break;
4857 
4858 #if QT_CONFIG(scrollbar)
4859     case PM_ScrollBarExtent:
4860         if (rule.hasContentsSize()) {
4861             QSize sz = rule.size();
4862             if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
4863                 return sb->orientation == Qt::Horizontal ? sz.height() : sz.width();
4864             return sz.width() == -1 ? sz.height() : sz.width();
4865         }
4866         break;
4867 
4868     case PM_ScrollBarSliderMin:
4869         if (hasStyleRule(w, PseudoElement_ScrollBarSlider)) {
4870             subRule = renderRule(w, opt, PseudoElement_ScrollBarSlider);
4871             QSize msz = subRule.minimumSize();
4872             if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
4873                 return sb->orientation == Qt::Horizontal ? msz.width() : msz.height();
4874             return msz.width() == -1 ? msz.height() : msz.width();
4875         }
4876         break;
4877 
4878     case PM_ScrollView_ScrollBarSpacing:
4879         if(!rule.hasNativeBorder() || rule.hasBox())
4880             return 0;
4881         break;
4882 #endif // QT_CONFIG(scrollbar)
4883 
4884     case PM_ProgressBarChunkWidth:
4885         subRule = renderRule(w, opt, PseudoElement_ProgressBarChunk);
4886         if (subRule.hasContentsSize()) {
4887             QSize sz = subRule.size();
4888             return (opt->state & QStyle::State_Horizontal)
4889                    ? sz.width() : sz.height();
4890         }
4891         break;
4892 
4893 #if QT_CONFIG(tabwidget)
4894     case PM_TabBarTabHSpace:
4895     case PM_TabBarTabVSpace:
4896         subRule = renderRule(w, opt, PseudoElement_TabBarTab);
4897         if (subRule.hasBox() || subRule.hasBorder())
4898             return 0;
4899         break;
4900 
4901     case PM_TabBarScrollButtonWidth:
4902         subRule = renderRule(w, opt, PseudoElement_TabBarScroller);
4903         if (subRule.hasContentsSize()) {
4904             QSize sz = subRule.size();
4905             return (sz.width() != -1 ? sz.width() : sz.height()) / 2;
4906         }
4907         break;
4908 
4909     case PM_TabBarTabShiftHorizontal:
4910     case PM_TabBarTabShiftVertical:
4911         subRule = renderRule(w, opt, PseudoElement_TabBarTab);
4912         if (subRule.hasBox())
4913             return 0;
4914         break;
4915 
4916     case PM_TabBarBaseOverlap: {
4917         const QWidget *tabWidget = qobject_cast<const QTabWidget *>(w);
4918         if (!tabWidget && w)
4919             tabWidget = w->parentWidget();
4920         if (hasStyleRule(tabWidget, PseudoElement_TabWidgetPane)) {
4921             return 0;
4922         }
4923         break;
4924     }
4925 #endif // QT_CONFIG(tabwidget)
4926 
4927     case PM_SliderThickness: // horizontal slider's height (sizeHint)
4928     case PM_SliderLength: // minimum length of slider
4929         if (rule.hasContentsSize()) {
4930             bool horizontal = opt->state & QStyle::State_Horizontal;
4931             if (m == PM_SliderThickness) {
4932                 QSize sz = rule.size();
4933                 return horizontal ? sz.height() : sz.width();
4934             } else {
4935                 QSize msz = rule.minimumContentsSize();
4936                 return horizontal ? msz.width() : msz.height();
4937             }
4938         }
4939         break;
4940 
4941     case PM_SliderControlThickness: {
4942         QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderHandle);
4943         if (!subRule.hasContentsSize())
4944             break;
4945         QSize size = subRule.size();
4946         return (opt->state & QStyle::State_Horizontal) ? size.height() : size.width();
4947                                     }
4948 
4949     case PM_ToolBarIconSize:
4950     case PM_ListViewIconSize:
4951     case PM_IconViewIconSize:
4952     case PM_TabBarIconSize:
4953     case PM_MessageBoxIconSize:
4954     case PM_ButtonIconSize:
4955     case PM_SmallIconSize:
4956         if (rule.hasStyleHint(QLatin1String("icon-size"))) {
4957             return rule.styleHint(QLatin1String("icon-size")).toSize().width();
4958         }
4959         break;
4960 
4961     case PM_DockWidgetTitleMargin: {
4962         QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
4963         if (!subRule.hasBox())
4964             break;
4965         return (subRule.border() ? subRule.border()->borders[TopEdge] : 0)
4966                 + (subRule.hasBox() ? subRule.box()->margins[TopEdge] + subRule.box()->paddings[TopEdge]: 0);
4967                                    }
4968 
4969     case PM_DockWidgetSeparatorExtent: {
4970         QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetSeparator);
4971         if (!subRule.hasContentsSize())
4972             break;
4973         QSize sz = subRule.size();
4974         return qMax(sz.width(), sz.height());
4975                                         }
4976 
4977     case PM_TitleBarHeight: {
4978         QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
4979         if (subRule.hasContentsSize())
4980             return subRule.size().height();
4981         else if (subRule.hasBox() || subRule.hasBorder()) {
4982             QFontMetrics fm = opt ?  opt->fontMetrics : w->fontMetrics();
4983             return subRule.size(QSize(0, fm.height())).height();
4984         }
4985         break;
4986                             }
4987 
4988     case PM_MdiSubWindowFrameWidth:
4989         if (rule.hasBox() || rule.hasBorder()) {
4990             return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4991                    + (rule.hasBox() ? rule.box()->paddings[LeftEdge]+rule.box()->margins[LeftEdge]: 0);
4992         }
4993         break;
4994 
4995     case PM_MdiSubWindowMinimizedWidth: {
4996         QRenderRule subRule = renderRule(w, PseudoElement_None, PseudoClass_Minimized);
4997         int width = subRule.size().width();
4998         if (width != -1)
4999             return width;
5000         break;
5001                                      }
5002     default:
5003         break;
5004     }
5005 
5006     return baseStyle()->pixelMetric(m, opt, w);
5007 }
5008 
sizeFromContents(ContentsType ct,const QStyleOption * opt,const QSize & csz,const QWidget * w) const5009 QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
5010                                          const QSize &csz, const QWidget *w) const
5011 {
5012     RECURSION_GUARD(return baseStyle()->sizeFromContents(ct, opt, csz, w))
5013 
5014     QRenderRule rule = renderRule(w, opt);
5015     QSize sz = rule.adjustSize(csz);
5016 
5017     switch (ct) {
5018 #if QT_CONFIG(spinbox)
5019     case CT_SpinBox:
5020         if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5021             if (spinbox->buttonSymbols != QAbstractSpinBox::NoButtons) {
5022                 // Add some space for the up/down buttons
5023                 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
5024                 if (subRule.hasDrawable()) {
5025                     QRect r = positionRect(w, rule, subRule, PseudoElement_SpinBoxUpButton,
5026                                            opt->rect, opt->direction);
5027                     sz.rwidth() += r.width();
5028                 } else {
5029                     QSize defaultUpSize = defaultSize(w, subRule.size(), spinbox->rect, PseudoElement_SpinBoxUpButton);
5030                     sz.rwidth() += defaultUpSize.width();
5031                 }
5032             }
5033             if (rule.hasBox() || rule.hasBorder() || !rule.hasNativeBorder())
5034                 sz = rule.boxSize(sz);
5035             return sz;
5036         }
5037         break;
5038 #endif // QT_CONFIG(spinbox)
5039     case CT_ToolButton:
5040         if (rule.hasBox() || !rule.hasNativeBorder() || !rule.baseStyleCanDraw())
5041             sz += QSize(3, 3); // ### broken QToolButton
5042         Q_FALLTHROUGH();
5043     case CT_ComboBox:
5044     case CT_PushButton:
5045         if (rule.hasBox() || !rule.hasNativeBorder()) {
5046             if(ct == CT_ComboBox) {
5047                 //add some space for the drop down.
5048                 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5049                 QRect comboRect = positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown, opt->rect, opt->direction);
5050                 //+2 because there is hardcoded margins in QCommonStyle::drawControl(CE_ComboBoxLabel)
5051                 sz += QSize(comboRect.width() + 2, 0);
5052             }
5053             return rule.boxSize(sz);
5054         }
5055         sz = rule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
5056                                      : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
5057         return rule.boxSize(sz, Margin);
5058 
5059     case CT_HeaderSection: {
5060             if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
5061                 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
5062                 if (subRule.hasGeometry() || subRule.hasBox() || !subRule.hasNativeBorder() || subRule.hasFont) {
5063                     sz = subRule.adjustSize(csz);
5064                     if (!sz.isValid()) {
5065                         // Try to set the missing values based on the base style.
5066                         const auto baseSize = baseStyle()->sizeFromContents(ct, opt, sz, w);
5067                         if (sz.width() < 0)
5068                             sz.setWidth(baseSize.width());
5069                         if (sz.height() < 0)
5070                             sz.setHeight(baseSize.height());
5071                     }
5072                     if (!subRule.hasGeometry()) {
5073                         QSize nativeContentsSize;
5074                         bool nullIcon = hdr->icon.isNull();
5075                         const int margin = pixelMetric(QStyle::PM_HeaderMargin, hdr, w);
5076                         int iconSize = nullIcon ? 0 : pixelMetric(QStyle::PM_SmallIconSize, hdr, w);
5077                         QFontMetrics fm = hdr->fontMetrics;
5078                         if (subRule.hasFont) {
5079                             QFont styleFont = w ? subRule.font.resolve(w->font()) : subRule.font;
5080                             fm = QFontMetrics(styleFont);
5081                         }
5082                         const QSize txt = fm.size(0, hdr->text);
5083                         nativeContentsSize.setHeight(margin + qMax(iconSize, txt.height()) + margin);
5084                         nativeContentsSize.setWidth((nullIcon ? 0 : margin) + iconSize
5085                                                     + (hdr->text.isNull() ? 0 : margin) + txt.width() + margin);
5086                         sz = sz.expandedTo(nativeContentsSize);
5087                     }
5088                     return subRule.size(sz);
5089                 }
5090                 return subRule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
5091                                                   : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
5092             }
5093         }
5094         break;
5095     case CT_GroupBox:
5096     case CT_LineEdit:
5097 #if QT_CONFIG(spinbox)
5098         if (qobject_cast<QAbstractSpinBox *>(w ? w->parentWidget() : nullptr))
5099             return csz; // we only care about the size hint of the line edit
5100 #endif
5101         if (rule.hasBox() || !rule.hasNativeBorder()) {
5102             return rule.boxSize(sz);
5103         }
5104         break;
5105 
5106     case CT_CheckBox:
5107     case CT_RadioButton:
5108         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
5109             if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5110                 bool isRadio = (ct == CT_RadioButton);
5111                 int iw = pixelMetric(isRadio ? PM_ExclusiveIndicatorWidth
5112                                              : PM_IndicatorWidth, btn, w);
5113                 int ih = pixelMetric(isRadio ? PM_ExclusiveIndicatorHeight
5114                                              : PM_IndicatorHeight, btn, w);
5115 
5116                 int spacing = pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
5117                                                   : PM_CheckBoxLabelSpacing, btn, w);
5118                 sz.setWidth(sz.width() + iw + spacing);
5119                 sz.setHeight(qMax(sz.height(), ih));
5120                 return rule.boxSize(sz);
5121             }
5122         }
5123         break;
5124 
5125     case CT_Menu:
5126     case CT_MenuBar: // already has everything!
5127     case CT_ScrollBar:
5128         if (rule.hasBox() || rule.hasBorder())
5129             return sz;
5130         break;
5131 
5132     case CT_MenuItem:
5133         if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5134             PseudoElement pe = (mi->menuItemType == QStyleOptionMenuItem::Separator)
5135                                     ? PseudoElement_MenuSeparator : PseudoElement_Item;
5136             QRenderRule subRule = renderRule(w, opt, pe);
5137             if ((pe == PseudoElement_MenuSeparator) && subRule.hasContentsSize()) {
5138                 return QSize(sz.width(), subRule.size().height());
5139             }
5140             if ((pe == PseudoElement_Item) && (subRule.hasBox() || subRule.hasBorder() || subRule.hasFont)) {
5141                 QSize sz(csz);
5142                 if (mi->text.contains(QLatin1Char('\t')))
5143                     sz.rwidth() += 12; //as in QCommonStyle
5144                 bool checkable = mi->checkType != QStyleOptionMenuItem::NotCheckable;
5145                 if (!mi->icon.isNull()) {
5146                     const int pmSmall = pixelMetric(PM_SmallIconSize);
5147                     const QSize pmSize = mi->icon.actualSize(QSize(pmSmall, pmSmall));
5148                     sz.rwidth() += pmSize.width() + 4;
5149                 } else if (checkable) {
5150                     QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
5151                     QRect checkmarkRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction);
5152                     sz.rwidth() += std::max(mi->maxIconWidth, checkmarkRect.width()) + 4;
5153                 }
5154                 if (subRule.hasFont) {
5155                     QFontMetrics fm(subRule.font);
5156                     const QRect r = fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, mi->text);
5157                     sz = sz.expandedTo(r.size());
5158                 }
5159                 return subRule.boxSize(subRule.adjustSize(sz));
5160             }
5161         }
5162         break;
5163 
5164     case CT_Splitter:
5165     case CT_MenuBarItem: {
5166         PseudoElement pe = (ct == CT_Splitter) ? PseudoElement_SplitterHandle : PseudoElement_Item;
5167         QRenderRule subRule = renderRule(w, opt, pe);
5168         if (subRule.hasBox() || subRule.hasBorder())
5169             return subRule.boxSize(sz);
5170         break;
5171                         }
5172 
5173     case CT_ProgressBar:
5174     case CT_SizeGrip:
5175         return (rule.hasContentsSize())
5176             ? rule.size(sz)
5177             : rule.boxSize(baseStyle()->sizeFromContents(ct, opt, sz, w));
5178         break;
5179 
5180     case CT_Slider:
5181         if (rule.hasBorder() || rule.hasBox() || rule.hasGeometry())
5182             return rule.boxSize(sz);
5183         break;
5184 
5185 #if QT_CONFIG(tabbar)
5186     case CT_TabBarTab: {
5187         QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
5188         if (subRule.hasBox() || !subRule.hasNativeBorder()) {
5189             int spaceForIcon = 0;
5190             bool vertical = false;
5191             if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
5192                 if (!tab->icon.isNull())
5193                     spaceForIcon = 6 /* icon offset */ + 4 /* spacing */ + 2 /* magic */; // ###: hardcoded to match with common style
5194                 vertical = verticalTabs(tab->shape);
5195             }
5196             sz = csz + QSize(vertical ? 0 : spaceForIcon, vertical ? spaceForIcon : 0);
5197             return subRule.boxSize(subRule.adjustSize(sz));
5198         }
5199         sz = subRule.adjustSize(csz);
5200         break;
5201     }
5202 #endif // QT_CONFIG(tabbar)
5203 
5204     case CT_MdiControls:
5205         if (const QStyleOptionComplex *ccOpt = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
5206             if (!hasStyleRule(w, PseudoElement_MdiCloseButton)
5207                 && !hasStyleRule(w, PseudoElement_MdiNormalButton)
5208                 && !hasStyleRule(w, PseudoElement_MdiMinButton))
5209                 break;
5210 
5211             QList<QVariant> layout = rule.styleHint(QLatin1String("button-layout")).toList();
5212             if (layout.isEmpty())
5213                 layout = subControlLayout(QLatin1String("mNX"));
5214 
5215             int width = 0, height = 0;
5216             for (int i = 0; i < layout.count(); i++) {
5217                 int layoutButton = layout[i].toInt();
5218                 if (layoutButton < PseudoElement_MdiCloseButton
5219                     || layoutButton > PseudoElement_MdiNormalButton)
5220                     continue;
5221                 QStyle::SubControl sc = knownPseudoElements[layoutButton].subControl;
5222                 if (!(ccOpt->subControls & sc))
5223                     continue;
5224                 QRenderRule subRule = renderRule(w, opt, layoutButton);
5225                 QSize sz = subRule.size();
5226                 width += sz.width();
5227                 height = qMax(height, sz.height());
5228             }
5229 
5230             return QSize(width, height);
5231         }
5232         break;
5233 
5234 #if QT_CONFIG(itemviews)
5235     case CT_ItemViewItem: {
5236         QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
5237         sz = baseStyle()->sizeFromContents(ct, opt, csz, w);
5238         sz = subRule.adjustSize(sz);
5239         if (subRule.hasBox() || subRule.hasBorder())
5240             sz = subRule.boxSize(sz);
5241         return sz;
5242                       }
5243 #endif // QT_CONFIG(itemviews)
5244 
5245     default:
5246         break;
5247     }
5248 
5249     return baseStyle()->sizeFromContents(ct, opt, sz, w);
5250 }
5251 
5252 /*!
5253     \internal
5254 */
propertyNameForStandardPixmap(QStyle::StandardPixmap sp)5255 static QLatin1String propertyNameForStandardPixmap(QStyle::StandardPixmap sp)
5256 {
5257     switch (sp) {
5258         case QStyle::SP_TitleBarMenuButton: return QLatin1String("titlebar-menu-icon");
5259         case QStyle::SP_TitleBarMinButton: return QLatin1String("titlebar-minimize-icon");
5260         case QStyle::SP_TitleBarMaxButton: return QLatin1String("titlebar-maximize-icon");
5261         case QStyle::SP_TitleBarCloseButton: return QLatin1String("titlebar-close-icon");
5262         case QStyle::SP_TitleBarNormalButton: return QLatin1String("titlebar-normal-icon");
5263         case QStyle::SP_TitleBarShadeButton: return QLatin1String("titlebar-shade-icon");
5264         case QStyle::SP_TitleBarUnshadeButton: return QLatin1String("titlebar-unshade-icon");
5265         case QStyle::SP_TitleBarContextHelpButton: return QLatin1String("titlebar-contexthelp-icon");
5266         case QStyle::SP_DockWidgetCloseButton: return QLatin1String("dockwidget-close-icon");
5267         case QStyle::SP_MessageBoxInformation: return QLatin1String("messagebox-information-icon");
5268         case QStyle::SP_MessageBoxWarning: return QLatin1String("messagebox-warning-icon");
5269         case QStyle::SP_MessageBoxCritical: return QLatin1String("messagebox-critical-icon");
5270         case QStyle::SP_MessageBoxQuestion: return QLatin1String("messagebox-question-icon");
5271         case QStyle::SP_DesktopIcon: return QLatin1String("desktop-icon");
5272         case QStyle::SP_TrashIcon: return QLatin1String("trash-icon");
5273         case QStyle::SP_ComputerIcon: return QLatin1String("computer-icon");
5274         case QStyle::SP_DriveFDIcon: return QLatin1String("floppy-icon");
5275         case QStyle::SP_DriveHDIcon: return QLatin1String("harddisk-icon");
5276         case QStyle::SP_DriveCDIcon: return QLatin1String("cd-icon");
5277         case QStyle::SP_DriveDVDIcon: return QLatin1String("dvd-icon");
5278         case QStyle::SP_DriveNetIcon: return QLatin1String("network-icon");
5279         case QStyle::SP_DirOpenIcon: return QLatin1String("directory-open-icon");
5280         case QStyle::SP_DirClosedIcon: return QLatin1String("directory-closed-icon");
5281         case QStyle::SP_DirLinkIcon: return QLatin1String("directory-link-icon");
5282         case QStyle::SP_FileIcon: return QLatin1String("file-icon");
5283         case QStyle::SP_FileLinkIcon: return QLatin1String("file-link-icon");
5284         case QStyle::SP_FileDialogStart: return QLatin1String("filedialog-start-icon");
5285         case QStyle::SP_FileDialogEnd: return QLatin1String("filedialog-end-icon");
5286         case QStyle::SP_FileDialogToParent: return QLatin1String("filedialog-parent-directory-icon");
5287         case QStyle::SP_FileDialogNewFolder: return QLatin1String("filedialog-new-directory-icon");
5288         case QStyle::SP_FileDialogDetailedView: return QLatin1String("filedialog-detailedview-icon");
5289         case QStyle::SP_FileDialogInfoView: return QLatin1String("filedialog-infoview-icon");
5290         case QStyle::SP_FileDialogContentsView: return QLatin1String("filedialog-contentsview-icon");
5291         case QStyle::SP_FileDialogListView: return QLatin1String("filedialog-listview-icon");
5292         case QStyle::SP_FileDialogBack: return QLatin1String("filedialog-backward-icon");
5293         case QStyle::SP_DirIcon: return QLatin1String("directory-icon");
5294         case QStyle::SP_DialogOkButton: return QLatin1String("dialog-ok-icon");
5295         case QStyle::SP_DialogCancelButton: return QLatin1String("dialog-cancel-icon");
5296         case QStyle::SP_DialogHelpButton: return QLatin1String("dialog-help-icon");
5297         case QStyle::SP_DialogOpenButton: return QLatin1String("dialog-open-icon");
5298         case QStyle::SP_DialogSaveButton: return QLatin1String("dialog-save-icon");
5299         case QStyle::SP_DialogCloseButton: return QLatin1String("dialog-close-icon");
5300         case QStyle::SP_DialogApplyButton: return QLatin1String("dialog-apply-icon");
5301         case QStyle::SP_DialogResetButton: return QLatin1String("dialog-reset-icon");
5302         case QStyle::SP_DialogDiscardButton: return QLatin1String("dialog-discard-icon");
5303         case QStyle::SP_DialogYesButton: return QLatin1String("dialog-yes-icon");
5304         case QStyle::SP_DialogNoButton: return QLatin1String("dialog-no-icon");
5305         case QStyle::SP_ArrowUp: return QLatin1String("uparrow-icon");
5306         case QStyle::SP_ArrowDown: return QLatin1String("downarrow-icon");
5307         case QStyle::SP_ArrowLeft: return QLatin1String("leftarrow-icon");
5308         case QStyle::SP_ArrowRight: return QLatin1String("rightarrow-icon");
5309         case QStyle::SP_ArrowBack: return QLatin1String("backward-icon");
5310         case QStyle::SP_ArrowForward: return QLatin1String("forward-icon");
5311         case QStyle::SP_DirHomeIcon: return QLatin1String("home-icon");
5312         default: return QLatin1String("");
5313     }
5314 }
5315 
standardIcon(StandardPixmap standardIcon,const QStyleOption * opt,const QWidget * w) const5316 QIcon QStyleSheetStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *opt,
5317                                      const QWidget *w) const
5318 {
5319     RECURSION_GUARD(return baseStyle()->standardIcon(standardIcon, opt, w))
5320     QString s = propertyNameForStandardPixmap(standardIcon);
5321     if (!s.isEmpty()) {
5322         QRenderRule rule = renderRule(w, opt);
5323         if (rule.hasStyleHint(s))
5324             return qvariant_cast<QIcon>(rule.styleHint(s));
5325     }
5326     return baseStyle()->standardIcon(standardIcon, opt, w);
5327 }
5328 
standardPalette() const5329 QPalette QStyleSheetStyle::standardPalette() const
5330 {
5331     return baseStyle()->standardPalette();
5332 }
5333 
standardPixmap(StandardPixmap standardPixmap,const QStyleOption * opt,const QWidget * w) const5334 QPixmap QStyleSheetStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
5335                                          const QWidget *w) const
5336 {
5337     RECURSION_GUARD(return baseStyle()->standardPixmap(standardPixmap, opt, w))
5338     QString s = propertyNameForStandardPixmap(standardPixmap);
5339     if (!s.isEmpty()) {
5340         QRenderRule rule = renderRule(w, opt);
5341         if (rule.hasStyleHint(s)) {
5342             QIcon icon = qvariant_cast<QIcon>(rule.styleHint(s));
5343             return icon.pixmap(16, 16); // ###: unhard-code this if someone complains
5344         }
5345     }
5346     return baseStyle()->standardPixmap(standardPixmap, opt, w);
5347 }
5348 
layoutSpacing(QSizePolicy::ControlType control1,QSizePolicy::ControlType control2,Qt::Orientation orientation,const QStyleOption * option,const QWidget * widget) const5349 int QStyleSheetStyle::layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2,
5350                           Qt::Orientation orientation, const QStyleOption *option,
5351                           const QWidget *widget) const
5352 {
5353     return baseStyle()->layoutSpacing(control1, control2, orientation, option, widget);
5354 }
5355 
styleHint(StyleHint sh,const QStyleOption * opt,const QWidget * w,QStyleHintReturn * shret) const5356 int QStyleSheetStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
5357                            QStyleHintReturn *shret) const
5358 {
5359     RECURSION_GUARD(return baseStyle()->styleHint(sh, opt, w, shret))
5360     // Prevent endless loop if somebody use isActiveWindow property as selector.
5361     // QWidget::isActiveWindow uses this styleHint to determine if the window is active or not
5362     if (sh == SH_Widget_ShareActivation)
5363         return baseStyle()->styleHint(sh, opt, w, shret);
5364 
5365     QRenderRule rule = renderRule(w, opt);
5366     QString s;
5367     switch (sh) {
5368         case SH_LineEdit_PasswordCharacter: s = QLatin1String("lineedit-password-character"); break;
5369         case SH_LineEdit_PasswordMaskDelay: s = QLatin1String("lineedit-password-mask-delay"); break;
5370         case SH_DitherDisabledText: s = QLatin1String("dither-disabled-text"); break;
5371         case SH_EtchDisabledText: s = QLatin1String("etch-disabled-text"); break;
5372         case SH_ItemView_ActivateItemOnSingleClick: s = QLatin1String("activate-on-singleclick"); break;
5373         case SH_ItemView_ShowDecorationSelected: s = QLatin1String("show-decoration-selected"); break;
5374         case SH_Table_GridLineColor: s = QLatin1String("gridline-color"); break;
5375         case SH_DialogButtonLayout: s = QLatin1String("button-layout"); break;
5376         case SH_ToolTipLabel_Opacity: s = QLatin1String("opacity"); break;
5377         case SH_ComboBox_Popup: s = QLatin1String("combobox-popup"); break;
5378         case SH_ComboBox_ListMouseTracking: s = QLatin1String("combobox-list-mousetracking"); break;
5379         case SH_MenuBar_AltKeyNavigation: s = QLatin1String("menubar-altkey-navigation"); break;
5380         case SH_Menu_Scrollable: s = QLatin1String("menu-scrollable"); break;
5381         case SH_DrawMenuBarSeparator: s = QLatin1String("menubar-separator"); break;
5382         case SH_MenuBar_MouseTracking: s = QLatin1String("mouse-tracking"); break;
5383         case SH_SpinBox_ClickAutoRepeatRate: s = QLatin1String("spinbox-click-autorepeat-rate"); break;
5384         case SH_SpinControls_DisableOnBounds: s = QLatin1String("spincontrol-disable-on-bounds"); break;
5385         case SH_MessageBox_TextInteractionFlags: s = QLatin1String("messagebox-text-interaction-flags"); break;
5386         case SH_ToolButton_PopupDelay: s = QLatin1String("toolbutton-popup-delay"); break;
5387         case SH_ToolBox_SelectedPageTitleBold:
5388             if (renderRule(w, opt, PseudoElement_ToolBoxTab).hasFont)
5389                 return 0;
5390             break;
5391         case SH_GroupBox_TextLabelColor:
5392             if (rule.hasPalette() && rule.palette()->foreground.style() != Qt::NoBrush)
5393                 return rule.palette()->foreground.color().rgba();
5394             break;
5395         case SH_ScrollView_FrameOnlyAroundContents: s = QLatin1String("scrollview-frame-around-contents"); break;
5396         case SH_ScrollBar_ContextMenu: s = QLatin1String("scrollbar-contextmenu"); break;
5397         case SH_ScrollBar_LeftClickAbsolutePosition: s = QLatin1String("scrollbar-leftclick-absolute-position"); break;
5398         case SH_ScrollBar_MiddleClickAbsolutePosition: s = QLatin1String("scrollbar-middleclick-absolute-position"); break;
5399         case SH_ScrollBar_RollBetweenButtons: s = QLatin1String("scrollbar-roll-between-buttons"); break;
5400         case SH_ScrollBar_ScrollWhenPointerLeavesControl: s = QLatin1String("scrollbar-scroll-when-pointer-leaves-control"); break;
5401         case SH_TabBar_Alignment:
5402 #if QT_CONFIG(tabwidget)
5403             if (qobject_cast<const QTabWidget *>(w)) {
5404                 rule = renderRule(w, opt, PseudoElement_TabWidgetTabBar);
5405                 if (rule.hasPosition())
5406                     return rule.position()->position;
5407             }
5408 #endif // QT_CONFIG(tabwidget)
5409             s = QLatin1String("alignment");
5410             break;
5411 #if QT_CONFIG(tabbar)
5412         case SH_TabBar_CloseButtonPosition:
5413             rule = renderRule(w, opt, PseudoElement_TabBarTabCloseButton);
5414             if (rule.hasPosition()) {
5415                 Qt::Alignment align = rule.position()->position;
5416                 if (align & Qt::AlignLeft || align & Qt::AlignTop)
5417                     return QTabBar::LeftSide;
5418                 if (align & Qt::AlignRight || align & Qt::AlignBottom)
5419                     return QTabBar::RightSide;
5420             }
5421             break;
5422 #endif
5423         case SH_TabBar_ElideMode: s = QLatin1String("tabbar-elide-mode"); break;
5424         case SH_TabBar_PreferNoArrows: s = QLatin1String("tabbar-prefer-no-arrows"); break;
5425         case SH_ComboBox_PopupFrameStyle:
5426 #if QT_CONFIG(combobox)
5427             if (qobject_cast<const QComboBox *>(w)) {
5428                 QAbstractItemView *view = w->findChild<QAbstractItemView *>();
5429                 if (view) {
5430                     view->ensurePolished();
5431                     QRenderRule subRule = renderRule(view, PseudoElement_None);
5432                     if (subRule.hasBox() || !subRule.hasNativeBorder())
5433                         return QFrame::NoFrame;
5434                 }
5435             }
5436 #endif // QT_CONFIG(combobox)
5437             break;
5438         case SH_DialogButtonBox_ButtonsHaveIcons: s = QLatin1String("dialogbuttonbox-buttons-have-icons"); break;
5439         case SH_Workspace_FillSpaceOnMaximize: s = QLatin1String("mdi-fill-space-on-maximize"); break;
5440         case SH_TitleBar_NoBorder:
5441             if (rule.hasBorder())
5442                 return !rule.border()->borders[LeftEdge];
5443             break;
5444         case SH_TitleBar_AutoRaise: { // plain absurd
5445             QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
5446             if (subRule.hasDrawable())
5447                 return 1;
5448             break;
5449                                    }
5450         case SH_ItemView_ArrowKeysNavigateIntoChildren: s = QLatin1String("arrow-keys-navigate-into-children"); break;
5451         case SH_ItemView_PaintAlternatingRowColorsForEmptyArea: s = QLatin1String("paint-alternating-row-colors-for-empty-area"); break;
5452         case SH_TitleBar_ShowToolTipsOnButtons: s = QLatin1String("titlebar-show-tooltips-on-buttons"); break;
5453         case SH_Widget_Animation_Duration: s = QLatin1String("widget-animation-duration"); break;
5454         default: break;
5455     }
5456     if (!s.isEmpty() && rule.hasStyleHint(s)) {
5457         return rule.styleHint(s).toInt();
5458     }
5459 
5460     return baseStyle()->styleHint(sh, opt, w, shret);
5461 }
5462 
subControlRect(ComplexControl cc,const QStyleOptionComplex * opt,SubControl sc,const QWidget * w) const5463 QRect QStyleSheetStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5464                               const QWidget *w) const
5465 {
5466     RECURSION_GUARD(return baseStyle()->subControlRect(cc, opt, sc, w))
5467 
5468     QRenderRule rule = renderRule(w, opt);
5469     switch (cc) {
5470     case CC_ComboBox:
5471         if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5472             if (rule.hasBox() || !rule.hasNativeBorder()) {
5473                 switch (sc) {
5474                 case SC_ComboBoxFrame: return rule.borderRect(opt->rect);
5475                 case SC_ComboBoxEditField:
5476                     {
5477                         QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5478                         QRect r = rule.contentsRect(opt->rect);
5479                         QRect r2 = positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown,
5480                                 opt->rect, opt->direction);
5481                         if (subRule.hasPosition() && subRule.position()->position & Qt::AlignLeft) {
5482                             return visualRect(opt->direction, r, r.adjusted(r2.width(),0,0,0));
5483                         } else {
5484                             return visualRect(opt->direction, r, r.adjusted(0,0,-r2.width(),0));
5485                         }
5486                     }
5487                 case SC_ComboBoxArrow: {
5488                     QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5489                     return positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown, opt->rect, opt->direction);
5490                                                                            }
5491                 case SC_ComboBoxListBoxPopup:
5492                 default:
5493                     return baseStyle()->subControlRect(cc, opt, sc, w);
5494                 }
5495             }
5496 
5497             QStyleOptionComboBox comboBox(*cb);
5498             comboBox.rect = rule.borderRect(opt->rect);
5499             return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &comboBox, sc, w)
5500                                            : QWindowsStyle::subControlRect(cc, &comboBox, sc, w);
5501         }
5502         break;
5503 
5504 #if QT_CONFIG(spinbox)
5505     case CC_SpinBox:
5506         if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5507             QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
5508             QRenderRule downRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
5509             bool ruleMatch = rule.hasBox() || !rule.hasNativeBorder();
5510             bool upRuleMatch = upRule.hasGeometry() || upRule.hasPosition();
5511             bool downRuleMatch = downRule.hasGeometry() || downRule.hasPosition();
5512             if (ruleMatch || upRuleMatch || downRuleMatch) {
5513                 switch (sc) {
5514                 case SC_SpinBoxFrame:
5515                     return rule.borderRect(opt->rect);
5516                 case SC_SpinBoxEditField:
5517                     {
5518                         QRect r = rule.contentsRect(opt->rect);
5519                         // Use the widest button on each side to determine edit field size.
5520                         Qt::Alignment upAlign, downAlign;
5521 
5522                         upAlign = upRule.hasPosition() ? upRule.position()->position
5523                                 : Qt::Alignment(Qt::AlignRight);
5524                         upAlign = resolveAlignment(opt->direction, upAlign);
5525 
5526                         downAlign = downRule.hasPosition() ? downRule.position()->position
5527                                 : Qt::Alignment(Qt::AlignRight);
5528                         downAlign = resolveAlignment(opt->direction, downAlign);
5529 
5530                         const bool hasButtons = (spin->buttonSymbols != QAbstractSpinBox::NoButtons);
5531                         const int upSize = hasButtons
5532                                 ? subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w).width() : 0;
5533                         const int downSize = hasButtons
5534                                 ? subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w).width() : 0;
5535 
5536                         int widestL = qMax((upAlign & Qt::AlignLeft) ? upSize : 0,
5537                                 (downAlign & Qt::AlignLeft) ? downSize : 0);
5538                         int widestR = qMax((upAlign & Qt::AlignRight) ? upSize : 0,
5539                                 (downAlign & Qt::AlignRight) ? downSize : 0);
5540                         r.setRight(r.right() - widestR);
5541                         r.setLeft(r.left() + widestL);
5542                         return r;
5543                     }
5544                 case SC_SpinBoxDown:
5545                     if (downRuleMatch)
5546                         return positionRect(w, rule, downRule, PseudoElement_SpinBoxDownButton,
5547                                 opt->rect, opt->direction);
5548                     break;
5549                 case SC_SpinBoxUp:
5550                     if (upRuleMatch)
5551                         return positionRect(w, rule, upRule, PseudoElement_SpinBoxUpButton,
5552                                 opt->rect, opt->direction);
5553                     break;
5554                 default:
5555                     break;
5556                 }
5557 
5558                 return baseStyle()->subControlRect(cc, opt, sc, w);
5559             }
5560 
5561             QStyleOptionSpinBox spinBox(*spin);
5562             spinBox.rect = rule.borderRect(opt->rect);
5563             return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &spinBox, sc, w)
5564                                            : QWindowsStyle::subControlRect(cc, &spinBox, sc, w);
5565         }
5566         break;
5567 #endif // QT_CONFIG(spinbox)
5568 
5569     case CC_GroupBox:
5570         if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5571             switch (sc) {
5572             case SC_GroupBoxFrame:
5573             case SC_GroupBoxContents: {
5574                 if (rule.hasBox() || !rule.hasNativeBorder()) {
5575                     return sc == SC_GroupBoxFrame ? rule.borderRect(opt->rect)
5576                                                   : rule.contentsRect(opt->rect);
5577                 }
5578                 QStyleOptionGroupBox groupBox(*gb);
5579                 groupBox.rect = rule.borderRect(opt->rect);
5580                 return baseStyle()->subControlRect(cc, &groupBox, sc, w);
5581             }
5582             default:
5583             case SC_GroupBoxLabel:
5584             case SC_GroupBoxCheckBox: {
5585                 QRenderRule indRule = renderRule(w, opt, PseudoElement_GroupBoxIndicator);
5586                 QRenderRule labelRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
5587                 if (!labelRule.hasPosition() && !labelRule.hasGeometry() && !labelRule.hasBox()
5588                     && !labelRule.hasBorder() && !indRule.hasContentsSize()) {
5589                     QStyleOptionGroupBox groupBox(*gb);
5590                     groupBox.rect = rule.borderRect(opt->rect);
5591                     return baseStyle()->subControlRect(cc, &groupBox, sc, w);
5592                 }
5593                 int tw = opt->fontMetrics.horizontalAdvance(gb->text);
5594                 int th = opt->fontMetrics.height();
5595                 int spacing = pixelMetric(QStyle::PM_CheckBoxLabelSpacing, opt, w);
5596                 int iw = pixelMetric(QStyle::PM_IndicatorWidth, opt, w);
5597                 int ih = pixelMetric(QStyle::PM_IndicatorHeight, opt, w);
5598 
5599                 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
5600                     tw = tw + iw + spacing;
5601                     th = qMax(th, ih);
5602                 }
5603                 if (!labelRule.hasGeometry()) {
5604                     labelRule.geo = new QStyleSheetGeometryData(tw, th, tw, th, -1, -1);
5605                 } else {
5606                     labelRule.geo->width = tw;
5607                     labelRule.geo->height = th;
5608                 }
5609                 if (!labelRule.hasPosition()) {
5610                     labelRule.p = new QStyleSheetPositionData(0, 0, 0, 0, defaultOrigin(PseudoElement_GroupBoxTitle),
5611                                                               gb->textAlignment, PositionMode_Static);
5612                 }
5613                 QRect r = positionRect(w, rule, labelRule, PseudoElement_GroupBoxTitle,
5614                                       opt->rect, opt->direction);
5615                 if (gb->subControls & SC_GroupBoxCheckBox) {
5616                     r = labelRule.contentsRect(r);
5617                     if (sc == SC_GroupBoxLabel) {
5618                         r.setLeft(r.left() + iw + spacing);
5619                         r.setTop(r.center().y() - th/2);
5620                     } else {
5621                         r = QRect(r.left(), r.center().y() - ih/2, iw, ih);
5622                     }
5623                     return r;
5624                 } else {
5625                     return labelRule.contentsRect(r);
5626                 }
5627             }
5628             } // switch
5629         }
5630         break;
5631 
5632     case CC_ToolButton:
5633         if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5634             if (rule.hasBox() || !rule.hasNativeBorder()) {
5635                 switch (sc) {
5636                 case SC_ToolButton: return rule.borderRect(opt->rect);
5637                 case SC_ToolButtonMenu: {
5638                     QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
5639                     return positionRect(w, rule, subRule, PseudoElement_ToolButtonMenu, opt->rect, opt->direction);
5640                                                                             }
5641                 default:
5642                     break;
5643                 }
5644             }
5645 
5646             QStyleOptionToolButton tool(*tb);
5647             tool.rect = rule.borderRect(opt->rect);
5648             return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &tool, sc, w)
5649                                            : QWindowsStyle::subControlRect(cc, &tool, sc, w);
5650             }
5651             break;
5652 
5653 #if QT_CONFIG(scrollbar)
5654     case CC_ScrollBar:
5655         if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5656             QStyleOptionSlider styleOptionSlider(*sb);
5657             styleOptionSlider.rect = rule.borderRect(opt->rect);
5658             if (rule.hasDrawable() || rule.hasBox()) {
5659                 QRect grooveRect;
5660                 if (!rule.hasBox()) {
5661                     grooveRect = rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, sb, SC_ScrollBarGroove, w)
5662                                  : QWindowsStyle::subControlRect(cc, sb, SC_ScrollBarGroove, w);
5663                 } else {
5664                     grooveRect = rule.contentsRect(opt->rect);
5665                 }
5666 
5667                 PseudoElement pe = PseudoElement_None;
5668 
5669                 switch (sc) {
5670                 case SC_ScrollBarGroove:
5671                     return grooveRect;
5672                 case SC_ScrollBarAddPage:
5673                 case SC_ScrollBarSubPage:
5674                 case SC_ScrollBarSlider: {
5675                     QRect contentRect = grooveRect;
5676                     if (hasStyleRule(w, PseudoElement_ScrollBarSlider)) {
5677                         QRenderRule sliderRule = renderRule(w, opt, PseudoElement_ScrollBarSlider);
5678                         Origin origin = sliderRule.hasPosition() ? sliderRule.position()->origin : defaultOrigin(PseudoElement_ScrollBarSlider);
5679                         contentRect = rule.originRect(opt->rect, origin);
5680                     }
5681                     int maxlen = (styleOptionSlider.orientation == Qt::Horizontal) ? contentRect.width() : contentRect.height();
5682                     int sliderlen;
5683                     if (sb->maximum != sb->minimum) {
5684                         uint range = sb->maximum - sb->minimum;
5685                         sliderlen = (qint64(sb->pageStep) * maxlen) / (range + sb->pageStep);
5686 
5687                         int slidermin = pixelMetric(PM_ScrollBarSliderMin, sb, w);
5688                         if (sliderlen < slidermin || range > INT_MAX / 2)
5689                             sliderlen = slidermin;
5690                         if (sliderlen > maxlen)
5691                             sliderlen = maxlen;
5692                     } else {
5693                         sliderlen = maxlen;
5694                     }
5695                     int sliderstart = (styleOptionSlider.orientation == Qt::Horizontal ? contentRect.left() : contentRect.top())
5696                         + sliderPositionFromValue(sb->minimum, sb->maximum, sb->sliderPosition,
5697                                                   maxlen - sliderlen, sb->upsideDown);
5698 
5699                     QRect sr = (sb->orientation == Qt::Horizontal)
5700                                ? QRect(sliderstart, contentRect.top(), sliderlen, contentRect.height())
5701                                : QRect(contentRect.left(), sliderstart, contentRect.width(), sliderlen);
5702                     if (sc == SC_ScrollBarSubPage)
5703                         sr = QRect(contentRect.topLeft(), sb->orientation == Qt::Horizontal ? sr.bottomLeft() : sr.topRight());
5704                     else if (sc == SC_ScrollBarAddPage)
5705                         sr = QRect(sb->orientation == Qt::Horizontal ? sr.topRight() : sr.bottomLeft(), contentRect.bottomRight());
5706                     return visualRect(styleOptionSlider.direction, grooveRect, sr);
5707                 }
5708                 case SC_ScrollBarAddLine: pe = PseudoElement_ScrollBarAddLine; break;
5709                 case SC_ScrollBarSubLine: pe = PseudoElement_ScrollBarSubLine; break;
5710                 case SC_ScrollBarFirst: pe = PseudoElement_ScrollBarFirst;  break;
5711                 case SC_ScrollBarLast: pe = PseudoElement_ScrollBarLast; break;
5712                 default: break;
5713                 }
5714                 if (hasStyleRule(w,pe)) {
5715                     QRenderRule subRule = renderRule(w, opt, pe);
5716                     if (subRule.hasPosition() || subRule.hasGeometry() || subRule.hasBox()) {
5717                         const QStyleSheetPositionData *pos = subRule.position();
5718                         QRect originRect = grooveRect;
5719                         if (rule.hasBox()) {
5720                             Origin origin = (pos && pos->origin != Origin_Unknown) ? pos->origin : defaultOrigin(pe);
5721                             originRect = rule.originRect(opt->rect, origin);
5722                         }
5723                         return positionRect(w, subRule, pe, originRect, styleOptionSlider.direction);
5724                     }
5725                 }
5726             }
5727             return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &styleOptionSlider, sc, w)
5728                                            : QWindowsStyle::subControlRect(cc, &styleOptionSlider, sc, w);
5729         }
5730         break;
5731 #endif // QT_CONFIG(scrollbar)
5732 
5733 #if QT_CONFIG(slider)
5734     case CC_Slider:
5735         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5736             QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderGroove);
5737             if (!subRule.hasDrawable())
5738                 break;
5739             subRule.img = nullptr;
5740             QRect gr = positionRect(w, rule, subRule, PseudoElement_SliderGroove, opt->rect, opt->direction);
5741             switch (sc) {
5742             case SC_SliderGroove:
5743                 return gr;
5744             case SC_SliderHandle: {
5745                 bool horizontal = slider->orientation & Qt::Horizontal;
5746                 QRect cr = subRule.contentsRect(gr);
5747                 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderHandle);
5748                 int len = horizontal ? subRule2.size().width() : subRule2.size().height();
5749                 subRule2.img = nullptr;
5750                 subRule2.geo = nullptr;
5751                 cr = positionRect(w, subRule2, PseudoElement_SliderHandle, cr, opt->direction);
5752                 int thickness = horizontal ? cr.height() : cr.width();
5753                 int sliderPos = sliderPositionFromValue(slider->minimum, slider->maximum, slider->sliderPosition,
5754                                                         (horizontal ? cr.width() : cr.height()) - len, slider->upsideDown);
5755                 cr = horizontal ? QRect(cr.x() + sliderPos, cr.y(), len, thickness)
5756                                   : QRect(cr.x(), cr.y() + sliderPos, thickness, len);
5757                 return subRule2.borderRect(cr);
5758                 break; }
5759             case SC_SliderTickmarks:
5760                 // TODO...
5761             default:
5762                 break;
5763             }
5764         }
5765         break;
5766 #endif // QT_CONFIG(slider)
5767 
5768     case CC_MdiControls:
5769         if (hasStyleRule(w, PseudoElement_MdiCloseButton)
5770             || hasStyleRule(w, PseudoElement_MdiNormalButton)
5771             || hasStyleRule(w, PseudoElement_MdiMinButton)) {
5772             QList<QVariant> layout = rule.styleHint(QLatin1String("button-layout")).toList();
5773             if (layout.isEmpty())
5774                 layout = subControlLayout(QLatin1String("mNX"));
5775 
5776             int x = 0, width = 0;
5777             QRenderRule subRule;
5778             for (int i = 0; i < layout.count(); i++) {
5779                 int layoutButton = layout[i].toInt();
5780                 if (layoutButton < PseudoElement_MdiCloseButton
5781                     || layoutButton > PseudoElement_MdiNormalButton)
5782                     continue;
5783                 QStyle::SubControl control = knownPseudoElements[layoutButton].subControl;
5784                 if (!(opt->subControls & control))
5785                     continue;
5786                 subRule = renderRule(w, opt, layoutButton);
5787                 width = subRule.size().width();
5788                 if (sc == control)
5789                     break;
5790                 x += width;
5791             }
5792 
5793             return subRule.borderRect(QRect(x, opt->rect.top(), width, opt->rect.height()));
5794         }
5795         break;
5796 
5797     case CC_TitleBar:
5798         if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5799             QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
5800             if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
5801                 break;
5802             QHash<QStyle::SubControl, QRect> layoutRects = titleBarLayout(w, tb);
5803             return layoutRects.value(sc);
5804         }
5805         break;
5806 
5807     default:
5808         break;
5809     }
5810 
5811     return baseStyle()->subControlRect(cc, opt, sc, w);
5812 }
5813 
subElementRect(SubElement se,const QStyleOption * opt,const QWidget * w) const5814 QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, const QWidget *w) const
5815 {
5816     RECURSION_GUARD(return baseStyle()->subElementRect(se, opt, w))
5817 
5818     QRenderRule rule = renderRule(w, opt);
5819 #if QT_CONFIG(tabbar)
5820     int pe = PseudoElement_None;
5821 #endif
5822 
5823     switch (se) {
5824     case SE_PushButtonContents:
5825     case SE_PushButtonBevel:
5826     case SE_PushButtonFocusRect:
5827         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
5828             if (rule.hasBox() || !rule.hasNativeBorder()) {
5829                 return visualRect(opt->direction, opt->rect, se == SE_PushButtonBevel
5830                                                                 ? rule.borderRect(opt->rect)
5831                                                                 : rule.contentsRect(opt->rect));
5832             }
5833             return rule.baseStyleCanDraw() ? baseStyle()->subElementRect(se, btn, w)
5834                                            : QWindowsStyle::subElementRect(se, btn, w);
5835         }
5836         break;
5837 
5838     case SE_LineEditContents:
5839     case SE_FrameContents:
5840     case SE_ShapedFrameContents:
5841         if (rule.hasBox() || !rule.hasNativeBorder()) {
5842             return visualRect(opt->direction, opt->rect, rule.contentsRect(opt->rect));
5843         }
5844         break;
5845 
5846     case SE_CheckBoxIndicator:
5847     case SE_RadioButtonIndicator:
5848         if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5849             PseudoElement pe = se == SE_CheckBoxIndicator ? PseudoElement_Indicator : PseudoElement_ExclusiveIndicator;
5850             QRenderRule subRule = renderRule(w, opt, pe);
5851             return positionRect(w, rule, subRule, pe, opt->rect, opt->direction);
5852         }
5853         break;
5854 
5855     case SE_CheckBoxContents:
5856     case SE_RadioButtonContents:
5857         if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5858             bool isRadio = se == SE_RadioButtonContents;
5859             QRect ir = subElementRect(isRadio ? SE_RadioButtonIndicator : SE_CheckBoxIndicator,
5860                                       opt, w);
5861             ir = visualRect(opt->direction, opt->rect, ir);
5862             int spacing = pixelMetric(isRadio ? PM_RadioButtonLabelSpacing : PM_CheckBoxLabelSpacing, nullptr, w);
5863             QRect cr = rule.contentsRect(opt->rect);
5864             ir.setRect(ir.left() + ir.width() + spacing, cr.y(),
5865                        cr.width() - ir.width() - spacing, cr.height());
5866             return visualRect(opt->direction, opt->rect, ir);
5867         }
5868         break;
5869 
5870     case SE_ToolBoxTabContents:
5871         if (w && hasStyleRule(w->parentWidget(), PseudoElement_ToolBoxTab)) {
5872             QRenderRule subRule = renderRule(w->parentWidget(), opt, PseudoElement_ToolBoxTab);
5873             return visualRect(opt->direction, opt->rect, subRule.contentsRect(opt->rect));
5874         }
5875         break;
5876 
5877     case SE_RadioButtonFocusRect:
5878     case SE_RadioButtonClickRect: // focusrect | indicator
5879         if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5880             return opt->rect;
5881         }
5882         break;
5883 
5884     case SE_CheckBoxFocusRect:
5885     case SE_CheckBoxClickRect: // relies on indicator and contents
5886         return ParentStyle::subElementRect(se, opt, w);
5887 
5888 #if QT_CONFIG(itemviews)
5889     case SE_ItemViewItemCheckIndicator:
5890         if (!qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
5891             return subElementRect(SE_CheckBoxIndicator, opt, w);
5892         }
5893         Q_FALLTHROUGH();
5894     case SE_ItemViewItemText:
5895     case SE_ItemViewItemDecoration:
5896     case SE_ItemViewItemFocusRect:
5897         if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
5898             QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
5899             PseudoElement pe = PseudoElement_None;
5900             if (se == SE_ItemViewItemText || se == SE_ItemViewItemFocusRect)
5901                 pe = PseudoElement_ViewItemText;
5902             else if (se == SE_ItemViewItemDecoration && vopt->features & QStyleOptionViewItem::HasDecoration)
5903                 pe = PseudoElement_ViewItemIcon;
5904             else if (se == SE_ItemViewItemCheckIndicator && vopt->features & QStyleOptionViewItem::HasCheckIndicator)
5905                 pe = PseudoElement_ViewItemIndicator;
5906             else
5907                 break;
5908             if (subRule.hasGeometry() || subRule.hasBox() || !subRule.hasNativeBorder() || hasStyleRule(w, pe)) {
5909                 QRenderRule subRule2 = renderRule(w, opt, pe);
5910                 QStyleOptionViewItem optCopy(*vopt);
5911                 optCopy.rect = subRule.contentsRect(vopt->rect);
5912                 QRect rect = ParentStyle::subElementRect(se, &optCopy, w);
5913                 return positionRect(w, subRule2, pe, rect, opt->direction);
5914             }
5915          }
5916         break;
5917 #endif // QT_CONFIG(itemviews)
5918 
5919     case SE_HeaderArrow: {
5920         QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewUpArrow);
5921         if (subRule.hasPosition() || subRule.hasGeometry())
5922             return positionRect(w, rule, subRule, PseudoElement_HeaderViewUpArrow, opt->rect, opt->direction);
5923                          }
5924         break;
5925 
5926     case SE_HeaderLabel: {
5927         QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
5928         if (subRule.hasBox() || !subRule.hasNativeBorder())
5929             return subRule.contentsRect(opt->rect);
5930                          }
5931         break;
5932 
5933     case SE_ProgressBarGroove:
5934     case SE_ProgressBarContents:
5935     case SE_ProgressBarLabel:
5936         if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
5937             if (rule.hasBox() || !rule.hasNativeBorder() || rule.hasPosition() || hasStyleRule(w, PseudoElement_ProgressBarChunk)) {
5938                 if (se == SE_ProgressBarGroove)
5939                     return rule.borderRect(pb->rect);
5940                 else if (se == SE_ProgressBarContents)
5941                     return rule.contentsRect(pb->rect);
5942 
5943                 QSize sz = pb->fontMetrics.size(0, pb->text);
5944                 return QStyle::alignedRect(Qt::LeftToRight, rule.hasPosition() ? rule.position()->textAlignment : pb->textAlignment,
5945                                            sz, pb->rect);
5946             }
5947         }
5948         break;
5949 
5950 #if QT_CONFIG(tabbar)
5951     case SE_TabWidgetLeftCorner:
5952         pe = PseudoElement_TabWidgetLeftCorner;
5953         Q_FALLTHROUGH();
5954     case SE_TabWidgetRightCorner:
5955         if (pe == PseudoElement_None)
5956             pe = PseudoElement_TabWidgetRightCorner;
5957         Q_FALLTHROUGH();
5958     case SE_TabWidgetTabBar:
5959         if (pe == PseudoElement_None)
5960             pe = PseudoElement_TabWidgetTabBar;
5961         Q_FALLTHROUGH();
5962     case SE_TabWidgetTabPane:
5963     case SE_TabWidgetTabContents:
5964         if (pe == PseudoElement_None)
5965             pe = PseudoElement_TabWidgetPane;
5966 
5967         if (hasStyleRule(w, pe)) {
5968             QRect r = QWindowsStyle::subElementRect(pe == PseudoElement_TabWidgetPane ? SE_TabWidgetTabPane : se, opt, w);
5969             QRenderRule subRule = renderRule(w, opt, pe);
5970             r = positionRect(w, subRule, pe, r, opt->direction);
5971             if (pe == PseudoElement_TabWidgetTabBar) {
5972                 Q_ASSERT(opt);
5973                 r = opt->rect.intersected(r);
5974             }
5975             if (se == SE_TabWidgetTabContents)
5976                 r = subRule.contentsRect(r);
5977             return r;
5978         }
5979         break;
5980 
5981     case SE_TabBarScrollLeftButton:
5982     case SE_TabBarScrollRightButton:
5983         if (hasStyleRule(w, PseudoElement_TabBarScroller))
5984             return ParentStyle::subElementRect(se, opt, w);
5985         break;
5986 
5987     case SE_TabBarTearIndicator: {
5988         QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTear);
5989         if (subRule.hasContentsSize()) {
5990             QRect r;
5991             if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
5992                 switch (tab->shape) {
5993                 case QTabBar::RoundedNorth:
5994                 case QTabBar::TriangularNorth:
5995                 case QTabBar::RoundedSouth:
5996                 case QTabBar::TriangularSouth:
5997                     r.setRect(tab->rect.left(), tab->rect.top(), subRule.size().width(), opt->rect.height());
5998                     break;
5999                 case QTabBar::RoundedWest:
6000                 case QTabBar::TriangularWest:
6001                 case QTabBar::RoundedEast:
6002                 case QTabBar::TriangularEast:
6003                     r.setRect(tab->rect.left(), tab->rect.top(), opt->rect.width(), subRule.size().height());
6004                     break;
6005                 default:
6006                     break;
6007                 }
6008                 r = visualRect(opt->direction, opt->rect, r);
6009             }
6010             return r;
6011         }
6012         break;
6013     }
6014     case SE_TabBarTabText:
6015     case SE_TabBarTabLeftButton:
6016     case SE_TabBarTabRightButton: {
6017         QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
6018         if (subRule.hasBox() || !subRule.hasNativeBorder()) {
6019             if (se == SE_TabBarTabText) {
6020                 if (const QStyleOptionTabV4 *tab = qstyleoption_cast<const QStyleOptionTabV4 *>(opt)) {
6021                     const QTabBar *bar = qobject_cast<const QTabBar *>(w);
6022                     const QRect optRect = bar && tab->tabIndex != -1 ? bar->tabRect(tab->tabIndex) : opt->rect;
6023                     const QRect r = positionRect(w, subRule, PseudoElement_TabBarTab, optRect, opt->direction);
6024                     QStyleOptionTabV4 tabCopy(*tab);
6025                     tabCopy.rect = subRule.contentsRect(r);
6026                     return ParentStyle::subElementRect(se, &tabCopy, w);
6027                 }
6028             }
6029             return ParentStyle::subElementRect(se, opt, w);
6030         }
6031         break;
6032     }
6033 #endif // QT_CONFIG(tabbar)
6034 
6035     case SE_DockWidgetCloseButton:
6036     case SE_DockWidgetFloatButton: {
6037         PseudoElement pe = (se == SE_DockWidgetCloseButton) ? PseudoElement_DockWidgetCloseButton : PseudoElement_DockWidgetFloatButton;
6038         QRenderRule subRule2 = renderRule(w, opt, pe);
6039         if (!subRule2.hasPosition())
6040             break;
6041         QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
6042         return positionRect(w, subRule, subRule2, pe, opt->rect, opt->direction);
6043                                    }
6044 
6045 #if QT_CONFIG(toolbar)
6046     case SE_ToolBarHandle:
6047         if (hasStyleRule(w, PseudoElement_ToolBarHandle))
6048             return ParentStyle::subElementRect(se, opt, w);
6049         break;
6050 #endif // QT_CONFIG(toolbar)
6051 
6052     // On mac we make pixel adjustments to layouts which are not
6053     // desireable when you have custom style sheets on them
6054     case SE_CheckBoxLayoutItem:
6055     case SE_ComboBoxLayoutItem:
6056     case SE_DateTimeEditLayoutItem:
6057     case SE_LabelLayoutItem:
6058     case SE_ProgressBarLayoutItem:
6059     case SE_PushButtonLayoutItem:
6060     case SE_RadioButtonLayoutItem:
6061     case SE_SliderLayoutItem:
6062     case SE_SpinBoxLayoutItem:
6063     case SE_ToolButtonLayoutItem:
6064     case SE_FrameLayoutItem:
6065     case SE_GroupBoxLayoutItem:
6066     case SE_TabWidgetLayoutItem:
6067         if (!rule.hasNativeBorder())
6068             return opt->rect;
6069         break;
6070 
6071     default:
6072         break;
6073     }
6074 
6075     return baseStyle()->subElementRect(se, opt, w);
6076 }
6077 
event(QEvent * e)6078 bool QStyleSheetStyle::event(QEvent *e)
6079 {
6080     return (baseStyle()->event(e) && e->isAccepted()) || ParentStyle::event(e);
6081 }
6082 
updateStyleSheetFont(QWidget * w) const6083 void QStyleSheetStyle::updateStyleSheetFont(QWidget* w) const
6084 {
6085     // Qt's fontDialog relies on the font of the sample edit for its selection,
6086     // we should never override it.
6087     if (w->objectName() == QLatin1String("qt_fontDialog_sampleEdit"))
6088         return;
6089 
6090     QWidget *container = containerWidget(w);
6091     QRenderRule rule = renderRule(container, PseudoElement_None,
6092             PseudoClass_Active | PseudoClass_Enabled | extendedPseudoClass(container));
6093 
6094     const bool useStyleSheetPropagationInWidgetStyles =
6095         QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles);
6096 
6097     if (useStyleSheetPropagationInWidgetStyles) {
6098         unsetStyleSheetFont(w);
6099 
6100         if (rule.font.resolve()) {
6101             QFont wf = w->d_func()->localFont();
6102             styleSheetCaches->customFontWidgets.insert(w, {wf, rule.font.resolve()});
6103 
6104             QFont font = rule.font.resolve(wf);
6105             font.resolve(wf.resolve() | rule.font.resolve());
6106             w->setFont(font);
6107         }
6108     } else {
6109         QFont wf = w->d_func()->localFont();
6110         QFont font = rule.font.resolve(wf);
6111         font.resolve(wf.resolve() | rule.font.resolve());
6112 
6113         if ((!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
6114             && isNaturalChild(w) && qobject_cast<QWidget *>(w->parent())) {
6115 
6116             font = font.resolve(static_cast<QWidget *>(w->parent())->font());
6117         }
6118 
6119         if (wf.resolve() == font.resolve() && wf == font)
6120             return;
6121 
6122         w->data->fnt = font;
6123         w->d_func()->directFontResolveMask = font.resolve();
6124 
6125         QEvent e(QEvent::FontChange);
6126         QCoreApplication::sendEvent(w, &e);
6127     }
6128 }
6129 
saveWidgetFont(QWidget * w,const QFont & font) const6130 void QStyleSheetStyle::saveWidgetFont(QWidget* w, const QFont& font) const
6131 {
6132     w->setProperty("_q_styleSheetWidgetFont", font);
6133 }
6134 
clearWidgetFont(QWidget * w) const6135 void QStyleSheetStyle::clearWidgetFont(QWidget* w) const
6136 {
6137     w->setProperty("_q_styleSheetWidgetFont", QVariant());
6138 }
6139 
6140 // Polish palette that should be used for a particular widget, with particular states
6141 // (eg. :focus, :hover, ...)
6142 // this is called by widgets that paint themself in their paint event
6143 // Returns \c true if there is a new palette in pal.
styleSheetPalette(const QWidget * w,const QStyleOption * opt,QPalette * pal)6144 bool QStyleSheetStyle::styleSheetPalette(const QWidget* w, const QStyleOption* opt, QPalette* pal)
6145 {
6146     if (!w || !opt || !pal)
6147         return false;
6148 
6149     RECURSION_GUARD(return false)
6150 
6151     w = containerWidget(w);
6152 
6153     QRenderRule rule = renderRule(w, PseudoElement_None, pseudoClass(opt->state) | extendedPseudoClass(w));
6154     if (!rule.hasPalette())
6155         return false;
6156 
6157     rule.configurePalette(pal, QPalette::NoRole, QPalette::NoRole);
6158     return true;
6159 }
6160 
resolveAlignment(Qt::LayoutDirection layDir,Qt::Alignment src)6161 Qt::Alignment QStyleSheetStyle::resolveAlignment(Qt::LayoutDirection layDir, Qt::Alignment src)
6162 {
6163     if (layDir == Qt::LeftToRight || src & Qt::AlignAbsolute)
6164         return src;
6165 
6166     if (src & Qt::AlignLeft) {
6167         src &= ~Qt::AlignLeft;
6168         src |= Qt::AlignRight;
6169     } else if (src & Qt::AlignRight) {
6170         src &= ~Qt::AlignRight;
6171         src |= Qt::AlignLeft;
6172     }
6173     src |= Qt::AlignAbsolute;
6174     return src;
6175 }
6176 
6177 // Returns whether the given QWidget has a "natural" parent, meaning that
6178 // the parent contains this child as part of its normal operation.
6179 // An example is the QTabBar inside a QTabWidget.
6180 // This does not mean that any QTabBar which is a child of QTabWidget will
6181 // match, only the one that was created by the QTabWidget initialization
6182 // (and hence has the correct object name).
isNaturalChild(const QObject * obj)6183 bool QStyleSheetStyle::isNaturalChild(const QObject *obj)
6184 {
6185     if (obj->objectName().startsWith(QLatin1String("qt_")))
6186         return true;
6187 
6188     return false;
6189 }
6190 
loadPixmap(const QString & fileName,const QObject * context)6191 QPixmap QStyleSheetStyle::loadPixmap(const QString &fileName, const QObject *context)
6192 {
6193     qreal ratio = -1.0;
6194     if (const QWidget *widget = qobject_cast<const QWidget *>(context)) {
6195         if (QScreen *screen = QApplication::screenAt(widget->mapToGlobal(QPoint(0, 0))))
6196             ratio = screen->devicePixelRatio();
6197     }
6198 
6199     if (ratio < 0) {
6200         if (const QApplication *app = qApp)
6201             ratio = app->devicePixelRatio();
6202         else
6203             ratio = 1.0;
6204     }
6205 
6206     qreal sourceDevicePixelRatio = 1.0;
6207     QString resolvedFileName = qt_findAtNxFile(fileName, ratio, &sourceDevicePixelRatio);
6208     QPixmap pixmap(resolvedFileName);
6209     pixmap.setDevicePixelRatio(sourceDevicePixelRatio);
6210     return pixmap;
6211 }
6212 
6213 QT_END_NAMESPACE
6214 
6215 #include "moc_qstylesheetstyle_p.cpp"
6216 
6217 #endif // QT_CONFIG(style_stylesheet)
6218