1de8153a3a1f3b8f9821d97613676c52106ac0ca
[WebKit-https.git] / Source / WebCore / platform / qt / RenderThemeQt.cpp
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 "CSSValueKeywords.h"
34 #include "Chrome.h"
35 #include "ChromeClient.h"
36 #include "Color.h"
37 #include "FileList.h"
38 #include "Font.h"
39 #include "FontSelector.h"
40 #include "GraphicsContext.h"
41 #include "HTMLInputElement.h"
42 #include "HTMLMediaElement.h"
43 #include "HTMLNames.h"
44 #include "LocalizedStrings.h"
45 #if ENABLE(VIDEO)
46 #include "MediaControlElements.h"
47 #endif
48 #include "NotImplemented.h"
49 #include "Page.h"
50 #include "PaintInfo.h"
51 #include "RenderBox.h"
52 #if ENABLE(PROGRESS_ELEMENT)
53 #include "RenderProgress.h"
54 #endif
55 #include "RenderTheme.h"
56 #include "RenderThemeQtMobile.h"
57 #include "ScrollbarTheme.h"
58 #include "StyleResolver.h"
59 #include "TimeRanges.h"
60 #include "UserAgentStyleSheets.h"
61 #include <wtf/text/StringBuilder.h>
62
63 #include <QGuiApplication>
64 #include <QColor>
65 #include <QFile>
66 #include <QFontMetrics>
67
68 #include <QStyleHints>
69
70 namespace WebCore {
71
72 using namespace HTMLNames;
73
74 // These values all match Safari/Win/Chromium
75 static const float defaultControlFontPixelSize = 13;
76 static const float defaultCancelButtonSize = 9;
77 static const float minCancelButtonSize = 5;
78 static const float maxCancelButtonSize = 21;
79 static const float defaultSearchFieldResultsDecorationSize = 13;
80 static const float minSearchFieldResultsDecorationSize = 9;
81 static const float maxSearchFieldResultsDecorationSize = 30;
82 static const float defaultSearchFieldResultsButtonWidth = 18;
83
84 static QtThemeFactoryFunction themeFactory;
85 static ScrollbarTheme* scrollbarTheme;
86
87 RenderThemeQt::RenderThemeQt(Page* page)
88     : RenderTheme()
89     , m_page(page)
90 {
91     m_buttonFontFamily = QGuiApplication::font().family();
92 }
93
94 void RenderThemeQt::setCustomTheme(QtThemeFactoryFunction factory, ScrollbarTheme* customScrollbarTheme)
95 {
96     themeFactory = factory;
97     scrollbarTheme = customScrollbarTheme;
98 }
99
100 ScrollbarTheme* RenderThemeQt::customScrollbarTheme()
101 {
102     return scrollbarTheme;
103 }
104
105 static PassRefPtr<RenderTheme> createTheme(Page* page)
106 {
107     if (themeFactory)
108         return themeFactory(page);
109     return RenderThemeQtMobile::create(page);
110 }
111
112 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
113 {
114     if (page)
115         return createTheme(page);
116     static RenderTheme* fallback = createTheme(0).leakRef();
117     return fallback;
118 }
119
120 // Remove this when SearchFieldPart is style-able in RenderTheme::isControlStyled()
121 bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& fill, const Color& backgroundColor) const
122 {
123     switch (style->appearance()) {
124     case SearchFieldPart:
125         // Test the style to see if the UA border and background match.
126         return (style->border() != border
127                 || *style->backgroundLayers() != fill
128                 || style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor);
129     default:
130         return RenderTheme::isControlStyled(style, border, fill, backgroundColor);
131     }
132 }
133
134 String RenderThemeQt::extraDefaultStyleSheet()
135 {
136     StringBuilder result;
137     result.append(RenderTheme::extraDefaultStyleSheet());
138     // When no theme factory is provided we default to using our platform independent "Mobile Qt" theme,
139     // which requires the following stylesheets.
140     if (!themeFactory) {
141         result.append(String(themeQtNoListboxesUserAgentStyleSheet, sizeof(themeQtNoListboxesUserAgentStyleSheet)));
142         result.append(String(mobileThemeQtUserAgentStyleSheet, sizeof(mobileThemeQtUserAgentStyleSheet)));
143     }
144     return result.toString();
145 }
146
147 bool RenderThemeQt::supportsHover(const RenderStyle*) const
148 {
149     return true;
150 }
151
152 bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const
153 {
154     switch (style->appearance()) {
155     case CheckboxPart:
156     case RadioPart:
157     case PushButtonPart:
158     case SquareButtonPart:
159     case ButtonPart:
160     case ButtonBevelPart:
161     case ListboxPart:
162     case ListItemPart:
163     case MenulistPart:
164     case MenulistButtonPart:
165     case SliderHorizontalPart:
166     case SliderVerticalPart:
167     case SliderThumbHorizontalPart:
168     case SliderThumbVerticalPart:
169     case SearchFieldPart:
170     case SearchFieldResultsButtonPart:
171     case SearchFieldCancelButtonPart:
172     case TextFieldPart:
173     case TextAreaPart:
174         return true;
175     default:
176         return false;
177     }
178 }
179
180 LayoutUnit RenderThemeQt::baselinePosition(const RenderObject* o) const
181 {
182     if (!o->isBox())
183         return 0;
184
185     if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart)
186         return toRenderBox(o)->marginTop() + toRenderBox(o)->height() - 2; // Same as in old khtml
187     return RenderTheme::baselinePosition(o);
188 }
189
190 bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const
191 {
192     if (!isEnabled(o))
193         return false;
194
195     // Checkboxes only have tint when checked.
196     if (o->style()->appearance() == CheckboxPart)
197         return isChecked(o);
198
199     // For now assume other controls have tint if enabled.
200     return true;
201 }
202
203 bool RenderThemeQt::supportsControlTints() const
204 {
205     return true;
206 }
207
208 QRect RenderThemeQt::inflateButtonRect(const QRect& originalRect) const
209 {
210     return originalRect;
211 }
212
213 void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& rect)
214 {
215     switch (o->style()->appearance()) {
216     case CheckboxPart:
217         break;
218     case RadioPart:
219         break;
220     case PushButtonPart:
221     case ButtonPart: {
222         QRect inflatedRect = inflateButtonRect(rect);
223         rect = IntRect(inflatedRect.x(), inflatedRect.y(), inflatedRect.width(), inflatedRect.height());
224         break;
225     }
226     case MenulistPart:
227         break;
228     default:
229         break;
230     }
231 }
232
233 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
234 {
235     return colorPalette().brush(QPalette::Active, QPalette::Highlight).color();
236 }
237
238 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
239 {
240     return colorPalette().brush(QPalette::Inactive, QPalette::Highlight).color();
241 }
242
243 Color RenderThemeQt::platformActiveSelectionForegroundColor() const
244 {
245     return colorPalette().brush(QPalette::Active, QPalette::HighlightedText).color();
246 }
247
248 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
249 {
250     return colorPalette().brush(QPalette::Inactive, QPalette::HighlightedText).color();
251 }
252
253 Color RenderThemeQt::platformFocusRingColor() const
254 {
255     return colorPalette().brush(QPalette::Active, QPalette::Highlight).color();
256 }
257
258 void RenderThemeQt::systemFont(int, FontDescription&) const
259 {
260     // no-op
261 }
262
263 Color RenderThemeQt::systemColor(int cssValueId) const
264 {
265     QPalette pal = colorPalette();
266     switch (cssValueId) {
267     case CSSValueButtontext:
268         return pal.brush(QPalette::Active, QPalette::ButtonText).color();
269     case CSSValueCaptiontext:
270         return pal.brush(QPalette::Active, QPalette::Text).color();
271     default:
272         return RenderTheme::systemColor(cssValueId);
273     }
274 }
275
276 int RenderThemeQt::minimumMenuListSize(RenderStyle*) const
277 {
278     // FIXME: Later we need a way to query the UI process for the dpi
279     const QFontMetrics fm(QGuiApplication::font());
280     return fm.width(QLatin1Char('x'));
281 }
282
283 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
284 {
285     computeSizeBasedOnStyle(style);
286 }
287
288 bool RenderThemeQt::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
289 {
290     return paintButton(o, i, r);
291 }
292
293 void RenderThemeQt::setRadioSize(RenderStyle* style) const
294 {
295     computeSizeBasedOnStyle(style);
296 }
297
298 bool RenderThemeQt::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
299 {
300     return paintButton(o, i, r);
301 }
302
303 void RenderThemeQt::setButtonSize(RenderStyle* style) const
304 {
305     computeSizeBasedOnStyle(style);
306 }
307
308 void RenderThemeQt::adjustTextFieldStyle(StyleResolver*, RenderStyle* style, Element*) const
309 {
310     // Resetting the style like this leads to differences like:
311     // - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)]
312     // + RenderTextControl {INPUT} at (2,2) size 166x26
313     // in layout tests when a CSS style is applied that doesn't affect background color, border or
314     // padding. Just worth keeping in mind!
315     style->setBackgroundColor(Color::transparent);
316     style->resetBorder();
317     style->resetPadding();
318     computeSizeBasedOnStyle(style);
319 }
320
321 void RenderThemeQt::adjustTextAreaStyle(StyleResolver* selector, RenderStyle* style, Element* element) const
322 {
323     adjustTextFieldStyle(selector, style, element);
324 }
325
326 bool RenderThemeQt::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
327 {
328     return paintTextField(o, i, r);
329 }
330
331 void RenderThemeQt::adjustMenuListStyle(StyleResolver*, RenderStyle* style, Element*) const
332 {
333     style->resetBorder();
334
335     // Height is locked to auto.
336     style->setHeight(Length(Auto));
337
338     // White-space is locked to pre
339     style->setWhiteSpace(PRE);
340
341     computeSizeBasedOnStyle(style);
342
343     // Add in the padding that we'd like to use.
344     setPopupPadding(style);
345 }
346
347 void RenderThemeQt::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
348 {
349     // Height is locked to auto.
350     style->setHeight(Length(Auto));
351
352     // White-space is locked to pre
353     style->setWhiteSpace(PRE);
354
355     computeSizeBasedOnStyle(style);
356
357     // Add in the padding that we'd like to use.
358     setPopupPadding(style);
359 }
360
361 #if ENABLE(PROGRESS_ELEMENT)
362 double RenderThemeQt::animationRepeatIntervalForProgressBar(RenderProgress* renderProgress) const
363 {
364     if (renderProgress->position() >= 0)
365         return 0;
366
367     // FIXME: Use hard-coded value until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed.
368     // Use the value from windows style which is 10 fps.
369     return 0.1;
370 }
371
372 void RenderThemeQt::adjustProgressBarStyle(StyleResolver*, RenderStyle* style, Element*) const
373 {
374     style->setBoxShadow(nullptr);
375 }
376 #endif
377
378 void RenderThemeQt::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
379 {
380     style->setBoxShadow(nullptr);
381 }
382
383 void RenderThemeQt::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
384 {
385     RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
386     style->setBoxShadow(nullptr);
387 }
388
389 #if ENABLE(DATALIST_ELEMENT)
390 IntSize RenderThemeQt::sliderTickSize() const
391 {
392     // FIXME: We need to set this to the size of one tick mark.
393     return IntSize(0, 0);
394 }
395
396 int RenderThemeQt::sliderTickOffsetFromTrackCenter() const
397 {
398     // FIXME: We need to set this to the position of the tick marks.
399     return 0;
400 }
401 #endif
402
403 bool RenderThemeQt::paintSearchField(RenderObject* o, const PaintInfo& pi,
404                                      const IntRect& r)
405 {
406     return paintTextField(o, pi, r);
407 }
408
409 void RenderThemeQt::adjustSearchFieldStyle(StyleResolver*, RenderStyle* style, Element*) const
410 {
411     // Resetting the style like this leads to differences like:
412     // - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)]
413     // + RenderTextControl {INPUT} at (2,2) size 166x26
414     // in layout tests when a CSS style is applied that doesn't affect background color, border or
415     // padding. Just worth keeping in mind!
416     style->setBackgroundColor(Color::transparent);
417     style->resetBorder();
418     style->resetPadding();
419     computeSizeBasedOnStyle(style);
420 }
421
422 void RenderThemeQt::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
423 {
424     // Logic taken from RenderThemeChromium.cpp.
425     // Scale the button size based on the font size.
426     float fontScale = style->fontSize() / defaultControlFontPixelSize;
427     int cancelButtonSize = lroundf(qMin(qMax(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
428     style->setWidth(Length(cancelButtonSize, Fixed));
429     style->setHeight(Length(cancelButtonSize, Fixed));
430 }
431
432 // Function taken from RenderThemeChromium.cpp
433 IntRect RenderThemeQt::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, IntRect partRect, const IntRect& localOffset) const
434 {
435     // Compute an offset between the part renderer and the input renderer.
436     IntSize offsetFromInputRenderer = -roundedIntSize(partRenderer->offsetFromAncestorContainer(inputRenderer));
437     // Move the rect into partRenderer's coords.
438     partRect.move(offsetFromInputRenderer);
439     // Account for the local drawing offset.
440     partRect.move(localOffset.x(), localOffset.y());
441
442     return partRect;
443 }
444
445 QPalette RenderThemeQt::colorPalette() const
446 {
447     return QGuiApplication::palette();
448 }
449
450 bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& pi,
451                                                  const IntRect& r)
452 {
453     // Logic copied from RenderThemeChromium.cpp.
454
455     // Get the renderer of <input> element.
456     Node* input = o->node()->shadowHost();
457     if (!input)
458         input = o->node();
459     if (!input->renderer()->isBox())
460         return false;
461     RenderBox* inputRenderBox = toRenderBox(input->renderer());
462     IntRect inputContentBox = pixelSnappedIntRect(inputRenderBox->contentBoxRect());
463
464     // Make sure the scaled button stays square and will fit in its parent's box.
465     int cancelButtonSize = qMin(inputContentBox.width(), qMin(inputContentBox.height(), r.height()));
466     // Calculate cancel button's coordinates relative to the input element.
467     // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will
468     // be one pixel closer to the bottom of the field. This tends to look better with the text.
469     IntRect cancelButtonRect(o->offsetFromAncestorContainer(inputRenderBox).width(),
470                              inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2,
471                              cancelButtonSize, cancelButtonSize);
472     IntRect paintingRect = convertToPaintingRect(inputRenderBox, o, cancelButtonRect, r);
473     static Image* cancelImage = Image::loadPlatformResource("searchCancelButton").leakRef();
474     static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelButtonPressed").leakRef();
475     pi.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage,
476                                  o->style()->colorSpace(), paintingRect);
477     return false;
478 }
479
480 void RenderThemeQt::adjustSearchFieldDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
481 {
482     notImplemented();
483     RenderTheme::adjustSearchFieldDecorationStyle(styleResolver, style, e);
484 }
485
486 bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const PaintInfo& pi,
487                                                const IntRect& r)
488 {
489     notImplemented();
490     return RenderTheme::paintSearchFieldDecoration(o, pi, r);
491 }
492
493 void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
494 {
495     notImplemented();
496     RenderTheme::adjustSearchFieldResultsDecorationStyle(styleResolver, style, e);
497 }
498
499 bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& pi,
500                                                       const IntRect& r)
501 {
502     notImplemented();
503     return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r);
504 }
505
506 #ifndef QT_NO_SPINBOX
507 void RenderThemeQt::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
508 {
509     // Use the same width as our native scrollbar
510     int width = ScrollbarTheme::theme()->scrollbarThickness();
511     style->setWidth(Length(width, Fixed));
512     style->setMinWidth(Length(width, Fixed));
513 }
514 #endif
515
516 bool RenderThemeQt::supportsFocus(ControlPart appearance) const
517 {
518     switch (appearance) {
519     case PushButtonPart:
520     case ButtonPart:
521     case TextFieldPart:
522     case TextAreaPart:
523     case ListboxPart:
524     case MenulistPart:
525     case RadioPart:
526     case CheckboxPart:
527     case SliderHorizontalPart:
528     case SliderVerticalPart:
529         return true;
530     default: // No for all others...
531         return false;
532     }
533 }
534
535 #if ENABLE(VIDEO)
536
537 String RenderThemeQt::extraMediaControlsStyleSheet()
538 {
539     String result = String(mediaControlsQtUserAgentStyleSheet, sizeof(mediaControlsQtUserAgentStyleSheet));
540
541     if (m_page && m_page->chrome()->requiresFullscreenForVideoPlayback())
542         result.append(String(mediaControlsQtFullscreenUserAgentStyleSheet, sizeof(mediaControlsQtFullscreenUserAgentStyleSheet)));
543
544     return result;
545 }
546
547 // Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100
548 class WorldMatrixTransformer {
549 public:
550     WorldMatrixTransformer(QPainter* painter, RenderObject* renderObject, const IntRect& r) : m_painter(painter)
551     {
552         RenderStyle* style = renderObject->style();
553         m_originalTransform = m_painter->transform();
554         m_painter->translate(r.x() + style->paddingLeft().value(), r.y() + style->paddingTop().value());
555         m_painter->scale((r.width() - style->paddingLeft().value() - style->paddingRight().value()) / 100.0,
556              (r.height() - style->paddingTop().value() - style->paddingBottom().value()) / 100.0);
557     }
558
559     ~WorldMatrixTransformer() { m_painter->setTransform(m_originalTransform); }
560
561 private:
562     QPainter* m_painter;
563     QTransform m_originalTransform;
564 };
565
566 double RenderThemeQt::mediaControlsBaselineOpacity() const
567 {
568     return 0.4;
569 }
570
571 void RenderThemeQt::paintMediaBackground(QPainter* painter, const IntRect& r) const
572 {
573     painter->setPen(Qt::NoPen);
574     static QColor transparentBlack(0, 0, 0, mediaControlsBaselineOpacity() * 255);
575     painter->setBrush(transparentBlack);
576     painter->drawRoundedRect(r.x(), r.y(), r.width(), r.height(), 5.0, 5.0);
577 }
578
579 static bool mediaElementCanPlay(RenderObject* o)
580 {
581     HTMLMediaElement* mediaElement = toParentMediaElement(o);
582     if (!mediaElement)
583         return false;
584
585     return mediaElement->readyState() > HTMLMediaElement::HAVE_METADATA
586            || (mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING
587                && o->style()->appearance() == MediaPlayButtonPart && mediaElement->preload() == "none");
588 }
589
590 QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const
591 {
592     QColor fgColor = platformActiveSelectionBackgroundColor();
593     if (!o)
594         return fgColor;
595
596     if (o->node()->active())
597         fgColor = fgColor.lighter();
598
599     if (!mediaElementCanPlay(o))
600         fgColor = colorPalette().brush(QPalette::Disabled, QPalette::Text).color();
601
602     return fgColor;
603 }
604
605 bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
606 {
607     HTMLMediaElement* mediaElement = toParentMediaElement(o);
608     if (!mediaElement)
609         return false;
610
611     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
612     if (p.isNull() || !p->isValid())
613         return true;
614
615     p->painter->setRenderHint(QPainter::Antialiasing, true);
616
617     paintMediaBackground(p->painter, r);
618
619     WorldMatrixTransformer transformer(p->painter, o, r);
620     const QPointF arrowPolygon[9] = { QPointF(20, 0), QPointF(100, 0), QPointF(100, 80),
621             QPointF(80, 80), QPointF(80, 30), QPointF(10, 100), QPointF(0, 90), QPointF(70, 20), QPointF(20, 20)};
622
623     p->painter->setBrush(getMediaControlForegroundColor(o));
624     p->painter->drawPolygon(arrowPolygon, 9);
625
626     return false;
627 }
628
629 bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
630 {
631     HTMLMediaElement* mediaElement = toParentMediaElement(o);
632     if (!mediaElement)
633         return false;
634
635     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
636     if (p.isNull() || !p->isValid())
637         return true;
638
639     p->painter->setRenderHint(QPainter::Antialiasing, true);
640
641     paintMediaBackground(p->painter, r);
642
643     WorldMatrixTransformer transformer(p->painter, o, r);
644     const QPointF speakerPolygon[6] = { QPointF(20, 30), QPointF(50, 30), QPointF(80, 0),
645             QPointF(80, 100), QPointF(50, 70), QPointF(20, 70)};
646
647     p->painter->setBrush(mediaElement->muted() ? Qt::darkRed : getMediaControlForegroundColor(o));
648     p->painter->drawPolygon(speakerPolygon, 6);
649
650     return false;
651 }
652
653 bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
654 {
655     HTMLMediaElement* mediaElement = toParentMediaElement(o);
656     if (!mediaElement)
657         return false;
658
659     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
660     if (p.isNull() || !p->isValid())
661         return true;
662
663     p->painter->setRenderHint(QPainter::Antialiasing, true);
664
665     paintMediaBackground(p->painter, r);
666
667     WorldMatrixTransformer transformer(p->painter, o, r);
668     p->painter->setBrush(getMediaControlForegroundColor(o));
669     if (mediaElement->canPlay()) {
670         const QPointF playPolygon[3] = { QPointF(0, 0), QPointF(100, 50), QPointF(0, 100)};
671         p->painter->drawPolygon(playPolygon, 3);
672     } else {
673         p->painter->drawRect(0, 0, 30, 100);
674         p->painter->drawRect(70, 0, 30, 100);
675     }
676
677     return false;
678 }
679
680 bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&)
681 {
682     // We don't want to paint this at the moment.
683     return false;
684 }
685
686 bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&)
687 {
688     // We don't want to paint this at the moment.
689     return false;
690 }
691
692 bool RenderThemeQt::paintMediaCurrentTime(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
693 {
694     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
695     if (p.isNull() || !p->isValid())
696         return true;
697
698     p->painter->setRenderHint(QPainter::Antialiasing, true);
699     paintMediaBackground(p->painter, r);
700
701     return false;
702 }
703
704 String RenderThemeQt::formatMediaControlsCurrentTime(float currentTime, float duration) const
705 {
706     return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
707 }
708
709 String RenderThemeQt::formatMediaControlsRemainingTime(float currentTime, float duration) const
710 {
711     return String();
712 }
713
714 bool RenderThemeQt::paintMediaVolumeSliderTrack(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r)
715 {
716     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
717     if (p.isNull() || !p->isValid())
718         return true;
719
720     p->painter->setRenderHint(QPainter::Antialiasing, true);
721
722     paintMediaBackground(p->painter, r);
723
724     if (!o->isSlider())
725         return false;
726
727     IntRect b = pixelSnappedIntRect(toRenderBox(o)->contentBoxRect());
728
729     // Position the outer rectangle
730     int top = r.y() + b.y();
731     int left = r.x() + b.x();
732     int width = b.width();
733     int height = b.height();
734
735     QPalette pal = colorPalette();
736     const QColor highlightText = pal.brush(QPalette::Active, QPalette::HighlightedText).color();
737     const QColor scaleColor(highlightText.red(), highlightText.green(), highlightText.blue(), mediaControlsBaselineOpacity() * 255);
738
739     // Draw the outer rectangle
740     p->painter->setBrush(scaleColor);
741     p->painter->drawRect(left, top, width, height);
742
743     if (!o->node() || !o->node()->hasTagName(inputTag))
744         return false;
745
746     HTMLInputElement* slider = static_cast<HTMLInputElement*>(o->node());
747
748     // Position the inner rectangle
749     height = height * slider->valueAsNumber();
750     top += b.height() - height;
751
752     // Draw the inner rectangle
753     p->painter->setPen(Qt::NoPen);
754     p->painter->setBrush(getMediaControlForegroundColor(o));
755     p->painter->drawRect(left, top, width, height);
756
757     return false;
758 }
759
760 bool RenderThemeQt::paintMediaVolumeSliderThumb(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r)
761 {
762     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
763     if (p.isNull() || !p->isValid())
764         return true;
765
766     // Nothing to draw here, this is all done in the track
767     return false;
768 }
769
770 bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
771 {
772     HTMLMediaElement* mediaElement = toParentMediaElement(o);
773     if (!mediaElement)
774         return false;
775
776     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
777     if (p.isNull() || !p->isValid())
778         return true;
779
780     p->painter->setRenderHint(QPainter::Antialiasing, true);
781
782     paintMediaBackground(p->painter, r);
783
784     if (MediaPlayer* player = mediaElement->player()) {
785         // Get the buffered parts of the media
786         RefPtr<TimeRanges> buffered = player->buffered();
787         if (buffered->length() > 0 && player->duration() < std::numeric_limits<float>::infinity()) {
788             // Set the transform and brush
789             WorldMatrixTransformer transformer(p->painter, o, r);
790             p->painter->setBrush(getMediaControlForegroundColor());
791
792             // Paint each buffered section
793             ExceptionCode ex;
794             for (int i = 0; i < buffered->length(); i++) {
795                 float startX = (buffered->start(i, ex) / player->duration()) * 100;
796                 float width = ((buffered->end(i, ex) / player->duration()) * 100) - startX;
797                 p->painter->drawRect(startX, 37, width, 26);
798             }
799         }
800     }
801
802     return false;
803 }
804
805 bool RenderThemeQt::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
806 {
807     ASSERT(o->node());
808     Node* hostNode = o->node()->shadowHost();
809     if (!hostNode)
810         hostNode = o->node();
811     HTMLMediaElement* mediaElement = toParentMediaElement(hostNode);
812     if (!mediaElement)
813         return false;
814
815     QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
816     if (p.isNull() || !p->isValid())
817         return true;
818
819     p->painter->setRenderHint(QPainter::Antialiasing, true);
820
821     p->painter->setPen(Qt::NoPen);
822     p->painter->setBrush(getMediaControlForegroundColor(hostNode->renderer()));
823     p->painter->drawRect(r.x(), r.y(), r.width(), r.height());
824
825     return false;
826 }
827 #endif
828
829 void RenderThemeQt::adjustSliderThumbSize(RenderStyle* style, Element*) const
830 {
831     // timelineThumbHeight should match the height property of -webkit-media-controls-timeline in mediaControlsQt.css.
832     const int timelineThumbHeight = 12;
833     const int timelineThumbWidth = timelineThumbHeight / 3;
834     // volumeThumbWidth should match the width property of -webkit-media-controls-volume-slider in mediaControlsQt.css.
835     const int volumeThumbWidth = 12;
836     const int volumeThumbHeight = volumeThumbWidth / 3;
837     ControlPart part = style->appearance();
838
839     if (part == MediaSliderThumbPart) {
840         style->setWidth(Length(timelineThumbWidth, Fixed));
841         style->setHeight(Length(timelineThumbHeight, Fixed));
842     } else if (part == MediaVolumeSliderThumbPart) {
843         style->setHeight(Length(volumeThumbHeight, Fixed));
844         style->setWidth(Length(volumeThumbWidth, Fixed));
845     }
846 }
847
848 double RenderThemeQt::caretBlinkInterval() const
849 {
850     return static_cast<QGuiApplication*>(qApp)->styleHints()->cursorFlashTime() / 1000.0 / 2.0;
851 }
852
853 String RenderThemeQt::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
854 {
855     UNUSED_PARAM(multipleFilesAllowed);
856     if (width <= 0)
857         return String();
858
859     String string;
860     if (fileList->isEmpty())
861         string = fileButtonNoFileSelectedLabel();
862     else if (fileList->length() == 1) {
863         String fname = fileList->item(0)->path();
864         QFontMetrics fm(font.syntheticFont());
865         string = fm.elidedText(fname, Qt::ElideLeft, width);
866     } else {
867         int n = fileList->length();
868         string = QCoreApplication::translate("QWebPage", "%n file(s)",
869                                              "number of chosen file",
870                                              n);
871     }
872
873     return string;
874 }
875
876 StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo)
877     : painter(0)
878 {
879     Q_UNUSED(theme);
880     ASSERT(paintInfo.context);
881     init(paintInfo.context);
882 }
883
884 StylePainter::StylePainter()
885     : painter(0)
886 {
887 }
888
889 void StylePainter::init(GraphicsContext* context)
890 {
891     painter = static_cast<QPainter*>(context->platformContext());
892
893     if (painter) {
894         // the styles often assume being called with a pristine painter where no brush is set,
895         // so reset it manually
896         m_previousBrush = painter->brush();
897         painter->setBrush(Qt::NoBrush);
898
899         // painting the widget with anti-aliasing will make it blurry
900         // disable it here and restore it later
901         m_previousAntialiasing = painter->testRenderHint(QPainter::Antialiasing);
902         painter->setRenderHint(QPainter::Antialiasing, false);
903     }
904 }
905
906 StylePainter::~StylePainter()
907 {
908     if (painter) {
909         painter->setBrush(m_previousBrush);
910         painter->setRenderHints(QPainter::Antialiasing, m_previousAntialiasing);
911     }
912 }
913
914 }
915
916 // vim: ts=4 sw=4 et