Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/rendering/RenderTheme.h"
24
25 #include "core/CSSValueKeywords.h"
26 #include "core/HTMLNames.h"
27 #include "core/InputTypeNames.h"
28 #include "core/dom/Document.h"
29 #include "core/dom/shadow/ElementShadow.h"
30 #include "core/editing/FrameSelection.h"
31 #include "core/fileapi/FileList.h"
32 #include "core/frame/LocalFrame.h"
33 #include "core/html/HTMLCollection.h"
34 #include "core/html/HTMLDataListElement.h"
35 #include "core/html/HTMLFormControlElement.h"
36 #include "core/html/HTMLInputElement.h"
37 #include "core/html/HTMLMeterElement.h"
38 #include "core/html/HTMLOptionElement.h"
39 #include "core/html/parser/HTMLParserIdioms.h"
40 #include "core/html/shadow/MediaControlElements.h"
41 #include "core/html/shadow/ShadowElementNames.h"
42 #include "core/html/shadow/SpinButtonElement.h"
43 #include "core/html/shadow/TextControlInnerElements.h"
44 #include "core/page/FocusController.h"
45 #include "core/page/Page.h"
46 #include "core/frame/Settings.h"
47 #include "core/rendering/PaintInfo.h"
48 #include "core/rendering/RenderMeter.h"
49 #include "core/rendering/RenderView.h"
50 #include "core/rendering/style/RenderStyle.h"
51 #include "platform/FileMetadata.h"
52 #include "platform/FloatConversion.h"
53 #include "platform/RuntimeEnabledFeatures.h"
54 #include "platform/fonts/FontSelector.h"
55 #include "platform/graphics/GraphicsContextStateSaver.h"
56 #include "platform/text/PlatformLocale.h"
57 #include "platform/text/StringTruncator.h"
58 #include "public/platform/Platform.h"
59 #include "public/platform/WebFallbackThemeEngine.h"
60 #include "public/platform/WebRect.h"
61 #include "wtf/text/StringBuilder.h"
62
63 // The methods in this file are shared by all themes on every platform.
64
65 namespace blink {
66
67 using namespace HTMLNames;
68
69 static WebFallbackThemeEngine::State getWebFallbackThemeState(const RenderTheme* theme, const RenderObject* o)
70 {
71     if (!theme->isEnabled(o))
72         return WebFallbackThemeEngine::StateDisabled;
73     if (theme->isPressed(o))
74         return WebFallbackThemeEngine::StatePressed;
75     if (theme->isHovered(o))
76         return WebFallbackThemeEngine::StateHover;
77
78     return WebFallbackThemeEngine::StateNormal;
79 }
80
81 RenderTheme::RenderTheme()
82     : m_hasCustomFocusRingColor(false)
83 #if USE(NEW_THEME)
84     , m_platformTheme(platformTheme())
85 #endif
86 {
87 }
88
89 void RenderTheme::adjustStyle(RenderStyle* style, Element* e, const CachedUAStyle* uaStyle)
90 {
91     // Force inline and table display styles to be inline-block (except for table- which is block)
92     ControlPart part = style->appearance();
93     if (style->display() == INLINE || style->display() == INLINE_TABLE || style->display() == TABLE_ROW_GROUP
94         || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_FOOTER_GROUP
95         || style->display() == TABLE_ROW || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_COLUMN
96         || style->display() == TABLE_CELL || style->display() == TABLE_CAPTION)
97         style->setDisplay(INLINE_BLOCK);
98     else if (style->display() == LIST_ITEM || style->display() == TABLE)
99         style->setDisplay(BLOCK);
100
101     if (uaStyle && uaStyle->hasAppearance && isControlStyled(style, uaStyle)) {
102         if (part == MenulistPart) {
103             style->setAppearance(MenulistButtonPart);
104             part = MenulistButtonPart;
105         } else
106             style->setAppearance(NoControlPart);
107     }
108
109     if (!style->hasAppearance())
110         return;
111
112     if (shouldUseFallbackTheme(style)) {
113         adjustStyleUsingFallbackTheme(style, e);
114         return;
115     }
116
117 #if USE(NEW_THEME)
118     switch (part) {
119     case CheckboxPart:
120     case InnerSpinButtonPart:
121     case RadioPart:
122     case PushButtonPart:
123     case SquareButtonPart:
124     case ButtonPart: {
125         // Border
126         LengthBox borderBox(style->borderTopWidth(), style->borderRightWidth(), style->borderBottomWidth(), style->borderLeftWidth());
127         borderBox = m_platformTheme->controlBorder(part, style->font().fontDescription(), borderBox, style->effectiveZoom());
128         if (borderBox.top().value() != static_cast<int>(style->borderTopWidth())) {
129             if (borderBox.top().value())
130                 style->setBorderTopWidth(borderBox.top().value());
131             else
132                 style->resetBorderTop();
133         }
134         if (borderBox.right().value() != static_cast<int>(style->borderRightWidth())) {
135             if (borderBox.right().value())
136                 style->setBorderRightWidth(borderBox.right().value());
137             else
138                 style->resetBorderRight();
139         }
140         if (borderBox.bottom().value() != static_cast<int>(style->borderBottomWidth())) {
141             style->setBorderBottomWidth(borderBox.bottom().value());
142             if (borderBox.bottom().value())
143                 style->setBorderBottomWidth(borderBox.bottom().value());
144             else
145                 style->resetBorderBottom();
146         }
147         if (borderBox.left().value() != static_cast<int>(style->borderLeftWidth())) {
148             style->setBorderLeftWidth(borderBox.left().value());
149             if (borderBox.left().value())
150                 style->setBorderLeftWidth(borderBox.left().value());
151             else
152                 style->resetBorderLeft();
153         }
154
155         // Padding
156         LengthBox paddingBox = m_platformTheme->controlPadding(part, style->font().fontDescription(), style->paddingBox(), style->effectiveZoom());
157         if (paddingBox != style->paddingBox())
158             style->setPaddingBox(paddingBox);
159
160         // Whitespace
161         if (m_platformTheme->controlRequiresPreWhiteSpace(part))
162             style->setWhiteSpace(PRE);
163
164         // Width / Height
165         // The width and height here are affected by the zoom.
166         // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
167         LengthSize controlSize = m_platformTheme->controlSize(part, style->font().fontDescription(), LengthSize(style->width(), style->height()), style->effectiveZoom());
168         if (controlSize.width() != style->width())
169             style->setWidth(controlSize.width());
170         if (controlSize.height() != style->height())
171             style->setHeight(controlSize.height());
172
173         // Min-Width / Min-Height
174         LengthSize minControlSize = m_platformTheme->minimumControlSize(part, style->font().fontDescription(), style->effectiveZoom());
175         if (minControlSize.width() != style->minWidth())
176             style->setMinWidth(minControlSize.width());
177         if (minControlSize.height() != style->minHeight())
178             style->setMinHeight(minControlSize.height());
179
180         // Font
181         FontDescription controlFont = m_platformTheme->controlFont(part, style->font().fontDescription(), style->effectiveZoom());
182         if (controlFont != style->font().fontDescription()) {
183             // Reset our line-height
184             style->setLineHeight(RenderStyle::initialLineHeight());
185
186             // Now update our font.
187             if (style->setFontDescription(controlFont))
188                 style->font().update(nullptr);
189         }
190     }
191     default:
192         break;
193     }
194 #endif
195
196     // Call the appropriate style adjustment method based off the appearance value.
197     switch (style->appearance()) {
198 #if !USE(NEW_THEME)
199     case CheckboxPart:
200         return adjustCheckboxStyle(style, e);
201     case RadioPart:
202         return adjustRadioStyle(style, e);
203     case PushButtonPart:
204     case SquareButtonPart:
205     case ButtonPart:
206         return adjustButtonStyle(style, e);
207     case InnerSpinButtonPart:
208         return adjustInnerSpinButtonStyle(style, e);
209 #endif
210     case MenulistPart:
211         return adjustMenuListStyle(style, e);
212     case MenulistButtonPart:
213         return adjustMenuListButtonStyle(style, e);
214     case SliderThumbHorizontalPart:
215     case SliderThumbVerticalPart:
216         return adjustSliderThumbStyle(style, e);
217     case SearchFieldPart:
218         return adjustSearchFieldStyle(style, e);
219     case SearchFieldCancelButtonPart:
220         return adjustSearchFieldCancelButtonStyle(style, e);
221     case SearchFieldDecorationPart:
222         return adjustSearchFieldDecorationStyle(style, e);
223     case SearchFieldResultsDecorationPart:
224         return adjustSearchFieldResultsDecorationStyle(style, e);
225     default:
226         break;
227     }
228 }
229
230 bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
231 {
232     ControlPart part = o->style()->appearance();
233
234     if (shouldUseFallbackTheme(o->style()))
235         return paintUsingFallbackTheme(o, paintInfo, r);
236
237 #if USE(NEW_THEME)
238     switch (part) {
239     case CheckboxPart:
240     case RadioPart:
241     case PushButtonPart:
242     case SquareButtonPart:
243     case ButtonPart:
244     case InnerSpinButtonPart:
245         m_platformTheme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView());
246         return false;
247     default:
248         break;
249     }
250 #endif
251
252     // Call the appropriate paint method based off the appearance value.
253     switch (part) {
254 #if !USE(NEW_THEME)
255     case CheckboxPart:
256         return paintCheckbox(o, paintInfo, r);
257     case RadioPart:
258         return paintRadio(o, paintInfo, r);
259     case PushButtonPart:
260     case SquareButtonPart:
261     case ButtonPart:
262         return paintButton(o, paintInfo, r);
263     case InnerSpinButtonPart:
264         return paintInnerSpinButton(o, paintInfo, r);
265 #endif
266     case MenulistPart:
267         return paintMenuList(o, paintInfo, r);
268     case MeterPart:
269     case RelevancyLevelIndicatorPart:
270     case ContinuousCapacityLevelIndicatorPart:
271     case DiscreteCapacityLevelIndicatorPart:
272     case RatingLevelIndicatorPart:
273         return paintMeter(o, paintInfo, r);
274     case ProgressBarPart:
275         return paintProgressBar(o, paintInfo, r);
276     case SliderHorizontalPart:
277     case SliderVerticalPart:
278         return paintSliderTrack(o, paintInfo, r);
279     case SliderThumbHorizontalPart:
280     case SliderThumbVerticalPart:
281         return paintSliderThumb(o, paintInfo, r);
282     case MediaEnterFullscreenButtonPart:
283     case MediaExitFullscreenButtonPart:
284         return paintMediaFullscreenButton(o, paintInfo, r);
285     case MediaPlayButtonPart:
286         return paintMediaPlayButton(o, paintInfo, r);
287     case MediaOverlayPlayButtonPart:
288         return paintMediaOverlayPlayButton(o, paintInfo, r);
289     case MediaMuteButtonPart:
290         return paintMediaMuteButton(o, paintInfo, r);
291     case MediaToggleClosedCaptionsButtonPart:
292         return paintMediaToggleClosedCaptionsButton(o, paintInfo, r);
293     case MediaSliderPart:
294         return paintMediaSliderTrack(o, paintInfo, r);
295     case MediaSliderThumbPart:
296         return paintMediaSliderThumb(o, paintInfo, r);
297     case MediaVolumeSliderContainerPart:
298         return paintMediaVolumeSliderContainer(o, paintInfo, r);
299     case MediaVolumeSliderPart:
300         return paintMediaVolumeSliderTrack(o, paintInfo, r);
301     case MediaVolumeSliderThumbPart:
302         return paintMediaVolumeSliderThumb(o, paintInfo, r);
303     case MediaFullScreenVolumeSliderPart:
304         return paintMediaFullScreenVolumeSliderTrack(o, paintInfo, r);
305     case MediaFullScreenVolumeSliderThumbPart:
306         return paintMediaFullScreenVolumeSliderThumb(o, paintInfo, r);
307     case MediaTimeRemainingPart:
308         return paintMediaTimeRemaining(o, paintInfo, r);
309     case MediaCurrentTimePart:
310         return paintMediaCurrentTime(o, paintInfo, r);
311     case MediaControlsBackgroundPart:
312         return paintMediaControlsBackground(o, paintInfo, r);
313     case MenulistButtonPart:
314     case TextFieldPart:
315     case TextAreaPart:
316         return true;
317     case SearchFieldPart:
318         return paintSearchField(o, paintInfo, r);
319     case SearchFieldCancelButtonPart:
320         return paintSearchFieldCancelButton(o, paintInfo, r);
321     case SearchFieldDecorationPart:
322         return paintSearchFieldDecoration(o, paintInfo, r);
323     case SearchFieldResultsDecorationPart:
324         return paintSearchFieldResultsDecoration(o, paintInfo, r);
325     default:
326         break;
327     }
328
329     return true; // We don't support the appearance, so let the normal background/border paint.
330 }
331
332 bool RenderTheme::paintBorderOnly(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
333 {
334     // Call the appropriate paint method based off the appearance value.
335     switch (o->style()->appearance()) {
336     case TextFieldPart:
337         return paintTextField(o, paintInfo, r);
338     case TextAreaPart:
339         return paintTextArea(o, paintInfo, r);
340     case MenulistButtonPart:
341     case SearchFieldPart:
342     case ListboxPart:
343         return true;
344     case CheckboxPart:
345     case RadioPart:
346     case PushButtonPart:
347     case SquareButtonPart:
348     case ButtonPart:
349     case MenulistPart:
350     case MeterPart:
351     case RelevancyLevelIndicatorPart:
352     case ContinuousCapacityLevelIndicatorPart:
353     case DiscreteCapacityLevelIndicatorPart:
354     case RatingLevelIndicatorPart:
355     case ProgressBarPart:
356     case SliderHorizontalPart:
357     case SliderVerticalPart:
358     case SliderThumbHorizontalPart:
359     case SliderThumbVerticalPart:
360     case SearchFieldCancelButtonPart:
361     case SearchFieldDecorationPart:
362     case SearchFieldResultsDecorationPart:
363     default:
364         break;
365     }
366
367     return false;
368 }
369
370 bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
371 {
372     // Call the appropriate paint method based off the appearance value.
373     switch (o->style()->appearance()) {
374     case MenulistButtonPart:
375         return paintMenuListButton(o, paintInfo, r);
376     case TextFieldPart:
377     case TextAreaPart:
378     case CheckboxPart:
379     case RadioPart:
380     case PushButtonPart:
381     case SquareButtonPart:
382     case ButtonPart:
383     case MenulistPart:
384     case MeterPart:
385     case RelevancyLevelIndicatorPart:
386     case ContinuousCapacityLevelIndicatorPart:
387     case DiscreteCapacityLevelIndicatorPart:
388     case RatingLevelIndicatorPart:
389     case ProgressBarPart:
390     case SliderHorizontalPart:
391     case SliderVerticalPart:
392     case SliderThumbHorizontalPart:
393     case SliderThumbVerticalPart:
394     case SearchFieldPart:
395     case SearchFieldCancelButtonPart:
396     case SearchFieldDecorationPart:
397     case SearchFieldResultsDecorationPart:
398     default:
399         break;
400     }
401
402     return false;
403 }
404
405 String RenderTheme::extraDefaultStyleSheet()
406 {
407     StringBuilder runtimeCSS;
408     if (RuntimeEnabledFeatures::dialogElementEnabled()) {
409         runtimeCSS.appendLiteral("dialog:not([open]) { display: none; }");
410         runtimeCSS.appendLiteral("dialog { position: absolute; left: 0; right: 0; width: -webkit-fit-content; height: -webkit-fit-content; margin: auto; border: solid; padding: 1em; background: white; color: black;}");
411         runtimeCSS.appendLiteral("dialog::backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0,0,0,0.1); }");
412     }
413
414     if (RuntimeEnabledFeatures::contextMenuEnabled()) {
415         runtimeCSS.appendLiteral("menu[type=\"popup\" i] { display: none; }");
416     }
417
418     return runtimeCSS.toString();
419 }
420
421 String RenderTheme::formatMediaControlsTime(float time) const
422 {
423     if (!std::isfinite(time))
424         time = 0;
425     int seconds = (int)fabsf(time);
426     int hours = seconds / (60 * 60);
427     int minutes = (seconds / 60) % 60;
428     seconds %= 60;
429     if (hours) {
430         if (hours > 9)
431             return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
432
433         return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
434     }
435
436     return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
437 }
438
439 String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*duration*/) const
440 {
441     return formatMediaControlsTime(currentTime);
442 }
443
444 Color RenderTheme::activeSelectionBackgroundColor() const
445 {
446     return platformActiveSelectionBackgroundColor().blendWithWhite();
447 }
448
449 Color RenderTheme::inactiveSelectionBackgroundColor() const
450 {
451     return platformInactiveSelectionBackgroundColor().blendWithWhite();
452 }
453
454 Color RenderTheme::activeSelectionForegroundColor() const
455 {
456     return platformActiveSelectionForegroundColor();
457 }
458
459 Color RenderTheme::inactiveSelectionForegroundColor() const
460 {
461     return platformInactiveSelectionForegroundColor();
462 }
463
464 Color RenderTheme::activeListBoxSelectionBackgroundColor() const
465 {
466     return platformActiveListBoxSelectionBackgroundColor();
467 }
468
469 Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const
470 {
471     return platformInactiveListBoxSelectionBackgroundColor();
472 }
473
474 Color RenderTheme::activeListBoxSelectionForegroundColor() const
475 {
476     return platformActiveListBoxSelectionForegroundColor();
477 }
478
479 Color RenderTheme::inactiveListBoxSelectionForegroundColor() const
480 {
481     return platformInactiveListBoxSelectionForegroundColor();
482 }
483
484 Color RenderTheme::platformActiveSelectionBackgroundColor() const
485 {
486     // Use a blue color by default if the platform theme doesn't define anything.
487     return Color(0, 0, 255);
488 }
489
490 Color RenderTheme::platformActiveSelectionForegroundColor() const
491 {
492     // Use a white color by default if the platform theme doesn't define anything.
493     return Color::white;
494 }
495
496 Color RenderTheme::platformInactiveSelectionBackgroundColor() const
497 {
498     // Use a grey color by default if the platform theme doesn't define anything.
499     // This color matches Firefox's inactive color.
500     return Color(176, 176, 176);
501 }
502
503 Color RenderTheme::platformInactiveSelectionForegroundColor() const
504 {
505     // Use a black color by default.
506     return Color::black;
507 }
508
509 Color RenderTheme::platformActiveListBoxSelectionBackgroundColor() const
510 {
511     return platformActiveSelectionBackgroundColor();
512 }
513
514 Color RenderTheme::platformActiveListBoxSelectionForegroundColor() const
515 {
516     return platformActiveSelectionForegroundColor();
517 }
518
519 Color RenderTheme::platformInactiveListBoxSelectionBackgroundColor() const
520 {
521     return platformInactiveSelectionBackgroundColor();
522 }
523
524 Color RenderTheme::platformInactiveListBoxSelectionForegroundColor() const
525 {
526     return platformInactiveSelectionForegroundColor();
527 }
528
529 int RenderTheme::baselinePosition(const RenderObject* o) const
530 {
531     if (!o->isBox())
532         return 0;
533
534     const RenderBox* box = toRenderBox(o);
535
536 #if USE(NEW_THEME)
537     return box->height() + box->marginTop() + m_platformTheme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom();
538 #else
539     return box->height() + box->marginTop();
540 #endif
541 }
542
543 bool RenderTheme::isControlContainer(ControlPart appearance) const
544 {
545     // There are more leaves than this, but we'll patch this function as we add support for
546     // more controls.
547     return appearance != CheckboxPart && appearance != RadioPart;
548 }
549
550 static bool isBackgroundOrBorderStyled(const RenderStyle& style, const CachedUAStyle& uaStyle)
551 {
552     // Code below excludes the background-repeat from comparison by resetting it
553     FillLayer backgroundCopy = uaStyle.backgroundLayers;
554     FillLayer backgroundLayersCopy = style.backgroundLayers();
555     backgroundCopy.setRepeatX(NoRepeatFill);
556     backgroundCopy.setRepeatY(NoRepeatFill);
557     backgroundLayersCopy.setRepeatX(NoRepeatFill);
558     backgroundLayersCopy.setRepeatY(NoRepeatFill);
559     // Test the style to see if the UA border and background match.
560     return style.border() != uaStyle.border
561         || backgroundLayersCopy != backgroundCopy
562         || style.visitedDependentColor(CSSPropertyBackgroundColor) != uaStyle.backgroundColor;
563 }
564
565 bool RenderTheme::isControlStyled(const RenderStyle* style, const CachedUAStyle* uaStyle) const
566 {
567     ASSERT(uaStyle);
568
569     switch (style->appearance()) {
570     case PushButtonPart:
571     case SquareButtonPart:
572     case ButtonPart:
573     case ProgressBarPart:
574     case MeterPart:
575     case RelevancyLevelIndicatorPart:
576     case ContinuousCapacityLevelIndicatorPart:
577     case DiscreteCapacityLevelIndicatorPart:
578     case RatingLevelIndicatorPart:
579         return isBackgroundOrBorderStyled(*style, *uaStyle);
580
581     case MenulistPart:
582     case SearchFieldPart:
583     case TextAreaPart:
584     case TextFieldPart:
585         return isBackgroundOrBorderStyled(*style, *uaStyle) || style->boxShadow();
586
587     case SliderHorizontalPart:
588     case SliderVerticalPart:
589         return style->boxShadow();
590
591     default:
592         return false;
593     }
594 }
595
596 void RenderTheme::adjustRepaintRect(const RenderObject* o, IntRect& r)
597 {
598 #if USE(NEW_THEME)
599     m_platformTheme->inflateControlPaintRect(o->style()->appearance(), controlStatesForRenderer(o), r, o->style()->effectiveZoom());
600 #endif
601 }
602
603 bool RenderTheme::shouldDrawDefaultFocusRing(RenderObject* renderer) const
604 {
605     if (supportsFocusRing(renderer->style()))
606         return false;
607     if (!renderer->style()->hasAppearance())
608         return true;
609     Node* node = renderer->node();
610     if (!node)
611         return true;
612     // We can't use RenderTheme::isFocused because outline:auto might be
613     // specified to non-:focus rulesets.
614     if (node->focused() && !node->shouldHaveFocusAppearance())
615         return false;
616     return true;
617 }
618
619 bool RenderTheme::supportsFocusRing(const RenderStyle* style) const
620 {
621     return (style->hasAppearance() && style->appearance() != TextFieldPart && style->appearance() != TextAreaPart && style->appearance() != MenulistButtonPart && style->appearance() != ListboxPart);
622 }
623
624 bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const
625 {
626     // Default implementation assumes the controls don't respond to changes in :hover state
627     if (state == HoverControlState && !supportsHover(o->style()))
628         return false;
629
630     // Assume pressed state is only responded to if the control is enabled.
631     if (state == PressedControlState && !isEnabled(o))
632         return false;
633
634     // Repaint the control.
635     o->paintInvalidationForWholeRenderer();
636     return true;
637 }
638
639 ControlStates RenderTheme::controlStatesForRenderer(const RenderObject* o) const
640 {
641     ControlStates result = 0;
642     if (isHovered(o)) {
643         result |= HoverControlState;
644         if (isSpinUpButtonPartHovered(o))
645             result |= SpinUpControlState;
646     }
647     if (isPressed(o)) {
648         result |= PressedControlState;
649         if (isSpinUpButtonPartPressed(o))
650             result |= SpinUpControlState;
651     }
652     if (isFocused(o) && o->style()->outlineStyleIsAuto())
653         result |= FocusControlState;
654     if (isEnabled(o))
655         result |= EnabledControlState;
656     if (isChecked(o))
657         result |= CheckedControlState;
658     if (isReadOnlyControl(o))
659         result |= ReadOnlyControlState;
660     if (!isActive(o))
661         result |= WindowInactiveControlState;
662     if (isIndeterminate(o))
663         result |= IndeterminateControlState;
664     return result;
665 }
666
667 bool RenderTheme::isActive(const RenderObject* o) const
668 {
669     Node* node = o->node();
670     if (!node)
671         return false;
672
673     Page* page = node->document().page();
674     if (!page)
675         return false;
676
677     return page->focusController().isActive();
678 }
679
680 bool RenderTheme::isChecked(const RenderObject* o) const
681 {
682     if (!isHTMLInputElement(o->node()))
683         return false;
684     return toHTMLInputElement(o->node())->shouldAppearChecked();
685 }
686
687 bool RenderTheme::isIndeterminate(const RenderObject* o) const
688 {
689     if (!isHTMLInputElement(o->node()))
690         return false;
691     return toHTMLInputElement(o->node())->shouldAppearIndeterminate();
692 }
693
694 bool RenderTheme::isEnabled(const RenderObject* o) const
695 {
696     Node* node = o->node();
697     if (!node || !node->isElementNode())
698         return true;
699     return !toElement(node)->isDisabledFormControl();
700 }
701
702 bool RenderTheme::isFocused(const RenderObject* o) const
703 {
704     Node* node = o->node();
705     if (!node)
706         return false;
707
708     node = node->focusDelegate();
709     Document& document = node->document();
710     LocalFrame* frame = document.frame();
711     return node == document.focusedElement() && node->focused() && node->shouldHaveFocusAppearance() && frame && frame->selection().isFocusedAndActive();
712 }
713
714 bool RenderTheme::isPressed(const RenderObject* o) const
715 {
716     if (!o->node())
717         return false;
718     return o->node()->active();
719 }
720
721 bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject* o) const
722 {
723     Node* node = o->node();
724     if (!node || !node->active() || !node->isElementNode()
725         || !toElement(node)->isSpinButtonElement())
726         return false;
727     SpinButtonElement* element = toSpinButtonElement(node);
728     return element->upDownState() == SpinButtonElement::Up;
729 }
730
731 bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
732 {
733     Node* node = o->node();
734     if (!node || !node->isElementNode() || !toElement(node)->isFormControlElement())
735         return false;
736     HTMLFormControlElement* element = toHTMLFormControlElement(node);
737     return element->isReadOnly();
738 }
739
740 bool RenderTheme::isHovered(const RenderObject* o) const
741 {
742     Node* node = o->node();
743     if (!node)
744         return false;
745     if (!node->isElementNode() || !toElement(node)->isSpinButtonElement())
746         return node->hovered();
747     SpinButtonElement* element = toSpinButtonElement(node);
748     return element->hovered() && element->upDownState() != SpinButtonElement::Indeterminate;
749 }
750
751 bool RenderTheme::isSpinUpButtonPartHovered(const RenderObject* o) const
752 {
753     Node* node = o->node();
754     if (!node || !node->isElementNode() || !toElement(node)->isSpinButtonElement())
755         return false;
756     SpinButtonElement* element = toSpinButtonElement(node);
757     return element->upDownState() == SpinButtonElement::Up;
758 }
759
760 #if !USE(NEW_THEME)
761
762 void RenderTheme::adjustCheckboxStyle(RenderStyle* style, Element*) const
763 {
764     // A summary of the rules for checkbox designed to match WinIE:
765     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
766     // font-size - not honored (control has no text), but we use it to decide which control size to use.
767     setCheckboxSize(style);
768
769     // padding - not honored by WinIE, needs to be removed.
770     style->resetPadding();
771
772     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
773     // for now, we will not honor it.
774     style->resetBorder();
775 }
776
777 void RenderTheme::adjustRadioStyle(RenderStyle* style, Element*) const
778 {
779     // A summary of the rules for checkbox designed to match WinIE:
780     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
781     // font-size - not honored (control has no text), but we use it to decide which control size to use.
782     setRadioSize(style);
783
784     // padding - not honored by WinIE, needs to be removed.
785     style->resetPadding();
786
787     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
788     // for now, we will not honor it.
789     style->resetBorder();
790 }
791
792 void RenderTheme::adjustButtonStyle(RenderStyle* style, Element*) const
793 {
794 }
795
796 void RenderTheme::adjustInnerSpinButtonStyle(RenderStyle*, Element*) const
797 {
798 }
799 #endif
800
801 void RenderTheme::adjustMenuListStyle(RenderStyle*, Element*) const
802 {
803 }
804
805 IntSize RenderTheme::meterSizeForBounds(const RenderMeter*, const IntRect& bounds) const
806 {
807     return bounds.size();
808 }
809
810 bool RenderTheme::supportsMeter(ControlPart) const
811 {
812     return false;
813 }
814
815 bool RenderTheme::paintMeter(RenderObject*, const PaintInfo&, const IntRect&)
816 {
817     return true;
818 }
819
820 void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
821 {
822     Node* node = o->node();
823     if (!isHTMLInputElement(node))
824         return;
825
826     HTMLInputElement* input = toHTMLInputElement(node);
827     if (!input->isRangeControl())
828         return;
829
830     HTMLDataListElement* dataList = input->dataList();
831     if (!dataList)
832         return;
833
834     double min = input->minimum();
835     double max = input->maximum();
836     ControlPart part = o->style()->appearance();
837     // We don't support ticks on alternate sliders like MediaVolumeSliders.
838     if (part !=  SliderHorizontalPart && part != SliderVerticalPart)
839         return;
840     bool isHorizontal = part ==  SliderHorizontalPart;
841
842     IntSize thumbSize;
843     RenderObject* thumbRenderer = input->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderThumb())->renderer();
844     if (thumbRenderer) {
845         RenderStyle* thumbStyle = thumbRenderer->style();
846         int thumbWidth = thumbStyle->width().intValue();
847         int thumbHeight = thumbStyle->height().intValue();
848         thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight);
849         thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth);
850     }
851
852     IntSize tickSize = sliderTickSize();
853     float zoomFactor = o->style()->effectiveZoom();
854     FloatRect tickRect;
855     int tickRegionSideMargin = 0;
856     int tickRegionWidth = 0;
857     IntRect trackBounds;
858     RenderObject* trackRenderer = input->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderTrack())->renderer();
859     // We can ignoring transforms because transform is handled by the graphics context.
860     if (trackRenderer)
861         trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms();
862     IntRect sliderBounds = o->absoluteBoundingBoxRectIgnoringTransforms();
863
864     // Make position relative to the transformed ancestor element.
865     trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x());
866     trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y());
867
868     if (isHorizontal) {
869         tickRect.setWidth(floor(tickSize.width() * zoomFactor));
870         tickRect.setHeight(floor(tickSize.height() * zoomFactor));
871         tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
872         tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
873         tickRegionWidth = trackBounds.width() - thumbSize.width();
874     } else {
875         tickRect.setWidth(floor(tickSize.height() * zoomFactor));
876         tickRect.setHeight(floor(tickSize.width() * zoomFactor));
877         tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
878         tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
879         tickRegionWidth = trackBounds.height() - thumbSize.width();
880     }
881     RefPtrWillBeRawPtr<HTMLCollection> options = dataList->options();
882     GraphicsContextStateSaver stateSaver(*paintInfo.context);
883     paintInfo.context->setFillColor(o->resolveColor(CSSPropertyColor));
884     for (unsigned i = 0; Element* element = options->item(i); i++) {
885         ASSERT(isHTMLOptionElement(*element));
886         HTMLOptionElement& optionElement = toHTMLOptionElement(*element);
887         String value = optionElement.value();
888         if (!input->isValidValue(value))
889             continue;
890         double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value));
891         double tickFraction = (parsedValue - min) / (max - min);
892         double tickRatio = isHorizontal && o->style()->isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction;
893         double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio);
894         if (isHorizontal)
895             tickRect.setX(tickPosition);
896         else
897             tickRect.setY(tickPosition);
898         paintInfo.context->fillRect(tickRect);
899     }
900 }
901
902 double RenderTheme::animationRepeatIntervalForProgressBar(RenderProgress*) const
903 {
904     return 0;
905 }
906
907 double RenderTheme::animationDurationForProgressBar(RenderProgress*) const
908 {
909     return 0;
910 }
911
912 bool RenderTheme::shouldHaveSpinButton(HTMLInputElement* inputElement) const
913 {
914     return inputElement->isSteppable() && !inputElement->isRangeControl();
915 }
916
917 void RenderTheme::adjustMenuListButtonStyle(RenderStyle*, Element*) const
918 {
919 }
920
921 void RenderTheme::adjustSliderThumbStyle(RenderStyle* style, Element* element) const
922 {
923     adjustSliderThumbSize(style, element);
924 }
925
926 void RenderTheme::adjustSliderThumbSize(RenderStyle*, Element*) const
927 {
928 }
929
930 void RenderTheme::adjustSearchFieldStyle(RenderStyle*, Element*) const
931 {
932 }
933
934 void RenderTheme::adjustSearchFieldCancelButtonStyle(RenderStyle*, Element*) const
935 {
936 }
937
938 void RenderTheme::adjustSearchFieldDecorationStyle(RenderStyle*, Element*) const
939 {
940 }
941
942 void RenderTheme::adjustSearchFieldResultsDecorationStyle(RenderStyle*, Element*) const
943 {
944 }
945
946 void RenderTheme::platformColorsDidChange()
947 {
948     Page::scheduleForcedStyleRecalcForAllPages();
949 }
950
951 Color RenderTheme::systemColor(CSSValueID cssValueId) const
952 {
953     switch (cssValueId) {
954     case CSSValueActiveborder:
955         return 0xFFFFFFFF;
956     case CSSValueActivecaption:
957         return 0xFFCCCCCC;
958     case CSSValueAppworkspace:
959         return 0xFFFFFFFF;
960     case CSSValueBackground:
961         return 0xFF6363CE;
962     case CSSValueButtonface:
963         return 0xFFC0C0C0;
964     case CSSValueButtonhighlight:
965         return 0xFFDDDDDD;
966     case CSSValueButtonshadow:
967         return 0xFF888888;
968     case CSSValueButtontext:
969         return 0xFF000000;
970     case CSSValueCaptiontext:
971         return 0xFF000000;
972     case CSSValueGraytext:
973         return 0xFF808080;
974     case CSSValueHighlight:
975         return 0xFFB5D5FF;
976     case CSSValueHighlighttext:
977         return 0xFF000000;
978     case CSSValueInactiveborder:
979         return 0xFFFFFFFF;
980     case CSSValueInactivecaption:
981         return 0xFFFFFFFF;
982     case CSSValueInactivecaptiontext:
983         return 0xFF7F7F7F;
984     case CSSValueInfobackground:
985         return 0xFFFBFCC5;
986     case CSSValueInfotext:
987         return 0xFF000000;
988     case CSSValueMenu:
989         return 0xFFC0C0C0;
990     case CSSValueMenutext:
991         return 0xFF000000;
992     case CSSValueScrollbar:
993         return 0xFFFFFFFF;
994     case CSSValueText:
995         return 0xFF000000;
996     case CSSValueThreeddarkshadow:
997         return 0xFF666666;
998     case CSSValueThreedface:
999         return 0xFFC0C0C0;
1000     case CSSValueThreedhighlight:
1001         return 0xFFDDDDDD;
1002     case CSSValueThreedlightshadow:
1003         return 0xFFC0C0C0;
1004     case CSSValueThreedshadow:
1005         return 0xFF888888;
1006     case CSSValueWindow:
1007         return 0xFFFFFFFF;
1008     case CSSValueWindowframe:
1009         return 0xFFCCCCCC;
1010     case CSSValueWindowtext:
1011         return 0xFF000000;
1012     case CSSValueInternalActiveListBoxSelection:
1013         return activeListBoxSelectionBackgroundColor();
1014         break;
1015     case CSSValueInternalActiveListBoxSelectionText:
1016         return activeListBoxSelectionForegroundColor();
1017         break;
1018     case CSSValueInternalInactiveListBoxSelection:
1019         return inactiveListBoxSelectionBackgroundColor();
1020         break;
1021     case CSSValueInternalInactiveListBoxSelectionText:
1022         return inactiveListBoxSelectionForegroundColor();
1023         break;
1024     default:
1025         break;
1026     }
1027     ASSERT_NOT_REACHED();
1028     return Color();
1029 }
1030
1031 Color RenderTheme::platformActiveTextSearchHighlightColor() const
1032 {
1033     return Color(255, 150, 50); // Orange.
1034 }
1035
1036 Color RenderTheme::platformInactiveTextSearchHighlightColor() const
1037 {
1038     return Color(255, 255, 0); // Yellow.
1039 }
1040
1041 Color RenderTheme::tapHighlightColor()
1042 {
1043     return theme().platformTapHighlightColor();
1044 }
1045
1046 void RenderTheme::setCustomFocusRingColor(const Color& c)
1047 {
1048     m_customFocusRingColor = c;
1049     m_hasCustomFocusRingColor = true;
1050 }
1051
1052 Color RenderTheme::focusRingColor() const
1053 {
1054     return m_hasCustomFocusRingColor ? m_customFocusRingColor : theme().platformFocusRingColor();
1055 }
1056
1057 String RenderTheme::fileListNameForWidth(Locale& locale, const FileList* fileList, const Font& font, int width) const
1058 {
1059     if (width <= 0)
1060         return String();
1061
1062     String string;
1063     if (fileList->isEmpty()) {
1064         string = locale.queryString(WebLocalizedString::FileButtonNoFileSelectedLabel);
1065     } else if (fileList->length() == 1) {
1066         string = fileList->item(0)->name();
1067     } else {
1068         // FIXME: Localization of fileList->length().
1069         return StringTruncator::rightTruncate(locale.queryString(WebLocalizedString::MultipleFileUploadText, String::number(fileList->length())), width, font);
1070     }
1071
1072     return StringTruncator::centerTruncate(string, width, font);
1073 }
1074
1075 bool RenderTheme::shouldOpenPickerWithF4Key() const
1076 {
1077     return false;
1078 }
1079
1080 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
1081 bool RenderTheme::supportsCalendarPicker(const AtomicString& type) const
1082 {
1083     return type == InputTypeNames::date
1084         || type == InputTypeNames::datetime
1085         || type == InputTypeNames::datetime_local
1086         || type == InputTypeNames::month
1087         || type == InputTypeNames::week;
1088 }
1089 #endif
1090
1091 bool RenderTheme::shouldUseFallbackTheme(RenderStyle*) const
1092 {
1093     return false;
1094 }
1095
1096 void RenderTheme::adjustStyleUsingFallbackTheme(RenderStyle* style, Element* e)
1097 {
1098     ControlPart part = style->appearance();
1099     switch (part) {
1100     case CheckboxPart:
1101         return adjustCheckboxStyleUsingFallbackTheme(style, e);
1102     case RadioPart:
1103         return adjustRadioStyleUsingFallbackTheme(style, e);
1104     default:
1105         break;
1106     }
1107 }
1108
1109 bool RenderTheme::paintUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r)
1110 {
1111     ControlPart part = o->style()->appearance();
1112     switch (part) {
1113     case CheckboxPart:
1114         return paintCheckboxUsingFallbackTheme(o, i, r);
1115     case RadioPart:
1116         return paintRadioUsingFallbackTheme(o, i, r);
1117     default:
1118         break;
1119     }
1120     return true;
1121 }
1122
1123 // static
1124 void RenderTheme::setSizeIfAuto(RenderStyle* style, const IntSize& size)
1125 {
1126     if (style->width().isIntrinsicOrAuto())
1127         style->setWidth(Length(size.width(), Fixed));
1128     if (style->height().isAuto())
1129         style->setHeight(Length(size.height(), Fixed));
1130 }
1131
1132 bool RenderTheme::paintCheckboxUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r)
1133 {
1134     WebFallbackThemeEngine::ExtraParams extraParams;
1135     WebCanvas* canvas = i.context->canvas();
1136     extraParams.button.checked = isChecked(o);
1137     extraParams.button.indeterminate = isIndeterminate(o);
1138
1139     float zoomLevel = o->style()->effectiveZoom();
1140     GraphicsContextStateSaver stateSaver(*i.context);
1141     IntRect unzoomedRect = r;
1142     if (zoomLevel != 1) {
1143         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1144         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1145         i.context->translate(unzoomedRect.x(), unzoomedRect.y());
1146         i.context->scale(zoomLevel, zoomLevel);
1147         i.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1148     }
1149
1150     Platform::current()->fallbackThemeEngine()->paint(canvas, WebFallbackThemeEngine::PartCheckbox, getWebFallbackThemeState(this, o), WebRect(unzoomedRect), &extraParams);
1151     return false;
1152 }
1153
1154 void RenderTheme::adjustCheckboxStyleUsingFallbackTheme(RenderStyle* style, Element*) const
1155 {
1156     // If the width and height are both specified, then we have nothing to do.
1157     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1158         return;
1159
1160     IntSize size = Platform::current()->fallbackThemeEngine()->getSize(WebFallbackThemeEngine::PartCheckbox);
1161     float zoomLevel = style->effectiveZoom();
1162     size.setWidth(size.width() * zoomLevel);
1163     size.setHeight(size.height() * zoomLevel);
1164     setSizeIfAuto(style, size);
1165
1166     // padding - not honored by WinIE, needs to be removed.
1167     style->resetPadding();
1168
1169     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
1170     // for now, we will not honor it.
1171     style->resetBorder();
1172 }
1173
1174 bool RenderTheme::paintRadioUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r)
1175 {
1176     WebFallbackThemeEngine::ExtraParams extraParams;
1177     WebCanvas* canvas = i.context->canvas();
1178     extraParams.button.checked = isChecked(o);
1179     extraParams.button.indeterminate = isIndeterminate(o);
1180
1181     float zoomLevel = o->style()->effectiveZoom();
1182     GraphicsContextStateSaver stateSaver(*i.context);
1183     IntRect unzoomedRect = r;
1184     if (zoomLevel != 1) {
1185         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1186         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1187         i.context->translate(unzoomedRect.x(), unzoomedRect.y());
1188         i.context->scale(zoomLevel, zoomLevel);
1189         i.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1190     }
1191
1192     Platform::current()->fallbackThemeEngine()->paint(canvas, WebFallbackThemeEngine::PartRadio, getWebFallbackThemeState(this, o), WebRect(unzoomedRect), &extraParams);
1193     return false;
1194 }
1195
1196 void RenderTheme::adjustRadioStyleUsingFallbackTheme(RenderStyle* style, Element*) const
1197 {
1198     // If the width and height are both specified, then we have nothing to do.
1199     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1200         return;
1201
1202     IntSize size = Platform::current()->fallbackThemeEngine()->getSize(WebFallbackThemeEngine::PartRadio);
1203     float zoomLevel = style->effectiveZoom();
1204     size.setWidth(size.width() * zoomLevel);
1205     size.setHeight(size.height() * zoomLevel);
1206     setSizeIfAuto(style, size);
1207
1208     // padding - not honored by WinIE, needs to be removed.
1209     style->resetPadding();
1210
1211     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
1212     // for now, we will not honor it.
1213     style->resetBorder();
1214 }
1215
1216 } // namespace blink