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 "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 
     84 namespace WebCore {
     85 
     86 using namespace HTMLNames;
     87 
     88 inline 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
    101 static const float defaultControlFontPixelSize = 13;
    102 static const float defaultCancelButtonSize = 9;
    103 static const float minCancelButtonSize = 5;
    104 static const float maxCancelButtonSize = 21;
    105 static const float defaultSearchFieldResultsDecorationSize = 13;
    106 static const float minSearchFieldResultsDecorationSize = 9;
    107 static const float maxSearchFieldResultsDecorationSize = 30;
    108 static const float defaultSearchFieldResultsButtonWidth = 18;
    109 
    110 #if USE(QT_MOBILE_THEME)
    111 namespace {
    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 
    121 StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo)
    122 {
    123     init(paintInfo.context ? paintInfo.context : 0, theme->qStyle());
    124 }
    125 
    126 StylePainter::StylePainter(ScrollbarThemeQt* theme, GraphicsContext* context)
    127 {
    128     init(context, theme->style());
    129 }
    130 
    131 void 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 
    155 StylePainter::~StylePainter()
    156 {
    157     if (painter) {
    158         painter->setBrush(oldBrush);
    159         painter->setRenderHints(QPainter::Antialiasing, oldAntialiasing);
    160     }
    161 }
    162 
    163 PassRefPtr<RenderTheme> RenderThemeQt::create(Page* page)
    164 {
    165     return adoptRef(new RenderThemeQt(page));
    166 }
    167 
    168 PassRefPtr<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 
    177 RenderThemeQt::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 
    198 RenderThemeQt::~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)
    207 bool 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 
    228 int RenderThemeQt::popupInternalPaddingBottom(RenderStyle* style) const
    229 {
    230     return 1;
    231 }
    232 #else
    233 // Remove this when SearchFieldPart is style-able in RenderTheme::isControlStyled()
    234 bool 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
    249 QStyle* RenderThemeQt::fallbackStyle() const
    250 {
    251     return (m_fallbackStyle) ? m_fallbackStyle : QApplication::style();
    252 }
    253 
    254 QStyle* 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 
    270 String 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 
    279 bool RenderThemeQt::supportsHover(const RenderStyle*) const
    280 {
    281     return true;
    282 }
    283 
    284 bool 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 
    312 int 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 
    322 bool 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 
    335 bool RenderThemeQt::supportsControlTints() const
    336 {
    337     return true;
    338 }
    339 
    340 int 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 
    355 static 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 
    373 void 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 
    393 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
    394 {
    395     QPalette pal = QApplication::palette();
    396     setPaletteFromPageClientIfExists(pal);
    397     return pal.brush(QPalette::Active, QPalette::Highlight).color();
    398 }
    399 
    400 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
    401 {
    402     QPalette pal = QApplication::palette();
    403     setPaletteFromPageClientIfExists(pal);
    404     return pal.brush(QPalette::Inactive, QPalette::Highlight).color();
    405 }
    406 
    407 Color RenderThemeQt::platformActiveSelectionForegroundColor() const
    408 {
    409     QPalette pal = QApplication::palette();
    410     setPaletteFromPageClientIfExists(pal);
    411     return pal.brush(QPalette::Active, QPalette::HighlightedText).color();
    412 }
    413 
    414 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
    415 {
    416     QPalette pal = QApplication::palette();
    417     setPaletteFromPageClientIfExists(pal);
    418     return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color();
    419 }
    420 
    421 Color RenderThemeQt::platformFocusRingColor() const
    422 {
    423     QPalette pal = QApplication::palette();
    424     setPaletteFromPageClientIfExists(pal);
    425     return pal.brush(QPalette::Active, QPalette::Highlight).color();
    426 }
    427 
    428 void RenderThemeQt::systemFont(int, FontDescription&) const
    429 {
    430     // no-op
    431 }
    432 
    433 Color 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 
    446 int RenderThemeQt::minimumMenuListSize(RenderStyle*) const
    447 {
    448     const QFontMetrics &fm = QApplication::fontMetrics();
    449     return 7 * fm.width(QLatin1Char('x'));
    450 }
    451 
    452 void 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 
    535 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
    536 {
    537     computeSizeBasedOnStyle(style);
    538 }
    539 
    540 bool RenderThemeQt::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
    541 {
    542     return paintButton(o, i, r);
    543 }
    544 
    545 void RenderThemeQt::setRadioSize(RenderStyle* style) const
    546 {
    547     computeSizeBasedOnStyle(style);
    548 }
    549 
    550 bool RenderThemeQt::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
    551 {
    552     return paintButton(o, i, r);
    553 }
    554 
    555 void 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 
    591 void RenderThemeQt::setButtonSize(RenderStyle* style) const
    592 {
    593     computeSizeBasedOnStyle(style);
    594 }
    595 
    596 #if !USE(QT_MOBILE_THEME)
    597 void 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
    632 void 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 
    643 bool 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 
    666 void 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 
    683 bool 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 
    714 void RenderThemeQt::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
    715 {
    716     adjustTextFieldStyle(selector, style, element);
    717 }
    718 
    719 bool RenderThemeQt::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
    720 {
    721     return paintTextField(o, i, r);
    722 }
    723 
    724 void 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 
    743 void 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 
    759 bool 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 
    789 void 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 
    811 bool 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)
    832 double 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 
    842 double 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 
    854 void RenderThemeQt::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    855 {
    856     style->setBoxShadow(0);
    857 }
    858 
    859 bool 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 
    902 bool 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 
    951 void RenderThemeQt::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    952 {
    953     style->setBoxShadow(0);
    954 }
    955 
    956 bool 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 
    963 void RenderThemeQt::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    964 {
    965     style->setBoxShadow(0);
    966 }
    967 
    968 bool RenderThemeQt::paintSearchField(RenderObject* o, const PaintInfo& pi,
    969                                      const IntRect& r)
    970 {
    971     return paintTextField(o, pi, r);
    972 }
    973 
    974 void 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 
    988 void 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
   1000 IntRect 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 
   1012 bool 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 
   1040 void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
   1041                                                      Element* e) const
   1042 {
   1043     notImplemented();
   1044     RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e);
   1045 }
   1046 
   1047 bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const PaintInfo& pi,
   1048                                                const IntRect& r)
   1049 {
   1050     notImplemented();
   1051     return RenderTheme::paintSearchFieldDecoration(o, pi, r);
   1052 }
   1053 
   1054 void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
   1055                                                             Element* e) const
   1056 {
   1057     notImplemented();
   1058     RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e);
   1059 }
   1060 
   1061 bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& pi,
   1062                                                       const IntRect& r)
   1063 {
   1064     notImplemented();
   1065     return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r);
   1066 }
   1067 
   1068 bool 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 
   1087 void 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 
   1109 ControlPart 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 
   1168 String 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
   1179 class WorldMatrixTransformer {
   1180 public:
   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 
   1192 private:
   1193     QPainter* m_painter;
   1194     QTransform m_originalTransform;
   1195 };
   1196 
   1197 double RenderThemeQt::mediaControlsBaselineOpacity() const
   1198 {
   1199     return 0.4;
   1200 }
   1201 
   1202 void 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 
   1210 QColor 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 
   1218 bool 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 
   1242 bool 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 
   1266 bool 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 
   1293 bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&)
   1294 {
   1295     // We don't want to paint this at the moment.
   1296     return false;
   1297 }
   1298 
   1299 bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&)
   1300 {
   1301     // We don't want to paint this at the moment.
   1302     return false;
   1303 }
   1304 
   1305 bool 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 
   1317 String RenderThemeQt::formatMediaControlsCurrentTime(float currentTime, float duration) const
   1318 {
   1319     return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
   1320 }
   1321 
   1322 String RenderThemeQt::formatMediaControlsRemainingTime(float currentTime, float duration) const
   1323 {
   1324     return String();
   1325 }
   1326 
   1327 bool 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 
   1375 bool 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 
   1385 bool 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 
   1420 bool 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 
   1436 void 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 
   1468 double RenderThemeQt::caretBlinkInterval() const
   1469 {
   1470     return  QApplication::cursorFlashTime() / 1000.0 / 2.0;
   1471 }
   1472 
   1473 }
   1474 
   1475 // vim: ts=4 sw=4 et
   1476