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