diff options
Diffstat (limited to 'Source/WebCore/platform/qt/RenderThemeQStyle.cpp')
-rw-r--r-- | Source/WebCore/platform/qt/RenderThemeQStyle.cpp | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/Source/WebCore/platform/qt/RenderThemeQStyle.cpp b/Source/WebCore/platform/qt/RenderThemeQStyle.cpp new file mode 100644 index 000000000..f7e8bf5c9 --- /dev/null +++ b/Source/WebCore/platform/qt/RenderThemeQStyle.cpp @@ -0,0 +1,620 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2008-2012 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 "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, /*RenderObject*/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; + + ASSERT(m_page->chrome()); + 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 the width and height are both specified, then we have nothing to do. + 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 the style supports layout rects we use that, and compensate accordingly + // in paintButton() below. + 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; + } + + // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. + 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 +{ + // Ditch the border. + style->resetBorder(); + +#ifdef Q_WS_MAC + if (style->appearance() == PushButtonPart) { + // The Mac ports ignore the specified height for <input type="button"> elements + // unless a border and/or background CSS property is also specified. + 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 + + FontFamily fontFamily; + fontFamily.setFamily(m_buttonFontFamily); + fontDescription.setFamily(fontFamily); + style->setFontDescription(fontDescription); + style->font().update(styleResolver->fontSelector()); + style->setLineHeight(RenderStyle::initialLineHeight()); + setButtonSize(style); + setButtonPadding(style); +} + +void RenderThemeQStyle::setButtonPadding(RenderStyle* style) const +{ + // Fake a button rect here, since we're just computing deltas + QRect originalRect = QRect(0, 0, 100, 30); + + // Default padding is based on the button margin pixel metric + int buttonMargin = m_qStyle->buttonMargin(QStyleFacade::State_Small, originalRect); + int paddingLeft = buttonMargin; + int paddingRight = buttonMargin; + int paddingTop = buttonMargin; + int paddingBottom = buttonMargin; + + // Then check if the style uses layout margins + 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(); + + // Can't use this right now because we don't have the baseline to compensate + // paddingBottom = layoutRect.bottom() - contentsRect.bottom(); + } + 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; + + // Get the correct theme data for a text field + if (p.appearance != TextFieldPart + && p.appearance != SearchFieldPart + && p.appearance != TextAreaPart + && p.appearance != ListboxPart) + return true; + + // Now paint the text field. + 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 +{ + // WORKAROUND because html.css specifies -webkit-border-radius for <select> so we override it here + // see also http://bugs.webkit.org/show_bug.cgi?id=18399 + 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(); + // FIXME: Until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed, + // we simulate one square animating across the progress bar. + 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; + + // some styles need this to show a highlight on one side of the groove + HTMLInputElement* slider = o->node()->toInputElement(); + if (slider) { + p.styleOption.slider.upsideDown = (p.appearance == SliderHorizontalPart) && !o->style()->isLeftToRightDirection(); + // Use the width as a multiplier in case the slider values are <= 1 + 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 +{ + // Default bits: no focus, no mouse over + option.state &= ~(QStyleFacade::State_HasFocus | QStyleFacade::State_MouseOver); + + if (isReadOnlyControl(o)) + // Readonly is supported on textfields. + 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); +} + +} + +// vim: ts=4 sw=4 et |