• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of the WebKit project.
3  *
4  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
5  *
6  * Copyright (C) 2006 Zack Rusin <zack@kde.org>
7  *               2006 Dirk Mueller <mueller@kde.org>
8  *               2006 Nikolas Zimmermann <zimmermann@kde.org>
9  * Copyright (C) 2008 Holger Hans Peter Freyther
10  *
11  * All rights reserved.
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public License
24  * along with this library; see the file COPYING.LIB.  If not, write to
25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26  * Boston, MA 02110-1301, USA.
27  *
28  */
29 
30 #include "config.h"
31 #include "RenderThemeQt.h"
32 
33 #include "CSSStyleSelector.h"
34 #include "CSSStyleSheet.h"
35 #include "CSSValueKeywords.h"
36 #include "Chrome.h"
37 #include "ChromeClientQt.h"
38 #include "Color.h"
39 #include "Document.h"
40 #include "Font.h"
41 #include "FontSelector.h"
42 #include "GraphicsContext.h"
43 #include "HTMLInputElement.h"
44 #include "HTMLMediaElement.h"
45 #include "HTMLNames.h"
46 #if USE(QT_MOBILE_THEME)
47 #include "QtMobileWebStyle.h"
48 #endif
49 #if ENABLE(VIDEO)
50 #include "MediaControlElements.h"
51 #endif
52 #include "NotImplemented.h"
53 #include "PaintInfo.h"
54 #include "Page.h"
55 #include "QWebPageClient.h"
56 #include "QtStyleOptionWebComboBox.h"
57 #include "qwebsettings.h"
58 #include "RenderBox.h"
59 #if ENABLE(PROGRESS_TAG)
60 #include "RenderProgress.h"
61 #endif
62 #include "RenderSlider.h"
63 #include "RenderTheme.h"
64 #include "ScrollbarThemeQt.h"
65 #include "TimeRanges.h"
66 #include "UserAgentStyleSheets.h"
67 
68 #include <QApplication>
69 #include <QColor>
70 #include <QFile>
71 #include <QLineEdit>
72 #include <QMacStyle>
73 #include <QPainter>
74 #include <QPushButton>
75 #include <QStyleFactory>
76 #include <QStyleOptionButton>
77 #include <QStyleOptionFrameV2>
78 #if ENABLE(PROGRESS_TAG)
79 #include <QStyleOptionProgressBarV2>
80 #endif
81 #include <QStyleOptionSlider>
82 #include <QWidget>
83 
84 namespace WebCore {
85 
86 using namespace HTMLNames;
87 
initStyleOption(QWidget * widget,QStyleOption & option)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 
StylePainter(RenderThemeQt * theme,const PaintInfo & paintInfo)121 StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo)
122 {
123     init(paintInfo.context ? paintInfo.context : 0, theme->qStyle());
124 }
125 
StylePainter(ScrollbarThemeQt * theme,GraphicsContext * context)126 StylePainter::StylePainter(ScrollbarThemeQt* theme, GraphicsContext* context)
127 {
128     init(context, theme->style());
129 }
130 
init(GraphicsContext * context,QStyle * themeStyle)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 
~StylePainter()155 StylePainter::~StylePainter()
156 {
157     if (painter) {
158         painter->setBrush(oldBrush);
159         painter->setRenderHints(QPainter::Antialiasing, oldAntialiasing);
160     }
161 }
162 
create(Page * page)163 PassRefPtr<RenderTheme> RenderThemeQt::create(Page* page)
164 {
165     return adoptRef(new RenderThemeQt(page));
166 }
167 
themeForPage(Page * page)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 
RenderThemeQt(Page * page)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 
~RenderThemeQt()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)
isControlStyled(const RenderStyle * style,const BorderData & border,const FillLayer & fill,const Color & backgroundColor) const207 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 
popupInternalPaddingBottom(RenderStyle * style) const228 int RenderThemeQt::popupInternalPaddingBottom(RenderStyle* style) const
229 {
230     return 1;
231 }
232 #else
233 // Remove this when SearchFieldPart is style-able in RenderTheme::isControlStyled()
isControlStyled(const RenderStyle * style,const BorderData & border,const FillLayer & fill,const Color & backgroundColor) const234 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
fallbackStyle() const249 QStyle* RenderThemeQt::fallbackStyle() const
250 {
251     return (m_fallbackStyle) ? m_fallbackStyle : QApplication::style();
252 }
253 
qStyle() const254 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 
extraDefaultStyleSheet()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 
supportsHover(const RenderStyle *) const279 bool RenderThemeQt::supportsHover(const RenderStyle*) const
280 {
281     return true;
282 }
283 
supportsFocusRing(const RenderStyle * style) const284 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 
baselinePosition(const RenderObject * o) const312 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 
controlSupportsTints(const RenderObject * o) const322 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 
supportsControlTints() const335 bool RenderThemeQt::supportsControlTints() const
336 {
337     return true;
338 }
339 
findFrameLineWidth(QStyle * style) const340 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 
inflateButtonRect(const QRect & originalRect,QStyle * style)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 
adjustRepaintRect(const RenderObject * o,IntRect & rect)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 
platformActiveSelectionBackgroundColor() const393 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
394 {
395     QPalette pal = QApplication::palette();
396     setPaletteFromPageClientIfExists(pal);
397     return pal.brush(QPalette::Active, QPalette::Highlight).color();
398 }
399 
platformInactiveSelectionBackgroundColor() const400 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
401 {
402     QPalette pal = QApplication::palette();
403     setPaletteFromPageClientIfExists(pal);
404     return pal.brush(QPalette::Inactive, QPalette::Highlight).color();
405 }
406 
platformActiveSelectionForegroundColor() const407 Color RenderThemeQt::platformActiveSelectionForegroundColor() const
408 {
409     QPalette pal = QApplication::palette();
410     setPaletteFromPageClientIfExists(pal);
411     return pal.brush(QPalette::Active, QPalette::HighlightedText).color();
412 }
413 
platformInactiveSelectionForegroundColor() const414 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
415 {
416     QPalette pal = QApplication::palette();
417     setPaletteFromPageClientIfExists(pal);
418     return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color();
419 }
420 
platformFocusRingColor() const421 Color RenderThemeQt::platformFocusRingColor() const
422 {
423     QPalette pal = QApplication::palette();
424     setPaletteFromPageClientIfExists(pal);
425     return pal.brush(QPalette::Active, QPalette::Highlight).color();
426 }
427 
systemFont(int,FontDescription &) const428 void RenderThemeQt::systemFont(int, FontDescription&) const
429 {
430     // no-op
431 }
432 
systemColor(int cssValueId) const433 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 
minimumMenuListSize(RenderStyle *) const446 int RenderThemeQt::minimumMenuListSize(RenderStyle*) const
447 {
448     const QFontMetrics &fm = QApplication::fontMetrics();
449     return 7 * fm.width(QLatin1Char('x'));
450 }
451 
computeSizeBasedOnStyle(RenderStyle * renderStyle) const452 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 
setCheckboxSize(RenderStyle * style) const535 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
536 {
537     computeSizeBasedOnStyle(style);
538 }
539 
paintCheckbox(RenderObject * o,const PaintInfo & i,const IntRect & r)540 bool RenderThemeQt::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
541 {
542     return paintButton(o, i, r);
543 }
544 
setRadioSize(RenderStyle * style) const545 void RenderThemeQt::setRadioSize(RenderStyle* style) const
546 {
547     computeSizeBasedOnStyle(style);
548 }
549 
paintRadio(RenderObject * o,const PaintInfo & i,const IntRect & r)550 bool RenderThemeQt::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
551 {
552     return paintButton(o, i, r);
553 }
554 
adjustButtonStyle(CSSStyleSelector * selector,RenderStyle * style,Element *) const555 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 
setButtonSize(RenderStyle * style) const591 void RenderThemeQt::setButtonSize(RenderStyle* style) const
592 {
593     computeSizeBasedOnStyle(style);
594 }
595 
596 #if !USE(QT_MOBILE_THEME)
setButtonPadding(RenderStyle * style) const597 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
setButtonPadding(RenderStyle * style) const632 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 
paintButton(RenderObject * o,const PaintInfo & i,const IntRect & r)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 
adjustTextFieldStyle(CSSStyleSelector *,RenderStyle * style,Element *) const666 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 
paintTextField(RenderObject * o,const PaintInfo & i,const IntRect & r)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 
adjustTextAreaStyle(CSSStyleSelector * selector,RenderStyle * style,Element * element) const714 void RenderThemeQt::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
715 {
716     adjustTextFieldStyle(selector, style, element);
717 }
718 
paintTextArea(RenderObject * o,const PaintInfo & i,const IntRect & r)719 bool RenderThemeQt::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
720 {
721     return paintTextField(o, i, r);
722 }
723 
adjustMenuListStyle(CSSStyleSelector *,RenderStyle * style,Element *) const724 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 
setPopupPadding(RenderStyle * style) const743 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 
paintMenuList(RenderObject * o,const PaintInfo & i,const IntRect & r)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 
adjustMenuListButtonStyle(CSSStyleSelector *,RenderStyle * style,Element *) const789 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 
paintMenuListButton(RenderObject * o,const PaintInfo & i,const IntRect & r)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)
animationRepeatIntervalForProgressBar(RenderProgress * renderProgress) const832 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 
animationDurationForProgressBar(RenderProgress * renderProgress) const842 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 
adjustProgressBarStyle(CSSStyleSelector *,RenderStyle * style,Element *) const854 void RenderThemeQt::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
855 {
856     style->setBoxShadow(0);
857 }
858 
paintProgressBar(RenderObject * o,const PaintInfo & pi,const IntRect & r)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 
paintSliderTrack(RenderObject * o,const PaintInfo & pi,const IntRect & r)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 
adjustSliderTrackStyle(CSSStyleSelector *,RenderStyle * style,Element *) const951 void RenderThemeQt::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
952 {
953     style->setBoxShadow(0);
954 }
955 
paintSliderThumb(RenderObject * o,const PaintInfo & pi,const IntRect & r)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 
adjustSliderThumbStyle(CSSStyleSelector *,RenderStyle * style,Element *) const963 void RenderThemeQt::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
964 {
965     style->setBoxShadow(0);
966 }
967 
paintSearchField(RenderObject * o,const PaintInfo & pi,const IntRect & r)968 bool RenderThemeQt::paintSearchField(RenderObject* o, const PaintInfo& pi,
969                                      const IntRect& r)
970 {
971     return paintTextField(o, pi, r);
972 }
973 
adjustSearchFieldStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const974 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 
adjustSearchFieldCancelButtonStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const988 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
convertToPaintingRect(RenderObject * inputRenderer,const RenderObject * partRenderer,IntRect partRect,const IntRect & localOffset) const1000 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 
paintSearchFieldCancelButton(RenderObject * o,const PaintInfo & pi,const IntRect & r)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 
adjustSearchFieldDecorationStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const1040 void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
1041                                                      Element* e) const
1042 {
1043     notImplemented();
1044     RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e);
1045 }
1046 
paintSearchFieldDecoration(RenderObject * o,const PaintInfo & pi,const IntRect & r)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 
adjustSearchFieldResultsDecorationStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const1054 void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style,
1055                                                             Element* e) const
1056 {
1057     notImplemented();
1058     RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e);
1059 }
1060 
paintSearchFieldResultsDecoration(RenderObject * o,const PaintInfo & pi,const IntRect & r)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 
supportsFocus(ControlPart appearance) const1068 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 
setPaletteFromPageClientIfExists(QPalette & palette) const1087 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 
initializeCommonQStyleOptions(QStyleOption & option,RenderObject * o) const1109 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 
extraMediaControlsStyleSheet()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:
WorldMatrixTransformer(QPainter * painter,RenderObject * renderObject,const IntRect & r)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 
~WorldMatrixTransformer()1190     ~WorldMatrixTransformer() { m_painter->setTransform(m_originalTransform); }
1191 
1192 private:
1193     QPainter* m_painter;
1194     QTransform m_originalTransform;
1195 };
1196 
mediaControlsBaselineOpacity() const1197 double RenderThemeQt::mediaControlsBaselineOpacity() const
1198 {
1199     return 0.4;
1200 }
1201 
paintMediaBackground(QPainter * painter,const IntRect & r) const1202 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 
getMediaControlForegroundColor(RenderObject * o) const1210 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 
paintMediaFullscreenButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
paintMediaMuteButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
paintMediaPlayButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
paintMediaSeekBackButton(RenderObject *,const PaintInfo &,const IntRect &)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 
paintMediaSeekForwardButton(RenderObject *,const PaintInfo &,const IntRect &)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 
paintMediaCurrentTime(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
formatMediaControlsCurrentTime(float currentTime,float duration) const1317 String RenderThemeQt::formatMediaControlsCurrentTime(float currentTime, float duration) const
1318 {
1319     return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
1320 }
1321 
formatMediaControlsRemainingTime(float currentTime,float duration) const1322 String RenderThemeQt::formatMediaControlsRemainingTime(float currentTime, float duration) const
1323 {
1324     return String();
1325 }
1326 
paintMediaVolumeSliderTrack(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
paintMediaVolumeSliderThumb(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
paintMediaSliderTrack(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
paintMediaSliderThumb(RenderObject * o,const PaintInfo & paintInfo,const IntRect & r)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 
adjustSliderThumbSize(RenderObject * o) const1436 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 
caretBlinkInterval() const1468 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