Home | History | Annotate | Download | only in qt
      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 (at) kde.org>
      7  *               2006 Dirk Mueller <mueller (at) kde.org>
      8  *               2006 Nikolas Zimmermann <zimmermann (at) 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 "Chrome.h"
     36 #include "ChromeClientQt.h"
     37 #include "Color.h"
     38 #include "Document.h"
     39 #include "Font.h"
     40 #include "FontSelector.h"
     41 #include "GraphicsContext.h"
     42 #include "HTMLMediaElement.h"
     43 #include "HTMLNames.h"
     44 #include "NotImplemented.h"
     45 #include "Page.h"
     46 #include "QWebPageClient.h"
     47 #include "RenderBox.h"
     48 #include "RenderSlider.h"
     49 #include "RenderTheme.h"
     50 #include "ScrollbarThemeQt.h"
     51 #include "UserAgentStyleSheets.h"
     52 #include "qwebpage.h"
     53 
     54 #include <QApplication>
     55 #include <QColor>
     56 #include <QDebug>
     57 #include <QFile>
     58 #include <QLineEdit>
     59 #include <QPainter>
     60 #include <QPushButton>
     61 #include <QStyleFactory>
     62 #include <QStyleOptionButton>
     63 #include <QStyleOptionFrameV2>
     64 #include <QStyleOptionSlider>
     65 #include <QWidget>
     66 
     67 
     68 namespace WebCore {
     69 
     70 using namespace HTMLNames;
     71 
     72 
     73 StylePainter::StylePainter(RenderThemeQt* theme, const RenderObject::PaintInfo& paintInfo)
     74 {
     75     init(paintInfo.context ? paintInfo.context : 0, theme->qStyle());
     76 }
     77 
     78 StylePainter::StylePainter(ScrollbarThemeQt* theme, GraphicsContext* context)
     79 {
     80     init(context, theme->style());
     81 }
     82 
     83 void StylePainter::init(GraphicsContext* context, QStyle* themeStyle)
     84 {
     85     painter = static_cast<QPainter*>(context->platformContext());
     86     widget = 0;
     87     QPaintDevice* dev = 0;
     88     if (painter)
     89         dev = painter->device();
     90     if (dev && dev->devType() == QInternal::Widget)
     91         widget = static_cast<QWidget*>(dev);
     92     style = themeStyle;
     93 
     94     if (painter) {
     95         // the styles often assume being called with a pristine painter where no brush is set,
     96         // so reset it manually
     97         oldBrush = painter->brush();
     98         painter->setBrush(Qt::NoBrush);
     99 
    100         // painting the widget with anti-aliasing will make it blurry
    101         // disable it here and restore it later
    102         oldAntialiasing = painter->testRenderHint(QPainter::Antialiasing);
    103         painter->setRenderHint(QPainter::Antialiasing, false);
    104     }
    105 }
    106 
    107 StylePainter::~StylePainter()
    108 {
    109     if (painter) {
    110         painter->setBrush(oldBrush);
    111         painter->setRenderHints(QPainter::Antialiasing, oldAntialiasing);
    112     }
    113 }
    114 
    115 PassRefPtr<RenderTheme> RenderThemeQt::create(Page* page)
    116 {
    117     return adoptRef(new RenderThemeQt(page));
    118 }
    119 
    120 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
    121 {
    122     if (page)
    123         return RenderThemeQt::create(page);
    124 
    125     static RenderTheme* fallback = RenderThemeQt::create(0).releaseRef();
    126     return fallback;
    127 }
    128 
    129 RenderThemeQt::RenderThemeQt(Page* page)
    130     : RenderTheme()
    131     , m_page(page)
    132 {
    133     QPushButton button;
    134     button.setAttribute(Qt::WA_MacSmallSize);
    135     QFont defaultButtonFont = QApplication::font(&button);
    136     QFontInfo fontInfo(defaultButtonFont);
    137     m_buttonFontFamily = defaultButtonFont.family();
    138 #ifdef Q_WS_MAC
    139     m_buttonFontPixelSize = fontInfo.pixelSize();
    140 #endif
    141 
    142     m_fallbackStyle = QStyleFactory::create(QLatin1String("windows"));
    143 }
    144 
    145 RenderThemeQt::~RenderThemeQt()
    146 {
    147     delete m_fallbackStyle;
    148 }
    149 
    150 // for some widget painting, we need to fallback to Windows style
    151 QStyle* RenderThemeQt::fallbackStyle() const
    152 {
    153     return (m_fallbackStyle) ? m_fallbackStyle : QApplication::style();
    154 }
    155 
    156 QStyle* RenderThemeQt::qStyle() const
    157 {
    158 #ifdef Q_WS_MAEMO_5
    159     return fallbackStyle();
    160 #endif
    161 
    162     if (m_page) {
    163         QWebPageClient* pageClient = m_page->chrome()->client()->platformPageClient();
    164 
    165         if (pageClient)
    166             return pageClient->style();
    167     }
    168 
    169     return QApplication::style();
    170 }
    171 
    172 bool RenderThemeQt::supportsHover(const RenderStyle*) const
    173 {
    174     return true;
    175 }
    176 
    177 bool RenderThemeQt::supportsFocusRing(const RenderStyle*) const
    178 {
    179     return true; // Qt provides this through the style
    180 }
    181 
    182 int RenderThemeQt::baselinePosition(const RenderObject* o) const
    183 {
    184     if (!o->isBox())
    185         return 0;
    186 
    187     if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart)
    188         return toRenderBox(o)->marginTop() + toRenderBox(o)->height() - 2; // Same as in old khtml
    189     return RenderTheme::baselinePosition(o);
    190 }
    191 
    192 bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const
    193 {
    194     if (!isEnabled(o))
    195         return false;
    196 
    197     // Checkboxes only have tint when checked.
    198     if (o->style()->appearance() == CheckboxPart)
    199         return isChecked(o);
    200 
    201     // For now assume other controls have tint if enabled.
    202     return true;
    203 }
    204 
    205 bool RenderThemeQt::supportsControlTints() const
    206 {
    207     return true;
    208 }
    209 
    210 static int findFrameLineWidth(QStyle* style)
    211 {
    212     QLineEdit lineEdit;
    213     QStyleOptionFrameV2 opt;
    214     return style->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, &lineEdit);
    215 }
    216 
    217 static QRect inflateButtonRect(const QRect& originalRect, QStyle* style)
    218 {
    219     QStyleOptionButton option;
    220     option.state |= QStyle::State_Small;
    221     option.rect = originalRect;
    222 
    223     QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem, &option, 0);
    224     if (!layoutRect.isNull()) {
    225         int paddingLeft = layoutRect.left() - originalRect.left();
    226         int paddingRight = originalRect.right() - layoutRect.right();
    227         int paddingTop = layoutRect.top() - originalRect.top();
    228         int paddingBottom = originalRect.bottom() - layoutRect.bottom();
    229 
    230         return originalRect.adjusted(-paddingLeft, -paddingTop, paddingRight, paddingBottom);
    231     }
    232     return originalRect;
    233 }
    234 
    235 void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& rect)
    236 {
    237     switch (o->style()->appearance()) {
    238     case CheckboxPart:
    239         break;
    240     case RadioPart:
    241         break;
    242     case PushButtonPart:
    243     case ButtonPart: {
    244         QRect inflatedRect = inflateButtonRect(rect, qStyle());
    245         rect = IntRect(inflatedRect.x(), inflatedRect.y(), inflatedRect.width(), inflatedRect.height());
    246         break;
    247     }
    248     case MenulistPart:
    249         break;
    250     default:
    251         break;
    252     }
    253 }
    254 
    255 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
    256 {
    257     QPalette pal = QApplication::palette();
    258     return pal.brush(QPalette::Active, QPalette::Highlight).color();
    259 }
    260 
    261 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
    262 {
    263     QPalette pal = QApplication::palette();
    264     return pal.brush(QPalette::Inactive, QPalette::Highlight).color();
    265 }
    266 
    267 Color RenderThemeQt::platformActiveSelectionForegroundColor() const
    268 {
    269     QPalette pal = QApplication::palette();
    270     return pal.brush(QPalette::Active, QPalette::HighlightedText).color();
    271 }
    272 
    273 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
    274 {
    275     QPalette pal = QApplication::palette();
    276     return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color();
    277 }
    278 
    279 void RenderThemeQt::systemFont(int, FontDescription&) const
    280 {
    281     // no-op
    282 }
    283 
    284 int RenderThemeQt::minimumMenuListSize(RenderStyle*) const
    285 {
    286     const QFontMetrics &fm = QApplication::fontMetrics();
    287     return 7 * fm.width(QLatin1Char('x'));
    288 }
    289 
    290 void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const
    291 {
    292     // If the width and height are both specified, then we have nothing to do.
    293     if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto())
    294         return;
    295 
    296     QSize size(0, 0);
    297     const QFontMetrics fm(renderStyle->font().font());
    298     QStyle* style = qStyle();
    299 
    300     switch (renderStyle->appearance()) {
    301     case CheckboxPart: {
    302         QStyleOption styleOption;
    303         styleOption.state |= QStyle::State_Small;
    304         int checkBoxWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &styleOption);
    305         size = QSize(checkBoxWidth, checkBoxWidth);
    306         break;
    307     }
    308     case RadioPart: {
    309         QStyleOption styleOption;
    310         styleOption.state |= QStyle::State_Small;
    311         int radioWidth = style->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, &styleOption);
    312         size = QSize(radioWidth, radioWidth);
    313         break;
    314     }
    315     case PushButtonPart:
    316     case ButtonPart: {
    317         QStyleOptionButton styleOption;
    318         styleOption.state |= QStyle::State_Small;
    319         QSize contentSize = fm.size(Qt::TextShowMnemonic, QString::fromLatin1("X"));
    320         QSize pushButtonSize = style->sizeFromContents(QStyle::CT_PushButton,
    321                                                        &styleOption, contentSize, 0);
    322         styleOption.rect = QRect(0, 0, pushButtonSize.width(), pushButtonSize.height());
    323         QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem,
    324                                                  &styleOption, 0);
    325 
    326         // If the style supports layout rects we use that, and  compensate accordingly
    327         // in paintButton() below.
    328         if (!layoutRect.isNull())
    329             size.setHeight(layoutRect.height());
    330         else
    331             size.setHeight(pushButtonSize.height());
    332 
    333         break;
    334     }
    335     case MenulistPart: {
    336         QStyleOptionComboBox styleOption;
    337         styleOption.state |= QStyle::State_Small;
    338         int contentHeight = qMax(fm.lineSpacing(), 14) + 2;
    339         QSize menuListSize = style->sizeFromContents(QStyle::CT_ComboBox,
    340                                                      &styleOption, QSize(0, contentHeight), 0);
    341         size.setHeight(menuListSize.height());
    342         break;
    343     }
    344     case TextFieldPart: {
    345         const int verticalMargin = 1;
    346         const int horizontalMargin = 2;
    347         int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin;
    348         int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin;
    349         QStyleOptionFrameV2 opt;
    350         opt.lineWidth = findFrameLineWidth(style);
    351         QSize sz = style->sizeFromContents(QStyle::CT_LineEdit,
    352                                            &opt,
    353                                            QSize(w, h).expandedTo(QApplication::globalStrut()),
    354                                            0);
    355         size.setHeight(sz.height());
    356 
    357         renderStyle->setPaddingLeft(Length(opt.lineWidth, Fixed));
    358         renderStyle->setPaddingRight(Length(opt.lineWidth, Fixed));
    359         break;
    360     }
    361     default:
    362         break;
    363     }
    364 
    365     // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
    366     if (renderStyle->width().isIntrinsicOrAuto() && size.width() > 0)
    367         renderStyle->setWidth(Length(size.width(), Fixed));
    368     if (renderStyle->height().isAuto() && size.height() > 0)
    369         renderStyle->setHeight(Length(size.height(), Fixed));
    370 }
    371 
    372 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
    373 {
    374     computeSizeBasedOnStyle(style);
    375 }
    376 
    377 bool RenderThemeQt::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    378 {
    379     return paintButton(o, i, r);
    380 }
    381 
    382 void RenderThemeQt::setRadioSize(RenderStyle* style) const
    383 {
    384     computeSizeBasedOnStyle(style);
    385 }
    386 
    387 bool RenderThemeQt::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    388 {
    389     return paintButton(o, i, r);
    390 }
    391 
    392 void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const
    393 {
    394     // Ditch the border.
    395     style->resetBorder();
    396 
    397 #ifdef Q_WS_MAC
    398     if (style->appearance() == PushButtonPart) {
    399         // The Mac ports ignore the specified height for <input type="button"> elements
    400         // unless a border and/or background CSS property is also specified.
    401         style->setHeight(Length(Auto));
    402     }
    403 #endif
    404 
    405     // White-space is locked to pre
    406     style->setWhiteSpace(PRE);
    407 
    408     FontDescription fontDescription = style->fontDescription();
    409     fontDescription.setIsAbsoluteSize(true);
    410 
    411 #ifdef Q_WS_MAC // Use fixed font size and family on Mac (like Safari does)
    412     fontDescription.setSpecifiedSize(m_buttonFontPixelSize);
    413     fontDescription.setComputedSize(m_buttonFontPixelSize);
    414 #else
    415     fontDescription.setSpecifiedSize(style->fontSize());
    416     fontDescription.setComputedSize(style->fontSize());
    417 #endif
    418 
    419     FontFamily fontFamily;
    420     fontFamily.setFamily(m_buttonFontFamily);
    421     fontDescription.setFamily(fontFamily);
    422     style->setFontDescription(fontDescription);
    423     style->font().update(selector->fontSelector());
    424     style->setLineHeight(RenderStyle::initialLineHeight());
    425 
    426     setButtonSize(style);
    427     setButtonPadding(style);
    428 }
    429 
    430 void RenderThemeQt::setButtonSize(RenderStyle* style) const
    431 {
    432     computeSizeBasedOnStyle(style);
    433 }
    434 
    435 void RenderThemeQt::setButtonPadding(RenderStyle* style) const
    436 {
    437     QStyleOptionButton styleOption;
    438     styleOption.state |= QStyle::State_Small;
    439 
    440     // Fake a button rect here, since we're just computing deltas
    441     QRect originalRect = QRect(0, 0, 100, 30);
    442     styleOption.rect = originalRect;
    443 
    444     // Default padding is based on the button margin pixel metric
    445     int buttonMargin = qStyle()->pixelMetric(QStyle::PM_ButtonMargin, &styleOption, 0);
    446     int paddingLeft = buttonMargin;
    447     int paddingRight = buttonMargin;
    448     int paddingTop = 1;
    449     int paddingBottom = 0;
    450 
    451     // Then check if the style uses layout margins
    452     QRect layoutRect = qStyle()->subElementRect(QStyle::SE_PushButtonLayoutItem,
    453                                                 &styleOption, 0);
    454     if (!layoutRect.isNull()) {
    455         QRect contentsRect = qStyle()->subElementRect(QStyle::SE_PushButtonContents,
    456                                                       &styleOption, 0);
    457         paddingLeft = contentsRect.left() - layoutRect.left();
    458         paddingRight = layoutRect.right() - contentsRect.right();
    459         paddingTop = contentsRect.top() - layoutRect.top();
    460 
    461         // Can't use this right now because we don't have the baseline to compensate
    462         // paddingBottom = layoutRect.bottom() - contentsRect.bottom();
    463     }
    464 
    465     style->setPaddingLeft(Length(paddingLeft, Fixed));
    466     style->setPaddingRight(Length(paddingRight, Fixed));
    467     style->setPaddingTop(Length(paddingTop, Fixed));
    468     style->setPaddingBottom(Length(paddingBottom, Fixed));
    469 }
    470 
    471 bool RenderThemeQt::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    472 {
    473     StylePainter p(this, i);
    474     if (!p.isValid())
    475        return true;
    476 
    477     QStyleOptionButton option;
    478     if (p.widget)
    479        option.initFrom(p.widget);
    480 
    481     option.rect = r;
    482     option.state |= QStyle::State_Small;
    483 
    484     ControlPart appearance = initializeCommonQStyleOptions(option, o);
    485     if (appearance == PushButtonPart || appearance == ButtonPart) {
    486         option.rect = inflateButtonRect(option.rect, qStyle());
    487         p.drawControl(QStyle::CE_PushButton, option);
    488     } else if (appearance == RadioPart)
    489        p.drawControl(QStyle::CE_RadioButton, option);
    490     else if (appearance == CheckboxPart)
    491        p.drawControl(QStyle::CE_CheckBox, option);
    492 
    493     return false;
    494 }
    495 
    496 void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    497 {
    498     style->setBackgroundColor(Color::transparent);
    499     style->resetBorder();
    500     style->resetPadding();
    501     computeSizeBasedOnStyle(style);
    502 }
    503 
    504 bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    505 {
    506     StylePainter p(this, i);
    507     if (!p.isValid())
    508         return true;
    509 
    510     QStyleOptionFrameV2 panel;
    511     if (p.widget)
    512         panel.initFrom(p.widget);
    513 
    514     panel.rect = r;
    515     panel.lineWidth = findFrameLineWidth(qStyle());
    516     panel.state |= QStyle::State_Sunken;
    517     panel.features = QStyleOptionFrameV2::None;
    518 
    519     // Get the correct theme data for a text field
    520     ControlPart appearance = initializeCommonQStyleOptions(panel, o);
    521     if (appearance != TextFieldPart
    522         && appearance != SearchFieldPart
    523         && appearance != TextAreaPart
    524         && appearance != ListboxPart)
    525         return true;
    526 
    527     // Now paint the text field.
    528     p.drawPrimitive(QStyle::PE_PanelLineEdit, panel);
    529 
    530     return false;
    531 }
    532 
    533 void RenderThemeQt::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
    534 {
    535     adjustTextFieldStyle(selector, style, element);
    536 }
    537 
    538 bool RenderThemeQt::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    539 {
    540     return paintTextField(o, i, r);
    541 }
    542 
    543 void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    544 {
    545     style->resetBorder();
    546 
    547     // Height is locked to auto.
    548     style->setHeight(Length(Auto));
    549 
    550     // White-space is locked to pre
    551     style->setWhiteSpace(PRE);
    552 
    553     computeSizeBasedOnStyle(style);
    554 
    555     // Add in the padding that we'd like to use.
    556     setPopupPadding(style);
    557 }
    558 
    559 void RenderThemeQt::setPopupPadding(RenderStyle* style) const
    560 {
    561     const int padding = 8;
    562     style->setPaddingLeft(Length(padding, Fixed));
    563 
    564     QStyleOptionComboBox opt;
    565     int w = qStyle()->pixelMetric(QStyle::PM_ButtonIconSize, &opt, 0);
    566     style->setPaddingRight(Length(padding + w, Fixed));
    567 
    568     style->setPaddingTop(Length(2, Fixed));
    569     style->setPaddingBottom(Length(0, Fixed));
    570 }
    571 
    572 
    573 bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    574 {
    575     StylePainter p(this, i);
    576     if (!p.isValid())
    577         return true;
    578 
    579     QStyleOptionComboBox opt;
    580     if (p.widget)
    581         opt.initFrom(p.widget);
    582     initializeCommonQStyleOptions(opt, o);
    583 
    584     const QPoint topLeft = r.topLeft();
    585     p.painter->translate(topLeft);
    586     opt.rect.moveTo(QPoint(0, 0));
    587     opt.rect.setSize(r.size());
    588 
    589     p.drawComplexControl(QStyle::CC_ComboBox, opt);
    590     p.painter->translate(-topLeft);
    591     return false;
    592 }
    593 
    594 void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    595 {
    596     // WORKAROUND because html.css specifies -webkit-border-radius for <select> so we override it here
    597     // see also http://bugs.webkit.org/show_bug.cgi?id=18399
    598     style->resetBorderRadius();
    599 
    600     // Height is locked to auto.
    601     style->setHeight(Length(Auto));
    602 
    603     // White-space is locked to pre
    604     style->setWhiteSpace(PRE);
    605 
    606     computeSizeBasedOnStyle(style);
    607 
    608     // Add in the padding that we'd like to use.
    609     setPopupPadding(style);
    610 }
    611 
    612 bool RenderThemeQt::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i,
    613                                         const IntRect& r)
    614 {
    615     StylePainter p(this, i);
    616     if (!p.isValid())
    617         return true;
    618 
    619     QStyleOptionComboBox option;
    620     if (p.widget)
    621         option.initFrom(p.widget);
    622     initializeCommonQStyleOptions(option, o);
    623     option.rect = r;
    624 
    625     // for drawing the combo box arrow, rely only on the fallback style
    626     p.style = fallbackStyle();
    627     option.subControls = QStyle::SC_ComboBoxArrow;
    628     p.drawComplexControl(QStyle::CC_ComboBox, option);
    629 
    630     return false;
    631 }
    632 
    633 bool RenderThemeQt::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& pi,
    634                                      const IntRect& r)
    635 {
    636     StylePainter p(this, pi);
    637     if (!p.isValid())
    638        return true;
    639 
    640     QStyleOptionSlider option;
    641     if (p.widget)
    642        option.initFrom(p.widget);
    643     ControlPart appearance = initializeCommonQStyleOptions(option, o);
    644 
    645     RenderSlider* renderSlider = toRenderSlider(o);
    646     IntRect thumbRect = renderSlider->thumbRect();
    647 
    648     option.rect = r;
    649 
    650     int value;
    651     if (appearance == SliderVerticalPart) {
    652         option.maximum = r.height() - thumbRect.height();
    653         value = thumbRect.y();
    654     } else {
    655         option.maximum = r.width() - thumbRect.width();
    656         value = thumbRect.x();
    657     }
    658 
    659     value = QStyle::sliderValueFromPosition(0, option.maximum, value, option.maximum);
    660 
    661     option.sliderValue = value;
    662     option.sliderPosition = value;
    663     if (appearance == SliderVerticalPart)
    664         option.orientation = Qt::Vertical;
    665 
    666     if (renderSlider->inDragMode()) {
    667         option.activeSubControls = QStyle::SC_SliderHandle;
    668         option.state |= QStyle::State_Sunken;
    669     }
    670 
    671     const QPoint topLeft = r.topLeft();
    672     p.painter->translate(topLeft);
    673     option.rect.moveTo(QPoint(0, 0));
    674     option.rect.setSize(r.size());
    675 
    676     p.drawComplexControl(QStyle::CC_Slider, option);
    677     p.painter->translate(-topLeft);
    678 
    679     return false;
    680 }
    681 
    682 void RenderThemeQt::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    683 {
    684     style->setBoxShadow(0);
    685 }
    686 
    687 bool RenderThemeQt::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& pi,
    688                                      const IntRect& r)
    689 {
    690     // We've already painted it in paintSliderTrack(), no need to do anything here.
    691     return false;
    692 }
    693 
    694 void RenderThemeQt::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    695 {
    696     style->setBoxShadow(0);
    697 }
    698 
    699 bool RenderThemeQt::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& pi,
    700                                      const IntRect& r)
    701 {
    702     return true;
    703 }
    704 
    705 void RenderThemeQt::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style,
    706                                            Element* e) const
    707 {
    708     notImplemented();
    709     RenderTheme::adjustSearchFieldStyle(selector, style, e);
    710 }
    711 
    712 void RenderThemeQt::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style,
    713                                                        Element* e) const
    714 {
    715     notImplemented();
    716     RenderTheme::adjustSearchFieldCancelButtonStyle(selector, style, e);
    717 }
    718 
    719 bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& pi,
    720                                                  const IntRect& r)
    721 {
    722     notImplemented();
    723     return RenderTheme::paintSearchFieldCancelButton(o, pi, r);
    724 }
    725 
    726 void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
    727                                                      Element* e) const
    728 {
    729     notImplemented();
    730     RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e);
    731 }
    732 
    733 bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& pi,
    734                                                const IntRect& r)
    735 {
    736     notImplemented();
    737     return RenderTheme::paintSearchFieldDecoration(o, pi, r);
    738 }
    739 
    740 void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
    741                                                             Element* e) const
    742 {
    743     notImplemented();
    744     RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e);
    745 }
    746 
    747 bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& pi,
    748                                                       const IntRect& r)
    749 {
    750     notImplemented();
    751     return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r);
    752 }
    753 
    754 bool RenderThemeQt::supportsFocus(ControlPart appearance) const
    755 {
    756     switch (appearance) {
    757     case PushButtonPart:
    758     case ButtonPart:
    759     case TextFieldPart:
    760     case TextAreaPart:
    761     case ListboxPart:
    762     case MenulistPart:
    763     case RadioPart:
    764     case CheckboxPart:
    765     case SliderHorizontalPart:
    766     case SliderVerticalPart:
    767         return true;
    768     default: // No for all others...
    769         return false;
    770     }
    771 }
    772 
    773 void RenderThemeQt::setPaletteFromPageClientIfExists(QPalette& palette) const
    774 {
    775 #ifdef Q_WS_MAEMO_5
    776     static QPalette lightGrayPalette(Qt::lightGray);
    777     palette = lightGrayPalette;
    778     return;
    779 #endif
    780     // If the webview has a custom palette, use it
    781     if (!m_page)
    782         return;
    783     Chrome* chrome = m_page->chrome();
    784     if (!chrome)
    785         return;
    786     ChromeClient* chromeClient = chrome->client();
    787     if (!chromeClient)
    788         return;
    789     QWebPageClient* pageClient = chromeClient->platformPageClient();
    790     if (!pageClient)
    791         return;
    792     palette = pageClient->palette();
    793 }
    794 
    795 ControlPart RenderThemeQt::initializeCommonQStyleOptions(QStyleOption& option, RenderObject* o) const
    796 {
    797     // Default bits: no focus, no mouse over
    798     option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
    799 
    800     if (!isEnabled(o))
    801         option.state &= ~QStyle::State_Enabled;
    802 
    803     if (isReadOnlyControl(o))
    804         // Readonly is supported on textfields.
    805         option.state |= QStyle::State_ReadOnly;
    806 
    807     option.direction = Qt::LeftToRight;
    808 
    809     if (isHovered(o))
    810         option.state |= QStyle::State_MouseOver;
    811 
    812     setPaletteFromPageClientIfExists(option.palette);
    813     RenderStyle* style = o->style();
    814     if (!style)
    815         return NoControlPart;
    816 
    817     ControlPart result = style->appearance();
    818     if (supportsFocus(result) && isFocused(o)) {
    819         option.state |= QStyle::State_HasFocus;
    820         option.state |= QStyle::State_KeyboardFocusChange;
    821     }
    822 
    823     if (style->direction() == WebCore::RTL)
    824         option.direction = Qt::RightToLeft;
    825 
    826     switch (result) {
    827     case PushButtonPart:
    828     case SquareButtonPart:
    829     case ButtonPart:
    830     case ButtonBevelPart:
    831     case ListItemPart:
    832     case MenulistButtonPart:
    833     case SearchFieldResultsButtonPart:
    834     case SearchFieldCancelButtonPart: {
    835         if (isPressed(o))
    836             option.state |= QStyle::State_Sunken;
    837         else if (result == PushButtonPart)
    838             option.state |= QStyle::State_Raised;
    839         break;
    840     }
    841     case RadioPart:
    842     case CheckboxPart:
    843         option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off);
    844     }
    845 
    846     return result;
    847 }
    848 
    849 #if ENABLE(VIDEO)
    850 
    851 String RenderThemeQt::extraMediaControlsStyleSheet()
    852 {
    853     return String(mediaControlsQtUserAgentStyleSheet, sizeof(mediaControlsQtUserAgentStyleSheet));
    854 }
    855 
    856 // Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100
    857 class WorldMatrixTransformer {
    858 public:
    859     WorldMatrixTransformer(QPainter* painter, RenderObject* renderObject, const IntRect& r) : m_painter(painter)
    860     {
    861         RenderStyle* style = renderObject->style();
    862         m_originalTransform = m_painter->transform();
    863         m_painter->translate(r.x() + style->paddingLeft().value(), r.y() + style->paddingTop().value());
    864         m_painter->scale((r.width() - style->paddingLeft().value() - style->paddingRight().value()) / 100.0,
    865              (r.height() - style->paddingTop().value() - style->paddingBottom().value()) / 100.0);
    866     }
    867 
    868     ~WorldMatrixTransformer() { m_painter->setTransform(m_originalTransform); }
    869 
    870 private:
    871     QPainter* m_painter;
    872     QTransform m_originalTransform;
    873 };
    874 
    875 HTMLMediaElement* RenderThemeQt::getMediaElementFromRenderObject(RenderObject* o) const
    876 {
    877     Node* node = o->node();
    878     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
    879     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
    880         return 0;
    881 
    882     return static_cast<HTMLMediaElement*>(mediaNode);
    883 }
    884 
    885 void RenderThemeQt::paintMediaBackground(QPainter* painter, const IntRect& r) const
    886 {
    887     painter->setPen(Qt::NoPen);
    888     static QColor transparentBlack(0, 0, 0, 100);
    889     painter->setBrush(transparentBlack);
    890     painter->drawRoundedRect(r.x(), r.y(), r.width(), r.height(), 5.0, 5.0);
    891 }
    892 
    893 QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const
    894 {
    895     QColor fgColor = platformActiveSelectionBackgroundColor();
    896     if (o && o->node()->active())
    897         fgColor = fgColor.lighter();
    898     return fgColor;
    899 }
    900 
    901 bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    902 {
    903     return RenderTheme::paintMediaFullscreenButton(o, paintInfo, r);
    904 }
    905 
    906 bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    907 {
    908     HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o);
    909     if (!mediaElement)
    910         return false;
    911 
    912     StylePainter p(this, paintInfo);
    913     if (!p.isValid())
    914         return true;
    915 
    916     p.painter->setRenderHint(QPainter::Antialiasing, true);
    917 
    918     paintMediaBackground(p.painter, r);
    919 
    920     WorldMatrixTransformer transformer(p.painter, o, r);
    921     const QPointF speakerPolygon[6] = { QPointF(20, 30), QPointF(50, 30), QPointF(80, 0),
    922             QPointF(80, 100), QPointF(50, 70), QPointF(20, 70)};
    923 
    924     p.painter->setBrush(getMediaControlForegroundColor(o));
    925     p.painter->drawPolygon(speakerPolygon, 6);
    926 
    927     if (mediaElement->muted()) {
    928         p.painter->setPen(Qt::red);
    929         p.painter->drawLine(0, 100, 100, 0);
    930     }
    931 
    932     return false;
    933 }
    934 
    935 bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    936 {
    937     HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o);
    938     if (!mediaElement)
    939         return false;
    940 
    941     StylePainter p(this, paintInfo);
    942     if (!p.isValid())
    943         return true;
    944 
    945     p.painter->setRenderHint(QPainter::Antialiasing, true);
    946 
    947     paintMediaBackground(p.painter, r);
    948 
    949     WorldMatrixTransformer transformer(p.painter, o, r);
    950     p.painter->setBrush(getMediaControlForegroundColor(o));
    951     if (mediaElement->canPlay()) {
    952         const QPointF playPolygon[3] = { QPointF(0, 0), QPointF(100, 50), QPointF(0, 100)};
    953         p.painter->drawPolygon(playPolygon, 3);
    954     } else {
    955         p.painter->drawRect(0, 0, 30, 100);
    956         p.painter->drawRect(70, 0, 30, 100);
    957     }
    958 
    959     return false;
    960 }
    961 
    962 bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
    963 {
    964     // We don't want to paint this at the moment.
    965     return false;
    966 }
    967 
    968 bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
    969 {
    970     // We don't want to paint this at the moment.
    971     return false;
    972 }
    973 
    974 bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    975 {
    976     HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o);
    977     if (!mediaElement)
    978         return false;
    979 
    980     StylePainter p(this, paintInfo);
    981     if (!p.isValid())
    982         return true;
    983 
    984     p.painter->setRenderHint(QPainter::Antialiasing, true);
    985 
    986     paintMediaBackground(p.painter, r);
    987 
    988     return false;
    989 }
    990 
    991 bool RenderThemeQt::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    992 {
    993     HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o->parent());
    994     if (!mediaElement)
    995         return false;
    996 
    997     StylePainter p(this, paintInfo);
    998     if (!p.isValid())
    999         return true;
   1000 
   1001     p.painter->setRenderHint(QPainter::Antialiasing, true);
   1002 
   1003     p.painter->setPen(Qt::NoPen);
   1004     p.painter->setBrush(getMediaControlForegroundColor(o));
   1005     p.painter->drawRect(r.x(), r.y(), r.width(), r.height());
   1006 
   1007     return false;
   1008 }
   1009 #endif
   1010 
   1011 void RenderThemeQt::adjustSliderThumbSize(RenderObject* o) const
   1012 {
   1013     ControlPart part = o->style()->appearance();
   1014 
   1015     if (part == MediaSliderThumbPart) {
   1016         RenderStyle* parentStyle = o->parent()->style();
   1017         Q_ASSERT(parentStyle);
   1018 
   1019         int parentHeight = parentStyle->height().value();
   1020         o->style()->setWidth(Length(parentHeight / 3, Fixed));
   1021         o->style()->setHeight(Length(parentHeight, Fixed));
   1022     } else if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
   1023         QStyleOptionSlider option;
   1024         if (part == SliderThumbVerticalPart)
   1025             option.orientation = Qt::Vertical;
   1026 
   1027         QStyle* style = qStyle();
   1028 
   1029         int width = style->pixelMetric(QStyle::PM_SliderLength, &option);
   1030         int height = style->pixelMetric(QStyle::PM_SliderThickness, &option);
   1031         o->style()->setWidth(Length(width, Fixed));
   1032         o->style()->setHeight(Length(height, Fixed));
   1033     }
   1034 }
   1035 
   1036 double RenderThemeQt::caretBlinkInterval() const
   1037 {
   1038     return  QApplication::cursorFlashTime() / 1000.0 / 2.0;
   1039 }
   1040 
   1041 }
   1042 
   1043 // vim: ts=4 sw=4 et
   1044