Chromium Code Reviews| Index: Source/core/rendering/RenderThemeChromiumDefault.cpp |
| diff --git a/Source/core/rendering/RenderThemeChromiumDefault.cpp b/Source/core/rendering/RenderThemeChromiumDefault.cpp |
| index 0eec664ebea08898b1e560fc2caa0279ca653e8d..956364cf5730a68747aede431c68a364e55abb8c 100644 |
| --- a/Source/core/rendering/RenderThemeChromiumDefault.cpp |
| +++ b/Source/core/rendering/RenderThemeChromiumDefault.cpp |
| @@ -29,9 +29,11 @@ |
| #include "UserAgentStyleSheets.h" |
| #include "core/platform/graphics/GraphicsContext.h" |
| #include "core/platform/graphics/GraphicsContextStateSaver.h" |
| +#include "core/platform/graphics/chromium/TransparencyWin.h" |
| #include "core/rendering/PaintInfo.h" |
| #include "core/rendering/RenderObject.h" |
| #include "core/rendering/RenderProgress.h" |
| +#include "platform/LayoutTestSupport.h" |
| #include "platform/graphics/Color.h" |
| #include "public/platform/default/WebThemeEngine.h" |
| #include "public/platform/Platform.h" |
| @@ -39,6 +41,53 @@ |
| namespace WebCore { |
| +namespace { |
| + |
| +// FIXME: The ThemePainter concept was needed on Windows to emulate the way the |
| +// GDI controls handled transparency (see RenderThemeChromiumWin.cpp and |
| +// core/platform/graphics/chromium/TransparencyWin.cpp). We use it here so that |
| +// we can match the mock theme baselines that were based on the native code. |
| +// Not using the theme painter produces a few minor diffs on tests that involve |
| +// translated or rotated controls; we'd need to investigate if those diffs |
| +// involve real bugs before we get rid of this. |
| +class ThemePainter { |
| +public: |
| + ThemePainter(GraphicsContext* context, const IntRect& r) |
| + { |
| + TransparencyWin::TransformMode transformMode; |
| + |
| + AffineTransform matrix = context->getCTM(); |
| + if (matrix.b() || matrix.c()) // Skew.0 |
| + transformMode = TransparencyWin::Untransform; |
| + else if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. |
| + transformMode = TransparencyWin::ScaleTransform; |
| + else // Nothing interesting. |
| + transformMode = TransparencyWin::KeepTransform; |
| + |
| + TransparencyWin::LayerMode layerMode; |
| + if (context->canvas()->isDrawingToLayer()) |
| + layerMode = TransparencyWin::OpaqueCompositeLayer; |
| + else if (transformMode == TransparencyWin::KeepTransform) |
| + layerMode = TransparencyWin::NoLayer; |
| + else |
| + layerMode = TransparencyWin::OpaqueCompositeLayer; |
| + |
| + m_helper.init(context, layerMode, transformMode, r); |
| + } |
| + |
| + GraphicsContext* context() { return m_helper.context(); } |
| + |
| + WebKit::WebCanvas* canvas() { return m_helper.context()->canvas(); } |
| + |
| + const IntRect& drawRect() { return m_helper.drawRect(); } |
| + |
| + void composite() { m_helper.composite(); } |
| +private: |
| + TransparencyWin m_helper; |
| +}; |
| + |
| +} // namespace |
| + |
| unsigned RenderThemeChromiumDefault::m_activeSelectionBackgroundColor = |
| 0xff1e90ff; |
| unsigned RenderThemeChromiumDefault::m_activeSelectionForegroundColor = |
| @@ -54,6 +103,23 @@ static const unsigned defaultButtonBackgroundColor = 0xffdddddd; |
| static WebKit::WebThemeEngine::State getWebThemeState(const RenderTheme* theme, const RenderObject* o) |
| { |
| + if (isRunningLayoutTest()) { |
| + // The order of these is important: readonly > focused > hot. |
| + // The normal Aura theme doesn't render readonly specially, nor does |
| + // it distinguish between hover and hot states. |
| + if (!theme->isEnabled(o)) |
| + return WebKit::WebThemeEngine::StateDisabled; |
| + if (theme->isReadOnlyControl(o)) |
| + return WebKit::WebThemeEngine::StateReadonly; |
| + if (theme->isPressed(o)) |
| + return WebKit::WebThemeEngine::StatePressed; |
| + if (theme->isFocused(o)) |
| + return WebKit::WebThemeEngine::StateFocused; |
| + if (theme->isHovered(o)) |
| + return WebKit::WebThemeEngine::StateHot; // Hot, not hover: hover is only used in scroll bars in the mock theme. |
| + return WebKit::WebThemeEngine::StateNormal; |
| + } |
| + |
| if (!theme->isEnabled(o)) |
| return WebKit::WebThemeEngine::StateDisabled; |
| if (theme->isPressed(o)) |
| @@ -87,13 +153,29 @@ RenderThemeChromiumDefault::~RenderThemeChromiumDefault() |
| { |
| } |
| +bool RenderThemeChromiumDefault::supportsFocusRing(const RenderStyle* style) const |
| +{ |
| + if (isRunningLayoutTest()) { |
| + // Don't use focus rings for buttons when mocking controls. |
| + return style->appearance() == ButtonPart |
| + || style->appearance() == PushButtonPart |
| + || style->appearance() == SquareButtonPart; |
| + } |
| + |
| + // Otherwise, use the default implementation. |
| + return RenderTheme::supportsFocusRing(style); |
| +} |
| + |
| Color RenderThemeChromiumDefault::systemColor(CSSValueID cssValueId) const |
| { |
| static const Color defaultButtonGrayColor(0xffdddddd); |
| static const Color defaultMenuColor(0xfff7f7f7); |
| - if (cssValueId == CSSValueButtonface) |
| + if (cssValueId == CSSValueButtonface) { |
| + if (isRunningLayoutTest()) |
| + return Color(0xc0, 0xc0, 0xc0); |
| return defaultButtonGrayColor; |
| + } |
| if (cssValueId == CSSValueMenu) |
| return defaultMenuColor; |
| return RenderTheme::systemColor(cssValueId); |
| @@ -138,36 +220,64 @@ Color RenderThemeChromiumDefault::inactiveListBoxSelectionForegroundColor() cons |
| Color RenderThemeChromiumDefault::platformActiveSelectionBackgroundColor() const |
| { |
| + if (isRunningLayoutTest()) |
| + return Color(0x00, 0x00, 0xff); // Royal blue. |
|
jamesr
2013/11/06 21:54:09
the activeSelectionBackgroundColor (and other sele
Dirk Pranke
2013/11/06 22:29:11
I don't think I was aware of that API. I will look
|
| return m_activeSelectionBackgroundColor; |
| } |
| Color RenderThemeChromiumDefault::platformInactiveSelectionBackgroundColor() const |
| { |
| + if (isRunningLayoutTest()) |
| + return Color(0x99, 0x99, 0x99); // Medium gray. |
| return m_inactiveSelectionBackgroundColor; |
| } |
| Color RenderThemeChromiumDefault::platformActiveSelectionForegroundColor() const |
| { |
| + if (isRunningLayoutTest()) |
| + return Color(0xff, 0xff, 0xcc); // Pale yellow. |
| return m_activeSelectionForegroundColor; |
| } |
| Color RenderThemeChromiumDefault::platformInactiveSelectionForegroundColor() const |
| { |
| + if (isRunningLayoutTest()) |
| + return Color::white; |
| return m_inactiveSelectionForegroundColor; |
| } |
| IntSize RenderThemeChromiumDefault::sliderTickSize() const |
| { |
| + if (isRunningLayoutTest()) |
| + return IntSize(1, 3); |
| return IntSize(1, 6); |
| } |
| int RenderThemeChromiumDefault::sliderTickOffsetFromTrackCenter() const |
| { |
| + if (isRunningLayoutTest()) |
| + return 11; |
| return -16; |
| } |
| void RenderThemeChromiumDefault::adjustSliderThumbSize(RenderStyle* style, Element* element) const |
| { |
| + if (isRunningLayoutTest()) { |
| + // These sizes match what WinXP draws for various menus. |
|
jamesr
2013/11/06 21:54:09
we're about to call into the theme to get the size
Dirk Pranke
2013/11/06 22:29:11
Good question, I'll look into that.
|
| + const int sliderThumbAlongAxis = 11; |
| + const int sliderThumbAcrossAxis = 21; |
| + if (style->appearance() == SliderThumbHorizontalPart) { |
| + style->setWidth(Length(sliderThumbAlongAxis, Fixed)); |
| + style->setHeight(Length(sliderThumbAcrossAxis, Fixed)); |
| + } else if (style->appearance() == SliderThumbVerticalPart) { |
| + style->setWidth(Length(sliderThumbAcrossAxis, Fixed)); |
| + style->setHeight(Length(sliderThumbAlongAxis, Fixed)); |
| + } else { |
| + RenderThemeChromiumSkia::adjustSliderThumbSize(style, element); |
| + } |
| + return; |
| + } |
| + |
| IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartSliderThumb); |
| float zoomLevel = style->effectiveZoom(); |
| if (style->appearance() == SliderThumbHorizontalPart) { |
| @@ -270,6 +380,18 @@ bool RenderThemeChromiumDefault::paintButton(RenderObject* o, const PaintInfo& i |
| WebKit::WebThemeEngine::ExtraParams extraParams; |
| WebKit::WebCanvas* canvas = i.context->canvas(); |
| extraParams.button.hasBorder = true; |
| + |
| + if (isRunningLayoutTest()) { |
| + extraParams.button.backgroundColor = 0xffc0c0c0; |
| + if (o->hasBackground()) |
| + extraParams.button.backgroundColor = o->resolveColor(CSSPropertyBackgroundColor).rgb(); |
| + ThemePainter painter(i.context, rect); |
|
jamesr
2013/11/06 21:54:09
why do we need a ThemePainter in the layout test p
Dirk Pranke
2013/11/06 22:29:11
To be honest, I don't fully understand/recall how
jamesr
2013/11/06 23:16:15
I think it'd be better to either mark those as fai
Dirk Pranke
2013/11/06 23:46:38
Yes, that is certainly true. I will remove it and
|
| + WebKit::Platform::current()->themeEngine()->paint(painter.canvas(), WebKit::WebThemeEngine::PartButton, |
| + getWebThemeState(this, o), WebKit::WebRect(painter.drawRect()), &extraParams); |
| + painter.composite(); |
| + return false; |
| + } |
| + |
| extraParams.button.backgroundColor = defaultButtonBackgroundColor; |
| if (o->hasBackground()) |
| extraParams.button.backgroundColor = o->resolveColor(CSSPropertyBackgroundColor).rgb(); |
| @@ -297,6 +419,13 @@ bool RenderThemeChromiumDefault::paintTextField(RenderObject* o, const PaintInfo |
| Color backgroundColor = o->resolveColor(CSSPropertyBackgroundColor, Color::white); |
| extraParams.textField.backgroundColor = backgroundColor.rgb(); |
| + if (isRunningLayoutTest()) { |
| + ThemePainter painter(i.context, rect); |
|
jamesr
2013/11/06 21:54:09
same question here
Dirk Pranke
2013/11/06 22:29:11
same answer :).
|
| + WebKit::Platform::current()->themeEngine()->paint(painter.canvas(), WebKit::WebThemeEngine::PartTextField, getWebThemeState(this, o), WebKit::WebRect(painter.drawRect()), &extraParams); |
| + painter.composite(); |
| + return false; |
| + } |
| + |
| WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartTextField, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); |
| return false; |
| } |
| @@ -310,17 +439,57 @@ bool RenderThemeChromiumDefault::paintMenuList(RenderObject* o, const PaintInfo& |
| const int middle = rect.y() + rect.height() / 2; |
| WebKit::WebThemeEngine::ExtraParams extraParams; |
| - extraParams.menuList.arrowX = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13; |
| extraParams.menuList.arrowY = middle; |
| const RenderBox* box = toRenderBox(o); |
| // Match Chromium Win behaviour of showing all borders if any are shown. |
| extraParams.menuList.hasBorder = box->borderRight() || box->borderLeft() || box->borderTop() || box->borderBottom(); |
| extraParams.menuList.hasBorderRadius = o->style()->hasBorderRadius(); |
| // Fallback to transparent if the specified color object is invalid. |
| - extraParams.menuList.backgroundColor = Color::transparent; |
| + Color backgroundColor(Color::transparent); |
| if (o->hasBackground()) |
| - extraParams.menuList.backgroundColor = o->resolveColor(CSSPropertyBackgroundColor).rgb(); |
| + backgroundColor = o->resolveColor(CSSPropertyBackgroundColor); |
| + extraParams.menuList.backgroundColor = backgroundColor.rgb(); |
| + |
| + // If we have a background image, don't fill the content area to expose the |
| + // parent's background. Also, we shouldn't fill the content area if the |
| + // alpha of the color is 0. The API of Windows GDI ignores the alpha. |
| + // FIXME: the normal Aura theme doesn't care about this, so we should |
| + // investigate if we really need fillContentArea. |
| + extraParams.menuList.fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha(); |
| + |
| + if (isRunningLayoutTest()) { |
| + // The size and position of the drop-down button is different between |
| + // the mock theme and the regular aura theme. |
| + int borderLeft = box->borderLeft(); |
| + int borderRight = box->borderRight(); |
| + int borderTop = box->borderTop(); |
| + int borderBottom = box->borderBottom(); |
| + int spacingTop = borderTop + box->paddingTop(); |
| + int spacingBottom = borderBottom + box->paddingBottom(); |
| + int spacingLeft = borderLeft + box->paddingLeft(); |
| + int spacingRight = borderRight + box->paddingRight(); |
| + |
| + extraParams.menuList.arrowX = (o->style()->direction() == RTL) ? rect.x() + 4 + spacingRight: right - 13 - spacingRight; |
| + extraParams.menuList.arrowHeight = rect.height() - spacingBottom - spacingTop; |
| + |
| + if (o->style()->hasBorderRadius()) { |
| + // If the style has rounded borders, setup the context to clip the |
| + // background (themed or filled) appropriately. |
| + // FIXME: make sure we do the right thing if css background-clip is set. |
| + i.context->save(); |
| + i.context->clipRoundedRect(o->style()->getRoundedBorderFor(rect)); |
| + } |
| + |
| + ThemePainter painter(i.context, rect); |
| + WebKit::Platform::current()->themeEngine()->paint(painter.canvas(), WebKit::WebThemeEngine::PartMenuList, getWebThemeState(this, o), WebKit::WebRect(painter.drawRect()), &extraParams); |
| + painter.composite(); |
| + |
| + if (o->style()->hasBorderRadius()) |
| + i.context->restore(); |
| + return false; |
| + } |
| + extraParams.menuList.arrowX = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13; |
| WebKit::WebCanvas* canvas = i.context->canvas(); |
| WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartMenuList, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); |
| @@ -335,6 +504,13 @@ bool RenderThemeChromiumDefault::paintSliderTrack(RenderObject* o, const PaintIn |
| paintSliderTicks(o, i, rect); |
| + if (isRunningLayoutTest()) { |
| + ThemePainter painter(i.context, rect); |
| + WebKit::Platform::current()->themeEngine()->paint(painter.canvas(), WebKit::WebThemeEngine::PartSliderTrack, getWebThemeState(this, o), WebKit::WebRect(painter.drawRect()), &extraParams); |
| + painter.composite(); |
| + return false; |
| + } |
| + |
| float zoomLevel = o->style()->effectiveZoom(); |
| GraphicsContextStateSaver stateSaver(*i.context); |
| IntRect unzoomedRect = rect; |
| @@ -358,6 +534,14 @@ bool RenderThemeChromiumDefault::paintSliderThumb(RenderObject* o, const PaintIn |
| extraParams.slider.vertical = o->style()->appearance() == SliderThumbVerticalPart; |
| extraParams.slider.inDrag = isPressed(o); |
| + if (isRunningLayoutTest()) { |
| + ThemePainter painter(i.context, rect); |
| + WebKit::Platform::current()->themeEngine()->paint(painter.canvas(), |
| + WebKit::WebThemeEngine::PartSliderThumb, getWebThemeState(this, o), WebKit::WebRect(painter.drawRect()), &extraParams); |
| + painter.composite(); |
| + return false; |
| + } |
| + |
| float zoomLevel = o->style()->effectiveZoom(); |
| GraphicsContextStateSaver stateSaver(*i.context); |
| IntRect unzoomedRect = rect; |
| @@ -418,4 +602,15 @@ bool RenderThemeChromiumDefault::shouldOpenPickerWithF4Key() const |
| return true; |
| } |
| +bool RenderThemeChromiumDefault::shouldUseFallbackTheme(RenderStyle* style) const |
| +{ |
| + if (isRunningLayoutTest()) { |
| + // The mock theme can't handle zoomed controls, so we fall back to the "fallback" theme. |
| + ControlPart part = style->appearance(); |
| + if (part == CheckboxPart || part == RadioPart) |
| + return style->effectiveZoom() != 1; |
| + } |
| + return RenderTheme::shouldUseFallbackTheme(style); |
| +} |
| + |
| } // namespace WebCore |