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