2 * This file is part of the theme implementation for form controls in WebCore.
4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 #include "RenderTheme.h"
25 #include "CSSValueKeywords.h"
26 #include "ControlStates.h"
29 #include "FileSystem.h"
30 #include "FloatConversion.h"
31 #include "FocusController.h"
32 #include "FontSelector.h"
34 #include "FrameSelection.h"
35 #include "GraphicsContext.h"
36 #include "HTMLInputElement.h"
37 #include "HTMLNames.h"
38 #include "LocalizedStrings.h"
39 #include "MediaControlElements.h"
41 #include "PaintInfo.h"
42 #include "RenderStyle.h"
43 #include "RenderView.h"
45 #include "SpinButtonElement.h"
46 #include "StringTruncator.h"
47 #include "TextControlInnerElements.h"
49 #if ENABLE(METER_ELEMENT)
50 #include "HTMLMeterElement.h"
51 #include "RenderMeter.h"
54 #if ENABLE(DATALIST_ELEMENT)
55 #include "HTMLCollection.h"
56 #include "HTMLDataListElement.h"
57 #include "HTMLOptionElement.h"
58 #include "HTMLParserIdioms.h"
61 // The methods in this file are shared by all themes on every platform.
65 using namespace HTMLNames;
67 static Color& customFocusRingColor()
69 DEPRECATED_DEFINE_STATIC_LOCAL(Color, color, ());
73 RenderTheme::RenderTheme()
75 : m_theme(platformTheme())
80 void RenderTheme::adjustStyle(StyleResolver& styleResolver, RenderStyle& style, Element* e, bool UAHasAppearance, const BorderData& border, const FillLayer& background, const Color& backgroundColor)
82 // Force inline and table display styles to be inline-block (except for table- which is block)
83 ControlPart part = style.appearance();
84 if (style.display() == INLINE || style.display() == INLINE_TABLE || style.display() == TABLE_ROW_GROUP
85 || style.display() == TABLE_HEADER_GROUP || style.display() == TABLE_FOOTER_GROUP
86 || style.display() == TABLE_ROW || style.display() == TABLE_COLUMN_GROUP || style.display() == TABLE_COLUMN
87 || style.display() == TABLE_CELL || style.display() == TABLE_CAPTION)
88 style.setDisplay(INLINE_BLOCK);
89 else if (style.display() == COMPACT || style.display() == LIST_ITEM || style.display() == TABLE)
90 style.setDisplay(BLOCK);
92 if (UAHasAppearance && isControlStyled(style, border, background, backgroundColor)) {
93 if (part == MenulistPart) {
94 style.setAppearance(MenulistButtonPart);
95 part = MenulistButtonPart;
97 style.setAppearance(NoControlPart);
100 if (!style.hasAppearance())
103 // Never support box-shadow on native controls.
104 style.setBoxShadow(nullptr);
109 case InnerSpinButtonPart:
112 case SquareButtonPart:
113 case DefaultButtonPart:
116 LengthBox borderBox(style.borderTopWidth(), style.borderRightWidth(), style.borderBottomWidth(), style.borderLeftWidth());
117 borderBox = m_theme->controlBorder(part, style.font(), borderBox, style.effectiveZoom());
118 if (borderBox.top().value() != static_cast<int>(style.borderTopWidth())) {
119 if (borderBox.top().value())
120 style.setBorderTopWidth(borderBox.top().value());
122 style.resetBorderTop();
124 if (borderBox.right().value() != static_cast<int>(style.borderRightWidth())) {
125 if (borderBox.right().value())
126 style.setBorderRightWidth(borderBox.right().value());
128 style.resetBorderRight();
130 if (borderBox.bottom().value() != static_cast<int>(style.borderBottomWidth())) {
131 style.setBorderBottomWidth(borderBox.bottom().value());
132 if (borderBox.bottom().value())
133 style.setBorderBottomWidth(borderBox.bottom().value());
135 style.resetBorderBottom();
137 if (borderBox.left().value() != static_cast<int>(style.borderLeftWidth())) {
138 style.setBorderLeftWidth(borderBox.left().value());
139 if (borderBox.left().value())
140 style.setBorderLeftWidth(borderBox.left().value());
142 style.resetBorderLeft();
146 LengthBox paddingBox = m_theme->controlPadding(part, style.font(), style.paddingBox(), style.effectiveZoom());
147 if (paddingBox != style.paddingBox())
148 style.setPaddingBox(paddingBox);
151 if (m_theme->controlRequiresPreWhiteSpace(part))
152 style.setWhiteSpace(PRE);
155 // The width and height here are affected by the zoom.
156 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
157 LengthSize controlSize = m_theme->controlSize(part, style.font(), LengthSize(style.width(), style.height()), style.effectiveZoom());
158 if (controlSize.width() != style.width())
159 style.setWidth(controlSize.width());
160 if (controlSize.height() != style.height())
161 style.setHeight(controlSize.height());
163 // Min-Width / Min-Height
164 LengthSize minControlSize = m_theme->minimumControlSize(part, style.font(), style.effectiveZoom());
165 if (minControlSize.width() != style.minWidth())
166 style.setMinWidth(minControlSize.width());
167 if (minControlSize.height() != style.minHeight())
168 style.setMinHeight(minControlSize.height());
171 FontDescription controlFont = m_theme->controlFont(part, style.font(), style.effectiveZoom());
172 if (controlFont != style.font().fontDescription()) {
173 // Reset our line-height
174 style.setLineHeight(RenderStyle::initialLineHeight());
176 // Now update our font.
177 if (style.setFontDescription(controlFont))
178 style.font().update(0);
187 // Call the appropriate style adjustment method based off the appearance value.
188 switch (style.appearance()) {
191 return adjustCheckboxStyle(styleResolver, style, e);
193 return adjustRadioStyle(styleResolver, style, e);
195 case SquareButtonPart:
196 case DefaultButtonPart:
198 return adjustButtonStyle(styleResolver, style, e);
199 case InnerSpinButtonPart:
200 return adjustInnerSpinButtonStyle(styleResolver, style, e);
203 return adjustTextFieldStyle(styleResolver, style, e);
205 return adjustTextAreaStyle(styleResolver, style, e);
207 return adjustMenuListStyle(styleResolver, style, e);
208 case MenulistButtonPart:
209 return adjustMenuListButtonStyle(styleResolver, style, e);
210 case MediaPlayButtonPart:
211 case MediaCurrentTimePart:
212 case MediaTimeRemainingPart:
213 case MediaEnterFullscreenButtonPart:
214 case MediaExitFullscreenButtonPart:
215 case MediaMuteButtonPart:
216 case MediaVolumeSliderContainerPart:
217 return adjustMediaControlStyle(styleResolver, style, e);
218 case MediaSliderPart:
219 case MediaVolumeSliderPart:
220 case MediaFullScreenVolumeSliderPart:
221 case SliderHorizontalPart:
222 case SliderVerticalPart:
223 return adjustSliderTrackStyle(styleResolver, style, e);
224 case SliderThumbHorizontalPart:
225 case SliderThumbVerticalPart:
226 return adjustSliderThumbStyle(styleResolver, style, e);
227 case SearchFieldPart:
228 return adjustSearchFieldStyle(styleResolver, style, e);
229 case SearchFieldCancelButtonPart:
230 return adjustSearchFieldCancelButtonStyle(styleResolver, style, e);
231 case SearchFieldDecorationPart:
232 return adjustSearchFieldDecorationPartStyle(styleResolver, style, e);
233 case SearchFieldResultsDecorationPart:
234 return adjustSearchFieldResultsDecorationPartStyle(styleResolver, style, e);
235 case SearchFieldResultsButtonPart:
236 return adjustSearchFieldResultsButtonStyle(styleResolver, style, e);
237 case ProgressBarPart:
238 return adjustProgressBarStyle(styleResolver, style, e);
239 #if ENABLE(METER_ELEMENT)
241 case RelevancyLevelIndicatorPart:
242 case ContinuousCapacityLevelIndicatorPart:
243 case DiscreteCapacityLevelIndicatorPart:
244 case RatingLevelIndicatorPart:
245 return adjustMeterStyle(styleResolver, style, e);
247 #if ENABLE(SERVICE_CONTROLS)
248 case ImageControlsButtonPart:
256 bool RenderTheme::paint(const RenderObject& o, ControlStates* controlStates, const PaintInfo& paintInfo, const LayoutRect& r)
258 // If painting is disabled, but we aren't updating control tints, then just bail.
259 // If we are updating control tints, just schedule a repaint if the theme supports tinting
261 if (paintInfo.context->updatingControlTints()) {
262 if (controlSupportsTints(o))
266 if (paintInfo.context->paintingDisabled())
269 ControlPart part = o.style().appearance();
270 IntRect integralSnappedRect = snappedIntRect(r);
271 FloatRect devicePixelSnappedRect = snapRectToDevicePixels(r, o.document().deviceScaleFactor());
278 case SquareButtonPart:
279 case DefaultButtonPart:
281 case InnerSpinButtonPart:
282 updateControlStatesForRenderer(o, controlStates);
283 m_theme->paint(part, controlStates, const_cast<GraphicsContext*>(paintInfo.context), devicePixelSnappedRect, o.style().effectiveZoom(), &o.view().frameView());
289 UNUSED_PARAM(controlStates);
292 // Call the appropriate paint method based off the appearance value.
296 return paintCheckbox(o, paintInfo, integralSnappedRect);
298 return paintRadio(o, paintInfo, integralSnappedRect);
300 case SquareButtonPart:
301 case DefaultButtonPart:
303 return paintButton(o, paintInfo, integralSnappedRect);
304 case InnerSpinButtonPart:
305 return paintInnerSpinButton(o, paintInfo, integralSnappedRect);
308 return paintMenuList(o, paintInfo, devicePixelSnappedRect);
309 #if ENABLE(METER_ELEMENT)
311 case RelevancyLevelIndicatorPart:
312 case ContinuousCapacityLevelIndicatorPart:
313 case DiscreteCapacityLevelIndicatorPart:
314 case RatingLevelIndicatorPart:
315 return paintMeter(o, paintInfo, integralSnappedRect);
317 case ProgressBarPart:
318 return paintProgressBar(o, paintInfo, integralSnappedRect);
319 case SliderHorizontalPart:
320 case SliderVerticalPart:
321 return paintSliderTrack(o, paintInfo, integralSnappedRect);
322 case SliderThumbHorizontalPart:
323 case SliderThumbVerticalPart:
324 return paintSliderThumb(o, paintInfo, integralSnappedRect);
325 case MediaEnterFullscreenButtonPart:
326 case MediaExitFullscreenButtonPart:
327 return paintMediaFullscreenButton(o, paintInfo, integralSnappedRect);
328 case MediaPlayButtonPart:
329 return paintMediaPlayButton(o, paintInfo, integralSnappedRect);
330 case MediaOverlayPlayButtonPart:
331 return paintMediaOverlayPlayButton(o, paintInfo, integralSnappedRect);
332 case MediaMuteButtonPart:
333 return paintMediaMuteButton(o, paintInfo, integralSnappedRect);
334 case MediaSeekBackButtonPart:
335 return paintMediaSeekBackButton(o, paintInfo, integralSnappedRect);
336 case MediaSeekForwardButtonPart:
337 return paintMediaSeekForwardButton(o, paintInfo, integralSnappedRect);
338 case MediaRewindButtonPart:
339 return paintMediaRewindButton(o, paintInfo, integralSnappedRect);
340 case MediaReturnToRealtimeButtonPart:
341 return paintMediaReturnToRealtimeButton(o, paintInfo, integralSnappedRect);
342 case MediaToggleClosedCaptionsButtonPart:
343 return paintMediaToggleClosedCaptionsButton(o, paintInfo, integralSnappedRect);
344 case MediaSliderPart:
345 return paintMediaSliderTrack(o, paintInfo, integralSnappedRect);
346 case MediaSliderThumbPart:
347 return paintMediaSliderThumb(o, paintInfo, integralSnappedRect);
348 case MediaVolumeSliderMuteButtonPart:
349 return paintMediaMuteButton(o, paintInfo, integralSnappedRect);
350 case MediaVolumeSliderContainerPart:
351 return paintMediaVolumeSliderContainer(o, paintInfo, integralSnappedRect);
352 case MediaVolumeSliderPart:
353 return paintMediaVolumeSliderTrack(o, paintInfo, integralSnappedRect);
354 case MediaVolumeSliderThumbPart:
355 return paintMediaVolumeSliderThumb(o, paintInfo, integralSnappedRect);
356 case MediaFullScreenVolumeSliderPart:
357 return paintMediaFullScreenVolumeSliderTrack(o, paintInfo, integralSnappedRect);
358 case MediaFullScreenVolumeSliderThumbPart:
359 return paintMediaFullScreenVolumeSliderThumb(o, paintInfo, integralSnappedRect);
360 case MediaTimeRemainingPart:
361 return paintMediaTimeRemaining(o, paintInfo, integralSnappedRect);
362 case MediaCurrentTimePart:
363 return paintMediaCurrentTime(o, paintInfo, integralSnappedRect);
364 case MediaControlsBackgroundPart:
365 return paintMediaControlsBackground(o, paintInfo, integralSnappedRect);
366 case MenulistButtonPart:
371 case SearchFieldPart:
372 return paintSearchField(o, paintInfo, integralSnappedRect);
373 case SearchFieldCancelButtonPart:
374 return paintSearchFieldCancelButton(o, paintInfo, integralSnappedRect);
375 case SearchFieldDecorationPart:
376 return paintSearchFieldDecorationPart(o, paintInfo, integralSnappedRect);
377 case SearchFieldResultsDecorationPart:
378 return paintSearchFieldResultsDecorationPart(o, paintInfo, integralSnappedRect);
379 case SearchFieldResultsButtonPart:
380 return paintSearchFieldResultsButton(o, paintInfo, integralSnappedRect);
381 case SnapshottedPluginOverlayPart:
382 return paintSnapshottedPluginOverlay(o, paintInfo, integralSnappedRect);
383 #if ENABLE(SERVICE_CONTROLS)
384 case ImageControlsButtonPart:
385 return paintImageControlsButton(o, paintInfo, integralSnappedRect);
391 return true; // We don't support the appearance, so let the normal background/border paint.
394 bool RenderTheme::paintBorderOnly(const RenderObject& o, const PaintInfo& paintInfo, const LayoutRect& r)
396 if (paintInfo.context->paintingDisabled())
401 return o.style().appearance() != NoControlPart;
403 FloatRect devicePixelSnappedRect = snapRectToDevicePixels(r, o.document().deviceScaleFactor());
404 // Call the appropriate paint method based off the appearance value.
405 switch (o.style().appearance()) {
407 return paintTextField(o, paintInfo, devicePixelSnappedRect);
410 return paintTextArea(o, paintInfo, devicePixelSnappedRect);
411 case MenulistButtonPart:
412 case SearchFieldPart:
417 case SquareButtonPart:
418 case DefaultButtonPart:
421 #if ENABLE(METER_ELEMENT)
423 case RelevancyLevelIndicatorPart:
424 case ContinuousCapacityLevelIndicatorPart:
425 case DiscreteCapacityLevelIndicatorPart:
426 case RatingLevelIndicatorPart:
428 case ProgressBarPart:
429 case SliderHorizontalPart:
430 case SliderVerticalPart:
431 case SliderThumbHorizontalPart:
432 case SliderThumbVerticalPart:
433 case SearchFieldCancelButtonPart:
434 case SearchFieldDecorationPart:
435 case SearchFieldResultsDecorationPart:
436 case SearchFieldResultsButtonPart:
437 #if ENABLE(SERVICE_CONTROLS)
438 case ImageControlsButtonPart:
448 bool RenderTheme::paintDecorations(const RenderObject& renderer, const PaintInfo& paintInfo, const LayoutRect& rect)
450 if (paintInfo.context->paintingDisabled())
453 IntRect integralSnappedRect = snappedIntRect(rect);
454 FloatRect devicePixelSnappedRect = snapRectToDevicePixels(rect, renderer.document().deviceScaleFactor());
456 // Call the appropriate paint method based off the appearance value.
457 switch (renderer.style().appearance()) {
458 case MenulistButtonPart:
459 return paintMenuListButtonDecorations(renderer, paintInfo, devicePixelSnappedRect);
461 return paintTextFieldDecorations(renderer, paintInfo, devicePixelSnappedRect);
463 return paintTextAreaDecorations(renderer, paintInfo, devicePixelSnappedRect);
465 return paintCheckboxDecorations(renderer, paintInfo, integralSnappedRect);
467 return paintRadioDecorations(renderer, paintInfo, integralSnappedRect);
469 return paintPushButtonDecorations(renderer, paintInfo, integralSnappedRect);
470 case SquareButtonPart:
471 return paintSquareButtonDecorations(renderer, paintInfo, integralSnappedRect);
473 return paintButtonDecorations(renderer, paintInfo, integralSnappedRect);
475 return paintMenuListDecorations(renderer, paintInfo, integralSnappedRect);
476 case SliderThumbHorizontalPart:
477 case SliderThumbVerticalPart:
478 return paintSliderThumbDecorations(renderer, paintInfo, integralSnappedRect);
479 case SearchFieldPart:
480 return paintSearchFieldDecorations(renderer, paintInfo, integralSnappedRect);
481 #if ENABLE(METER_ELEMENT)
483 case RelevancyLevelIndicatorPart:
484 case ContinuousCapacityLevelIndicatorPart:
485 case DiscreteCapacityLevelIndicatorPart:
486 case RatingLevelIndicatorPart:
488 case ProgressBarPart:
489 case SliderHorizontalPart:
490 case SliderVerticalPart:
492 case DefaultButtonPart:
493 case SearchFieldCancelButtonPart:
494 case SearchFieldDecorationPart:
495 case SearchFieldResultsDecorationPart:
496 case SearchFieldResultsButtonPart:
497 #if ENABLE(SERVICE_CONTROLS)
498 case ImageControlsButtonPart:
509 String RenderTheme::formatMediaControlsTime(float time) const
511 if (!std::isfinite(time))
513 int seconds = (int)fabsf(time);
514 int hours = seconds / (60 * 60);
515 int minutes = (seconds / 60) % 60;
519 return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
521 return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
524 return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
527 String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*duration*/) const
529 return formatMediaControlsTime(currentTime);
532 String RenderTheme::formatMediaControlsRemainingTime(float currentTime, float duration) const
534 return formatMediaControlsTime(currentTime - duration);
537 IntPoint RenderTheme::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const
539 int y = -size.height();
540 FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), IsFixed | UseTransforms);
541 if (absPoint.y() < 0)
542 y = muteButtonBox->height();
543 return IntPoint(0, y);
548 Color RenderTheme::activeSelectionBackgroundColor() const
550 if (!m_activeSelectionBackgroundColor.isValid())
551 m_activeSelectionBackgroundColor = platformActiveSelectionBackgroundColor().blendWithWhite();
552 return m_activeSelectionBackgroundColor;
555 Color RenderTheme::inactiveSelectionBackgroundColor() const
557 if (!m_inactiveSelectionBackgroundColor.isValid())
558 m_inactiveSelectionBackgroundColor = platformInactiveSelectionBackgroundColor().blendWithWhite();
559 return m_inactiveSelectionBackgroundColor;
562 Color RenderTheme::activeSelectionForegroundColor() const
564 if (!m_activeSelectionForegroundColor.isValid() && supportsSelectionForegroundColors())
565 m_activeSelectionForegroundColor = platformActiveSelectionForegroundColor();
566 return m_activeSelectionForegroundColor;
569 Color RenderTheme::inactiveSelectionForegroundColor() const
571 if (!m_inactiveSelectionForegroundColor.isValid() && supportsSelectionForegroundColors())
572 m_inactiveSelectionForegroundColor = platformInactiveSelectionForegroundColor();
573 return m_inactiveSelectionForegroundColor;
576 Color RenderTheme::activeListBoxSelectionBackgroundColor() const
578 if (!m_activeListBoxSelectionBackgroundColor.isValid())
579 m_activeListBoxSelectionBackgroundColor = platformActiveListBoxSelectionBackgroundColor();
580 return m_activeListBoxSelectionBackgroundColor;
583 Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const
585 if (!m_inactiveListBoxSelectionBackgroundColor.isValid())
586 m_inactiveListBoxSelectionBackgroundColor = platformInactiveListBoxSelectionBackgroundColor();
587 return m_inactiveListBoxSelectionBackgroundColor;
590 Color RenderTheme::activeListBoxSelectionForegroundColor() const
592 if (!m_activeListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors())
593 m_activeListBoxSelectionForegroundColor = platformActiveListBoxSelectionForegroundColor();
594 return m_activeListBoxSelectionForegroundColor;
597 Color RenderTheme::inactiveListBoxSelectionForegroundColor() const
599 if (!m_inactiveListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors())
600 m_inactiveListBoxSelectionForegroundColor = platformInactiveListBoxSelectionForegroundColor();
601 return m_inactiveListBoxSelectionForegroundColor;
604 Color RenderTheme::platformActiveSelectionBackgroundColor() const
606 // Use a blue color by default if the platform theme doesn't define anything.
607 return Color(0, 0, 255);
610 Color RenderTheme::platformActiveSelectionForegroundColor() const
612 // Use a white color by default if the platform theme doesn't define anything.
616 Color RenderTheme::platformInactiveSelectionBackgroundColor() const
618 // Use a grey color by default if the platform theme doesn't define anything.
619 // This color matches Firefox's inactive color.
620 return Color(176, 176, 176);
623 Color RenderTheme::platformInactiveSelectionForegroundColor() const
625 // Use a black color by default.
629 Color RenderTheme::platformActiveListBoxSelectionBackgroundColor() const
631 return platformActiveSelectionBackgroundColor();
634 Color RenderTheme::platformActiveListBoxSelectionForegroundColor() const
636 return platformActiveSelectionForegroundColor();
639 Color RenderTheme::platformInactiveListBoxSelectionBackgroundColor() const
641 return platformInactiveSelectionBackgroundColor();
644 Color RenderTheme::platformInactiveListBoxSelectionForegroundColor() const
646 return platformInactiveSelectionForegroundColor();
649 int RenderTheme::baselinePosition(const RenderObject& o) const
654 const RenderBox& box = *toRenderBox(&o);
657 return box.height() + box.marginTop() + m_theme->baselinePositionAdjustment(o.style().appearance()) * o.style().effectiveZoom();
659 return box.height() + box.marginTop();
663 bool RenderTheme::isControlContainer(ControlPart appearance) const
665 // There are more leaves than this, but we'll patch this function as we add support for
667 return appearance != CheckboxPart && appearance != RadioPart;
670 bool RenderTheme::isControlStyled(const RenderStyle& style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const
672 switch (style.appearance()) {
674 case SquareButtonPart:
675 case DefaultButtonPart:
679 case ProgressBarPart:
681 case RelevancyLevelIndicatorPart:
682 case ContinuousCapacityLevelIndicatorPart:
683 case DiscreteCapacityLevelIndicatorPart:
684 case RatingLevelIndicatorPart:
685 // FIXME: SearchFieldPart should be included here when making search fields style-able.
688 // Test the style to see if the UA border and background match.
689 return (style.border() != border
690 || *style.backgroundLayers() != background
691 || style.visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor);
697 void RenderTheme::adjustRepaintRect(const RenderObject& renderer, FloatRect& rect)
700 ControlStates states(extractControlStatesForRenderer(renderer));
701 m_theme->inflateControlPaintRect(renderer.style().appearance(), &states, rect, renderer.style().effectiveZoom());
703 UNUSED_PARAM(renderer);
708 bool RenderTheme::supportsFocusRing(const RenderStyle& style) const
710 return (style.hasAppearance() && style.appearance() != TextFieldPart && style.appearance() != TextAreaPart && style.appearance() != MenulistButtonPart && style.appearance() != ListboxPart);
713 bool RenderTheme::stateChanged(const RenderObject& o, ControlStates::States state) const
715 // Default implementation assumes the controls don't respond to changes in :hover state
716 if (state == ControlStates::HoverState && !supportsHover(o.style()))
719 // Assume pressed state is only responded to if the control is enabled.
720 if (state == ControlStates::PressedState && !isEnabled(o))
723 // Repaint the control.
728 void RenderTheme::updateControlStatesForRenderer(const RenderObject& o, ControlStates* controlStates) const
730 ControlStates newStates = extractControlStatesForRenderer(o);
731 controlStates->setStates(newStates.states());
733 controlStates->setTimeSinceControlWasFocused(o.document().page()->focusController().timeSinceFocusWasSet());
736 ControlStates::States RenderTheme::extractControlStatesForRenderer(const RenderObject& o) const
738 ControlStates::States states = 0;
740 states |= ControlStates::HoverState;
741 if (isSpinUpButtonPartHovered(o))
742 states |= ControlStates::SpinUpState;
745 states |= ControlStates::PressedState;
746 if (isSpinUpButtonPartPressed(o))
747 states |= ControlStates::SpinUpState;
749 if (isFocused(o) && o.style().outlineStyleIsAuto())
750 states |= ControlStates::FocusState;
752 states |= ControlStates::EnabledState;
754 states |= ControlStates::CheckedState;
756 states |= ControlStates::DefaultState;
758 states |= ControlStates::WindowInactiveState;
759 if (isIndeterminate(o))
760 states |= ControlStates::IndeterminateState;
764 bool RenderTheme::isActive(const RenderObject& o) const
766 Node* node = o.node();
770 Frame* frame = node->document().frame();
774 Page* page = frame->page();
778 return page->focusController().isActive();
781 bool RenderTheme::isChecked(const RenderObject& o) const
786 HTMLInputElement* inputElement = o.node()->toInputElement();
790 return inputElement->shouldAppearChecked();
793 bool RenderTheme::isIndeterminate(const RenderObject& o) const
798 HTMLInputElement* inputElement = o.node()->toInputElement();
802 return inputElement->shouldAppearIndeterminate();
805 bool RenderTheme::isEnabled(const RenderObject& o) const
807 Node* node = o.node();
808 if (!node || !node->isElementNode())
810 return !toElement(node)->isDisabledFormControl();
813 bool RenderTheme::isFocused(const RenderObject& o) const
815 Node* node = o.node();
816 if (!node || !node->isElementNode())
819 Element* focusDelegate = toElement(node)->focusDelegate();
820 Document& document = focusDelegate->document();
821 Frame* frame = document.frame();
822 return focusDelegate == document.focusedElement() && frame && frame->selection().isFocusedAndActive();
825 bool RenderTheme::isPressed(const RenderObject& o) const
827 if (!o.node() || !o.node()->isElementNode())
829 return toElement(o.node())->active();
832 bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject& o) const
834 Node* node = o.node();
835 if (!node || !node->isElementNode())
837 Element* element = toElement(node);
838 if (!element->active() || !element->isSpinButtonElement())
840 return static_cast<SpinButtonElement*>(element)->upDownState() == SpinButtonElement::Up;
843 bool RenderTheme::isReadOnlyControl(const RenderObject& o) const
845 Node* node = o.node();
846 if (!node || !node->isElementNode() || !toElement(node)->isFormControlElement())
848 return !toElement(node)->matchesReadWritePseudoClass();
851 bool RenderTheme::isHovered(const RenderObject& o) const
853 Node* node = o.node();
854 if (!node || !node->isElementNode())
856 if (!toElement(node)->isSpinButtonElement())
857 return toElement(node)->hovered();
858 SpinButtonElement* element = static_cast<SpinButtonElement*>(node);
859 return element->hovered() && element->upDownState() != SpinButtonElement::Indeterminate;
862 bool RenderTheme::isSpinUpButtonPartHovered(const RenderObject& o) const
864 Node* node = o.node();
865 if (!node || !node->isElementNode() || !toElement(node)->isSpinButtonElement())
867 SpinButtonElement* element = static_cast<SpinButtonElement*>(node);
868 return element->upDownState() == SpinButtonElement::Up;
871 bool RenderTheme::isDefault(const RenderObject& o) const
873 // A button should only have the default appearance if the page is active
877 if (!o.frame().settings().applicationChromeMode())
880 return o.style().appearance() == DefaultButtonPart;
885 void RenderTheme::adjustCheckboxStyle(StyleResolver&, RenderStyle& style, Element*) const
887 // A summary of the rules for checkbox designed to match WinIE:
888 // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
889 // font-size - not honored (control has no text), but we use it to decide which control size to use.
890 setCheckboxSize(style);
892 // padding - not honored by WinIE, needs to be removed.
893 style.resetPadding();
895 // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
896 // for now, we will not honor it.
899 style.setBoxShadow(nullptr);
902 void RenderTheme::adjustRadioStyle(StyleResolver&, RenderStyle& style, Element*) const
904 // A summary of the rules for checkbox designed to match WinIE:
905 // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
906 // font-size - not honored (control has no text), but we use it to decide which control size to use.
909 // padding - not honored by WinIE, needs to be removed.
910 style.resetPadding();
912 // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
913 // for now, we will not honor it.
916 style.setBoxShadow(nullptr);
919 void RenderTheme::adjustButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
921 // Most platforms will completely honor all CSS, and so we have no need to
922 // adjust the style at all by default. We will still allow the theme a crack
923 // at setting up a desired vertical size.
924 setButtonSize(style);
927 void RenderTheme::adjustInnerSpinButtonStyle(StyleResolver&, RenderStyle&, Element*) const
932 void RenderTheme::adjustTextFieldStyle(StyleResolver&, RenderStyle&, Element*) const
936 void RenderTheme::adjustTextAreaStyle(StyleResolver&, RenderStyle&, Element*) const
940 void RenderTheme::adjustMenuListStyle(StyleResolver&, RenderStyle&, Element*) const
944 #if ENABLE(METER_ELEMENT)
945 void RenderTheme::adjustMeterStyle(StyleResolver&, RenderStyle& style, Element*) const
947 style.setBoxShadow(nullptr);
950 IntSize RenderTheme::meterSizeForBounds(const RenderMeter&, const IntRect& bounds) const
952 return bounds.size();
955 bool RenderTheme::supportsMeter(ControlPart) const
960 bool RenderTheme::paintMeter(const RenderObject&, const PaintInfo&, const IntRect&)
967 #if ENABLE(DATALIST_ELEMENT)
968 LayoutUnit RenderTheme::sliderTickSnappingThreshold() const
973 void RenderTheme::paintSliderTicks(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& rect)
975 Node* node = o.node();
979 HTMLInputElement* input = node->toInputElement();
983 HTMLDataListElement* dataList = downcast<HTMLDataListElement>(input->list());
987 double min = input->minimum();
988 double max = input->maximum();
989 ControlPart part = o.style().appearance();
990 // We don't support ticks on alternate sliders like MediaVolumeSliders.
991 if (part != SliderHorizontalPart && part != SliderVerticalPart)
993 bool isHorizontal = part == SliderHorizontalPart;
996 const RenderObject* thumbRenderer = input->sliderThumbElement()->renderer();
998 const RenderStyle& thumbStyle = thumbRenderer->style();
999 int thumbWidth = thumbStyle.width().intValue();
1000 int thumbHeight = thumbStyle.height().intValue();
1001 thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight);
1002 thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth);
1005 IntSize tickSize = sliderTickSize();
1006 float zoomFactor = o.style().effectiveZoom();
1008 int tickRegionSideMargin = 0;
1009 int tickRegionWidth = 0;
1010 IntRect trackBounds;
1011 RenderObject* trackRenderer = input->sliderTrackElement()->renderer();
1012 // We can ignoring transforms because transform is handled by the graphics context.
1014 trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms();
1015 IntRect sliderBounds = o.absoluteBoundingBoxRectIgnoringTransforms();
1017 // Make position relative to the transformed ancestor element.
1018 trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x());
1019 trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y());
1022 tickRect.setWidth(floor(tickSize.width() * zoomFactor));
1023 tickRect.setHeight(floor(tickSize.height() * zoomFactor));
1024 tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
1025 tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
1026 tickRegionWidth = trackBounds.width() - thumbSize.width();
1028 tickRect.setWidth(floor(tickSize.height() * zoomFactor));
1029 tickRect.setHeight(floor(tickSize.width() * zoomFactor));
1030 tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
1031 tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
1032 tickRegionWidth = trackBounds.height() - thumbSize.width();
1034 RefPtr<HTMLCollection> options = dataList->options();
1035 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1036 paintInfo.context->setFillColor(o.style().visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
1037 for (unsigned i = 0; Node* node = options->item(i); i++) {
1038 ASSERT(isHTMLOptionElement(node));
1039 HTMLOptionElement& optionElement = downcast<HTMLOptionElement>(*node);
1040 String value = optionElement.value();
1041 if (!input->isValidValue(value))
1043 double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value));
1044 double tickFraction = (parsedValue - min) / (max - min);
1045 double tickRatio = isHorizontal && o.style().isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction;
1046 double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio);
1048 tickRect.setX(tickPosition);
1050 tickRect.setY(tickPosition);
1051 paintInfo.context->fillRect(tickRect);
1056 double RenderTheme::animationRepeatIntervalForProgressBar(RenderProgress&) const
1061 double RenderTheme::animationDurationForProgressBar(RenderProgress&) const
1066 void RenderTheme::adjustProgressBarStyle(StyleResolver&, RenderStyle&, Element*) const
1070 IntRect RenderTheme::progressBarRectForBounds(const RenderObject&, const IntRect& bounds) const
1075 bool RenderTheme::shouldHaveSpinButton(HTMLInputElement& inputElement) const
1077 return inputElement.isSteppable() && !inputElement.isRangeControl();
1080 void RenderTheme::adjustMenuListButtonStyle(StyleResolver&, RenderStyle&, Element*) const
1084 void RenderTheme::adjustMediaControlStyle(StyleResolver&, RenderStyle&, Element*) const
1088 void RenderTheme::adjustSliderTrackStyle(StyleResolver&, RenderStyle&, Element*) const
1092 void RenderTheme::adjustSliderThumbStyle(StyleResolver&, RenderStyle& style, Element* element) const
1094 adjustSliderThumbSize(style, element);
1097 void RenderTheme::adjustSliderThumbSize(RenderStyle&, Element*) const
1101 void RenderTheme::adjustSearchFieldStyle(StyleResolver&, RenderStyle&, Element*) const
1105 void RenderTheme::adjustSearchFieldCancelButtonStyle(StyleResolver&, RenderStyle&, Element*) const
1109 void RenderTheme::adjustSearchFieldDecorationPartStyle(StyleResolver&, RenderStyle&, Element*) const
1113 void RenderTheme::adjustSearchFieldResultsDecorationPartStyle(StyleResolver&, RenderStyle&, Element*) const
1117 void RenderTheme::adjustSearchFieldResultsButtonStyle(StyleResolver&, RenderStyle&, Element*) const
1121 void RenderTheme::platformColorsDidChange()
1123 m_activeSelectionForegroundColor = Color();
1124 m_inactiveSelectionForegroundColor = Color();
1125 m_activeSelectionBackgroundColor = Color();
1126 m_inactiveSelectionBackgroundColor = Color();
1128 m_activeListBoxSelectionForegroundColor = Color();
1129 m_inactiveListBoxSelectionForegroundColor = Color();
1130 m_activeListBoxSelectionBackgroundColor = Color();
1131 m_inactiveListBoxSelectionForegroundColor = Color();
1133 Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
1136 Color RenderTheme::systemColor(CSSValueID cssValueId) const
1138 switch (cssValueId) {
1139 case CSSValueActiveborder:
1141 case CSSValueActivecaption:
1143 case CSSValueAppworkspace:
1145 case CSSValueBackground:
1147 case CSSValueButtonface:
1149 case CSSValueButtonhighlight:
1151 case CSSValueButtonshadow:
1153 case CSSValueButtontext:
1155 case CSSValueActivebuttontext:
1157 case CSSValueCaptiontext:
1159 case CSSValueGraytext:
1161 case CSSValueHighlight:
1163 case CSSValueHighlighttext:
1165 case CSSValueInactiveborder:
1167 case CSSValueInactivecaption:
1169 case CSSValueInactivecaptiontext:
1171 case CSSValueInfobackground:
1173 case CSSValueInfotext:
1177 case CSSValueMenutext:
1179 case CSSValueScrollbar:
1183 case CSSValueThreeddarkshadow:
1185 case CSSValueThreedface:
1187 case CSSValueThreedhighlight:
1189 case CSSValueThreedlightshadow:
1191 case CSSValueThreedshadow:
1193 case CSSValueWindow:
1195 case CSSValueWindowframe:
1197 case CSSValueWindowtext:
1205 Color RenderTheme::platformActiveTextSearchHighlightColor() const
1207 return Color(255, 150, 50); // Orange.
1210 Color RenderTheme::platformInactiveTextSearchHighlightColor() const
1212 return Color(255, 255, 0); // Yellow.
1215 #if ENABLE(TOUCH_EVENTS)
1216 Color RenderTheme::tapHighlightColor()
1218 return defaultTheme()->platformTapHighlightColor();
1222 // Value chosen by observation. This can be tweaked.
1223 static const int minColorContrastValue = 1300;
1224 // For transparent or translucent background color, use lightening.
1225 static const int minDisabledColorAlphaValue = 128;
1227 Color RenderTheme::disabledTextColor(const Color& textColor, const Color& backgroundColor) const
1229 // The explicit check for black is an optimization for the 99% case (black on white).
1230 // This also means that black on black will turn into grey on black when disabled.
1231 Color disabledColor;
1232 if (textColor.rgb() == Color::black || backgroundColor.alpha() < minDisabledColorAlphaValue || differenceSquared(textColor, Color::white) > differenceSquared(backgroundColor, Color::white))
1233 disabledColor = textColor.light();
1235 disabledColor = textColor.dark();
1237 // If there's not very much contrast between the disabled color and the background color,
1238 // just leave the text color alone. We don't want to change a good contrast color scheme so that it has really bad contrast.
1239 // If the the contrast was already poor, then it doesn't do any good to change it to a different poor contrast color scheme.
1240 if (differenceSquared(disabledColor, backgroundColor) < minColorContrastValue)
1243 return disabledColor;
1246 void RenderTheme::setCustomFocusRingColor(const Color& c)
1248 customFocusRingColor() = c;
1251 Color RenderTheme::focusRingColor()
1253 return customFocusRingColor().isValid() ? customFocusRingColor() : defaultTheme()->platformFocusRingColor();
1256 String RenderTheme::fileListDefaultLabel(bool multipleFilesAllowed) const
1258 if (multipleFilesAllowed)
1259 return fileButtonNoFilesSelectedLabel();
1260 return fileButtonNoFileSelectedLabel();
1263 String RenderTheme::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
1269 if (fileList->isEmpty())
1270 string = fileListDefaultLabel(multipleFilesAllowed);
1271 else if (fileList->length() == 1)
1272 string = fileList->item(0)->name();
1274 return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
1276 return StringTruncator::centerTruncate(string, width, font, StringTruncator::EnableRoundingHacks);
1279 } // namespace WebCore