blob: 1f779c87fa34143009c7b317e6bec615fa17ba08 [file] [log] [blame]
/*
* This file is part of the WebKit project.
*
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
*
* Copyright (C) 2006 Zack Rusin <zack@kde.org>
* 2006 Dirk Mueller <mueller@kde.org>
* 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2008 Holger Hans Peter Freyther
*
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "RenderThemeQt.h"
#include "CSSValueKeywords.h"
#include "Chrome.h"
#include "ChromeClient.h"
#include "Color.h"
#include "ExceptionCodePlaceholder.h"
#include "FileList.h"
#include "Font.h"
#include "FontSelector.h"
#include "GraphicsContext.h"
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#include "LocalizedStrings.h"
#if ENABLE(VIDEO)
#include "MediaControlElements.h"
#endif
#include "NotImplemented.h"
#include "Page.h"
#include "PaintInfo.h"
#include "RenderBox.h"
#if ENABLE(PROGRESS_ELEMENT)
#include "RenderProgress.h"
#endif
#include "RenderTheme.h"
#include "RenderThemeQtMobile.h"
#include "ScrollbarTheme.h"
#include "StyleResolver.h"
#include "TimeRanges.h"
#include "UserAgentStyleSheets.h"
#include <wtf/text/StringBuilder.h>
#include <QColor>
#include <QFile>
#include <QFontMetrics>
#include <QGuiApplication>
#include <QStyleHints>
namespace WebCore {
using namespace HTMLNames;
// These values all match Safari/Win/Chromium
static const float defaultControlFontPixelSize = 13;
static const float defaultCancelButtonSize = 9;
static const float minCancelButtonSize = 5;
static const float maxCancelButtonSize = 21;
static const float defaultSearchFieldResultsDecorationSize = 13;
static const float minSearchFieldResultsDecorationSize = 9;
static const float maxSearchFieldResultsDecorationSize = 30;
static const float defaultSearchFieldResultsButtonWidth = 18;
static QtThemeFactoryFunction themeFactory;
static ScrollbarTheme* scrollbarTheme;
RenderThemeQt::RenderThemeQt(Page* page)
: RenderTheme()
, m_page(page)
{
m_buttonFontFamily = QGuiApplication::font().family();
}
void RenderThemeQt::setCustomTheme(QtThemeFactoryFunction factory, ScrollbarTheme* customScrollbarTheme)
{
themeFactory = factory;
scrollbarTheme = customScrollbarTheme;
}
ScrollbarTheme* RenderThemeQt::customScrollbarTheme()
{
return scrollbarTheme;
}
static PassRefPtr<RenderTheme> createTheme(Page* page)
{
if (themeFactory)
return themeFactory(page);
return RenderThemeQtMobile::create(page);
}
PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
{
if (page)
return createTheme(page);
static RenderTheme* fallback = createTheme(0).leakRef();
return fallback;
}
// Remove this when SearchFieldPart is style-able in RenderTheme::isControlStyled()
bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& fill, const Color& backgroundColor) const
{
switch (style->appearance()) {
case SearchFieldPart:
// Test the style to see if the UA border and background match.
return (style->border() != border
|| *style->backgroundLayers() != fill
|| style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor);
default:
return RenderTheme::isControlStyled(style, border, fill, backgroundColor);
}
}
String RenderThemeQt::extraDefaultStyleSheet()
{
StringBuilder result;
result.append(RenderTheme::extraDefaultStyleSheet());
// When no theme factory is provided we default to using our platform independent "Mobile Qt" theme,
// which requires the following stylesheets.
if (!themeFactory) {
result.append(String(themeQtNoListboxesUserAgentStyleSheet, sizeof(themeQtNoListboxesUserAgentStyleSheet)));
result.append(String(mobileThemeQtUserAgentStyleSheet, sizeof(mobileThemeQtUserAgentStyleSheet)));
}
return result.toString();
}
bool RenderThemeQt::supportsHover(const RenderStyle*) const
{
return true;
}
bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const
{
switch (style->appearance()) {
case CheckboxPart:
case RadioPart:
case PushButtonPart:
case SquareButtonPart:
case ButtonPart:
case ButtonBevelPart:
case ListboxPart:
case ListItemPart:
case MenulistPart:
case MenulistButtonPart:
case SliderHorizontalPart:
case SliderVerticalPart:
case SliderThumbHorizontalPart:
case SliderThumbVerticalPart:
case SearchFieldPart:
case SearchFieldResultsButtonPart:
case SearchFieldCancelButtonPart:
case TextFieldPart:
case TextAreaPart:
return true;
default:
return false;
}
}
int RenderThemeQt::baselinePosition(const RenderObject* o) const
{
if (!o->isBox())
return 0;
if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart)
return toRenderBox(o)->marginTop() + toRenderBox(o)->height() - 2; // Same as in old khtml
return RenderTheme::baselinePosition(o);
}
bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const
{
if (!isEnabled(o))
return false;
// Checkboxes only have tint when checked.
if (o->style()->appearance() == CheckboxPart)
return isChecked(o);
// For now assume other controls have tint if enabled.
return true;
}
bool RenderThemeQt::supportsControlTints() const
{
return true;
}
QRect RenderThemeQt::inflateButtonRect(const QRect& originalRect) const
{
return originalRect;
}
void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& rect)
{
switch (o->style()->appearance()) {
case CheckboxPart:
break;
case RadioPart:
break;
case PushButtonPart:
case ButtonPart: {
QRect inflatedRect = inflateButtonRect(rect);
rect = IntRect(inflatedRect.x(), inflatedRect.y(), inflatedRect.width(), inflatedRect.height());
break;
}
case MenulistPart:
break;
default:
break;
}
}
Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
{
return colorPalette().brush(QPalette::Active, QPalette::Highlight).color();
}
Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const
{
return colorPalette().brush(QPalette::Inactive, QPalette::Highlight).color();
}
Color RenderThemeQt::platformActiveSelectionForegroundColor() const
{
return colorPalette().brush(QPalette::Active, QPalette::HighlightedText).color();
}
Color RenderThemeQt::platformInactiveSelectionForegroundColor() const
{
return colorPalette().brush(QPalette::Inactive, QPalette::HighlightedText).color();
}
Color RenderThemeQt::platformFocusRingColor() const
{
return colorPalette().brush(QPalette::Active, QPalette::Highlight).color();
}
void RenderThemeQt::systemFont(int, FontDescription&) const
{
// no-op
}
Color RenderThemeQt::systemColor(int cssValueId) const
{
QPalette pal = colorPalette();
switch (cssValueId) {
case CSSValueButtontext:
return pal.brush(QPalette::Active, QPalette::ButtonText).color();
case CSSValueCaptiontext:
return pal.brush(QPalette::Active, QPalette::Text).color();
default:
return RenderTheme::systemColor(cssValueId);
}
}
int RenderThemeQt::minimumMenuListSize(RenderStyle*) const
{
// FIXME: Later we need a way to query the UI process for the dpi
const QFontMetrics fm(QGuiApplication::font());
return fm.width(QLatin1Char('x'));
}
void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
{
computeSizeBasedOnStyle(style);
}
bool RenderThemeQt::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
return paintButton(o, i, r);
}
void RenderThemeQt::setRadioSize(RenderStyle* style) const
{
computeSizeBasedOnStyle(style);
}
bool RenderThemeQt::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
return paintButton(o, i, r);
}
void RenderThemeQt::setButtonSize(RenderStyle* style) const
{
computeSizeBasedOnStyle(style);
}
void RenderThemeQt::adjustTextFieldStyle(StyleResolver*, RenderStyle* style, Element*) const
{
// Resetting the style like this leads to differences like:
// - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)]
// + RenderTextControl {INPUT} at (2,2) size 166x26
// in layout tests when a CSS style is applied that doesn't affect background color, border or
// padding. Just worth keeping in mind!
style->setBackgroundColor(Color::transparent);
style->resetBorder();
style->resetPadding();
computeSizeBasedOnStyle(style);
}
void RenderThemeQt::adjustTextAreaStyle(StyleResolver* selector, RenderStyle* style, Element* element) const
{
adjustTextFieldStyle(selector, style, element);
}
bool RenderThemeQt::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
return paintTextField(o, i, r);
}
void RenderThemeQt::adjustMenuListStyle(StyleResolver*, RenderStyle* style, Element*) const
{
style->resetBorder();
// Height is locked to auto.
style->setHeight(Length(Auto));
// White-space is locked to pre
style->setWhiteSpace(PRE);
computeSizeBasedOnStyle(style);
// Add in the padding that we'd like to use.
setPopupPadding(style);
}
void RenderThemeQt::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
{
// Height is locked to auto.
style->setHeight(Length(Auto));
// White-space is locked to pre
style->setWhiteSpace(PRE);
computeSizeBasedOnStyle(style);
// Add in the padding that we'd like to use.
setPopupPadding(style);
}
#if ENABLE(PROGRESS_ELEMENT)
double RenderThemeQt::animationRepeatIntervalForProgressBar(RenderProgress* renderProgress) const
{
if (renderProgress->position() >= 0)
return 0;
// FIXME: Use hard-coded value until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed.
// Use the value from windows style which is 10 fps.
return 0.1;
}
void RenderThemeQt::adjustProgressBarStyle(StyleResolver*, RenderStyle* style, Element*) const
{
style->setBoxShadow(nullptr);
}
#endif
void RenderThemeQt::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
{
style->setBoxShadow(nullptr);
}
void RenderThemeQt::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
{
RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
style->setBoxShadow(nullptr);
}
#if ENABLE(DATALIST_ELEMENT)
IntSize RenderThemeQt::sliderTickSize() const
{
// FIXME: We need to set this to the size of one tick mark.
return IntSize(0, 0);
}
int RenderThemeQt::sliderTickOffsetFromTrackCenter() const
{
// FIXME: We need to set this to the position of the tick marks.
return 0;
}
#endif
bool RenderThemeQt::paintSearchField(RenderObject* o, const PaintInfo& pi,
const IntRect& r)
{
return paintTextField(o, pi, r);
}
void RenderThemeQt::adjustSearchFieldStyle(StyleResolver*, RenderStyle* style, Element*) const
{
// Resetting the style like this leads to differences like:
// - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)]
// + RenderTextControl {INPUT} at (2,2) size 166x26
// in layout tests when a CSS style is applied that doesn't affect background color, border or
// padding. Just worth keeping in mind!
style->setBackgroundColor(Color::transparent);
style->resetBorder();
style->resetPadding();
computeSizeBasedOnStyle(style);
}
void RenderThemeQt::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
{
// Logic taken from RenderThemeChromium.cpp.
// Scale the button size based on the font size.
float fontScale = style->fontSize() / defaultControlFontPixelSize;
int cancelButtonSize = lroundf(qMin(qMax(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
style->setWidth(Length(cancelButtonSize, Fixed));
style->setHeight(Length(cancelButtonSize, Fixed));
}
// Function taken from RenderThemeChromium.cpp
IntRect RenderThemeQt::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, IntRect partRect, const IntRect& localOffset) const
{
// Compute an offset between the part renderer and the input renderer.
IntSize offsetFromInputRenderer = -roundedIntSize(partRenderer->offsetFromAncestorContainer(inputRenderer));
// Move the rect into partRenderer's coords.
partRect.move(offsetFromInputRenderer);
// Account for the local drawing offset.
partRect.move(localOffset.x(), localOffset.y());
return partRect;
}
QPalette RenderThemeQt::colorPalette() const
{
return QGuiApplication::palette();
}
bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& pi,
const IntRect& r)
{
// Logic copied from RenderThemeChromium.cpp.
// Get the renderer of <input> element.
Node* input = o->node()->shadowHost();
if (!input)
input = o->node();
if (!input->renderer()->isBox())
return false;
RenderBox* inputRenderBox = toRenderBox(input->renderer());
IntRect inputContentBox = pixelSnappedIntRect(inputRenderBox->contentBoxRect());
// Make sure the scaled button stays square and will fit in its parent's box.
int cancelButtonSize = qMin(inputContentBox.width(), qMin(inputContentBox.height(), r.height()));
// Calculate cancel button's coordinates relative to the input element.
// Center the button vertically. Round up though, so if it has to be one pixel off-center, it will
// be one pixel closer to the bottom of the field. This tends to look better with the text.
IntRect cancelButtonRect(o->offsetFromAncestorContainer(inputRenderBox).width(),
inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2,
cancelButtonSize, cancelButtonSize);
IntRect paintingRect = convertToPaintingRect(inputRenderBox, o, cancelButtonRect, r);
static Image* cancelImage = Image::loadPlatformResource("searchCancelButton").leakRef();
static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelButtonPressed").leakRef();
pi.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage,
o->style()->colorSpace(), paintingRect);
return false;
}
void RenderThemeQt::adjustSearchFieldDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
{
notImplemented();
RenderTheme::adjustSearchFieldDecorationStyle(styleResolver, style, e);
}
bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const PaintInfo& pi,
const IntRect& r)
{
notImplemented();
return RenderTheme::paintSearchFieldDecoration(o, pi, r);
}
void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
{
notImplemented();
RenderTheme::adjustSearchFieldResultsDecorationStyle(styleResolver, style, e);
}
bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& pi,
const IntRect& r)
{
notImplemented();
return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r);
}
#ifndef QT_NO_SPINBOX
void RenderThemeQt::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
{
// Use the same width as our native scrollbar
int width = ScrollbarTheme::theme()->scrollbarThickness();
style->setWidth(Length(width, Fixed));
style->setMinWidth(Length(width, Fixed));
}
#endif
bool RenderThemeQt::supportsFocus(ControlPart appearance) const
{
switch (appearance) {
case PushButtonPart:
case ButtonPart:
case TextFieldPart:
case TextAreaPart:
case ListboxPart:
case MenulistPart:
case RadioPart:
case CheckboxPart:
case SliderHorizontalPart:
case SliderVerticalPart:
return true;
default: // No for all others...
return false;
}
}
#if ENABLE(VIDEO)
String RenderThemeQt::extraMediaControlsStyleSheet()
{
String result = String(mediaControlsQtUserAgentStyleSheet, sizeof(mediaControlsQtUserAgentStyleSheet));
if (m_page && m_page->chrome()->requiresFullscreenForVideoPlayback())
result.append(String(mediaControlsQtFullscreenUserAgentStyleSheet, sizeof(mediaControlsQtFullscreenUserAgentStyleSheet)));
return result;
}
// Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100
class WorldMatrixTransformer {
public:
WorldMatrixTransformer(QPainter* painter, RenderObject* renderObject, const IntRect& r) : m_painter(painter)
{
RenderStyle* style = renderObject->style();
m_originalTransform = m_painter->transform();
m_painter->translate(r.x() + style->paddingLeft().value(), r.y() + style->paddingTop().value());
m_painter->scale((r.width() - style->paddingLeft().value() - style->paddingRight().value()) / 100.0,
(r.height() - style->paddingTop().value() - style->paddingBottom().value()) / 100.0);
}
~WorldMatrixTransformer() { m_painter->setTransform(m_originalTransform); }
private:
QPainter* m_painter;
QTransform m_originalTransform;
};
double RenderThemeQt::mediaControlsBaselineOpacity() const
{
return 0.4;
}
void RenderThemeQt::paintMediaBackground(QPainter* painter, const IntRect& r) const
{
painter->setPen(Qt::NoPen);
static QColor transparentBlack(0, 0, 0, mediaControlsBaselineOpacity() * 255);
painter->setBrush(transparentBlack);
painter->drawRoundedRect(r.x(), r.y(), r.width(), r.height(), 5.0, 5.0);
}
static bool mediaElementCanPlay(RenderObject* o)
{
HTMLMediaElement* mediaElement = toParentMediaElement(o);
if (!mediaElement)
return false;
return mediaElement->readyState() > HTMLMediaElement::HAVE_METADATA
|| (mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING
&& o->style()->appearance() == MediaPlayButtonPart && mediaElement->preload() == "none");
}
QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const
{
QColor fgColor = platformActiveSelectionBackgroundColor();
if (!o)
return fgColor;
if (o->node()->active())
fgColor = fgColor.lighter();
if (!mediaElementCanPlay(o))
fgColor = colorPalette().brush(QPalette::Disabled, QPalette::Text).color();
return fgColor;
}
bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
HTMLMediaElement* mediaElement = toParentMediaElement(o);
if (!mediaElement)
return false;
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
p->painter->setRenderHint(QPainter::Antialiasing, true);
paintMediaBackground(p->painter, r);
WorldMatrixTransformer transformer(p->painter, o, r);
const QPointF arrowPolygon[9] = { QPointF(20, 0), QPointF(100, 0), QPointF(100, 80),
QPointF(80, 80), QPointF(80, 30), QPointF(10, 100), QPointF(0, 90), QPointF(70, 20), QPointF(20, 20)};
p->painter->setBrush(getMediaControlForegroundColor(o));
p->painter->drawPolygon(arrowPolygon, 9);
return false;
}
bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
HTMLMediaElement* mediaElement = toParentMediaElement(o);
if (!mediaElement)
return false;
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
p->painter->setRenderHint(QPainter::Antialiasing, true);
paintMediaBackground(p->painter, r);
WorldMatrixTransformer transformer(p->painter, o, r);
const QPointF speakerPolygon[6] = { QPointF(20, 30), QPointF(50, 30), QPointF(80, 0),
QPointF(80, 100), QPointF(50, 70), QPointF(20, 70)};
p->painter->setBrush(mediaElement->muted() ? Qt::darkRed : getMediaControlForegroundColor(o));
p->painter->drawPolygon(speakerPolygon, 6);
return false;
}
bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
HTMLMediaElement* mediaElement = toParentMediaElement(o);
if (!mediaElement)
return false;
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
p->painter->setRenderHint(QPainter::Antialiasing, true);
paintMediaBackground(p->painter, r);
WorldMatrixTransformer transformer(p->painter, o, r);
p->painter->setBrush(getMediaControlForegroundColor(o));
if (mediaElement->canPlay()) {
const QPointF playPolygon[3] = { QPointF(0, 0), QPointF(100, 50), QPointF(0, 100)};
p->painter->drawPolygon(playPolygon, 3);
} else {
p->painter->drawRect(0, 0, 30, 100);
p->painter->drawRect(70, 0, 30, 100);
}
return false;
}
bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&)
{
// We don't want to paint this at the moment.
return false;
}
bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&)
{
// We don't want to paint this at the moment.
return false;
}
bool RenderThemeQt::paintMediaCurrentTime(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
p->painter->setRenderHint(QPainter::Antialiasing, true);
paintMediaBackground(p->painter, r);
return false;
}
String RenderThemeQt::formatMediaControlsCurrentTime(float currentTime, float duration) const
{
return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
}
String RenderThemeQt::formatMediaControlsRemainingTime(float currentTime, float duration) const
{
return String();
}
bool RenderThemeQt::paintMediaVolumeSliderTrack(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r)
{
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
p->painter->setRenderHint(QPainter::Antialiasing, true);
paintMediaBackground(p->painter, r);
if (!o->isSlider())
return false;
IntRect b = pixelSnappedIntRect(toRenderBox(o)->contentBoxRect());
// Position the outer rectangle
int top = r.y() + b.y();
int left = r.x() + b.x();
int width = b.width();
int height = b.height();
QPalette pal = colorPalette();
const QColor highlightText = pal.brush(QPalette::Active, QPalette::HighlightedText).color();
const QColor scaleColor(highlightText.red(), highlightText.green(), highlightText.blue(), mediaControlsBaselineOpacity() * 255);
// Draw the outer rectangle
p->painter->setBrush(scaleColor);
p->painter->drawRect(left, top, width, height);
if (!o->node() || !o->node()->hasTagName(inputTag))
return false;
HTMLInputElement* slider = static_cast<HTMLInputElement*>(o->node());
// Position the inner rectangle
height = height * slider->valueAsNumber();
top += b.height() - height;
// Draw the inner rectangle
p->painter->setPen(Qt::NoPen);
p->painter->setBrush(getMediaControlForegroundColor(o));
p->painter->drawRect(left, top, width, height);
return false;
}
bool RenderThemeQt::paintMediaVolumeSliderThumb(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r)
{
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
// Nothing to draw here, this is all done in the track
return false;
}
bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
HTMLMediaElement* mediaElement = toParentMediaElement(o);
if (!mediaElement)
return false;
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
p->painter->setRenderHint(QPainter::Antialiasing, true);
paintMediaBackground(p->painter, r);
if (MediaPlayer* player = mediaElement->player()) {
// Get the buffered parts of the media
RefPtr<TimeRanges> buffered = player->buffered();
if (buffered->length() > 0 && player->duration() < std::numeric_limits<float>::infinity()) {
// Set the transform and brush
WorldMatrixTransformer transformer(p->painter, o, r);
p->painter->setBrush(getMediaControlForegroundColor());
// Paint each buffered section
for (int i = 0; i < buffered->length(); i++) {
float startX = (buffered->start(i, IGNORE_EXCEPTION) / player->duration()) * 100;
float width = ((buffered->end(i, IGNORE_EXCEPTION) / player->duration()) * 100) - startX;
p->painter->drawRect(startX, 37, width, 26);
}
}
}
return false;
}
bool RenderThemeQt::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
ASSERT(o->node());
Node* hostNode = o->node()->shadowHost();
if (!hostNode)
hostNode = o->node();
HTMLMediaElement* mediaElement = toParentMediaElement(hostNode);
if (!mediaElement)
return false;
QSharedPointer<StylePainter> p = getStylePainter(paintInfo);
if (p.isNull() || !p->isValid())
return true;
p->painter->setRenderHint(QPainter::Antialiasing, true);
p->painter->setPen(Qt::NoPen);
p->painter->setBrush(getMediaControlForegroundColor(hostNode->renderer()));
p->painter->drawRect(r.x(), r.y(), r.width(), r.height());
return false;
}
#endif
void RenderThemeQt::adjustSliderThumbSize(RenderStyle* style, Element*) const
{
// timelineThumbHeight should match the height property of -webkit-media-controls-timeline in mediaControlsQt.css.
const int timelineThumbHeight = 12;
const int timelineThumbWidth = timelineThumbHeight / 3;
// volumeThumbWidth should match the width property of -webkit-media-controls-volume-slider in mediaControlsQt.css.
const int volumeThumbWidth = 12;
const int volumeThumbHeight = volumeThumbWidth / 3;
ControlPart part = style->appearance();
if (part == MediaSliderThumbPart) {
style->setWidth(Length(timelineThumbWidth, Fixed));
style->setHeight(Length(timelineThumbHeight, Fixed));
} else if (part == MediaVolumeSliderThumbPart) {
style->setHeight(Length(volumeThumbHeight, Fixed));
style->setWidth(Length(volumeThumbWidth, Fixed));
}
}
double RenderThemeQt::caretBlinkInterval() const
{
return static_cast<QGuiApplication*>(qApp)->styleHints()->cursorFlashTime() / 1000.0 / 2.0;
}
String RenderThemeQt::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
{
UNUSED_PARAM(multipleFilesAllowed);
if (width <= 0)
return String();
String string;
if (fileList->isEmpty())
string = fileButtonNoFileSelectedLabel();
else if (fileList->length() == 1) {
String fname = fileList->item(0)->path();
QFontMetrics fm(font.syntheticFont());
string = fm.elidedText(fname, Qt::ElideLeft, width);
} else {
int n = fileList->length();
string = QCoreApplication::translate("QWebPage", "%n file(s)",
"number of chosen file",
n);
}
return string;
}
StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo)
: painter(0)
{
Q_UNUSED(theme);
ASSERT(paintInfo.context);
init(paintInfo.context);
}
StylePainter::StylePainter()
: painter(0)
{
}
void StylePainter::init(GraphicsContext* context)
{
painter = static_cast<QPainter*>(context->platformContext());
if (painter) {
// the styles often assume being called with a pristine painter where no brush is set,
// so reset it manually
m_previousBrush = painter->brush();
painter->setBrush(Qt::NoBrush);
// painting the widget with anti-aliasing will make it blurry
// disable it here and restore it later
m_previousAntialiasing = painter->testRenderHint(QPainter::Antialiasing);
painter->setRenderHint(QPainter::Antialiasing, false);
}
}
StylePainter::~StylePainter()
{
if (painter) {
painter->setBrush(m_previousBrush);
painter->setRenderHints(QPainter::Antialiasing, m_previousAntialiasing);
}
}
}
// vim: ts=4 sw=4 et