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