Remove unneeded hack
[WebKit-https.git] / WebCore / platform / qt / RenderThemeQt.cpp
1 /*
2  * This file is part of the WebKit project.
3  *
4  * Copyright (C) 2006 Zack Rusin <zack@kde.org>
5  *               2006 Dirk Mueller <mueller@kde.org>
6  *               2006 Nikolas Zimmermann <zimmermann@kde.org>
7  *
8  * All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  */
26
27 #include "config.h"
28
29 #include "RenderThemeQt.h"
30
31 #include <QApplication>
32 #include <QColor>
33 #include <QDebug>
34 #include <QStyle>
35 #include <QWidget>
36 #include <QPainter>
37 #include <QStyleOptionButton>
38 #include <QStyleOptionFrameV2>
39
40 #include "Color.h"
41 #include "Document.h"
42 #include "Font.h"
43 #include "RenderTheme.h"
44 #include "GraphicsContext.h"
45
46 namespace WebCore {
47
48 RenderTheme* theme()
49 {
50     static RenderThemeQt rt;
51     return &rt;
52 }
53
54 RenderThemeQt::RenderThemeQt()
55     : RenderTheme()
56 {
57 }
58
59 bool RenderThemeQt::supportsHover(const RenderStyle*) const
60 {
61     return true;
62 }
63
64 bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const
65 {
66     return true;
67 }
68
69 short RenderThemeQt::baselinePosition(const RenderObject* o) const
70 {
71     if (o->style()->appearance() == CheckboxAppearance ||
72         o->style()->appearance() == RadioAppearance)
73         return o->marginTop() + o->height() - 2; // Same as in old khtml
74     return RenderTheme::baselinePosition(o);
75 }
76
77 bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const
78 {
79     if (!isEnabled(o))
80         return false;
81
82     // Checkboxes only have tint when checked.
83     if (o->style()->appearance() == CheckboxAppearance)
84         return isChecked(o);
85
86     // For now assume other controls have tint if enabled.
87     return true;
88 }
89
90 bool RenderThemeQt::supportsControlTints() const
91 {
92     return true;
93 }
94
95 void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& r)
96 {
97     switch (o->style()->appearance()) {
98     case CheckboxAppearance: {
99         break;
100     }
101     case RadioAppearance: {
102         break;
103     }
104     case PushButtonAppearance:
105     case ButtonAppearance: {
106         break;
107     }
108     case MenulistAppearance: {
109         break;
110     }
111     default:
112         break;
113     }
114 }
115
116 bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border,
117                                      const BackgroundLayer& background, const Color& backgroundColor) const
118 {
119     if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance)
120         return style->border() != border;
121
122     return RenderTheme::isControlStyled(style, border, background, backgroundColor);
123 }
124
125 void RenderThemeQt::paintResizeControl(GraphicsContext*, const IntRect&)
126 {
127 }
128
129
130 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
131 {
132     QPalette pal = QApplication::palette();
133     return pal.brush(QPalette::Active, QPalette::Highlight).color();
134 }
135
136 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
137 {
138     QPalette pal = QApplication::palette();
139     return pal.brush(QPalette::Inactive, QPalette::Highlight).color();
140 }
141
142 Color RenderThemeQt::platformActiveSelectionForegroundColor() const
143 {
144     QPalette pal = QApplication::palette();
145     return pal.brush(QPalette::Active, QPalette::HighlightedText).color();
146 }
147
148 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
149 {
150     QPalette pal = QApplication::palette();
151     return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color();
152 }
153
154 void RenderThemeQt::systemFont(int propId, FontDescription& fontDescription) const
155 {
156     // no-op
157 }
158
159 int RenderThemeQt::minimumMenuListSize(RenderStyle*) const
160 {
161     const QFontMetrics &fm = QApplication::fontMetrics();
162     return 7 * fm.width(QLatin1Char('x'));
163 }
164
165 void RenderThemeQt::adjustSliderThumbSize(RenderObject* o) const
166 {
167     RenderTheme::adjustSliderThumbSize(o);
168 }
169
170 bool RenderThemeQt::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
171 {
172     return paintButton(o, i, r);
173 }
174
175 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
176 {
177     // If the width and height are both specified, then we have nothing to do.
178     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
179         return;
180
181     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary for now.  It matches Firefox.
182     // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
183     // the higher DPI.  Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
184     // metrics.
185     const int ff = 13;
186     if (style->width().isIntrinsicOrAuto())
187         style->setWidth(Length(ff, Fixed));
188
189     if (style->height().isAuto())
190         style->setHeight(Length(ff, Fixed));
191 }
192
193 bool RenderThemeQt::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
194 {
195     return paintButton(o, i, r);
196 }
197
198 void RenderThemeQt::setRadioSize(RenderStyle* style) const
199 {
200     // This is the same as checkboxes.
201     setCheckboxSize(style);
202 }
203
204 void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
205 {
206     // Ditch the border.
207     style->resetBorder();
208
209     // Height is locked to auto.
210     style->setHeight(Length(Auto));
211
212     // White-space is locked to pre
213     style->setWhiteSpace(PRE);
214
215     setButtonSize(style);
216
217     setButtonPadding(style);
218 }
219
220 bool RenderThemeQt::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
221 {
222     QStyle* style = 0;
223     QPainter* painter = 0;
224     QWidget* widget = 0;
225
226     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
227         return true;
228
229     QStyleOptionButton option;
230     option.initFrom(widget);
231     option.rect = r;
232
233     // Get the correct theme data for a button
234     EAppearance appearance = applyTheme(option, o);
235
236     if(appearance == PushButtonAppearance || appearance == ButtonAppearance)
237         style->drawControl(QStyle::CE_PushButton, &option, painter);
238     else if(appearance == RadioAppearance)
239         style->drawControl(QStyle::CE_RadioButton, &option, painter);
240     else if(appearance == CheckboxAppearance)
241         style->drawControl(QStyle::CE_CheckBox, &option, painter);
242
243     return false;
244 }
245
246 void RenderThemeQt::setButtonSize(RenderStyle* style) const
247 {
248     setPrimitiveSize(style);
249 }
250
251 bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
252 {
253     QStyle* style = 0;
254     QPainter* painter = 0;
255     QWidget* widget = 0;
256
257     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
258         return true;
259
260     QStyleOptionFrameV2 panel;
261     panel.initFrom(widget);
262     panel.rect = r;
263     // Get the correct theme data for a button
264     EAppearance appearance = applyTheme(panel, o);
265     Q_ASSERT(appearance == TextFieldAppearance);
266
267     // Now paint the text field.
268     style->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, painter, widget);
269     style->drawPrimitive(QStyle::PE_FrameLineEdit, &panel, painter, widget);
270
271     return false;
272 }
273
274 void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
275 {
276 }
277
278 void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
279 {
280     style->resetBorder();
281
282     // Height is locked to auto.
283     style->setHeight(Length(Auto));
284
285     // White-space is locked to pre
286     style->setWhiteSpace(PRE);
287
288     setPrimitiveSize(style);
289
290     // Add in the padding that we'd like to use.
291     setPopupPadding(style);
292
293     // Our font is locked to the appropriate system font size for the control.  To clarify, we first use the CSS-specified font to figure out
294     // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
295     // system font for the control size instead.
296     //setFontFromControlSize(selector, style);
297 }
298
299 bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
300 {
301     QStyle* style = 0;
302     QPainter* painter = 0;
303     QWidget* widget = 0;
304
305     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
306         return true;
307
308     QStyleOptionComboBox opt;
309     opt.initFrom(widget);
310     opt.rect = r;
311     opt.frame = false;
312
313     style->drawComplexControl(QStyle::CC_ComboBox, &opt, painter, widget);
314     return false;
315 }
316
317
318 bool RenderThemeQt::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& pi,
319                                         const IntRect& r)
320 {
321     return RenderTheme::paintMenuListButton(o, pi, r);
322 }
323
324 void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style,
325                                               Element* e) const
326 {
327     RenderTheme::adjustMenuListButtonStyle(selector, style, e);
328 }
329
330 bool RenderThemeQt::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& pi,
331                                      const IntRect& r)
332 {
333     return RenderTheme::paintSliderTrack(o, pi, r);
334 }
335
336 bool RenderThemeQt::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& pi,
337                                      const IntRect& r)
338 {
339     return RenderTheme::paintSliderThumb(o, pi, r);
340 }
341
342 bool RenderThemeQt::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& pi,
343                                      const IntRect& r)
344 {
345     return RenderTheme::paintSearchField(o, pi, r);
346 }
347
348 void RenderThemeQt::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style,
349                                            Element* e) const
350 {
351     RenderTheme::adjustSearchFieldStyle(selector, style, e);
352 }
353
354 void RenderThemeQt::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style,
355                                                        Element* e) const
356 {
357     RenderTheme::adjustSearchFieldCancelButtonStyle(selector, style, e);
358 }
359
360 bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& pi,
361                                                  const IntRect& r)
362 {
363     return RenderTheme::paintSearchFieldCancelButton(o, pi, r);
364 }
365
366 void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
367                                                      Element* e) const
368 {
369     RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e);
370 }
371
372 bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& pi,
373                                                const IntRect& r)
374 {
375     return RenderTheme::paintSearchFieldDecoration(o, pi, r);
376 }
377
378 void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
379                                                             Element* e) const
380 {
381     RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e);
382 }
383
384 bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& pi,
385                                                       const IntRect& r)
386 {
387     return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r);
388 }
389
390 bool RenderThemeQt::supportsFocus(EAppearance appearance) const
391 {
392     switch (appearance) {
393         case PushButtonAppearance:
394         case ButtonAppearance:
395         case TextFieldAppearance:
396         case MenulistAppearance:
397             return true;
398         default: // No for all others...
399             return false;
400     }
401 }
402
403 bool RenderThemeQt::getStylePainterAndWidgetFromPaintInfo(const RenderObject::PaintInfo& i, QStyle*& style,
404                                                           QPainter*& painter, QWidget*& widget) const
405 {
406     painter = (i.context ? static_cast<QPainter*>(i.context->platformContext()) : 0);
407     widget = (painter ? static_cast<QWidget*>(painter->device()) : 0);
408     style = (widget ? widget->style() : 0);
409
410     return (painter && widget && style);
411 }
412
413 EAppearance RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) const
414 {
415     // Default bits: no focus, no mouse over
416     option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
417
418     if (!isEnabled(o))
419         option.state &= ~QStyle::State_Enabled;
420
421     if (isReadOnlyControl(o))
422         // Readonly is supported on textfields.
423         option.state |= QStyle::State_ReadOnly;
424
425     if (supportsFocus(o->style()->appearance()) && isFocused(o))
426         option.state |= QStyle::State_HasFocus;
427
428     if (isHovered(o))
429         option.state |= QStyle::State_MouseOver;
430
431     EAppearance result = o->style()->appearance();
432
433     if (isPressed(o))
434         option.state |= QStyle::State_Sunken;
435     else if (result == PushButtonAppearance)
436         option.state |= QStyle::State_Raised;
437
438     if(result == RadioAppearance || result == CheckboxAppearance)
439         option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off);
440
441     return result;
442 }
443
444 void RenderThemeQt::setSizeFromFont(RenderStyle* style) const
445 {
446     // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
447      IntSize size = sizeForFont(style);
448     if (style->width().isIntrinsicOrAuto() && size.width() > 0)
449         style->setWidth(Length(size.width(), Fixed));
450     if (style->height().isAuto() && size.height() > 0)
451         style->setHeight(Length(size.height(), Fixed));
452 }
453
454 IntSize RenderThemeQt::sizeForFont(RenderStyle* style) const
455 {
456     const QFontMetrics fm(style->font());
457     QSize size(0, 0);
458     switch (style->appearance()) {
459     case CheckboxAppearance: {
460         break;
461     }
462     case RadioAppearance: {
463         break;
464     }
465     case PushButtonAppearance:
466     case ButtonAppearance: {
467         QSize sz = fm.size(Qt::TextShowMnemonic, QString::fromLatin1("X"));
468         QStyleOptionButton opt;
469         sz = QApplication::style()->sizeFromContents(QStyle::CT_PushButton,
470                                                      &opt, sz, 0);
471         size.setHeight(sz.height());
472         break;
473     }
474     case MenulistAppearance: {
475         QSize sz;
476         sz.setHeight(qMax(fm.lineSpacing(), 14) + 2);
477         QStyleOptionComboBox opt;
478         sz = QApplication::style()->sizeFromContents(QStyle::CT_ComboBox,
479                                                      &opt, sz, 0);
480         size.setHeight(sz.height());
481         break;
482     }
483     case TextFieldAppearance: {
484         const int verticalMargin   = 1;
485         const int horizontalMargin = 2;
486         int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin;
487         int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin;
488         QStyleOptionFrameV2 opt;
489         opt.lineWidth = QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth,
490                                                            &opt, 0);
491         QSize sz = QApplication::style()->sizeFromContents(QStyle::CT_LineEdit,
492                                                            &opt,
493                                                            QSize(w, h).expandedTo(QApplication::globalStrut()),
494                                                            0);
495         size.setHeight(sz.height());
496         break;
497     }
498     default:
499         break;
500     }
501     return size;
502 }
503
504 void RenderThemeQt::setButtonPadding(RenderStyle* style) const
505 {
506     const int padding = 8;
507     style->setPaddingLeft(Length(padding, Fixed));
508     style->setPaddingRight(Length(padding, Fixed));
509     style->setPaddingTop(Length(0, Fixed));
510     style->setPaddingBottom(Length(0, Fixed));
511 }
512
513 void RenderThemeQt::setPopupPadding(RenderStyle* style) const
514 {
515     const int padding = 8;
516     style->setPaddingLeft(Length(padding, Fixed));
517     style->setPaddingRight(Length(padding, Fixed));
518     style->setPaddingTop(Length(1, Fixed));
519     style->setPaddingBottom(Length(0, Fixed));
520 }
521
522 void RenderThemeQt::setPrimitiveSize(RenderStyle* style) const
523 {
524     // If the width and height are both specified, then we have nothing to do.
525     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
526         return;
527
528     // Use the font size to determine the intrinsic width of the control.
529     setSizeFromFont(style);
530 }
531
532 }
533
534 // vim: ts=4 sw=4 et