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