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