[macOS] Color wells should appear pressed when presenting a color picker
[WebKit-https.git] / Source / WebCore / rendering / RenderTheme.cpp
1 /*
2  * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2014 Google Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "RenderTheme.h"
23
24 #include "CSSValueKeywords.h"
25 #include "ControlStates.h"
26 #include "Document.h"
27 #include "FileList.h"
28 #include "FileSystem.h"
29 #include "FloatConversion.h"
30 #include "FloatRoundedRect.h"
31 #include "FocusController.h"
32 #include "FontSelector.h"
33 #include "Frame.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"
40 #include "Page.h"
41 #include "PaintInfo.h"
42 #include "RenderStyle.h"
43 #include "RenderView.h"
44 #include "SpinButtonElement.h"
45 #include "StringTruncator.h"
46 #include "TextControlInnerElements.h"
47 #include <wtf/NeverDestroyed.h>
48
49 #if ENABLE(METER_ELEMENT)
50 #include "HTMLMeterElement.h"
51 #include "RenderMeter.h"
52 #endif
53
54 #if ENABLE(DATALIST_ELEMENT)
55 #include "HTMLCollection.h"
56 #include "HTMLDataListElement.h"
57 #include "HTMLOptionElement.h"
58 #include "HTMLParserIdioms.h"
59 #endif
60
61 #if USE(NEW_THEME)
62 #include "Theme.h"
63 #endif
64
65 namespace WebCore {
66
67 using namespace HTMLNames;
68
69 static Color& customFocusRingColor()
70 {
71     static NeverDestroyed<Color> color;
72     return color;
73 }
74
75 RenderTheme::RenderTheme()
76 {
77 }
78
79 void RenderTheme::adjustStyle(StyleResolver& styleResolver, RenderStyle& style, const Element* element, bool UAHasAppearance, const BorderData& border, const FillLayer& background, const Color& backgroundColor)
80 {
81     // Force inline and table display styles to be inline-block (except for table- which is block)
82     ControlPart part = style.appearance();
83     if (style.display() == DisplayType::Inline || style.display() == DisplayType::InlineTable || style.display() == DisplayType::TableRowGroup
84         || style.display() == DisplayType::TableHeaderGroup || style.display() == DisplayType::TableFooterGroup
85         || style.display() == DisplayType::TableRow || style.display() == DisplayType::TableColumnGroup || style.display() == DisplayType::TableColumn
86         || style.display() == DisplayType::TableCell || style.display() == DisplayType::TableCaption)
87         style.setDisplay(DisplayType::InlineBlock);
88     else if (style.display() == DisplayType::Compact || style.display() == DisplayType::ListItem || style.display() == DisplayType::Table)
89         style.setDisplay(DisplayType::Block);
90
91     if (UAHasAppearance && isControlStyled(style, border, background, backgroundColor)) {
92         switch (part) {
93         case MenulistPart:
94             style.setAppearance(MenulistButtonPart);
95             part = MenulistButtonPart;
96             break;
97         case TextFieldPart:
98             adjustTextFieldStyle(styleResolver, style, element);
99             FALLTHROUGH;
100         default:
101             style.setAppearance(NoControlPart);
102             break;
103         }
104     }
105
106     if (!style.hasAppearance())
107         return;
108
109     // Never support box-shadow on native controls.
110     style.setBoxShadow(nullptr);
111     
112 #if USE(NEW_THEME)
113     switch (part) {
114     case CheckboxPart:
115     case InnerSpinButtonPart:
116     case RadioPart:
117     case PushButtonPart:
118     case SquareButtonPart:
119 #if ENABLE(INPUT_TYPE_COLOR)
120     case ColorWellPart:
121 #endif
122     case DefaultButtonPart:
123     case ButtonPart: {
124         // Border
125         LengthBox borderBox(style.borderTopWidth(), style.borderRightWidth(), style.borderBottomWidth(), style.borderLeftWidth());
126         borderBox = Theme::singleton().controlBorder(part, style.fontCascade(), borderBox, style.effectiveZoom());
127         if (borderBox.top().value() != static_cast<int>(style.borderTopWidth())) {
128             if (borderBox.top().value())
129                 style.setBorderTopWidth(borderBox.top().value());
130             else
131                 style.resetBorderTop();
132         }
133         if (borderBox.right().value() != static_cast<int>(style.borderRightWidth())) {
134             if (borderBox.right().value())
135                 style.setBorderRightWidth(borderBox.right().value());
136             else
137                 style.resetBorderRight();
138         }
139         if (borderBox.bottom().value() != static_cast<int>(style.borderBottomWidth())) {
140             style.setBorderBottomWidth(borderBox.bottom().value());
141             if (borderBox.bottom().value())
142                 style.setBorderBottomWidth(borderBox.bottom().value());
143             else
144                 style.resetBorderBottom();
145         }
146         if (borderBox.left().value() != static_cast<int>(style.borderLeftWidth())) {
147             style.setBorderLeftWidth(borderBox.left().value());
148             if (borderBox.left().value())
149                 style.setBorderLeftWidth(borderBox.left().value());
150             else
151                 style.resetBorderLeft();
152         }
153
154         // Padding
155         LengthBox paddingBox = Theme::singleton().controlPadding(part, style.fontCascade(), style.paddingBox(), style.effectiveZoom());
156         if (paddingBox != style.paddingBox())
157             style.setPaddingBox(WTFMove(paddingBox));
158
159         // Whitespace
160         if (Theme::singleton().controlRequiresPreWhiteSpace(part))
161             style.setWhiteSpace(WhiteSpace::Pre);
162
163         // Width / Height
164         // The width and height here are affected by the zoom.
165         // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
166         LengthSize controlSize = Theme::singleton().controlSize(part, style.fontCascade(), { style.width(), style.height() }, style.effectiveZoom());
167         if (controlSize.width != style.width())
168             style.setWidth(WTFMove(controlSize.width));
169         if (controlSize.height != style.height())
170             style.setHeight(WTFMove(controlSize.height));
171
172         // Min-Width / Min-Height
173         LengthSize minControlSize = Theme::singleton().minimumControlSize(part, style.fontCascade(), style.effectiveZoom());
174         if (minControlSize.width != style.minWidth())
175             style.setMinWidth(WTFMove(minControlSize.width));
176         if (minControlSize.height != style.minHeight())
177             style.setMinHeight(WTFMove(minControlSize.height));
178
179         // Font
180         if (auto themeFont = Theme::singleton().controlFont(part, style.fontCascade(), style.effectiveZoom())) {
181             // If overriding the specified font with the theme font, also override the line height with the standard line height.
182             style.setLineHeight(RenderStyle::initialLineHeight());
183             if (style.setFontDescription(WTFMove(themeFont.value())))
184                 style.fontCascade().update(nullptr);
185         }
186
187         // Special style that tells enabled default buttons in active windows to use the ActiveButtonText color.
188         // The active window part of the test has to be done at paint time since it's not triggered by a style change.
189         style.setInsideDefaultButton(part == DefaultButtonPart && element && !element->isDisabledFormControl());
190         break;
191     }
192     default:
193         break;
194     }
195 #endif
196
197     // Call the appropriate style adjustment method based off the appearance value.
198     switch (style.appearance()) {
199 #if !USE(NEW_THEME)
200     case CheckboxPart:
201         return adjustCheckboxStyle(styleResolver, style, element);
202     case RadioPart:
203         return adjustRadioStyle(styleResolver, style, element);
204     case PushButtonPart:
205     case SquareButtonPart:
206 #if ENABLE(INPUT_TYPE_COLOR)
207     case ColorWellPart:
208 #endif
209     case DefaultButtonPart:
210     case ButtonPart:
211         return adjustButtonStyle(styleResolver, style, element);
212     case InnerSpinButtonPart:
213         return adjustInnerSpinButtonStyle(styleResolver, style, element);
214 #endif
215     case TextFieldPart:
216         return adjustTextFieldStyle(styleResolver, style, element);
217     case TextAreaPart:
218         return adjustTextAreaStyle(styleResolver, style, element);
219     case MenulistPart:
220         return adjustMenuListStyle(styleResolver, style, element);
221     case MenulistButtonPart:
222         return adjustMenuListButtonStyle(styleResolver, style, element);
223     case MediaPlayButtonPart:
224     case MediaCurrentTimePart:
225     case MediaTimeRemainingPart:
226     case MediaEnterFullscreenButtonPart:
227     case MediaExitFullscreenButtonPart:
228     case MediaMuteButtonPart:
229     case MediaVolumeSliderContainerPart:
230         return adjustMediaControlStyle(styleResolver, style, element);
231     case MediaSliderPart:
232     case MediaVolumeSliderPart:
233     case MediaFullScreenVolumeSliderPart:
234     case SliderHorizontalPart:
235     case SliderVerticalPart:
236         return adjustSliderTrackStyle(styleResolver, style, element);
237     case SliderThumbHorizontalPart:
238     case SliderThumbVerticalPart:
239         return adjustSliderThumbStyle(styleResolver, style, element);
240     case SearchFieldPart:
241         return adjustSearchFieldStyle(styleResolver, style, element);
242     case SearchFieldCancelButtonPart:
243         return adjustSearchFieldCancelButtonStyle(styleResolver, style, element);
244     case SearchFieldDecorationPart:
245         return adjustSearchFieldDecorationPartStyle(styleResolver, style, element);
246     case SearchFieldResultsDecorationPart:
247         return adjustSearchFieldResultsDecorationPartStyle(styleResolver, style, element);
248     case SearchFieldResultsButtonPart:
249         return adjustSearchFieldResultsButtonStyle(styleResolver, style, element);
250     case ProgressBarPart:
251         return adjustProgressBarStyle(styleResolver, style, element);
252 #if ENABLE(METER_ELEMENT)
253     case MeterPart:
254     case RelevancyLevelIndicatorPart:
255     case ContinuousCapacityLevelIndicatorPart:
256     case DiscreteCapacityLevelIndicatorPart:
257     case RatingLevelIndicatorPart:
258         return adjustMeterStyle(styleResolver, style, element);
259 #endif
260 #if ENABLE(SERVICE_CONTROLS)
261     case ImageControlsButtonPart:
262         break;
263 #endif
264     case CapsLockIndicatorPart:
265         return adjustCapsLockIndicatorStyle(styleResolver, style, element);
266 #if ENABLE(APPLE_PAY)
267     case ApplePayButtonPart:
268         return adjustApplePayButtonStyle(styleResolver, style, element);
269 #endif
270 #if ENABLE(ATTACHMENT_ELEMENT)
271     case AttachmentPart:
272     case BorderlessAttachmentPart:
273         return adjustAttachmentStyle(styleResolver, style, element);
274 #endif
275     default:
276         break;
277     }
278 }
279
280 bool RenderTheme::paint(const RenderBox& box, ControlStates& controlStates, const PaintInfo& paintInfo, const LayoutRect& rect)
281 {
282     // If painting is disabled, but we aren't updating control tints, then just bail.
283     // If we are updating control tints, just schedule a repaint if the theme supports tinting
284     // for that control.
285     if (paintInfo.context().invalidatingControlTints()) {
286         if (controlSupportsTints(box))
287             box.repaint();
288         return false;
289     }
290     if (paintInfo.context().paintingDisabled())
291         return false;
292
293     if (UNLIKELY(!paintInfo.context().hasPlatformContext()))
294         return false;
295
296     ControlPart part = box.style().appearance();
297     IntRect integralSnappedRect = snappedIntRect(rect);
298     float deviceScaleFactor = box.document().deviceScaleFactor();
299     FloatRect devicePixelSnappedRect = snapRectToDevicePixels(rect, deviceScaleFactor);
300     
301 #if USE(NEW_THEME)
302     float pageScaleFactor = box.page().pageScaleFactor();
303
304     switch (part) {
305     case CheckboxPart:
306     case RadioPart:
307     case PushButtonPart:
308     case SquareButtonPart:
309 #if ENABLE(INPUT_TYPE_COLOR)
310     case ColorWellPart:
311 #endif
312     case DefaultButtonPart:
313     case ButtonPart:
314     case InnerSpinButtonPart:
315         updateControlStatesForRenderer(box, controlStates);
316         Theme::singleton().paint(part, controlStates, paintInfo.context(), devicePixelSnappedRect, box.style().effectiveZoom(), &box.view().frameView(), deviceScaleFactor, pageScaleFactor, box.page().useSystemAppearance(), box.page().useDarkAppearance());
317         return false;
318     default:
319         break;
320     }
321 #else
322     UNUSED_PARAM(controlStates);
323 #endif
324
325     // Call the appropriate paint method based off the appearance value.
326     switch (part) {
327 #if !USE(NEW_THEME)
328     case CheckboxPart:
329         return paintCheckbox(box, paintInfo, integralSnappedRect);
330     case RadioPart:
331         return paintRadio(box, paintInfo, integralSnappedRect);
332     case PushButtonPart:
333     case SquareButtonPart:
334 #if ENABLE(INPUT_TYPE_COLOR)
335     case ColorWellPart:
336 #endif
337     case DefaultButtonPart:
338     case ButtonPart:
339         return paintButton(box, paintInfo, integralSnappedRect);
340     case InnerSpinButtonPart:
341         return paintInnerSpinButton(box, paintInfo, integralSnappedRect);
342 #endif
343     case MenulistPart:
344         return paintMenuList(box, paintInfo, devicePixelSnappedRect);
345 #if ENABLE(METER_ELEMENT)
346     case MeterPart:
347     case RelevancyLevelIndicatorPart:
348     case ContinuousCapacityLevelIndicatorPart:
349     case DiscreteCapacityLevelIndicatorPart:
350     case RatingLevelIndicatorPart:
351         return paintMeter(box, paintInfo, integralSnappedRect);
352 #endif
353     case ProgressBarPart:
354         return paintProgressBar(box, paintInfo, integralSnappedRect);
355     case SliderHorizontalPart:
356     case SliderVerticalPart:
357         return paintSliderTrack(box, paintInfo, integralSnappedRect);
358     case SliderThumbHorizontalPart:
359     case SliderThumbVerticalPart:
360         return paintSliderThumb(box, paintInfo, integralSnappedRect);
361     case MediaEnterFullscreenButtonPart:
362     case MediaExitFullscreenButtonPart:
363         return paintMediaFullscreenButton(box, paintInfo, integralSnappedRect);
364     case MediaPlayButtonPart:
365         return paintMediaPlayButton(box, paintInfo, integralSnappedRect);
366     case MediaOverlayPlayButtonPart:
367         return paintMediaOverlayPlayButton(box, paintInfo, integralSnappedRect);
368     case MediaMuteButtonPart:
369         return paintMediaMuteButton(box, paintInfo, integralSnappedRect);
370     case MediaSeekBackButtonPart:
371         return paintMediaSeekBackButton(box, paintInfo, integralSnappedRect);
372     case MediaSeekForwardButtonPart:
373         return paintMediaSeekForwardButton(box, paintInfo, integralSnappedRect);
374     case MediaRewindButtonPart:
375         return paintMediaRewindButton(box, paintInfo, integralSnappedRect);
376     case MediaReturnToRealtimeButtonPart:
377         return paintMediaReturnToRealtimeButton(box, paintInfo, integralSnappedRect);
378     case MediaToggleClosedCaptionsButtonPart:
379         return paintMediaToggleClosedCaptionsButton(box, paintInfo, integralSnappedRect);
380     case MediaSliderPart:
381         return paintMediaSliderTrack(box, paintInfo, integralSnappedRect);
382     case MediaSliderThumbPart:
383         return paintMediaSliderThumb(box, paintInfo, integralSnappedRect);
384     case MediaVolumeSliderMuteButtonPart:
385         return paintMediaMuteButton(box, paintInfo, integralSnappedRect);
386     case MediaVolumeSliderContainerPart:
387         return paintMediaVolumeSliderContainer(box, paintInfo, integralSnappedRect);
388     case MediaVolumeSliderPart:
389         return paintMediaVolumeSliderTrack(box, paintInfo, integralSnappedRect);
390     case MediaVolumeSliderThumbPart:
391         return paintMediaVolumeSliderThumb(box, paintInfo, integralSnappedRect);
392     case MediaFullScreenVolumeSliderPart:
393         return paintMediaFullScreenVolumeSliderTrack(box, paintInfo, integralSnappedRect);
394     case MediaFullScreenVolumeSliderThumbPart:
395         return paintMediaFullScreenVolumeSliderThumb(box, paintInfo, integralSnappedRect);
396     case MediaTimeRemainingPart:
397         return paintMediaTimeRemaining(box, paintInfo, integralSnappedRect);
398     case MediaCurrentTimePart:
399         return paintMediaCurrentTime(box, paintInfo, integralSnappedRect);
400     case MediaControlsBackgroundPart:
401         return paintMediaControlsBackground(box, paintInfo, integralSnappedRect);
402     case MenulistButtonPart:
403     case TextFieldPart:
404     case TextAreaPart:
405     case ListboxPart:
406         return true;
407     case SearchFieldPart:
408         return paintSearchField(box, paintInfo, integralSnappedRect);
409     case SearchFieldCancelButtonPart:
410         return paintSearchFieldCancelButton(box, paintInfo, integralSnappedRect);
411     case SearchFieldDecorationPart:
412         return paintSearchFieldDecorationPart(box, paintInfo, integralSnappedRect);
413     case SearchFieldResultsDecorationPart:
414         return paintSearchFieldResultsDecorationPart(box, paintInfo, integralSnappedRect);
415     case SearchFieldResultsButtonPart:
416         return paintSearchFieldResultsButton(box, paintInfo, integralSnappedRect);
417     case SnapshottedPluginOverlayPart:
418         return paintSnapshottedPluginOverlay(box, paintInfo, integralSnappedRect);
419 #if ENABLE(SERVICE_CONTROLS)
420     case ImageControlsButtonPart:
421         return paintImageControlsButton(box, paintInfo, integralSnappedRect);
422 #endif
423     case CapsLockIndicatorPart:
424         return paintCapsLockIndicator(box, paintInfo, integralSnappedRect);
425 #if ENABLE(APPLE_PAY)
426     case ApplePayButtonPart:
427         return paintApplePayButton(box, paintInfo, integralSnappedRect);
428 #endif
429 #if ENABLE(ATTACHMENT_ELEMENT)
430     case AttachmentPart:
431     case BorderlessAttachmentPart:
432         return paintAttachment(box, paintInfo, integralSnappedRect);
433 #endif
434     default:
435         break;
436     }
437
438     return true; // We don't support the appearance, so let the normal background/border paint.
439 }
440
441 bool RenderTheme::paintBorderOnly(const RenderBox& box, const PaintInfo& paintInfo, const LayoutRect& rect)
442 {
443     if (paintInfo.context().paintingDisabled())
444         return false;
445
446 #if PLATFORM(IOS)
447     UNUSED_PARAM(rect);
448     return box.style().appearance() != NoControlPart;
449 #else
450     FloatRect devicePixelSnappedRect = snapRectToDevicePixels(rect, box.document().deviceScaleFactor());
451     // Call the appropriate paint method based off the appearance value.
452     switch (box.style().appearance()) {
453     case TextFieldPart:
454         return paintTextField(box, paintInfo, devicePixelSnappedRect);
455     case ListboxPart:
456     case TextAreaPart:
457         return paintTextArea(box, paintInfo, devicePixelSnappedRect);
458     case MenulistButtonPart:
459     case SearchFieldPart:
460         return true;
461     case CheckboxPart:
462     case RadioPart:
463     case PushButtonPart:
464     case SquareButtonPart:
465 #if ENABLE(INPUT_TYPE_COLOR)
466     case ColorWellPart:
467 #endif
468     case DefaultButtonPart:
469     case ButtonPart:
470     case MenulistPart:
471 #if ENABLE(METER_ELEMENT)
472     case MeterPart:
473     case RelevancyLevelIndicatorPart:
474     case ContinuousCapacityLevelIndicatorPart:
475     case DiscreteCapacityLevelIndicatorPart:
476     case RatingLevelIndicatorPart:
477 #endif
478     case ProgressBarPart:
479     case SliderHorizontalPart:
480     case SliderVerticalPart:
481     case SliderThumbHorizontalPart:
482     case SliderThumbVerticalPart:
483     case SearchFieldCancelButtonPart:
484     case SearchFieldDecorationPart:
485     case SearchFieldResultsDecorationPart:
486     case SearchFieldResultsButtonPart:
487 #if ENABLE(SERVICE_CONTROLS)
488     case ImageControlsButtonPart:
489 #endif
490     default:
491         break;
492     }
493
494     return false;
495 #endif
496 }
497
498 bool RenderTheme::paintDecorations(const RenderBox& box, const PaintInfo& paintInfo, const LayoutRect& rect)
499 {
500     if (paintInfo.context().paintingDisabled())
501         return false;
502
503     IntRect integralSnappedRect = snappedIntRect(rect);
504     FloatRect devicePixelSnappedRect = snapRectToDevicePixels(rect, box.document().deviceScaleFactor());
505
506     // Call the appropriate paint method based off the appearance value.
507     switch (box.style().appearance()) {
508     case MenulistButtonPart:
509         return paintMenuListButtonDecorations(box, paintInfo, devicePixelSnappedRect);
510     case TextFieldPart:
511         return paintTextFieldDecorations(box, paintInfo, devicePixelSnappedRect);
512     case TextAreaPart:
513         return paintTextAreaDecorations(box, paintInfo, devicePixelSnappedRect);
514     case CheckboxPart:
515         return paintCheckboxDecorations(box, paintInfo, integralSnappedRect);
516     case RadioPart:
517         return paintRadioDecorations(box, paintInfo, integralSnappedRect);
518     case PushButtonPart:
519         return paintPushButtonDecorations(box, paintInfo, integralSnappedRect);
520     case SquareButtonPart:
521 #if ENABLE(INPUT_TYPE_COLOR)
522     case ColorWellPart:
523 #endif
524         return paintSquareButtonDecorations(box, paintInfo, integralSnappedRect);
525     case ButtonPart:
526         return paintButtonDecorations(box, paintInfo, integralSnappedRect);
527     case MenulistPart:
528         return paintMenuListDecorations(box, paintInfo, integralSnappedRect);
529     case SliderThumbHorizontalPart:
530     case SliderThumbVerticalPart:
531         return paintSliderThumbDecorations(box, paintInfo, integralSnappedRect);
532     case SearchFieldPart:
533         return paintSearchFieldDecorations(box, paintInfo, integralSnappedRect);
534 #if ENABLE(METER_ELEMENT)
535     case MeterPart:
536     case RelevancyLevelIndicatorPart:
537     case ContinuousCapacityLevelIndicatorPart:
538     case DiscreteCapacityLevelIndicatorPart:
539     case RatingLevelIndicatorPart:
540 #endif
541     case ProgressBarPart:
542     case SliderHorizontalPart:
543     case SliderVerticalPart:
544     case ListboxPart:
545     case DefaultButtonPart:
546     case SearchFieldCancelButtonPart:
547     case SearchFieldDecorationPart:
548     case SearchFieldResultsDecorationPart:
549     case SearchFieldResultsButtonPart:
550 #if ENABLE(SERVICE_CONTROLS)
551     case ImageControlsButtonPart:
552 #endif
553     default:
554         break;
555     }
556
557     return false;
558 }
559
560 #if ENABLE(VIDEO)
561
562 String RenderTheme::formatMediaControlsTime(float time) const
563 {
564     if (!std::isfinite(time))
565         time = 0;
566     int seconds = (int)fabsf(time);
567     int hours = seconds / (60 * 60);
568     int minutes = (seconds / 60) % 60;
569     seconds %= 60;
570     if (hours) {
571         if (hours > 9)
572             return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
573
574         return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
575     }
576
577     return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
578 }
579
580 String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*duration*/) const
581 {
582     return formatMediaControlsTime(currentTime);
583 }
584
585 String RenderTheme::formatMediaControlsRemainingTime(float currentTime, float duration) const
586 {
587     return formatMediaControlsTime(currentTime - duration);
588 }
589
590 LayoutPoint RenderTheme::volumeSliderOffsetFromMuteButton(const RenderBox& muteButtonBox, const LayoutSize& size) const
591 {
592     LayoutUnit y = -size.height();
593     FloatPoint absPoint = muteButtonBox.localToAbsolute(FloatPoint(muteButtonBox.offsetLeft(), y), IsFixed | UseTransforms);
594     if (absPoint.y() < 0)
595         y = muteButtonBox.height();
596     return LayoutPoint(0, y);
597 }
598
599 #endif
600
601 Color RenderTheme::activeSelectionBackgroundColor(OptionSet<StyleColor::Options> options) const
602 {
603     auto& cache = colorCache(options);
604     if (!cache.activeSelectionBackgroundColor.isValid())
605         cache.activeSelectionBackgroundColor = transformSelectionBackgroundColor(platformActiveSelectionBackgroundColor(options), options);
606     return cache.activeSelectionBackgroundColor;
607 }
608
609 Color RenderTheme::inactiveSelectionBackgroundColor(OptionSet<StyleColor::Options> options) const
610 {
611     auto& cache = colorCache(options);
612     if (!cache.inactiveSelectionBackgroundColor.isValid())
613         cache.inactiveSelectionBackgroundColor = transformSelectionBackgroundColor(platformInactiveSelectionBackgroundColor(options), options);
614     return cache.inactiveSelectionBackgroundColor;
615 }
616
617 Color RenderTheme::transformSelectionBackgroundColor(const Color& color, OptionSet<StyleColor::Options>) const
618 {
619     return color.blendWithWhite();
620 }
621
622 Color RenderTheme::activeSelectionForegroundColor(OptionSet<StyleColor::Options> options) const
623 {
624     auto& cache = colorCache(options);
625     if (!cache.activeSelectionForegroundColor.isValid() && supportsSelectionForegroundColors(options))
626         cache.activeSelectionForegroundColor = platformActiveSelectionForegroundColor(options);
627     return cache.activeSelectionForegroundColor;
628 }
629
630 Color RenderTheme::inactiveSelectionForegroundColor(OptionSet<StyleColor::Options> options) const
631 {
632     auto& cache = colorCache(options);
633     if (!cache.inactiveSelectionForegroundColor.isValid() && supportsSelectionForegroundColors(options))
634         cache.inactiveSelectionForegroundColor = platformInactiveSelectionForegroundColor(options);
635     return cache.inactiveSelectionForegroundColor;
636 }
637
638 Color RenderTheme::activeListBoxSelectionBackgroundColor(OptionSet<StyleColor::Options> options) const
639 {
640     auto& cache = colorCache(options);
641     if (!cache.activeListBoxSelectionBackgroundColor.isValid())
642         cache.activeListBoxSelectionBackgroundColor = platformActiveListBoxSelectionBackgroundColor(options);
643     return cache.activeListBoxSelectionBackgroundColor;
644 }
645
646 Color RenderTheme::inactiveListBoxSelectionBackgroundColor(OptionSet<StyleColor::Options> options) const
647 {
648     auto& cache = colorCache(options);
649     if (!cache.inactiveListBoxSelectionBackgroundColor.isValid())
650         cache.inactiveListBoxSelectionBackgroundColor = platformInactiveListBoxSelectionBackgroundColor(options);
651     return cache.inactiveListBoxSelectionBackgroundColor;
652 }
653
654 Color RenderTheme::activeListBoxSelectionForegroundColor(OptionSet<StyleColor::Options> options) const
655 {
656     auto& cache = colorCache(options);
657     if (!cache.activeListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors(options))
658         cache.activeListBoxSelectionForegroundColor = platformActiveListBoxSelectionForegroundColor(options);
659     return cache.activeListBoxSelectionForegroundColor;
660 }
661
662 Color RenderTheme::inactiveListBoxSelectionForegroundColor(OptionSet<StyleColor::Options> options) const
663 {
664     auto& cache = colorCache(options);
665     if (!cache.inactiveListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors(options))
666         cache.inactiveListBoxSelectionForegroundColor = platformInactiveListBoxSelectionForegroundColor(options);
667     return cache.inactiveListBoxSelectionForegroundColor;
668 }
669
670 Color RenderTheme::platformActiveSelectionBackgroundColor(OptionSet<StyleColor::Options>) const
671 {
672     // Use a blue color by default if the platform theme doesn't define anything.
673     return Color(0, 0, 255);
674 }
675
676 Color RenderTheme::platformActiveSelectionForegroundColor(OptionSet<StyleColor::Options>) const
677 {
678     // Use a white color by default if the platform theme doesn't define anything.
679     return Color::white;
680 }
681
682 Color RenderTheme::platformInactiveSelectionBackgroundColor(OptionSet<StyleColor::Options>) const
683 {
684     // Use a grey color by default if the platform theme doesn't define anything.
685     // This color matches Firefox's inactive color.
686     return Color(176, 176, 176);
687 }
688
689 Color RenderTheme::platformInactiveSelectionForegroundColor(OptionSet<StyleColor::Options>) const
690 {
691     // Use a black color by default.
692     return Color::black;
693 }
694
695 Color RenderTheme::platformActiveListBoxSelectionBackgroundColor(OptionSet<StyleColor::Options> options) const
696 {
697     return platformActiveSelectionBackgroundColor(options);
698 }
699
700 Color RenderTheme::platformActiveListBoxSelectionForegroundColor(OptionSet<StyleColor::Options> options) const
701 {
702     return platformActiveSelectionForegroundColor(options);
703 }
704
705 Color RenderTheme::platformInactiveListBoxSelectionBackgroundColor(OptionSet<StyleColor::Options> options) const
706 {
707     return platformInactiveSelectionBackgroundColor(options);
708 }
709
710 Color RenderTheme::platformInactiveListBoxSelectionForegroundColor(OptionSet<StyleColor::Options> options) const
711 {
712     return platformInactiveSelectionForegroundColor(options);
713 }
714
715 int RenderTheme::baselinePosition(const RenderBox& box) const
716 {
717 #if USE(NEW_THEME)
718     return box.height() + box.marginTop() + Theme::singleton().baselinePositionAdjustment(box.style().appearance()) * box.style().effectiveZoom();
719 #else
720     return box.height() + box.marginTop();
721 #endif
722 }
723
724 bool RenderTheme::isControlContainer(ControlPart appearance) const
725 {
726     // There are more leaves than this, but we'll patch this function as we add support for
727     // more controls.
728     return appearance != CheckboxPart && appearance != RadioPart;
729 }
730
731 bool RenderTheme::isControlStyled(const RenderStyle& style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const
732 {
733     switch (style.appearance()) {
734     case PushButtonPart:
735     case SquareButtonPart:
736 #if ENABLE(INPUT_TYPE_COLOR)
737     case ColorWellPart:
738 #endif
739     case DefaultButtonPart:
740     case ButtonPart:
741     case ListboxPart:
742     case MenulistPart:
743     case ProgressBarPart:
744     case MeterPart:
745     case RelevancyLevelIndicatorPart:
746     case ContinuousCapacityLevelIndicatorPart:
747     case DiscreteCapacityLevelIndicatorPart:
748     case RatingLevelIndicatorPart:
749     // FIXME: SearchFieldPart should be included here when making search fields style-able.
750     case TextFieldPart:
751     case TextAreaPart:
752         // Test the style to see if the UA border and background match.
753         return style.border() != border
754             || style.backgroundLayers() != background
755             || !style.backgroundColorEqualsToColorIgnoringVisited(backgroundColor);
756     default:
757         return false;
758     }
759 }
760
761 void RenderTheme::adjustRepaintRect(const RenderObject& renderer, FloatRect& rect)
762 {
763 #if USE(NEW_THEME)
764     ControlStates states(extractControlStatesForRenderer(renderer));
765     Theme::singleton().inflateControlPaintRect(renderer.style().appearance(), states, rect, renderer.style().effectiveZoom());
766 #else
767     UNUSED_PARAM(renderer);
768     UNUSED_PARAM(rect);
769 #endif
770 }
771
772 bool RenderTheme::supportsFocusRing(const RenderStyle& style) const
773 {
774     return (style.hasAppearance() && style.appearance() != TextFieldPart && style.appearance() != TextAreaPart && style.appearance() != MenulistButtonPart && style.appearance() != ListboxPart);
775 }
776
777 bool RenderTheme::stateChanged(const RenderObject& o, ControlStates::States state) const
778 {
779     // Default implementation assumes the controls don't respond to changes in :hover state
780     if (state == ControlStates::HoverState && !supportsHover(o.style()))
781         return false;
782
783     // Assume pressed state is only responded to if the control is enabled.
784     if (state == ControlStates::PressedState && !isEnabled(o))
785         return false;
786
787     // Repaint the control.
788     o.repaint();
789     return true;
790 }
791
792 void RenderTheme::updateControlStatesForRenderer(const RenderBox& box, ControlStates& controlStates) const
793 {
794     ControlStates newStates = extractControlStatesForRenderer(box);
795     controlStates.setStates(newStates.states());
796     if (isFocused(box))
797         controlStates.setTimeSinceControlWasFocused(box.page().focusController().timeSinceFocusWasSet());
798 }
799
800 ControlStates::States RenderTheme::extractControlStatesForRenderer(const RenderObject& o) const
801 {
802     ControlStates::States states = 0;
803     if (isHovered(o)) {
804         states |= ControlStates::HoverState;
805         if (isSpinUpButtonPartHovered(o))
806             states |= ControlStates::SpinUpState;
807     }
808     if (isPressed(o)) {
809         states |= ControlStates::PressedState;
810         if (isSpinUpButtonPartPressed(o))
811             states |= ControlStates::SpinUpState;
812     }
813     if (isFocused(o) && o.style().outlineStyleIsAuto() == OutlineIsAuto::On)
814         states |= ControlStates::FocusState;
815     if (isEnabled(o))
816         states |= ControlStates::EnabledState;
817     if (isChecked(o))
818         states |= ControlStates::CheckedState;
819     if (isDefault(o))
820         states |= ControlStates::DefaultState;
821     if (!isActive(o))
822         states |= ControlStates::WindowInactiveState;
823     if (isIndeterminate(o))
824         states |= ControlStates::IndeterminateState;
825     if (isPresenting(o))
826         states |= ControlStates::PresentingState;
827     return states;
828 }
829
830 bool RenderTheme::isActive(const RenderObject& renderer) const
831 {
832     return renderer.page().focusController().isActive();
833 }
834
835 bool RenderTheme::isChecked(const RenderObject& o) const
836 {
837     return is<HTMLInputElement>(o.node()) && downcast<HTMLInputElement>(*o.node()).shouldAppearChecked();
838 }
839
840 bool RenderTheme::isIndeterminate(const RenderObject& o) const
841 {
842     return is<HTMLInputElement>(o.node()) && downcast<HTMLInputElement>(*o.node()).shouldAppearIndeterminate();
843 }
844
845 bool RenderTheme::isEnabled(const RenderObject& renderer) const
846 {
847     Node* node = renderer.node();
848     if (!is<Element>(node))
849         return true;
850     return !downcast<Element>(*node).isDisabledFormControl();
851 }
852
853 bool RenderTheme::isFocused(const RenderObject& renderer) const
854 {
855     Node* node = renderer.node();
856     if (!is<Element>(node))
857         return false;
858
859     auto focusDelegate = downcast<Element>(*node).focusDelegate();
860     Document& document = focusDelegate->document();
861     Frame* frame = document.frame();
862     return focusDelegate == document.focusedElement() && frame && frame->selection().isFocusedAndActive();
863 }
864
865 bool RenderTheme::isPressed(const RenderObject& renderer) const
866 {
867     if (!is<Element>(renderer.node()))
868         return false;
869     return downcast<Element>(*renderer.node()).active();
870 }
871
872 bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject& renderer) const
873 {
874     Node* node = renderer.node();
875     if (!is<Element>(node))
876         return false;
877     Element& element = downcast<Element>(*node);
878     if (!element.active() || !is<SpinButtonElement>(element))
879         return false;
880     return downcast<SpinButtonElement>(element).upDownState() == SpinButtonElement::Up;
881 }
882
883 bool RenderTheme::isReadOnlyControl(const RenderObject& renderer) const
884 {
885     Node* node = renderer.node();
886     if (!is<HTMLFormControlElement>(node))
887         return false;
888     return !downcast<Element>(*node).matchesReadWritePseudoClass();
889 }
890
891 bool RenderTheme::isHovered(const RenderObject& renderer) const
892 {
893     Node* node = renderer.node();
894     if (!is<Element>(node))
895         return false;
896     Element& element = downcast<Element>(*node);
897     if (!is<SpinButtonElement>(element))
898         return element.hovered();
899     SpinButtonElement& spinButton = downcast<SpinButtonElement>(element);
900     return spinButton.hovered() && spinButton.upDownState() != SpinButtonElement::Indeterminate;
901 }
902
903 bool RenderTheme::isSpinUpButtonPartHovered(const RenderObject& renderer) const
904 {
905     Node* node = renderer.node();
906     if (!is<SpinButtonElement>(node))
907         return false;
908     return downcast<SpinButtonElement>(*node).upDownState() == SpinButtonElement::Up;
909 }
910
911 bool RenderTheme::isPresenting(const RenderObject& o) const
912 {
913     return is<HTMLInputElement>(o.node()) && downcast<HTMLInputElement>(*o.node()).isPresentingAttachedView();
914 }
915
916 bool RenderTheme::isDefault(const RenderObject& o) const
917 {
918     // A button should only have the default appearance if the page is active
919     if (!isActive(o))
920         return false;
921
922     return o.style().appearance() == DefaultButtonPart;
923 }
924
925 #if !USE(NEW_THEME)
926
927 void RenderTheme::adjustCheckboxStyle(StyleResolver&, RenderStyle& style, const Element*) const
928 {
929     // A summary of the rules for checkbox designed to match WinIE:
930     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
931     // font-size - not honored (control has no text), but we use it to decide which control size to use.
932     setCheckboxSize(style);
933
934     // padding - not honored by WinIE, needs to be removed.
935     style.resetPadding();
936
937     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
938     // for now, we will not honor it.
939     style.resetBorder();
940
941     style.setBoxShadow(nullptr);
942 }
943
944 void RenderTheme::adjustRadioStyle(StyleResolver&, RenderStyle& style, const Element*) const
945 {
946     // A summary of the rules for checkbox designed to match WinIE:
947     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
948     // font-size - not honored (control has no text), but we use it to decide which control size to use.
949     setRadioSize(style);
950
951     // padding - not honored by WinIE, needs to be removed.
952     style.resetPadding();
953
954     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
955     // for now, we will not honor it.
956     style.resetBorder();
957
958     style.setBoxShadow(nullptr);
959 }
960
961 void RenderTheme::adjustButtonStyle(StyleResolver&, RenderStyle& style, const Element*) const
962 {
963     // Most platforms will completely honor all CSS, and so we have no need to
964     // adjust the style at all by default. We will still allow the theme a crack
965     // at setting up a desired vertical size.
966     setButtonSize(style);
967 }
968
969 void RenderTheme::adjustInnerSpinButtonStyle(StyleResolver&, RenderStyle&, const Element*) const
970 {
971 }
972 #endif
973
974 void RenderTheme::adjustTextFieldStyle(StyleResolver&, RenderStyle&, const Element*) const
975 {
976 }
977
978 void RenderTheme::adjustTextAreaStyle(StyleResolver&, RenderStyle&, const Element*) const
979 {
980 }
981
982 void RenderTheme::adjustMenuListStyle(StyleResolver&, RenderStyle&, const Element*) const
983 {
984 }
985
986 #if ENABLE(METER_ELEMENT)
987
988 void RenderTheme::adjustMeterStyle(StyleResolver&, RenderStyle& style, const Element*) const
989 {
990     style.setBoxShadow(nullptr);
991 }
992
993 IntSize RenderTheme::meterSizeForBounds(const RenderMeter&, const IntRect& bounds) const
994 {
995     return bounds.size();
996 }
997
998 bool RenderTheme::supportsMeter(ControlPart) const
999 {
1000     return false;
1001 }
1002
1003 bool RenderTheme::paintMeter(const RenderObject&, const PaintInfo&, const IntRect&)
1004 {
1005     return true;
1006 }
1007
1008 #endif // METER_ELEMENT
1009
1010 void RenderTheme::adjustCapsLockIndicatorStyle(StyleResolver&, RenderStyle&, const Element*) const
1011 {
1012 }
1013
1014 bool RenderTheme::paintCapsLockIndicator(const RenderObject&, const PaintInfo&, const IntRect&)
1015 {
1016     return false;
1017 }
1018
1019 #if ENABLE(ATTACHMENT_ELEMENT)
1020
1021 void RenderTheme::adjustAttachmentStyle(StyleResolver&, RenderStyle&, const Element*) const
1022 {
1023 }
1024
1025 bool RenderTheme::paintAttachment(const RenderObject&, const PaintInfo&, const IntRect&)
1026 {
1027     return false;
1028 }
1029
1030 #endif
1031
1032 #if ENABLE(DATALIST_ELEMENT)
1033
1034 LayoutUnit RenderTheme::sliderTickSnappingThreshold() const
1035 {
1036     return 0;
1037 }
1038
1039 void RenderTheme::paintSliderTicks(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& rect)
1040 {
1041     if (!is<HTMLInputElement>(o.node()))
1042         return;
1043
1044     auto& input = downcast<HTMLInputElement>(*o.node());
1045
1046     if (!input.list())
1047         return;
1048
1049     auto& dataList = downcast<HTMLDataListElement>(*input.list());
1050
1051     double min = input.minimum();
1052     double max = input.maximum();
1053     ControlPart part = o.style().appearance();
1054     // We don't support ticks on alternate sliders like MediaVolumeSliders.
1055     if (part !=  SliderHorizontalPart && part != SliderVerticalPart)
1056         return;
1057     bool isHorizontal = part ==  SliderHorizontalPart;
1058
1059     IntSize thumbSize;
1060     const RenderObject* thumbRenderer = input.sliderThumbElement()->renderer();
1061     if (thumbRenderer) {
1062         const RenderStyle& thumbStyle = thumbRenderer->style();
1063         int thumbWidth = thumbStyle.width().intValue();
1064         int thumbHeight = thumbStyle.height().intValue();
1065         thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight);
1066         thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth);
1067     }
1068
1069     IntSize tickSize = sliderTickSize();
1070     float zoomFactor = o.style().effectiveZoom();
1071     FloatRect tickRect;
1072     int tickRegionSideMargin = 0;
1073     int tickRegionWidth = 0;
1074     IntRect trackBounds;
1075     RenderObject* trackRenderer = input.sliderTrackElement()->renderer();
1076     // We can ignoring transforms because transform is handled by the graphics context.
1077     if (trackRenderer)
1078         trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms();
1079     IntRect sliderBounds = o.absoluteBoundingBoxRectIgnoringTransforms();
1080
1081     // Make position relative to the transformed ancestor element.
1082     trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x());
1083     trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y());
1084
1085     if (isHorizontal) {
1086         tickRect.setWidth(floor(tickSize.width() * zoomFactor));
1087         tickRect.setHeight(floor(tickSize.height() * zoomFactor));
1088         tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
1089         tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
1090         tickRegionWidth = trackBounds.width() - thumbSize.width();
1091     } else {
1092         tickRect.setWidth(floor(tickSize.height() * zoomFactor));
1093         tickRect.setHeight(floor(tickSize.width() * zoomFactor));
1094         tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
1095         tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
1096         tickRegionWidth = trackBounds.height() - thumbSize.width();
1097     }
1098     Ref<HTMLCollection> options = dataList.options();
1099     GraphicsContextStateSaver stateSaver(paintInfo.context());
1100     paintInfo.context().setFillColor(o.style().visitedDependentColorWithColorFilter(CSSPropertyColor));
1101     for (unsigned i = 0; Node* node = options->item(i); i++) {
1102         ASSERT(is<HTMLOptionElement>(*node));
1103         HTMLOptionElement& optionElement = downcast<HTMLOptionElement>(*node);
1104         String value = optionElement.value();
1105         if (!input.isValidValue(value))
1106             continue;
1107         double parsedValue = parseToDoubleForNumberType(input.sanitizeValue(value));
1108         double tickFraction = (parsedValue - min) / (max - min);
1109         double tickRatio = isHorizontal && o.style().isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction;
1110         double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio);
1111         if (isHorizontal)
1112             tickRect.setX(tickPosition);
1113         else
1114             tickRect.setY(tickPosition);
1115         paintInfo.context().fillRect(tickRect);
1116     }
1117 }
1118
1119 #endif
1120
1121 Seconds RenderTheme::animationRepeatIntervalForProgressBar(RenderProgress&) const
1122 {
1123     return 0_s;
1124 }
1125
1126 Seconds RenderTheme::animationDurationForProgressBar(RenderProgress&) const
1127 {
1128     return 0_s;
1129 }
1130
1131 void RenderTheme::adjustProgressBarStyle(StyleResolver&, RenderStyle&, const Element*) const
1132 {
1133 }
1134
1135 IntRect RenderTheme::progressBarRectForBounds(const RenderObject&, const IntRect& bounds) const
1136 {
1137     return bounds;
1138 }
1139
1140 bool RenderTheme::shouldHaveSpinButton(const HTMLInputElement& inputElement) const
1141 {
1142     return inputElement.isSteppable() && !inputElement.isRangeControl();
1143 }
1144
1145 bool RenderTheme::shouldHaveCapsLockIndicator(const HTMLInputElement&) const
1146 {
1147     return false;
1148 }
1149
1150 void RenderTheme::adjustMenuListButtonStyle(StyleResolver&, RenderStyle&, const Element*) const
1151 {
1152 }
1153
1154 void RenderTheme::adjustMediaControlStyle(StyleResolver&, RenderStyle&, const Element*) const
1155 {
1156 }
1157
1158 void RenderTheme::adjustSliderTrackStyle(StyleResolver&, RenderStyle&, const Element*) const
1159 {
1160 }
1161
1162 void RenderTheme::adjustSliderThumbStyle(StyleResolver&, RenderStyle& style, const Element* element) const
1163 {
1164     adjustSliderThumbSize(style, element);
1165 }
1166
1167 void RenderTheme::adjustSliderThumbSize(RenderStyle&, const Element*) const
1168 {
1169 }
1170
1171 void RenderTheme::adjustSearchFieldStyle(StyleResolver&, RenderStyle&, const Element*) const
1172 {
1173 }
1174
1175 void RenderTheme::adjustSearchFieldCancelButtonStyle(StyleResolver&, RenderStyle&, const Element*) const
1176 {
1177 }
1178
1179 void RenderTheme::adjustSearchFieldDecorationPartStyle(StyleResolver&, RenderStyle&, const Element*) const
1180 {
1181 }
1182
1183 void RenderTheme::adjustSearchFieldResultsDecorationPartStyle(StyleResolver&, RenderStyle&, const Element*) const
1184 {
1185 }
1186
1187 void RenderTheme::adjustSearchFieldResultsButtonStyle(StyleResolver&, RenderStyle&, const Element*) const
1188 {
1189 }
1190
1191 void RenderTheme::purgeCaches()
1192 {
1193     m_colorCache = ColorCache();
1194 }
1195
1196 void RenderTheme::platformColorsDidChange()
1197 {
1198     m_colorCache = ColorCache();
1199
1200     Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
1201 }
1202
1203 FontCascadeDescription& RenderTheme::cachedSystemFontDescription(CSSValueID systemFontID) const
1204 {
1205     static NeverDestroyed<FontCascadeDescription> caption;
1206     static NeverDestroyed<FontCascadeDescription> icon;
1207     static NeverDestroyed<FontCascadeDescription> menu;
1208     static NeverDestroyed<FontCascadeDescription> messageBox;
1209     static NeverDestroyed<FontCascadeDescription> smallCaption;
1210     static NeverDestroyed<FontCascadeDescription> statusBar;
1211     static NeverDestroyed<FontCascadeDescription> webkitMiniControl;
1212     static NeverDestroyed<FontCascadeDescription> webkitSmallControl;
1213     static NeverDestroyed<FontCascadeDescription> webkitControl;
1214     static NeverDestroyed<FontCascadeDescription> defaultDescription;
1215
1216     switch (systemFontID) {
1217     case CSSValueCaption:
1218         return caption;
1219     case CSSValueIcon:
1220         return icon;
1221     case CSSValueMenu:
1222         return menu;
1223     case CSSValueMessageBox:
1224         return messageBox;
1225     case CSSValueSmallCaption:
1226         return smallCaption;
1227     case CSSValueStatusBar:
1228         return statusBar;
1229     case CSSValueWebkitMiniControl:
1230         return webkitMiniControl;
1231     case CSSValueWebkitSmallControl:
1232         return webkitSmallControl;
1233     case CSSValueWebkitControl:
1234         return webkitControl;
1235     case CSSValueNone:
1236         return defaultDescription;
1237     default:
1238         ASSERT_NOT_REACHED();
1239         return defaultDescription;
1240     }
1241 }
1242
1243 void RenderTheme::systemFont(CSSValueID systemFontID, FontCascadeDescription& fontDescription) const
1244 {
1245     fontDescription = cachedSystemFontDescription(systemFontID);
1246     if (fontDescription.isAbsoluteSize())
1247         return;
1248
1249     updateCachedSystemFontDescription(systemFontID, fontDescription);
1250 }
1251
1252 Color RenderTheme::systemColor(CSSValueID cssValueId, OptionSet<StyleColor::Options> options) const
1253 {
1254     switch (cssValueId) {
1255     case CSSValueWebkitLink:
1256         return options.contains(StyleColor::Options::ForVisitedLink) ? 0xFF551A8B : 0xFF0000EE;
1257     case CSSValueWebkitActivelink:
1258         return 0xFFFF0000;
1259     case CSSValueActiveborder:
1260         return 0xFFFFFFFF;
1261     case CSSValueActivebuttontext:
1262         return 0xFF000000;
1263     case CSSValueActivecaption:
1264         return 0xFFCCCCCC;
1265     case CSSValueAppworkspace:
1266         return 0xFFFFFFFF;
1267     case CSSValueBackground:
1268         return 0xFF6363CE;
1269     case CSSValueButtonface:
1270         return 0xFFC0C0C0;
1271     case CSSValueButtonhighlight:
1272         return 0xFFDDDDDD;
1273     case CSSValueButtonshadow:
1274         return 0xFF888888;
1275     case CSSValueButtontext:
1276         return 0xFF000000;
1277     case CSSValueCaptiontext:
1278         return 0xFF000000;
1279     case CSSValueGraytext:
1280         return 0xFF808080;
1281     case CSSValueHighlight:
1282         return 0xFFB5D5FF;
1283     case CSSValueHighlighttext:
1284         return 0xFF000000;
1285     case CSSValueInactiveborder:
1286         return 0xFFFFFFFF;
1287     case CSSValueInactivecaption:
1288         return 0xFFFFFFFF;
1289     case CSSValueInactivecaptiontext:
1290         return 0xFF7F7F7F;
1291     case CSSValueInfobackground:
1292         return 0xFFFBFCC5;
1293     case CSSValueInfotext:
1294         return 0xFF000000;
1295     case CSSValueMenu:
1296         return 0xFFC0C0C0;
1297     case CSSValueMenutext:
1298         return 0xFF000000;
1299     case CSSValueScrollbar:
1300         return 0xFFFFFFFF;
1301     case CSSValueText:
1302         return 0xFF000000;
1303     case CSSValueThreeddarkshadow:
1304         return 0xFF666666;
1305     case CSSValueThreedface:
1306         return 0xFFC0C0C0;
1307     case CSSValueThreedhighlight:
1308         return 0xFFDDDDDD;
1309     case CSSValueThreedlightshadow:
1310         return 0xFFC0C0C0;
1311     case CSSValueThreedshadow:
1312         return 0xFF888888;
1313     case CSSValueWindow:
1314         return 0xFFFFFFFF;
1315     case CSSValueWindowframe:
1316         return 0xFFCCCCCC;
1317     case CSSValueWindowtext:
1318         return 0xFF000000;
1319     default:
1320         break;
1321     }
1322     return Color();
1323 }
1324
1325 Color RenderTheme::activeTextSearchHighlightColor(OptionSet<StyleColor::Options> options) const
1326 {
1327     auto& cache = colorCache(options);
1328     if (!cache.activeTextSearchHighlightColor.isValid())
1329         cache.activeTextSearchHighlightColor = platformActiveTextSearchHighlightColor(options);
1330     return cache.activeTextSearchHighlightColor;
1331 }
1332
1333 Color RenderTheme::inactiveTextSearchHighlightColor(OptionSet<StyleColor::Options> options) const
1334 {
1335     auto& cache = colorCache(options);
1336     if (!cache.inactiveTextSearchHighlightColor.isValid())
1337         cache.inactiveTextSearchHighlightColor = platformInactiveTextSearchHighlightColor(options);
1338     return cache.inactiveTextSearchHighlightColor;
1339 }
1340
1341 Color RenderTheme::platformActiveTextSearchHighlightColor(OptionSet<StyleColor::Options>) const
1342 {
1343     return Color(255, 150, 50); // Orange.
1344 }
1345
1346 Color RenderTheme::platformInactiveTextSearchHighlightColor(OptionSet<StyleColor::Options>) const
1347 {
1348     return Color(255, 255, 0); // Yellow.
1349 }
1350
1351 #if ENABLE(TOUCH_EVENTS)
1352
1353 Color RenderTheme::tapHighlightColor()
1354 {
1355     return singleton().platformTapHighlightColor();
1356 }
1357
1358 #endif
1359
1360 // Value chosen by observation. This can be tweaked.
1361 static const int minColorContrastValue = 1300;
1362 // For transparent or translucent background color, use lightening.
1363 static const float minDisabledColorAlphaValue = 0.5;
1364
1365 Color RenderTheme::disabledTextColor(const Color& textColor, const Color& backgroundColor) const
1366 {
1367     // The explicit check for black is an optimization for the 99% case (black on white).
1368     // This also means that black on black will turn into grey on black when disabled.
1369     Color disabledColor;
1370     if (Color::isBlackColor(textColor) || backgroundColor.alphaAsFloat() < minDisabledColorAlphaValue || differenceSquared(textColor, Color::white) > differenceSquared(backgroundColor, Color::white))
1371         disabledColor = textColor.light();
1372     else
1373         disabledColor = textColor.dark();
1374     
1375     // If there's not very much contrast between the disabled color and the background color,
1376     // just leave the text color alone. We don't want to change a good contrast color scheme so that it has really bad contrast.
1377     // If the contrast was already poor, then it doesn't do any good to change it to a different poor contrast color scheme.
1378     if (differenceSquared(disabledColor, backgroundColor) < minColorContrastValue)
1379         return textColor;
1380     
1381     return disabledColor;
1382 }
1383
1384 void RenderTheme::setCustomFocusRingColor(const Color& color)
1385 {
1386     customFocusRingColor() = color;
1387 }
1388
1389 Color RenderTheme::focusRingColor(OptionSet<StyleColor::Options> options)
1390 {
1391     return customFocusRingColor().isValid() ? customFocusRingColor() : RenderTheme::singleton().platformFocusRingColor(options);
1392 }
1393
1394 String RenderTheme::fileListDefaultLabel(bool multipleFilesAllowed) const
1395 {
1396     if (multipleFilesAllowed)
1397         return fileButtonNoFilesSelectedLabel();
1398     return fileButtonNoFileSelectedLabel();
1399 }
1400
1401 String RenderTheme::fileListNameForWidth(const FileList* fileList, const FontCascade& font, int width, bool multipleFilesAllowed) const
1402 {
1403     if (width <= 0)
1404         return String();
1405
1406     String string;
1407     if (fileList->isEmpty())
1408         string = fileListDefaultLabel(multipleFilesAllowed);
1409     else if (fileList->length() == 1)
1410         string = fileList->item(0)->name();
1411     else
1412         return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font);
1413
1414     return StringTruncator::centerTruncate(string, width, font);
1415 }
1416
1417 #if USE(SYSTEM_PREVIEW)
1418 void RenderTheme::paintSystemPreviewBadge(Image& image, const PaintInfo& paintInfo, const FloatRect& rect)
1419 {
1420     // The default implementation paints a small marker
1421     // in the upper right corner, as long as the image is big enough.
1422
1423     UNUSED_PARAM(image);
1424     auto& context = paintInfo.context();
1425
1426     GraphicsContextStateSaver stateSaver { context };
1427
1428     if (rect.width() < 32 || rect.height() < 32)
1429         return;
1430
1431     auto markerRect = FloatRect {rect.x() + rect.width() - 24, rect.y() + 8, 16, 16 };
1432     auto roundedMarkerRect = FloatRoundedRect { markerRect, FloatRoundedRect::Radii { 8 } };
1433     auto color = Color { 255, 0, 0 };
1434     context.fillRoundedRect(roundedMarkerRect, color);
1435 }
1436 #endif
1437
1438 #if ENABLE(TOUCH_EVENTS)
1439
1440 Color RenderTheme::platformTapHighlightColor() const
1441 {
1442     // This color is expected to be drawn on a semi-transparent overlay,
1443     // making it more transparent than its alpha value indicates.
1444     return Color(0, 0, 0, 102);
1445 }
1446
1447 #endif
1448
1449 void RenderTheme::drawLineForDocumentMarker(const RenderText&, GraphicsContext&, const FloatPoint&, float, DocumentMarkerLineStyle)
1450 {
1451 }
1452
1453 } // namespace WebCore