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