RenderThemeQt.cpp revision 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00
1/*
2 * This file is part of the WebKit project.
3 *
4 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
5 *
6 * Copyright (C) 2006 Zack Rusin <zack@kde.org>
7 *               2006 Dirk Mueller <mueller@kde.org>
8 *               2006 Nikolas Zimmermann <zimmermann@kde.org>
9 * Copyright (C) 2008 Holger Hans Peter Freyther
10 *
11 * All rights reserved.
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 * Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB.  If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
27 *
28 */
29
30#include "config.h"
31#include "RenderThemeQt.h"
32
33#include "CSSStyleSelector.h"
34#include "CSSStyleSheet.h"
35#include "CSSValueKeywords.h"
36#include "Chrome.h"
37#include "ChromeClientQt.h"
38#include "Color.h"
39#include "Document.h"
40#include "Font.h"
41#include "FontSelector.h"
42#include "GraphicsContext.h"
43#include "HTMLInputElement.h"
44#include "HTMLMediaElement.h"
45#include "HTMLNames.h"
46#if USE(QT_MOBILE_THEME)
47#include "QtMobileWebStyle.h"
48#endif
49#if ENABLE(VIDEO)
50#include "MediaControlElements.h"
51#endif
52#include "NotImplemented.h"
53#include "PaintInfo.h"
54#include "Page.h"
55#include "QWebPageClient.h"
56#include "QtStyleOptionWebComboBox.h"
57#include "qwebsettings.h"
58#include "RenderBox.h"
59#if ENABLE(PROGRESS_TAG)
60#include "RenderProgress.h"
61#endif
62#include "RenderSlider.h"
63#include "RenderTheme.h"
64#include "ScrollbarThemeQt.h"
65#include "TimeRanges.h"
66#include "UserAgentStyleSheets.h"
67
68#include <QApplication>
69#include <QColor>
70#include <QFile>
71#include <QLineEdit>
72#include <QMacStyle>
73#include <QPainter>
74#include <QPushButton>
75#include <QStyleFactory>
76#include <QStyleOptionButton>
77#include <QStyleOptionFrameV2>
78#if ENABLE(PROGRESS_TAG)
79#include <QStyleOptionProgressBarV2>
80#endif
81#include <QStyleOptionSlider>
82#include <QWidget>
83
84namespace WebCore {
85
86using namespace HTMLNames;
87
88inline static void initStyleOption(QWidget *widget, QStyleOption& option)
89{
90    if (widget)
91        option.initFrom(widget);
92    else {
93        /*
94          If a widget is not directly available for rendering, we fallback to default
95          value for an active widget.
96         */
97        option.state = QStyle::State_Active | QStyle::State_Enabled;
98    }
99}
100// These values all match Safari/Win/Chromium
101static const float defaultControlFontPixelSize = 13;
102static const float defaultCancelButtonSize = 9;
103static const float minCancelButtonSize = 5;
104static const float maxCancelButtonSize = 21;
105static const float defaultSearchFieldResultsDecorationSize = 13;
106static const float minSearchFieldResultsDecorationSize = 9;
107static const float maxSearchFieldResultsDecorationSize = 30;
108static const float defaultSearchFieldResultsButtonWidth = 18;
109
110#if USE(QT_MOBILE_THEME)
111namespace {
112    float buttonPaddingLeft = 18;
113    float buttonPaddingRight = 18;
114    float buttonPaddingTop = 2;
115    float buttonPaddingBottom = 3;
116    float menuListPadding = 9;
117    float textFieldPadding = 5;
118}
119#endif
120
121StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo)
122{
123    init(paintInfo.context ? paintInfo.context : 0, theme->qStyle());
124}
125
126StylePainter::StylePainter(ScrollbarThemeQt* theme, GraphicsContext* context)
127{
128    init(context, theme->style());
129}
130
131void StylePainter::init(GraphicsContext* context, QStyle* themeStyle)
132{
133    painter = static_cast<QPainter*>(context->platformContext());
134    widget = 0;
135    QPaintDevice* dev = 0;
136    if (painter)
137        dev = painter->device();
138    if (dev && dev->devType() == QInternal::Widget)
139        widget = static_cast<QWidget*>(dev);
140    style = themeStyle;
141
142    if (painter) {
143        // the styles often assume being called with a pristine painter where no brush is set,
144        // so reset it manually
145        oldBrush = painter->brush();
146        painter->setBrush(Qt::NoBrush);
147
148        // painting the widget with anti-aliasing will make it blurry
149        // disable it here and restore it later
150        oldAntialiasing = painter->testRenderHint(QPainter::Antialiasing);
151        painter->setRenderHint(QPainter::Antialiasing, false);
152    }
153}
154
155StylePainter::~StylePainter()
156{
157    if (painter) {
158        painter->setBrush(oldBrush);
159        painter->setRenderHints(QPainter::Antialiasing, oldAntialiasing);
160    }
161}
162
163PassRefPtr<RenderTheme> RenderThemeQt::create(Page* page)
164{
165    return adoptRef(new RenderThemeQt(page));
166}
167
168PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
169{
170    if (page)
171        return RenderThemeQt::create(page);
172
173    static RenderTheme* fallback = RenderThemeQt::create(0).releaseRef();
174    return fallback;
175}
176
177RenderThemeQt::RenderThemeQt(Page* page)
178    : RenderTheme()
179    , m_page(page)
180    , m_lineEdit(0)
181{
182    QPushButton button;
183    button.setAttribute(Qt::WA_MacSmallSize);
184    QFont defaultButtonFont = QApplication::font(&button);
185    QFontInfo fontInfo(defaultButtonFont);
186    m_buttonFontFamily = defaultButtonFont.family();
187#ifdef Q_WS_MAC
188    m_buttonFontPixelSize = fontInfo.pixelSize();
189#endif
190
191#if USE(QT_MOBILE_THEME)
192    m_fallbackStyle = new QtMobileWebStyle;
193#else
194    m_fallbackStyle = QStyleFactory::create(QLatin1String("windows"));
195#endif
196}
197
198RenderThemeQt::~RenderThemeQt()
199{
200    delete m_fallbackStyle;
201#ifndef QT_NO_LINEEDIT
202    delete m_lineEdit;
203#endif
204}
205
206#if USE(QT_MOBILE_THEME)
207bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& fill, const Color& backgroundColor) const
208{
209    switch (style->appearance()) {
210    case PushButtonPart:
211    case ButtonPart:
212    case MenulistPart:
213    case SearchFieldPart:
214    case TextFieldPart:
215    case TextAreaPart:
216        // Test the style to see if the UA border and background match.
217        return (style->border() != border
218                || *style->backgroundLayers() != fill
219                || style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor);
220    case CheckboxPart:
221    case RadioPart:
222        return false;
223    default:
224        return RenderTheme::isControlStyled(style, border, fill, backgroundColor);
225    }
226}
227
228int RenderThemeQt::popupInternalPaddingBottom(RenderStyle* style) const
229{
230    return 1;
231}
232#else
233// Remove this when SearchFieldPart is style-able in RenderTheme::isControlStyled()
234bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& fill, const Color& backgroundColor) const
235{
236    switch (style->appearance()) {
237    case SearchFieldPart:
238        // Test the style to see if the UA border and background match.
239        return (style->border() != border
240                || *style->backgroundLayers() != fill
241                || style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor);
242    default:
243        return RenderTheme::isControlStyled(style, border, fill, backgroundColor);
244    }
245}
246#endif
247
248// for some widget painting, we need to fallback to Windows style
249QStyle* RenderThemeQt::fallbackStyle() const
250{
251    return (m_fallbackStyle) ? m_fallbackStyle : QApplication::style();
252}
253
254QStyle* RenderThemeQt::qStyle() const
255{
256#if USE(QT_MOBILE_THEME)
257    return fallbackStyle();
258#endif
259
260    if (m_page) {
261        QWebPageClient* pageClient = m_page->chrome()->client()->platformPageClient();
262
263        if (pageClient)
264            return pageClient->style();
265    }
266
267    return QApplication::style();
268}
269
270String RenderThemeQt::extraDefaultStyleSheet()
271{
272    String result = RenderTheme::extraDefaultStyleSheet();
273#if ENABLE(NO_LISTBOX_RENDERING)
274    result += String(themeQtNoListboxesUserAgentStyleSheet, sizeof(themeQtNoListboxesUserAgentStyleSheet));
275#endif
276    return result;
277}
278
279bool RenderThemeQt::supportsHover(const RenderStyle*) const
280{
281    return true;
282}
283
284bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const
285{
286    switch (style->appearance()) {
287    case CheckboxPart:
288    case RadioPart:
289    case PushButtonPart:
290    case SquareButtonPart:
291    case ButtonPart:
292    case ButtonBevelPart:
293    case ListboxPart:
294    case ListItemPart:
295    case MenulistPart:
296    case MenulistButtonPart:
297    case SliderHorizontalPart:
298    case SliderVerticalPart:
299    case SliderThumbHorizontalPart:
300    case SliderThumbVerticalPart:
301    case SearchFieldPart:
302    case SearchFieldResultsButtonPart:
303    case SearchFieldCancelButtonPart:
304    case TextFieldPart:
305    case TextAreaPart:
306        return true;
307    default:
308        return false;
309    }
310}
311
312int RenderThemeQt::baselinePosition(const RenderObject* o) const
313{
314    if (!o->isBox())
315        return 0;
316
317    if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart)
318        return toRenderBox(o)->marginTop() + toRenderBox(o)->height() - 2; // Same as in old khtml
319    return RenderTheme::baselinePosition(o);
320}
321
322bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const
323{
324    if (!isEnabled(o))
325        return false;
326
327    // Checkboxes only have tint when checked.
328    if (o->style()->appearance() == CheckboxPart)
329        return isChecked(o);
330
331    // For now assume other controls have tint if enabled.
332    return true;
333}
334
335bool RenderThemeQt::supportsControlTints() const
336{
337    return true;
338}
339
340int RenderThemeQt::findFrameLineWidth(QStyle* style) const
341{
342#ifndef QT_NO_LINEEDIT
343    if (!m_lineEdit)
344        m_lineEdit = new QLineEdit();
345#endif
346
347    QStyleOptionFrameV2 opt;
348    QWidget* widget = 0;
349#ifndef QT_NO_LINEEDIT
350    widget = m_lineEdit;
351#endif
352    return style->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, widget);
353}
354
355static QRect inflateButtonRect(const QRect& originalRect, QStyle* style)
356{
357    QStyleOptionButton option;
358    option.state |= QStyle::State_Small;
359    option.rect = originalRect;
360
361    QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem, &option, 0);
362    if (!layoutRect.isNull()) {
363        int paddingLeft = layoutRect.left() - originalRect.left();
364        int paddingRight = originalRect.right() - layoutRect.right();
365        int paddingTop = layoutRect.top() - originalRect.top();
366        int paddingBottom = originalRect.bottom() - layoutRect.bottom();
367
368        return originalRect.adjusted(-paddingLeft, -paddingTop, paddingRight, paddingBottom);
369    }
370    return originalRect;
371}
372
373void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& rect)
374{
375    switch (o->style()->appearance()) {
376    case CheckboxPart:
377        break;
378    case RadioPart:
379        break;
380    case PushButtonPart:
381    case ButtonPart: {
382        QRect inflatedRect = inflateButtonRect(rect, qStyle());
383        rect = IntRect(inflatedRect.x(), inflatedRect.y(), inflatedRect.width(), inflatedRect.height());
384        break;
385    }
386    case MenulistPart:
387        break;
388    default:
389        break;
390    }
391}
392
393Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
394{
395    QPalette pal = QApplication::palette();
396    setPaletteFromPageClientIfExists(pal);
397    return pal.brush(QPalette::Active, QPalette::Highlight).color();
398}
399
400Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
401{
402    QPalette pal = QApplication::palette();
403    setPaletteFromPageClientIfExists(pal);
404    return pal.brush(QPalette::Inactive, QPalette::Highlight).color();
405}
406
407Color RenderThemeQt::platformActiveSelectionForegroundColor() const
408{
409    QPalette pal = QApplication::palette();
410    setPaletteFromPageClientIfExists(pal);
411    return pal.brush(QPalette::Active, QPalette::HighlightedText).color();
412}
413
414Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
415{
416    QPalette pal = QApplication::palette();
417    setPaletteFromPageClientIfExists(pal);
418    return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color();
419}
420
421Color RenderThemeQt::platformFocusRingColor() const
422{
423    QPalette pal = QApplication::palette();
424    setPaletteFromPageClientIfExists(pal);
425    return pal.brush(QPalette::Active, QPalette::Highlight).color();
426}
427
428void RenderThemeQt::systemFont(int, FontDescription&) const
429{
430    // no-op
431}
432
433Color RenderThemeQt::systemColor(int cssValueId) const
434{
435    QPalette pal = QApplication::palette();
436    switch (cssValueId) {
437    case CSSValueButtontext:
438        return pal.brush(QPalette::Active, QPalette::ButtonText).color();
439    case CSSValueCaptiontext:
440        return pal.brush(QPalette::Active, QPalette::Text).color();
441    default:
442        return RenderTheme::systemColor(cssValueId);
443    }
444}
445
446int RenderThemeQt::minimumMenuListSize(RenderStyle*) const
447{
448    const QFontMetrics &fm = QApplication::fontMetrics();
449    return 7 * fm.width(QLatin1Char('x'));
450}
451
452void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const
453{
454    QSize size(0, 0);
455    const QFontMetrics fm(renderStyle->font().font());
456    QStyle* style = qStyle();
457
458    switch (renderStyle->appearance()) {
459    case TextAreaPart:
460    case SearchFieldPart:
461    case TextFieldPart: {
462        int padding = findFrameLineWidth(style);
463        renderStyle->setPaddingLeft(Length(padding, Fixed));
464        renderStyle->setPaddingRight(Length(padding, Fixed));
465        renderStyle->setPaddingTop(Length(padding, Fixed));
466        renderStyle->setPaddingBottom(Length(padding, Fixed));
467        break;
468    }
469    default:
470        break;
471    }
472    // If the width and height are both specified, then we have nothing to do.
473    if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto())
474        return;
475
476    switch (renderStyle->appearance()) {
477    case CheckboxPart: {
478        QStyleOption styleOption;
479        styleOption.state |= QStyle::State_Small;
480        int checkBoxWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &styleOption);
481        checkBoxWidth *= renderStyle->effectiveZoom();
482        size = QSize(checkBoxWidth, checkBoxWidth);
483        break;
484    }
485    case RadioPart: {
486        QStyleOption styleOption;
487        styleOption.state |= QStyle::State_Small;
488        int radioWidth = style->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, &styleOption);
489        radioWidth *= renderStyle->effectiveZoom();
490        size = QSize(radioWidth, radioWidth);
491        break;
492    }
493#if !USE(QT_MOBILE_THEME)
494    case PushButtonPart:
495    case ButtonPart: {
496        QStyleOptionButton styleOption;
497        styleOption.state |= QStyle::State_Small;
498        QSize contentSize = fm.size(Qt::TextShowMnemonic, QString::fromLatin1("X"));
499        QSize pushButtonSize = style->sizeFromContents(QStyle::CT_PushButton,
500                                                       &styleOption, contentSize, 0);
501        styleOption.rect = QRect(0, 0, pushButtonSize.width(), pushButtonSize.height());
502        QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem,
503                                                 &styleOption, 0);
504
505        // If the style supports layout rects we use that, and  compensate accordingly
506        // in paintButton() below.
507        if (!layoutRect.isNull())
508            size.setHeight(layoutRect.height());
509        else
510            size.setHeight(pushButtonSize.height());
511
512        break;
513    }
514    case MenulistPart: {
515        QStyleOptionComboBox styleOption;
516        styleOption.state |= QStyle::State_Small;
517        int contentHeight = qMax(fm.lineSpacing(), 14) + 2;
518        QSize menuListSize = style->sizeFromContents(QStyle::CT_ComboBox,
519                                                     &styleOption, QSize(0, contentHeight), 0);
520        size.setHeight(menuListSize.height());
521        break;
522    }
523#endif
524    default:
525        break;
526    }
527
528    // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
529    if (renderStyle->width().isIntrinsicOrAuto() && size.width() > 0)
530        renderStyle->setWidth(Length(size.width(), Fixed));
531    if (renderStyle->height().isAuto() && size.height() > 0)
532        renderStyle->setHeight(Length(size.height(), Fixed));
533}
534
535void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
536{
537    computeSizeBasedOnStyle(style);
538}
539
540bool RenderThemeQt::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
541{
542    return paintButton(o, i, r);
543}
544
545void RenderThemeQt::setRadioSize(RenderStyle* style) const
546{
547    computeSizeBasedOnStyle(style);
548}
549
550bool RenderThemeQt::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
551{
552    return paintButton(o, i, r);
553}
554
555void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const
556{
557    // Ditch the border.
558    style->resetBorder();
559
560#ifdef Q_WS_MAC
561    if (style->appearance() == PushButtonPart) {
562        // The Mac ports ignore the specified height for <input type="button"> elements
563        // unless a border and/or background CSS property is also specified.
564        style->setHeight(Length(Auto));
565    }
566#endif
567
568    FontDescription fontDescription = style->fontDescription();
569    fontDescription.setIsAbsoluteSize(true);
570
571#ifdef Q_WS_MAC // Use fixed font size and family on Mac (like Safari does)
572    fontDescription.setSpecifiedSize(m_buttonFontPixelSize);
573    fontDescription.setComputedSize(m_buttonFontPixelSize);
574#else
575    fontDescription.setSpecifiedSize(style->fontSize());
576    fontDescription.setComputedSize(style->fontSize());
577#endif
578
579#if !USE(QT_MOBILE_THEME)
580    FontFamily fontFamily;
581    fontFamily.setFamily(m_buttonFontFamily);
582    fontDescription.setFamily(fontFamily);
583    style->setFontDescription(fontDescription);
584    style->font().update(selector->fontSelector());
585#endif
586    style->setLineHeight(RenderStyle::initialLineHeight());
587    setButtonSize(style);
588    setButtonPadding(style);
589}
590
591void RenderThemeQt::setButtonSize(RenderStyle* style) const
592{
593    computeSizeBasedOnStyle(style);
594}
595
596#if !USE(QT_MOBILE_THEME)
597void RenderThemeQt::setButtonPadding(RenderStyle* style) const
598{
599    QStyleOptionButton styleOption;
600    styleOption.state |= QStyle::State_Small;
601
602    // Fake a button rect here, since we're just computing deltas
603    QRect originalRect = QRect(0, 0, 100, 30);
604    styleOption.rect = originalRect;
605
606    // Default padding is based on the button margin pixel metric
607    int buttonMargin = qStyle()->pixelMetric(QStyle::PM_ButtonMargin, &styleOption, 0);
608    int paddingLeft = buttonMargin;
609    int paddingRight = buttonMargin;
610    int paddingTop = 1;
611    int paddingBottom = 0;
612
613    // Then check if the style uses layout margins
614    QRect layoutRect = qStyle()->subElementRect(QStyle::SE_PushButtonLayoutItem,
615                                                &styleOption, 0);
616    if (!layoutRect.isNull()) {
617        QRect contentsRect = qStyle()->subElementRect(QStyle::SE_PushButtonContents,
618                                                      &styleOption, 0);
619        paddingLeft = contentsRect.left() - layoutRect.left();
620        paddingRight = layoutRect.right() - contentsRect.right();
621        paddingTop = contentsRect.top() - layoutRect.top();
622
623        // Can't use this right now because we don't have the baseline to compensate
624        // paddingBottom = layoutRect.bottom() - contentsRect.bottom();
625    }
626    style->setPaddingLeft(Length(paddingLeft, Fixed));
627    style->setPaddingRight(Length(paddingRight, Fixed));
628    style->setPaddingTop(Length(paddingTop, Fixed));
629    style->setPaddingBottom(Length(paddingBottom, Fixed));
630}
631#else
632void RenderThemeQt::setButtonPadding(RenderStyle* style) const
633{
634    if (!style)
635        return;
636    style->setPaddingLeft(Length(buttonPaddingLeft, Fixed));
637    style->setPaddingRight(Length(buttonPaddingRight, Fixed));
638    style->setPaddingTop(Length(buttonPaddingTop, Fixed));
639    style->setPaddingBottom(Length(buttonPaddingBottom, Fixed));
640}
641#endif
642
643bool RenderThemeQt::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
644{
645    StylePainter p(this, i);
646    if (!p.isValid())
647       return true;
648
649    QStyleOptionButton option;
650    initStyleOption(p.widget, option);
651    option.rect = r;
652    option.state |= QStyle::State_Small;
653
654    ControlPart appearance = initializeCommonQStyleOptions(option, o);
655    if (appearance == PushButtonPart || appearance == ButtonPart) {
656        option.rect = inflateButtonRect(option.rect, qStyle());
657        p.drawControl(QStyle::CE_PushButton, option);
658    } else if (appearance == RadioPart)
659       p.drawControl(QStyle::CE_RadioButton, option);
660    else if (appearance == CheckboxPart)
661       p.drawControl(QStyle::CE_CheckBox, option);
662
663    return false;
664}
665
666void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
667{
668    // Resetting the style like this leads to differences like:
669    // - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)]
670    // + RenderTextControl {INPUT} at (2,2) size 166x26
671    // in layout tests when a CSS style is applied that doesn't affect background color, border or
672    // padding. Just worth keeping in mind!
673    style->setBackgroundColor(Color::transparent);
674    style->resetBorder();
675    style->resetPadding();
676    computeSizeBasedOnStyle(style);
677#if USE(QT_MOBILE_THEME)
678    style->setPaddingLeft(Length(textFieldPadding, Fixed));
679    style->setPaddingRight(Length(textFieldPadding, Fixed));
680#endif
681}
682
683bool RenderThemeQt::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
684{
685    StylePainter p(this, i);
686    if (!p.isValid())
687        return true;
688
689    QStyleOptionFrameV2 panel;
690    initStyleOption(p.widget, panel);
691    panel.rect = r;
692    panel.lineWidth = findFrameLineWidth(qStyle());
693#if USE(QT_MOBILE_THEME)
694    if (isPressed(o))
695        panel.state |= QStyle::State_Sunken;
696#else
697    panel.state |= QStyle::State_Sunken;
698#endif
699    panel.features = QStyleOptionFrameV2::None;
700
701    // Get the correct theme data for a text field
702    ControlPart appearance = initializeCommonQStyleOptions(panel, o);
703    if (appearance != TextFieldPart
704        && appearance != SearchFieldPart
705        && appearance != TextAreaPart
706        && appearance != ListboxPart)
707        return true;
708
709    // Now paint the text field.
710    p.drawPrimitive(QStyle::PE_PanelLineEdit, panel);
711    return false;
712}
713
714void RenderThemeQt::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
715{
716    adjustTextFieldStyle(selector, style, element);
717}
718
719bool RenderThemeQt::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
720{
721    return paintTextField(o, i, r);
722}
723
724void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
725{
726    style->resetBorder();
727
728    // Height is locked to auto.
729    style->setHeight(Length(Auto));
730
731    // White-space is locked to pre
732    style->setWhiteSpace(PRE);
733
734    computeSizeBasedOnStyle(style);
735
736    // Add in the padding that we'd like to use.
737    setPopupPadding(style);
738#if USE(QT_MOBILE_THEME)
739    style->setPaddingLeft(Length(menuListPadding, Fixed));
740#endif
741}
742
743void RenderThemeQt::setPopupPadding(RenderStyle* style) const
744{
745    const int paddingLeft = 4;
746    const int paddingRight = style->width().isFixed() || style->width().isPercent() ? 5 : 8;
747
748    style->setPaddingLeft(Length(paddingLeft, Fixed));
749
750    QStyleOptionComboBox opt;
751    int w = qStyle()->pixelMetric(QStyle::PM_ButtonIconSize, &opt, 0);
752    style->setPaddingRight(Length(paddingRight + w, Fixed));
753
754    style->setPaddingTop(Length(2, Fixed));
755    style->setPaddingBottom(Length(2, Fixed));
756}
757
758
759bool RenderThemeQt::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
760{
761    StylePainter p(this, i);
762    if (!p.isValid())
763        return true;
764
765    QtStyleOptionWebComboBox opt(o);
766    initStyleOption(p.widget, opt);
767    initializeCommonQStyleOptions(opt, o);
768
769    IntRect rect = r;
770
771#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
772    // QMacStyle makes the combo boxes a little bit smaller to leave space for the focus rect.
773    // Because of it, the combo button is drawn at a point to the left of where it was expect to be and may end up
774    // overlapped with the text. This will force QMacStyle to draw the combo box with the expected width.
775    if (qobject_cast<QMacStyle*>(p.style))
776        rect.inflateX(3);
777#endif
778
779    const QPoint topLeft = rect.location();
780    p.painter->translate(topLeft);
781    opt.rect.moveTo(QPoint(0, 0));
782    opt.rect.setSize(rect.size());
783
784    p.drawComplexControl(QStyle::CC_ComboBox, opt);
785    p.painter->translate(-topLeft);
786    return false;
787}
788
789void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
790{
791#if USE(QT_MOBILE_THEME)
792    // Mobile theme uses border radius.
793#else
794    // WORKAROUND because html.css specifies -webkit-border-radius for <select> so we override it here
795    // see also http://bugs.webkit.org/show_bug.cgi?id=18399
796    style->resetBorderRadius();
797#endif
798
799    // Height is locked to auto.
800    style->setHeight(Length(Auto));
801
802    // White-space is locked to pre
803    style->setWhiteSpace(PRE);
804
805    computeSizeBasedOnStyle(style);
806
807    // Add in the padding that we'd like to use.
808    setPopupPadding(style);
809}
810
811bool RenderThemeQt::paintMenuListButton(RenderObject* o, const PaintInfo& i,
812                                        const IntRect& r)
813{
814    StylePainter p(this, i);
815    if (!p.isValid())
816        return true;
817
818    QtStyleOptionWebComboBox option(o);
819    initStyleOption(p.widget, option);
820    initializeCommonQStyleOptions(option, o);
821    option.rect = r;
822
823    // for drawing the combo box arrow, rely only on the fallback style
824    p.style = fallbackStyle();
825    option.subControls = QStyle::SC_ComboBoxArrow;
826    p.drawComplexControl(QStyle::CC_ComboBox, option);
827
828    return false;
829}
830
831#if ENABLE(PROGRESS_TAG)
832double RenderThemeQt::animationRepeatIntervalForProgressBar(RenderProgress* renderProgress) const
833{
834    if (renderProgress->position() >= 0)
835        return 0;
836
837    // FIXME: Use hard-coded value until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed.
838    // Use the value from windows style which is 10 fps.
839    return 0.1;
840}
841
842double RenderThemeQt::animationDurationForProgressBar(RenderProgress* renderProgress) const
843{
844    if (renderProgress->position() >= 0)
845        return 0;
846
847    QStyleOptionProgressBarV2 option;
848    option.rect.setSize(renderProgress->size());
849    // FIXME: Until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed,
850    // we simulate one square animating across the progress bar.
851    return (option.rect.width() / qStyle()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option)) * animationRepeatIntervalForProgressBar(renderProgress);
852}
853
854void RenderThemeQt::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
855{
856    style->setBoxShadow(0);
857}
858
859bool RenderThemeQt::paintProgressBar(RenderObject* o, const PaintInfo& pi, const IntRect& r)
860{
861    if (!o->isProgress())
862        return true;
863
864    StylePainter p(this, pi);
865    if (!p.isValid())
866       return true;
867
868    QStyleOptionProgressBarV2 option;
869    initStyleOption(p.widget, option);
870    initializeCommonQStyleOptions(option, o);
871
872    RenderProgress* renderProgress = toRenderProgress(o);
873    option.rect = r;
874    option.maximum = std::numeric_limits<int>::max();
875    option.minimum = 0;
876    option.progress = (renderProgress->position() * std::numeric_limits<int>::max());
877
878    const QPoint topLeft = r.location();
879    p.painter->translate(topLeft);
880    option.rect.moveTo(QPoint(0, 0));
881    option.rect.setSize(r.size());
882
883    if (option.progress < 0) {
884        // FIXME: Until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed,
885        // we simulate one square animating across the progress bar.
886        p.drawControl(QStyle::CE_ProgressBarGroove, option);
887        int chunkWidth = qStyle()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option);
888        QColor color = (option.palette.highlight() == option.palette.background()) ? option.palette.color(QPalette::Active, QPalette::Highlight) : option.palette.color(QPalette::Highlight);
889        if (renderProgress->style()->direction() == RTL)
890            p.painter->fillRect(option.rect.right() - chunkWidth  - renderProgress->animationProgress() * option.rect.width(), 0, chunkWidth, option.rect.height(), color);
891        else
892            p.painter->fillRect(renderProgress->animationProgress() * option.rect.width(), 0, chunkWidth, option.rect.height(), color);
893    } else
894        p.drawControl(QStyle::CE_ProgressBar, option);
895
896    p.painter->translate(-topLeft);
897
898    return false;
899}
900#endif
901
902bool RenderThemeQt::paintSliderTrack(RenderObject* o, const PaintInfo& pi,
903                                     const IntRect& r)
904{
905    StylePainter p(this, pi);
906    if (!p.isValid())
907       return true;
908
909    QStyleOptionSlider option;
910    initStyleOption(p.widget, option);
911    option.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
912    ControlPart appearance = initializeCommonQStyleOptions(option, o);
913
914    RenderSlider* renderSlider = toRenderSlider(o);
915    IntRect thumbRect = renderSlider->thumbRect();
916
917    option.rect = r;
918
919    int value;
920    if (appearance == SliderVerticalPart) {
921        option.maximum = r.height() - thumbRect.height();
922        value = thumbRect.y();
923    } else {
924        option.maximum = r.width() - thumbRect.width();
925        value = thumbRect.x();
926    }
927
928    value = QStyle::sliderValueFromPosition(0, option.maximum, value, option.maximum);
929
930    option.sliderValue = value;
931    option.sliderPosition = value;
932    if (appearance == SliderVerticalPart)
933        option.orientation = Qt::Vertical;
934
935    if (renderSlider->inDragMode()) {
936        option.activeSubControls = QStyle::SC_SliderHandle;
937        option.state |= QStyle::State_Sunken;
938    }
939
940    const QPoint topLeft = r.location();
941    p.painter->translate(topLeft);
942    option.rect.moveTo(QPoint(0, 0));
943    option.rect.setSize(r.size());
944
945    p.drawComplexControl(QStyle::CC_Slider, option);
946    p.painter->translate(-topLeft);
947
948    return false;
949}
950
951void RenderThemeQt::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
952{
953    style->setBoxShadow(0);
954}
955
956bool RenderThemeQt::paintSliderThumb(RenderObject* o, const PaintInfo& pi,
957                                     const IntRect& r)
958{
959    // We've already painted it in paintSliderTrack(), no need to do anything here.
960    return false;
961}
962
963void RenderThemeQt::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
964{
965    style->setBoxShadow(0);
966}
967
968bool RenderThemeQt::paintSearchField(RenderObject* o, const PaintInfo& pi,
969                                     const IntRect& r)
970{
971    return paintTextField(o, pi, r);
972}
973
974void RenderThemeQt::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style,
975                                           Element* e) const
976{
977    // Resetting the style like this leads to differences like:
978    // - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)]
979    // + RenderTextControl {INPUT} at (2,2) size 166x26
980    // in layout tests when a CSS style is applied that doesn't affect background color, border or
981    // padding. Just worth keeping in mind!
982    style->setBackgroundColor(Color::transparent);
983    style->resetBorder();
984    style->resetPadding();
985    computeSizeBasedOnStyle(style);
986}
987
988void RenderThemeQt::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style,
989                                                       Element* e) const
990{
991    // Logic taken from RenderThemeChromium.cpp.
992    // Scale the button size based on the font size.
993    float fontScale = style->fontSize() / defaultControlFontPixelSize;
994    int cancelButtonSize = lroundf(qMin(qMax(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
995    style->setWidth(Length(cancelButtonSize, Fixed));
996    style->setHeight(Length(cancelButtonSize, Fixed));
997}
998
999// Function taken from RenderThemeChromium.cpp
1000IntRect RenderThemeQt::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, IntRect partRect, const IntRect& localOffset) const
1001{
1002    // Compute an offset between the part renderer and the input renderer.
1003    IntSize offsetFromInputRenderer = -(partRenderer->offsetFromAncestorContainer(inputRenderer));
1004    // Move the rect into partRenderer's coords.
1005    partRect.move(offsetFromInputRenderer);
1006    // Account for the local drawing offset.
1007    partRect.move(localOffset.x(), localOffset.y());
1008
1009    return partRect;
1010}
1011
1012bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& pi,
1013                                                 const IntRect& r)
1014{
1015    // Logic copied from RenderThemeChromium.cpp.
1016
1017    // Get the renderer of <input> element.
1018    Node* input = o->node()->shadowAncestorNode();
1019    if (!input->renderer()->isBox())
1020        return false;
1021    RenderBox* inputRenderBox = toRenderBox(input->renderer());
1022    IntRect inputContentBox = inputRenderBox->contentBoxRect();
1023
1024    // Make sure the scaled button stays square and will fit in its parent's box.
1025    int cancelButtonSize = qMin(inputContentBox.width(), qMin(inputContentBox.height(), r.height()));
1026    // Calculate cancel button's coordinates relative to the input element.
1027    // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
1028    // be one pixel closer to the bottom of the field.  This tends to look better with the text.
1029    IntRect cancelButtonRect(o->offsetFromAncestorContainer(inputRenderBox).width(),
1030                             inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2,
1031                             cancelButtonSize, cancelButtonSize);
1032    IntRect paintingRect = convertToPaintingRect(inputRenderBox, o, cancelButtonRect, r);
1033    static Image* cancelImage = Image::loadPlatformResource("searchCancelButton").releaseRef();
1034    static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelButtonPressed").releaseRef();
1035    pi.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage,
1036                                 o->style()->colorSpace(), paintingRect);
1037    return false;
1038}
1039
1040void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
1041                                                     Element* e) const
1042{
1043    notImplemented();
1044    RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e);
1045}
1046
1047bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const PaintInfo& pi,
1048                                               const IntRect& r)
1049{
1050    notImplemented();
1051    return RenderTheme::paintSearchFieldDecoration(o, pi, r);
1052}
1053
1054void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
1055                                                            Element* e) const
1056{
1057    notImplemented();
1058    RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e);
1059}
1060
1061bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& pi,
1062                                                      const IntRect& r)
1063{
1064    notImplemented();
1065    return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r);
1066}
1067
1068bool RenderThemeQt::supportsFocus(ControlPart appearance) const
1069{
1070    switch (appearance) {
1071    case PushButtonPart:
1072    case ButtonPart:
1073    case TextFieldPart:
1074    case TextAreaPart:
1075    case ListboxPart:
1076    case MenulistPart:
1077    case RadioPart:
1078    case CheckboxPart:
1079    case SliderHorizontalPart:
1080    case SliderVerticalPart:
1081        return true;
1082    default: // No for all others...
1083        return false;
1084    }
1085}
1086
1087void RenderThemeQt::setPaletteFromPageClientIfExists(QPalette& palette) const
1088{
1089#if USE(QT_MOBILE_THEME)
1090    static QPalette lightGrayPalette(Qt::lightGray);
1091    palette = lightGrayPalette;
1092    return;
1093#endif
1094    // If the webview has a custom palette, use it
1095    if (!m_page)
1096        return;
1097    Chrome* chrome = m_page->chrome();
1098    if (!chrome)
1099        return;
1100    ChromeClient* chromeClient = chrome->client();
1101    if (!chromeClient)
1102        return;
1103    QWebPageClient* pageClient = chromeClient->platformPageClient();
1104    if (!pageClient)
1105        return;
1106    palette = pageClient->palette();
1107}
1108
1109ControlPart RenderThemeQt::initializeCommonQStyleOptions(QStyleOption& option, RenderObject* o) const
1110{
1111    // Default bits: no focus, no mouse over
1112    option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
1113
1114    if (isReadOnlyControl(o))
1115        // Readonly is supported on textfields.
1116        option.state |= QStyle::State_ReadOnly;
1117
1118    option.direction = Qt::LeftToRight;
1119
1120    if (isHovered(o))
1121        option.state |= QStyle::State_MouseOver;
1122
1123    setPaletteFromPageClientIfExists(option.palette);
1124
1125    if (!isEnabled(o)) {
1126        option.palette.setCurrentColorGroup(QPalette::Disabled);
1127        option.state &= ~QStyle::State_Enabled;
1128    }
1129
1130    RenderStyle* style = o->style();
1131    if (!style)
1132        return NoControlPart;
1133
1134    ControlPart result = style->appearance();
1135    if (supportsFocus(result) && isFocused(o)) {
1136        option.state |= QStyle::State_HasFocus;
1137        option.state |= QStyle::State_KeyboardFocusChange;
1138    }
1139
1140    if (style->direction() == WebCore::RTL)
1141        option.direction = Qt::RightToLeft;
1142
1143    switch (result) {
1144    case PushButtonPart:
1145    case SquareButtonPart:
1146    case ButtonPart:
1147    case ButtonBevelPart:
1148    case ListItemPart:
1149    case MenulistButtonPart:
1150    case SearchFieldResultsButtonPart:
1151    case SearchFieldCancelButtonPart: {
1152        if (isPressed(o))
1153            option.state |= QStyle::State_Sunken;
1154        else if (result == PushButtonPart || result == ButtonPart)
1155            option.state |= QStyle::State_Raised;
1156        break;
1157    }
1158    case RadioPart:
1159    case CheckboxPart:
1160        option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off);
1161    }
1162
1163    return result;
1164}
1165
1166#if ENABLE(VIDEO)
1167
1168String RenderThemeQt::extraMediaControlsStyleSheet()
1169{
1170    String result = String(mediaControlsQtUserAgentStyleSheet, sizeof(mediaControlsQtUserAgentStyleSheet));
1171
1172    if (m_page && m_page->chrome()->requiresFullscreenForVideoPlayback())
1173        result += String(mediaControlsQtFullscreenUserAgentStyleSheet, sizeof(mediaControlsQtFullscreenUserAgentStyleSheet));
1174
1175    return result;
1176}
1177
1178// Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100
1179class WorldMatrixTransformer {
1180public:
1181    WorldMatrixTransformer(QPainter* painter, RenderObject* renderObject, const IntRect& r) : m_painter(painter)
1182    {
1183        RenderStyle* style = renderObject->style();
1184        m_originalTransform = m_painter->transform();
1185        m_painter->translate(r.x() + style->paddingLeft().value(), r.y() + style->paddingTop().value());
1186        m_painter->scale((r.width() - style->paddingLeft().value() - style->paddingRight().value()) / 100.0,
1187             (r.height() - style->paddingTop().value() - style->paddingBottom().value()) / 100.0);
1188    }
1189
1190    ~WorldMatrixTransformer() { m_painter->setTransform(m_originalTransform); }
1191
1192private:
1193    QPainter* m_painter;
1194    QTransform m_originalTransform;
1195};
1196
1197double RenderThemeQt::mediaControlsBaselineOpacity() const
1198{
1199    return 0.4;
1200}
1201
1202void RenderThemeQt::paintMediaBackground(QPainter* painter, const IntRect& r) const
1203{
1204    painter->setPen(Qt::NoPen);
1205    static QColor transparentBlack(0, 0, 0, mediaControlsBaselineOpacity() * 255);
1206    painter->setBrush(transparentBlack);
1207    painter->drawRoundedRect(r.x(), r.y(), r.width(), r.height(), 5.0, 5.0);
1208}
1209
1210QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const
1211{
1212    QColor fgColor = platformActiveSelectionBackgroundColor();
1213    if (o && o->node()->active())
1214        fgColor = fgColor.lighter();
1215    return fgColor;
1216}
1217
1218bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1219{
1220    HTMLMediaElement* mediaElement = toParentMediaElement(o);
1221    if (!mediaElement)
1222        return false;
1223
1224    StylePainter p(this, paintInfo);
1225    if (!p.isValid())
1226        return true;
1227
1228    p.painter->setRenderHint(QPainter::Antialiasing, true);
1229
1230    paintMediaBackground(p.painter, r);
1231
1232    WorldMatrixTransformer transformer(p.painter, o, r);
1233    const QPointF arrowPolygon[9] = { QPointF(20, 0), QPointF(100, 0), QPointF(100, 80),
1234            QPointF(80, 80), QPointF(80, 30), QPointF(10, 100), QPointF(0, 90), QPointF(70, 20), QPointF(20, 20)};
1235
1236    p.painter->setBrush(getMediaControlForegroundColor(o));
1237    p.painter->drawPolygon(arrowPolygon, 9);
1238
1239    return false;
1240}
1241
1242bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1243{
1244    HTMLMediaElement* mediaElement = toParentMediaElement(o);
1245    if (!mediaElement)
1246        return false;
1247
1248    StylePainter p(this, paintInfo);
1249    if (!p.isValid())
1250        return true;
1251
1252    p.painter->setRenderHint(QPainter::Antialiasing, true);
1253
1254    paintMediaBackground(p.painter, r);
1255
1256    WorldMatrixTransformer transformer(p.painter, o, r);
1257    const QPointF speakerPolygon[6] = { QPointF(20, 30), QPointF(50, 30), QPointF(80, 0),
1258            QPointF(80, 100), QPointF(50, 70), QPointF(20, 70)};
1259
1260    p.painter->setBrush(mediaElement->muted() ? Qt::darkRed : getMediaControlForegroundColor(o));
1261    p.painter->drawPolygon(speakerPolygon, 6);
1262
1263    return false;
1264}
1265
1266bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1267{
1268    HTMLMediaElement* mediaElement = toParentMediaElement(o);
1269    if (!mediaElement)
1270        return false;
1271
1272    StylePainter p(this, paintInfo);
1273    if (!p.isValid())
1274        return true;
1275
1276    p.painter->setRenderHint(QPainter::Antialiasing, true);
1277
1278    paintMediaBackground(p.painter, r);
1279
1280    WorldMatrixTransformer transformer(p.painter, o, r);
1281    p.painter->setBrush(getMediaControlForegroundColor(o));
1282    if (mediaElement->canPlay()) {
1283        const QPointF playPolygon[3] = { QPointF(0, 0), QPointF(100, 50), QPointF(0, 100)};
1284        p.painter->drawPolygon(playPolygon, 3);
1285    } else {
1286        p.painter->drawRect(0, 0, 30, 100);
1287        p.painter->drawRect(70, 0, 30, 100);
1288    }
1289
1290    return false;
1291}
1292
1293bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&)
1294{
1295    // We don't want to paint this at the moment.
1296    return false;
1297}
1298
1299bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&)
1300{
1301    // We don't want to paint this at the moment.
1302    return false;
1303}
1304
1305bool RenderThemeQt::paintMediaCurrentTime(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1306{
1307    StylePainter p(this, paintInfo);
1308    if (!p.isValid())
1309        return true;
1310
1311    p.painter->setRenderHint(QPainter::Antialiasing, true);
1312    paintMediaBackground(p.painter, r);
1313
1314    return false;
1315}
1316
1317String RenderThemeQt::formatMediaControlsCurrentTime(float currentTime, float duration) const
1318{
1319    return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
1320}
1321
1322String RenderThemeQt::formatMediaControlsRemainingTime(float currentTime, float duration) const
1323{
1324    return String();
1325}
1326
1327bool RenderThemeQt::paintMediaVolumeSliderTrack(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r)
1328{
1329    StylePainter p(this, paintInfo);
1330    if (!p.isValid())
1331        return true;
1332
1333    p.painter->setRenderHint(QPainter::Antialiasing, true);
1334
1335    paintMediaBackground(p.painter, r);
1336
1337    if (!o->isSlider())
1338        return false;
1339
1340    IntRect b = toRenderBox(o)->contentBoxRect();
1341
1342    // Position the outer rectangle
1343    int top = r.y() + b.y();
1344    int left = r.x() + b.x();
1345    int width = b.width();
1346    int height = b.height();
1347
1348    // Get the scale color from the page client
1349    QPalette pal = QApplication::palette();
1350    setPaletteFromPageClientIfExists(pal);
1351    const QColor highlightText = pal.brush(QPalette::Active, QPalette::HighlightedText).color();
1352    const QColor scaleColor(highlightText.red(), highlightText.green(), highlightText.blue(), mediaControlsBaselineOpacity() * 255);
1353
1354    // Draw the outer rectangle
1355    p.painter->setBrush(scaleColor);
1356    p.painter->drawRect(left, top, width, height);
1357
1358    if (!o->node() || !o->node()->hasTagName(inputTag))
1359        return false;
1360
1361    HTMLInputElement* slider = static_cast<HTMLInputElement*>(o->node());
1362
1363    // Position the inner rectangle
1364    height = height * slider->valueAsNumber();
1365    top += b.height() - height;
1366
1367    // Draw the inner rectangle
1368    p.painter->setPen(Qt::NoPen);
1369    p.painter->setBrush(getMediaControlForegroundColor(o));
1370    p.painter->drawRect(left, top, width, height);
1371
1372    return false;
1373}
1374
1375bool RenderThemeQt::paintMediaVolumeSliderThumb(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r)
1376{
1377    StylePainter p(this, paintInfo);
1378    if (!p.isValid())
1379        return true;
1380
1381    // Nothing to draw here, this is all done in the track
1382    return false;
1383}
1384
1385bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1386{
1387    HTMLMediaElement* mediaElement = toParentMediaElement(o);
1388    if (!mediaElement)
1389        return false;
1390
1391    StylePainter p(this, paintInfo);
1392    if (!p.isValid())
1393        return true;
1394
1395    p.painter->setRenderHint(QPainter::Antialiasing, true);
1396
1397    paintMediaBackground(p.painter, r);
1398
1399    if (MediaPlayer* player = mediaElement->player()) {
1400        // Get the buffered parts of the media
1401        PassRefPtr<TimeRanges> buffered = player->buffered();
1402        if (buffered->length() > 0 && player->duration() < std::numeric_limits<float>::infinity()) {
1403            // Set the transform and brush
1404            WorldMatrixTransformer transformer(p.painter, o, r);
1405            p.painter->setBrush(getMediaControlForegroundColor());
1406
1407            // Paint each buffered section
1408            ExceptionCode ex;
1409            for (int i = 0; i < buffered->length(); i++) {
1410                float startX = (buffered->start(i, ex) / player->duration()) * 100;
1411                float width = ((buffered->end(i, ex) / player->duration()) * 100) - startX;
1412                p.painter->drawRect(startX, 37, width, 26);
1413            }
1414        }
1415    }
1416
1417    return false;
1418}
1419
1420bool RenderThemeQt::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1421{
1422    StylePainter p(this, paintInfo);
1423    if (!p.isValid())
1424        return true;
1425
1426    p.painter->setRenderHint(QPainter::Antialiasing, true);
1427
1428    p.painter->setPen(Qt::NoPen);
1429    p.painter->setBrush(getMediaControlForegroundColor(o));
1430    p.painter->drawRect(r.x(), r.y(), r.width(), r.height());
1431
1432    return false;
1433}
1434#endif
1435
1436void RenderThemeQt::adjustSliderThumbSize(RenderObject* o) const
1437{
1438    ControlPart part = o->style()->appearance();
1439
1440    if (part == MediaSliderThumbPart) {
1441        RenderStyle* parentStyle = o->parent()->style();
1442        Q_ASSERT(parentStyle);
1443
1444        int parentHeight = parentStyle->height().value();
1445        o->style()->setWidth(Length(parentHeight / 3, Fixed));
1446        o->style()->setHeight(Length(parentHeight, Fixed));
1447    } else if (part == MediaVolumeSliderThumbPart) {
1448        RenderStyle* parentStyle = o->parent()->style();
1449        Q_ASSERT(parentStyle);
1450
1451        int parentWidth = parentStyle->width().value();
1452        o->style()->setHeight(Length(parentWidth / 3, Fixed));
1453        o->style()->setWidth(Length(parentWidth, Fixed));
1454    } else if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
1455        QStyleOptionSlider option;
1456        if (part == SliderThumbVerticalPart)
1457            option.orientation = Qt::Vertical;
1458
1459        QStyle* style = qStyle();
1460
1461        int width = style->pixelMetric(QStyle::PM_SliderLength, &option);
1462        int height = style->pixelMetric(QStyle::PM_SliderThickness, &option);
1463        o->style()->setWidth(Length(width, Fixed));
1464        o->style()->setHeight(Length(height, Fixed));
1465    }
1466}
1467
1468double RenderThemeQt::caretBlinkInterval() const
1469{
1470    return  QApplication::cursorFlashTime() / 1000.0 / 2.0;
1471}
1472
1473}
1474
1475// vim: ts=4 sw=4 et
1476