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