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