RenderThemeQStyle.cpp [plain text]
#include "config.h"
#include "RenderThemeQStyle.h"
#include "CSSFontSelector.h"
#include "CSSValueKeywords.h"
#include "Chrome.h"
#include "ChromeClient.h"
#include "Color.h"
#include "Document.h"
#include "Font.h"
#include "FontSelector.h"
#include "GraphicsContext.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "LocalizedStrings.h"
#include "NotImplemented.h"
#include "Page.h"
#include "PaintInfo.h"
#include "QWebPageClient.h"
#include "RenderBox.h"
#if ENABLE(PROGRESS_ELEMENT)
#include "RenderProgress.h"
#endif
#include "RenderSlider.h"
#include "ScrollbarThemeQStyle.h"
#include "SliderThumbElement.h"
#include "StyleResolver.h"
#include "UserAgentStyleSheets.h"
#include <QPainter>
namespace WebCore {
using namespace HTMLNames;
QSharedPointer<StylePainter> RenderThemeQStyle::getStylePainter(const PaintInfo& paintInfo)
{
return QSharedPointer<StylePainter>(new StylePainterQStyle(this, paintInfo, 0));
}
StylePainterQStyle::StylePainterQStyle(RenderThemeQStyle* theme, const PaintInfo& paintInfo, RenderObject* renderObject)
: StylePainter(theme, paintInfo)
, qStyle(theme->qStyle())
, appearance(NoControlPart)
{
init(paintInfo.context ? paintInfo.context : 0);
if (renderObject)
appearance = theme->initializeCommonQStyleOptions(styleOption, renderObject);
}
StylePainterQStyle::StylePainterQStyle(ScrollbarThemeQStyle* theme, GraphicsContext* context)
: StylePainter()
, qStyle(theme->qStyle())
, appearance(NoControlPart)
{
init(context);
}
void StylePainterQStyle::init(GraphicsContext* context)
{
painter = static_cast<QPainter*>(context->platformContext());
if (QObject* widget = qStyle->widgetForPainter(painter)) {
styleOption.palette = widget->property("palette").value<QPalette>();
styleOption.rect = widget->property("rect").value<QRect>();
styleOption.direction = static_cast<Qt::LayoutDirection>(widget->property("layoutDirection").toInt());
}
StylePainter::init(context);
}
PassRefPtr<RenderTheme> RenderThemeQStyle::create(Page* page)
{
return adoptRef(new RenderThemeQStyle(page));
}
static QtStyleFactoryFunction styleFactoryFunction;
void RenderThemeQStyle::setStyleFactoryFunction(QtStyleFactoryFunction function)
{
styleFactoryFunction = function;
}
QtStyleFactoryFunction RenderThemeQStyle::styleFactory()
{
return styleFactoryFunction;
}
RenderThemeQStyle::RenderThemeQStyle(Page* page)
: RenderThemeQt(page)
, m_qStyle(adoptPtr(styleFactoryFunction(page)))
{
int buttonPixelSize = 0;
m_qStyle->getButtonMetrics(&m_buttonFontFamily, &buttonPixelSize);
#ifdef Q_WS_MAC
m_buttonFontPixelSize = buttonPixelSize;
#endif
}
RenderThemeQStyle::~RenderThemeQStyle()
{
}
void RenderThemeQStyle::setPaletteFromPageClientIfExists(QPalette& palette) const
{
if (!m_page)
return;
ChromeClient* chromeClient = m_page->chrome().client();
if (!chromeClient)
return;
if (QWebPageClient* pageClient = chromeClient->platformPageClient())
palette = pageClient->palette();
}
QRect RenderThemeQStyle::inflateButtonRect(const QRect& originalRect) const
{
QRect layoutRect = m_qStyle->buttonSubElementRect(QStyleFacade::PushButtonLayoutItem, QStyleFacade::State_Small, originalRect);
if (!layoutRect.isNull()) {
int paddingLeft = layoutRect.left() - originalRect.left();
int paddingRight = originalRect.right() - layoutRect.right();
int paddingTop = layoutRect.top() - originalRect.top();
int paddingBottom = originalRect.bottom() - layoutRect.bottom();
return originalRect.adjusted(-paddingLeft, -paddingTop, paddingRight, paddingBottom);
}
return originalRect;
}
void RenderThemeQStyle::computeSizeBasedOnStyle(RenderStyle* renderStyle) const
{
QSize size(0, 0);
const QFontMetrics fm(renderStyle->font().syntheticFont());
switch (renderStyle->appearance()) {
case TextAreaPart:
case SearchFieldPart:
case TextFieldPart: {
int padding = m_qStyle->findFrameLineWidth();
renderStyle->setPaddingLeft(Length(padding, Fixed));
renderStyle->setPaddingRight(Length(padding, Fixed));
renderStyle->setPaddingTop(Length(padding, Fixed));
renderStyle->setPaddingBottom(Length(padding, Fixed));
break;
}
default:
break;
}
if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto())
return;
switch (renderStyle->appearance()) {
case CheckboxPart: {
int checkBoxWidth = m_qStyle->simplePixelMetric(QStyleFacade::PM_IndicatorWidth, QStyleFacade::State_Small);
checkBoxWidth *= renderStyle->effectiveZoom();
size = QSize(checkBoxWidth, checkBoxWidth);
break;
}
case RadioPart: {
int radioWidth = m_qStyle->simplePixelMetric(QStyleFacade::PM_ExclusiveIndicatorWidth, QStyleFacade::State_Small);
radioWidth *= renderStyle->effectiveZoom();
size = QSize(radioWidth, radioWidth);
break;
}
case PushButtonPart:
case ButtonPart: {
QSize contentSize = fm.size(Qt::TextShowMnemonic, QString::fromLatin1("X"));
QSize pushButtonSize = m_qStyle->pushButtonSizeFromContents(QStyleFacade::State_Small, contentSize);
QRect layoutRect = m_qStyle->buttonSubElementRect(QStyleFacade::PushButtonLayoutItem, QStyleFacade::State_Small, QRect(0, 0, pushButtonSize.width(), pushButtonSize.height()));
if (!layoutRect.isNull())
size.setHeight(layoutRect.height());
else
size.setHeight(pushButtonSize.height());
break;
}
case MenulistPart: {
int contentHeight = qMax(fm.lineSpacing(), 14) + 2;
QSize menuListSize = m_qStyle->comboBoxSizeFromContents(QStyleFacade::State_Small, QSize(0, contentHeight));
size.setHeight(menuListSize.height());
break;
}
default:
break;
}
if (renderStyle->width().isIntrinsicOrAuto() && size.width() > 0)
renderStyle->setMinWidth(Length(size.width(), Fixed));
if (renderStyle->height().isAuto() && size.height() > 0)
renderStyle->setMinHeight(Length(size.height(), Fixed));
}
void RenderThemeQStyle::adjustButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const
{
style->resetBorder();
#ifdef Q_WS_MAC
if (style->appearance() == PushButtonPart) {
style->setHeight(Length(Auto));
}
#endif
FontDescription fontDescription = style->fontDescription();
fontDescription.setIsAbsoluteSize(true);
#ifdef Q_WS_MAC // Use fixed font size and family on Mac (like Safari does)
fontDescription.setSpecifiedSize(m_buttonFontPixelSize);
fontDescription.setComputedSize(m_buttonFontPixelSize);
#else
fontDescription.setSpecifiedSize(style->fontSize());
fontDescription.setComputedSize(style->fontSize());
#endif
Vector<AtomicString, 1> families;
families.append(m_buttonFontFamily);
fontDescription.setFamilies(families);
style->setFontDescription(fontDescription);
style->font().update(styleResolver->fontSelector());
style->setLineHeight(RenderStyle::initialLineHeight());
setButtonSize(style);
setButtonPadding(style);
}
void RenderThemeQStyle::setButtonPadding(RenderStyle* style) const
{
QRect originalRect = QRect(0, 0, 100, 30);
int buttonMargin = m_qStyle->buttonMargin(QStyleFacade::State_Small, originalRect);
int paddingLeft = buttonMargin;
int paddingRight = buttonMargin;
int paddingTop = buttonMargin;
int paddingBottom = buttonMargin;
QRect layoutRect = m_qStyle->buttonSubElementRect(QStyleFacade::PushButtonLayoutItem, QStyleFacade::State_Small, originalRect);
if (!layoutRect.isNull()) {
QRect contentsRect = m_qStyle->buttonSubElementRect(QStyleFacade::PushButtonContents, QStyleFacade::State_Small, originalRect);
paddingLeft = contentsRect.left() - layoutRect.left();
paddingRight = layoutRect.right() - contentsRect.right();
paddingTop = contentsRect.top() - layoutRect.top();
}
style->setPaddingLeft(Length(paddingLeft, Fixed));
style->setPaddingRight(Length(paddingRight, Fixed));
style->setPaddingTop(Length(paddingTop, Fixed));
style->setPaddingBottom(Length(paddingBottom, Fixed));
}
bool RenderThemeQStyle::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
StylePainterQStyle p(this, i, o);
if (!p.isValid())
return true;
p.styleOption.rect = r;
p.styleOption.state |= QStyleFacade::State_Small;
if (p.appearance == PushButtonPart || p.appearance == ButtonPart) {
p.styleOption.rect = inflateButtonRect(p.styleOption.rect);
p.paintButton(QStyleFacade::PushButton);
} else if (p.appearance == RadioPart)
p.paintButton(QStyleFacade::RadioButton);
else if (p.appearance == CheckboxPart)
p.paintButton(QStyleFacade::CheckBox);
return false;
}
bool RenderThemeQStyle::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
StylePainterQStyle p(this, i, o);
if (!p.isValid())
return true;
p.styleOption.rect = r;
p.styleOption.state |= QStyleFacade::State_Sunken;
if (p.appearance != TextFieldPart
&& p.appearance != SearchFieldPart
&& p.appearance != TextAreaPart
&& p.appearance != ListboxPart)
return true;
p.paintTextField();
return false;
}
void RenderThemeQStyle::adjustTextAreaStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
{
adjustTextFieldStyle(styleResolver, style, element);
}
bool RenderThemeQStyle::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
return paintTextField(o, i, r);
}
void RenderThemeQStyle::setPopupPadding(RenderStyle* style) const
{
const int paddingLeft = 4;
const int paddingRight = style->width().isFixed() || style->width().isPercent() ? 5 : 8;
style->setPaddingLeft(Length(paddingLeft, Fixed));
int w = m_qStyle->simplePixelMetric(QStyleFacade::PM_ButtonIconSize);
style->setPaddingRight(Length(paddingRight + w, Fixed));
style->setPaddingTop(Length(2, Fixed));
style->setPaddingBottom(Length(2, Fixed));
}
QPalette RenderThemeQStyle::colorPalette() const
{
QPalette palette = RenderThemeQt::colorPalette();
setPaletteFromPageClientIfExists(palette);
return palette;
}
bool RenderThemeQStyle::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
StylePainterQStyle p(this, i, o);
if (!p.isValid())
return true;
p.styleOption.rect = r;
p.paintComboBox();
return false;
}
void RenderThemeQStyle::adjustMenuListButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
{
style->resetBorderRadius();
RenderThemeQt::adjustMenuListButtonStyle(styleResolver, style, e);
}
bool RenderThemeQStyle::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
StylePainterQStyle p(this, i, o);
if (!p.isValid())
return true;
p.styleOption.rect = r;
p.paintComboBoxArrow();
return false;
}
#if ENABLE(PROGRESS_ELEMENT)
double RenderThemeQStyle::animationDurationForProgressBar(RenderProgress* renderProgress) const
{
if (renderProgress->position() >= 0)
return 0;
IntSize size = renderProgress->pixelSnappedSize();
return (size.width() / m_qStyle->progressBarChunkWidth(size)) * animationRepeatIntervalForProgressBar(renderProgress);
}
bool RenderThemeQStyle::paintProgressBar(RenderObject* o, const PaintInfo& pi, const IntRect& r)
{
if (!o->isProgress())
return true;
StylePainterQStyle p(this, pi, o);
if (!p.isValid())
return true;
p.styleOption.rect = r;
RenderProgress* renderProgress = toRenderProgress(o);
p.paintProgressBar(renderProgress->position(), renderProgress->animationProgress());
return false;
}
#endif
bool RenderThemeQStyle::paintSliderTrack(RenderObject* o, const PaintInfo& pi, const IntRect& r)
{
StylePainterQStyle p(this, pi, o);
if (!p.isValid())
return true;
const QPoint topLeft = r.location();
p.painter->translate(topLeft);
p.styleOption.rect = r;
p.styleOption.rect.moveTo(QPoint(0, 0));
if (p.appearance == SliderVerticalPart)
p.styleOption.slider.orientation = Qt::Vertical;
if (isPressed(o))
p.styleOption.state |= QStyleFacade::State_Sunken;
HTMLInputElement* slider = o->node()->toInputElement();
if (slider) {
p.styleOption.slider.upsideDown = (p.appearance == SliderHorizontalPart) && !o->style()->isLeftToRightDirection();
const int width = r.width() > 0 ? r.width() : 100;
p.styleOption.slider.maximum = slider->maximum() * width;
p.styleOption.slider.minimum = slider->minimum() * width;
if (!p.styleOption.slider.upsideDown)
p.styleOption.slider.position = slider->valueAsNumber() * width;
else
p.styleOption.slider.position = p.styleOption.slider.minimum + p.styleOption.slider.maximum - slider->valueAsNumber() * width;
}
p.paintSliderTrack();
p.painter->translate(-topLeft);
return false;
}
void RenderThemeQStyle::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
{
style->setBoxShadow(nullptr);
}
bool RenderThemeQStyle::paintSliderThumb(RenderObject* o, const PaintInfo& pi, const IntRect& r)
{
StylePainterQStyle p(this, pi, o);
if (!p.isValid())
return true;
const QPoint topLeft = r.location();
p.painter->translate(topLeft);
p.styleOption.rect = r;
p.styleOption.rect.moveTo(QPoint(0, 0));
p.styleOption.slider.orientation = Qt::Horizontal;
if (p.appearance == SliderThumbVerticalPart)
p.styleOption.slider.orientation = Qt::Vertical;
if (isPressed(o))
p.styleOption.state |= QStyleFacade::State_Sunken;
p.paintSliderThumb();
p.painter->translate(-topLeft);
return false;
}
void RenderThemeQStyle::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
{
RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
style->setBoxShadow(nullptr);
}
bool RenderThemeQStyle::paintSearchField(RenderObject* o, const PaintInfo& pi, const IntRect& r)
{
return paintTextField(o, pi, r);
}
void RenderThemeQStyle::adjustSearchFieldDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
{
notImplemented();
RenderTheme::adjustSearchFieldDecorationStyle(styleResolver, style, e);
}
bool RenderThemeQStyle::paintSearchFieldDecoration(RenderObject* o, const PaintInfo& pi, const IntRect& r)
{
notImplemented();
return RenderTheme::paintSearchFieldDecoration(o, pi, r);
}
void RenderThemeQStyle::adjustSearchFieldResultsDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
{
notImplemented();
RenderTheme::adjustSearchFieldResultsDecorationStyle(styleResolver, style, e);
}
bool RenderThemeQStyle::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& pi, const IntRect& r)
{
notImplemented();
return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r);
}
#ifndef QT_NO_SPINBOX
bool RenderThemeQStyle::paintInnerSpinButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
{
StylePainterQStyle p(this, paintInfo, o);
if (!p.isValid())
return true;
p.styleOption.rect = rect;
p.paintInnerSpinButton(isSpinUpButtonPartPressed(o));
return false;
}
#endif
ControlPart RenderThemeQStyle::initializeCommonQStyleOptions(QStyleFacadeOption &option, RenderObject* o) const
{
option.state &= ~(QStyleFacade::State_HasFocus | QStyleFacade::State_MouseOver);
option.state |= QStyleFacade::State_Enabled;
if (isReadOnlyControl(o))
option.state |= QStyleFacade::State_ReadOnly;
option.direction = Qt::LeftToRight;
if (isHovered(o))
option.state |= QStyleFacade::State_MouseOver;
setPaletteFromPageClientIfExists(option.palette);
if (!isEnabled(o)) {
option.palette.setCurrentColorGroup(QPalette::Disabled);
option.state &= ~QStyleFacade::State_Enabled;
}
RenderStyle* style = o->style();
if (!style)
return NoControlPart;
ControlPart result = style->appearance();
if (supportsFocus(result) && isFocused(o)) {
option.state |= QStyleFacade::State_HasFocus;
option.state |= QStyleFacade::State_KeyboardFocusChange;
}
if (style->direction() == WebCore::RTL)
option.direction = Qt::RightToLeft;
switch (result) {
case PushButtonPart:
case SquareButtonPart:
case ButtonPart:
case ButtonBevelPart:
case ListItemPart:
case MenulistButtonPart:
case InnerSpinButtonPart:
case SearchFieldResultsButtonPart:
case SearchFieldCancelButtonPart: {
if (isPressed(o))
option.state |= QStyleFacade::State_Sunken;
else if (result == PushButtonPart || result == ButtonPart)
option.state |= QStyleFacade::State_Raised;
break;
}
case RadioPart:
case CheckboxPart:
option.state |= (isChecked(o) ? QStyleFacade::State_On : QStyleFacade::State_Off);
}
return result;
}
void RenderThemeQStyle::adjustSliderThumbSize(RenderStyle* style, Element* element) const
{
const ControlPart part = style->appearance();
if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
Qt::Orientation orientation = Qt::Horizontal;
if (part == SliderThumbVerticalPart)
orientation = Qt::Vertical;
int length = m_qStyle->sliderLength(orientation);
int thickness = m_qStyle->sliderThickness(orientation);
if (orientation == Qt::Vertical) {
style->setWidth(Length(thickness, Fixed));
style->setHeight(Length(length, Fixed));
} else {
style->setWidth(Length(length, Fixed));
style->setHeight(Length(thickness, Fixed));
}
} else
RenderThemeQt::adjustSliderThumbSize(style, element);
}
}