5225c3ac342b417180365584cd5089984536578b
[WebKit-https.git] / WebCore / platform / qt / RenderThemeQt.cpp
1 /*
2  * This file is part of the WebKit project.
3  *
4  * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
5  *               2006 Nikolas Zimmermann <zimmermann@kde.org>
6  *
7  * All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25
26 #include "config.h"
27
28 #include <QApplication>
29 #include <QColor>
30 #include <QDebug>
31 #include <QStyle>
32 #include <QWidget>
33 #include <QPainter>
34 #include <QStyleOptionButton>
35 #include <QStyleOptionFrameV2>
36
37 #include "Color.h"
38 #include "Document.h"
39 #include "RenderTheme.h"
40 #include "GraphicsContext.h"
41
42 namespace WebCore {
43
44 class RenderThemeQt : public RenderTheme
45 {
46 public:
47     RenderThemeQt() : RenderTheme() { }
48
49     // A method asking if the theme's controls actually care about redrawing when hovered.
50     virtual bool supportsHover(const RenderStyle*) const { return true; }
51     virtual bool supportsFocusRing(const RenderStyle* style) const { return false; }
52
53     virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
54     {
55         return paintButton(o, i, r);
56     }
57
58     virtual void setCheckboxSize(RenderStyle*) const;
59
60     virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
61     {
62         return paintButton(o, i, r);
63     }
64
65     virtual void setRadioSize(RenderStyle*) const;
66
67     virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
68     virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
69
70     virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
71     virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
72
73     virtual bool isControlStyled(const RenderStyle*, const BorderData&,
74                                  const BackgroundLayer&, const Color&) const;
75
76     virtual bool controlSupportsTints(const RenderObject*) const;
77
78     virtual void systemFont(int propId, FontDescription&) const;
79
80     // The platform selection color.
81     virtual Color platformActiveSelectionBackgroundColor() const;
82     virtual Color platformInactiveSelectionBackgroundColor() const;
83     virtual Color platformActiveSelectionForegroundColor() const;
84     virtual Color platformInactiveSelectionForegroundColor() const;
85
86     void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
87     bool paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
88 private:
89     void addIntrinsicMargins(RenderStyle*) const;
90     void close();
91
92     bool supportsFocus(EAppearance) const;
93
94     bool getStylePainterAndWidgetFromPaintInfo(const RenderObject::PaintInfo&, QStyle*&, QPainter*&, QWidget*&) const;
95     EAppearance applyTheme(QStyleOption&, RenderObject*) const;
96 };
97
98 RenderTheme* theme()
99 {
100     static RenderThemeQt rt;
101     return &rt;
102 }
103
104 bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border,
105                                      const BackgroundLayer& background, const Color& backgroundColor) const
106 {
107     if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance)
108         return style->border() != border;
109
110     return RenderTheme::isControlStyled(style, border, background, backgroundColor);
111 }
112
113 bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const
114 {
115     if (!isEnabled(o))
116         return false;
117
118     // Checkboxes only have tint when checked.
119     if (o->style()->appearance() == CheckboxAppearance)
120         return isChecked(o);
121
122     // For now assume other controls have tint if enabled.
123     return true;
124 }
125
126 void RenderThemeQt::systemFont(int propId, FontDescription& fontDescription) const
127 {
128     // no-op
129 }
130
131 void RenderThemeQt::addIntrinsicMargins(RenderStyle* style) const
132 {
133     // Cut out the intrinsic margins completely if we end up using a small font size
134     if (style->fontSize() < 11)
135         return;
136
137     // Intrinsic margin value.
138     const int m = 2;
139
140     // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
141     if (style->width().isIntrinsicOrAuto()) {
142         if (style->marginLeft().quirk())
143             style->setMarginLeft(Length(m, Fixed));
144
145         if (style->marginRight().quirk())
146             style->setMarginRight(Length(m, Fixed));
147     }
148
149     if (style->height().isAuto()) {
150         if (style->marginTop().quirk())
151             style->setMarginTop(Length(m, Fixed));
152
153         if (style->marginBottom().quirk())
154             style->setMarginBottom(Length(m, Fixed));
155     }
156 }
157
158 bool RenderThemeQt::getStylePainterAndWidgetFromPaintInfo(const RenderObject::PaintInfo& i, QStyle*& style, QPainter*& painter, QWidget*& widget) const
159 {
160     painter = (i.context ? static_cast<QPainter*>(i.context->platformContext()) : 0);
161     widget = (painter ? static_cast<QWidget*>(painter->device()) : 0);
162     style = (widget ? widget->style() : 0);
163
164     return (painter && widget && style);
165 }
166
167 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
168 {
169     // If the width and height are both specified, then we have nothing to do.
170     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
171         return;
172
173     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary for now.  It matches Firefox.
174     // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
175     // the higher DPI.  Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
176     // metrics.
177     if (style->width().isIntrinsicOrAuto())
178         style->setWidth(Length(13, Fixed));
179
180     if (style->height().isAuto())
181         style->setHeight(Length(13, Fixed));
182 }
183
184 void RenderThemeQt::setRadioSize(RenderStyle* style) const
185 {
186     // This is the same as checkboxes.
187     setCheckboxSize(style);
188 }
189
190 bool RenderThemeQt::supportsFocus(EAppearance appearance) const
191 {
192     switch (appearance) {
193         case PushButtonAppearance:
194         case ButtonAppearance:
195         case TextFieldAppearance:
196             return true;
197         default: // No for all others...
198             return false;
199     }
200 }
201
202 EAppearance RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) const
203 {
204     // Default bits: no focus, no mouse over
205     option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
206
207     if (!isEnabled(o))
208         option.state &= ~QStyle::State_Enabled;
209
210     if (isReadOnlyControl(o))
211         // Readonly is supported on textfields.
212         option.state |= QStyle::State_ReadOnly;
213
214     if (supportsFocus(o->style()->appearance()) && isFocused(o))
215         option.state |= QStyle::State_HasFocus;
216
217     if (isHovered(o))
218         option.state |= QStyle::State_MouseOver;
219
220     if (isPressed(o))
221         option.state |= QStyle::State_Sunken;
222
223     EAppearance result = o->style()->appearance();
224     if(result == RadioAppearance || result == CheckboxAppearance)
225         option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off);
226
227     return result;
228 }
229
230 void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
231 {
232     addIntrinsicMargins(style);
233 }
234
235 void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
236 {
237     addIntrinsicMargins(style);
238 }
239
240 bool RenderThemeQt::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
241 {
242     QStyle* style = 0;
243     QPainter* painter = 0;
244     QWidget* widget = 0;
245
246     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
247         return true;
248
249     QStyleOptionButton option;
250     option.initFrom(widget);
251     option.rect = r;
252
253     // Get the correct theme data for a button
254     EAppearance appearance = applyTheme(option, o);
255
256     if(appearance == PushButtonAppearance || appearance == ButtonAppearance)
257         style->drawControl(QStyle::CE_PushButton, &option, painter);
258     else if(appearance == RadioAppearance)
259         style->drawControl(QStyle::CE_RadioButton, &option, painter);
260     else if(appearance == CheckboxAppearance)
261         style->drawControl(QStyle::CE_CheckBox, &option, painter);
262
263     return false;
264 }
265
266 void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
267 {
268     addIntrinsicMargins(style);
269 }
270
271 bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
272 {
273     QStyle* style = 0;
274     QPainter* painter = 0;
275     QWidget* widget = 0;
276
277     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
278         return true;
279
280     QStyleOptionFrameV2 panel;
281     panel.initFrom(widget);
282     panel.rect = r;
283     // Get the correct theme data for a button
284     EAppearance appearance = applyTheme(panel, o);
285     Q_ASSERT(appearance == TextFieldAppearance);
286
287     // Now paint the text field.
288     style->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, painter, widget);
289     style->drawPrimitive(QStyle::PE_FrameLineEdit, &panel, painter, widget);
290
291     return false;
292 }
293
294 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
295 {
296     QPalette pal = QApplication::palette();
297     return pal.brush(QPalette::Active, QPalette::Highlight).color();
298 }
299
300 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
301 {
302     QPalette pal = QApplication::palette();
303     return pal.brush(QPalette::Inactive, QPalette::Highlight).color();
304 }
305
306 Color RenderThemeQt::platformActiveSelectionForegroundColor() const
307 {
308     QPalette pal = QApplication::palette();
309     return pal.brush(QPalette::Active, QPalette::HighlightedText).color();
310 }
311
312 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
313 {
314     QPalette pal = QApplication::palette();
315     return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color();
316 }
317
318 bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
319 {
320     QStyle* style = 0;
321     QPainter* painter = 0;
322     QWidget* widget = 0;
323
324     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
325         return true;
326
327     QStyleOptionComboBox opt;
328     opt.initFrom(widget);
329     opt.rect = r;
330     style->drawComplexControl(QStyle::CC_ComboBox, &opt, painter, widget);
331     return false;
332 }
333
334 }
335
336 // vim: ts=4 sw=4 et