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