WebCore:
[WebKit-https.git] / WebCore / rendering / RenderTheme.cpp
1 /**
2  * This file is part of the theme implementation for form controls in WebCore.
3  *
4  * Copyright (C) 2005 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 "Frame.h"
28 #include "GraphicsContext.h"
29 #include "HTMLInputElement.h"
30 #include "HTMLNames.h"
31 #include "RenderStyle.h"
32
33 // The methods in this file are shared by all themes on every platform.
34
35 namespace WebCore {
36
37 using namespace HTMLNames;
38
39 void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e,
40                               bool UAHasAppearance, const BorderData& border, const BackgroundLayer& background, const Color& backgroundColor)
41 {
42     // Force inline and table display styles to be inline-block (except for table- which is block)
43     if (style->display() == INLINE || style->display() == INLINE_TABLE || style->display() == TABLE_ROW_GROUP ||
44         style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_FOOTER_GROUP ||
45         style->display() == TABLE_ROW || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_COLUMN ||
46         style->display() == TABLE_CELL || style->display() == TABLE_CAPTION)
47         style->setDisplay(INLINE_BLOCK);
48     else if (style->display() == COMPACT || style->display() == RUN_IN || style->display() == LIST_ITEM || style->display() == TABLE)
49         style->setDisplay(BLOCK);
50
51     if (UAHasAppearance && theme()->isControlStyled(style, border, background, backgroundColor)) {
52         if (style->appearance() == MenulistAppearance)
53             style->setAppearance(MenulistButtonAppearance);
54         else
55             style->setAppearance(NoAppearance);
56     }
57
58     // Call the appropriate style adjustment method based off the appearance value.
59     switch (style->appearance()) {
60         case CheckboxAppearance:
61             return adjustCheckboxStyle(selector, style, e);
62         case RadioAppearance:
63             return adjustRadioStyle(selector, style, e);
64         case PushButtonAppearance:
65         case SquareButtonAppearance:
66         case ButtonAppearance:
67             return adjustButtonStyle(selector, style, e);
68         case TextFieldAppearance:
69             return adjustTextFieldStyle(selector, style, e);
70         case TextAreaAppearance:
71             return adjustTextAreaStyle(selector, style, e);
72         case MenulistAppearance:
73             return adjustMenuListStyle(selector, style, e);
74         case MenulistButtonAppearance:
75             return adjustMenuListButtonStyle(selector, style, e);
76         case SliderHorizontalAppearance:
77         case SliderVerticalAppearance:
78             return adjustSliderTrackStyle(selector, style, e);
79         case SliderThumbHorizontalAppearance:
80         case SliderThumbVerticalAppearance:
81             return adjustSliderThumbStyle(selector, style, e);
82         case SearchFieldAppearance:
83             return adjustSearchFieldStyle(selector, style, e);
84         case SearchFieldCancelButtonAppearance:
85             return adjustSearchFieldCancelButtonStyle(selector, style, e);
86         case SearchFieldDecorationAppearance:
87             return adjustSearchFieldDecorationStyle(selector, style, e);
88         case SearchFieldResultsDecorationAppearance:
89             return adjustSearchFieldResultsDecorationStyle(selector, style, e);
90         case SearchFieldResultsButtonAppearance:
91             return adjustSearchFieldResultsButtonStyle(selector, style, e);
92         default:
93             break;
94     }
95 }
96
97 bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
98 {
99     // If painting is disabled, but we aren't updating control tints, then just bail.
100     // If we are updating control tints, just schedule a repaint if the theme supports tinting
101     // for that control.
102     if (paintInfo.context->updatingControlTints()) {
103         if (controlSupportsTints(o))
104             o->repaint();
105         return false;
106     }
107     if (paintInfo.context->paintingDisabled())
108         return false;
109
110     // Call the appropriate paint method based off the appearance value.
111     switch (o->style()->appearance()) {
112         case CheckboxAppearance:
113             return paintCheckbox(o, paintInfo, r);
114         case RadioAppearance:
115             return paintRadio(o, paintInfo, r);
116         case PushButtonAppearance:
117         case SquareButtonAppearance:
118         case ButtonAppearance:
119             return paintButton(o, paintInfo, r);
120         case MenulistAppearance:
121             return paintMenuList(o, paintInfo, r);
122         case SliderHorizontalAppearance:
123         case SliderVerticalAppearance:
124             return paintSliderTrack(o, paintInfo, r);
125         case SliderThumbHorizontalAppearance:
126         case SliderThumbVerticalAppearance:
127             if (o->parent()->isSlider())
128                 return paintSliderThumb(o, paintInfo, r);
129             // We don't support drawing a slider thumb without a parent slider
130             break;
131         case MenulistButtonAppearance:
132         case TextFieldAppearance:
133         case TextAreaAppearance:
134         case ListboxAppearance:
135             return true;
136         case SearchFieldAppearance:
137             return paintSearchField(o, paintInfo, r);
138         case SearchFieldCancelButtonAppearance:
139             return paintSearchFieldCancelButton(o, paintInfo, r);
140         case SearchFieldDecorationAppearance:
141             return paintSearchFieldDecoration(o, paintInfo, r);
142         case SearchFieldResultsDecorationAppearance:
143             return paintSearchFieldResultsDecoration(o, paintInfo, r);
144         case SearchFieldResultsButtonAppearance:
145             return paintSearchFieldResultsButton(o, paintInfo, r);
146         default:
147             break;
148     }
149
150     return true; // We don't support the appearance, so let the normal background/border paint.
151 }
152
153 bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
154 {
155     if (paintInfo.context->paintingDisabled())
156         return false;
157
158     // Call the appropriate paint method based off the appearance value.
159     switch (o->style()->appearance()) {
160         case TextFieldAppearance:
161             return paintTextField(o, paintInfo, r);
162         case ListboxAppearance:
163         case TextAreaAppearance:
164             return paintTextArea(o, paintInfo, r);
165         case MenulistButtonAppearance:
166             return true;
167         case CheckboxAppearance:
168         case RadioAppearance:
169         case PushButtonAppearance:
170         case SquareButtonAppearance:
171         case ButtonAppearance:
172         case MenulistAppearance:
173         case SliderHorizontalAppearance:
174         case SliderVerticalAppearance:
175         case SliderThumbHorizontalAppearance:
176         case SliderThumbVerticalAppearance:
177         case SearchFieldAppearance:
178         case SearchFieldCancelButtonAppearance:
179         case SearchFieldDecorationAppearance:
180         case SearchFieldResultsDecorationAppearance:
181         case SearchFieldResultsButtonAppearance:
182         default:
183             break;
184     }
185
186     return false;
187 }
188
189 bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
190 {
191     if (paintInfo.context->paintingDisabled())
192         return false;
193
194     // Call the appropriate paint method based off the appearance value.
195     switch (o->style()->appearance()) {
196         case MenulistButtonAppearance:
197             return paintMenuListButton(o, paintInfo, r);
198         case TextFieldAppearance:
199         case TextAreaAppearance:
200         case ListboxAppearance:
201         case CheckboxAppearance:
202         case RadioAppearance:
203         case PushButtonAppearance:
204         case SquareButtonAppearance:
205         case ButtonAppearance:
206         case MenulistAppearance:
207         case SliderHorizontalAppearance:
208         case SliderVerticalAppearance:
209         case SliderThumbHorizontalAppearance:
210         case SliderThumbVerticalAppearance:
211         case SearchFieldAppearance:
212         case SearchFieldCancelButtonAppearance:
213         case SearchFieldDecorationAppearance:
214         case SearchFieldResultsDecorationAppearance:
215         case SearchFieldResultsButtonAppearance:
216         default:
217             break;
218     }
219
220     return false;
221 }
222
223 Color RenderTheme::activeSelectionBackgroundColor() const
224 {
225     if (!m_activeSelectionColor.isValid())
226         m_activeSelectionColor = platformActiveSelectionBackgroundColor().blendWithWhite();
227     return m_activeSelectionColor;
228 }
229
230 Color RenderTheme::inactiveSelectionBackgroundColor() const
231 {
232     if (!m_inactiveSelectionColor.isValid())
233         m_inactiveSelectionColor = platformInactiveSelectionBackgroundColor().blendWithWhite();
234     return m_inactiveSelectionColor;
235 }
236
237 Color RenderTheme::platformActiveSelectionBackgroundColor() const
238 {
239     // Use a blue color by default if the platform theme doesn't define anything.
240     return Color(0, 0, 255);
241 }
242
243 Color RenderTheme::platformInactiveSelectionBackgroundColor() const
244 {
245     // Use a grey color by default if the platform theme doesn't define anything.
246     return Color(128, 128, 128);
247 }
248
249 Color RenderTheme::platformActiveSelectionForegroundColor() const
250 {
251     return Color();
252 }
253
254 Color RenderTheme::platformInactiveSelectionForegroundColor() const
255 {
256     return Color();
257 }
258
259 Color RenderTheme::activeListBoxSelectionBackgroundColor() const
260 {
261     return activeSelectionBackgroundColor();
262 }
263
264 Color RenderTheme::activeListBoxSelectionForegroundColor() const
265 {
266     // Use a white color by default if the platform theme doesn't define anything.
267     return Color(255, 255, 255);
268 }
269
270 Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const
271 {
272     return inactiveSelectionBackgroundColor();
273 }
274
275 Color RenderTheme::inactiveListBoxSelectionForegroundColor() const
276 {
277     // Use a black color by default if the platform theme doesn't define anything.
278     return Color(0, 0, 0);
279 }
280
281 short RenderTheme::baselinePosition(const RenderObject* o) const
282 {
283     return o->height() + o->marginTop();
284 }
285
286 bool RenderTheme::isControlContainer(EAppearance appearance) const
287 {
288     // There are more leaves than this, but we'll patch this function as we add support for
289     // more controls.
290     return appearance != CheckboxAppearance && appearance != RadioAppearance;
291 }
292
293 bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& border, const BackgroundLayer& background,
294                                   const Color& backgroundColor) const
295 {
296     switch (style->appearance()) {
297         case PushButtonAppearance:
298         case SquareButtonAppearance:
299         case ButtonAppearance:
300         case ListboxAppearance:
301         case MenulistAppearance:
302         // FIXME: Uncomment this when making search fields style-able.
303         // case SearchFieldAppearance:
304         case TextFieldAppearance:
305         case TextAreaAppearance:
306             // Test the style to see if the UA border and background match.
307             return (style->border() != border ||
308                     *style->backgroundLayers() != background ||
309                     style->backgroundColor() != backgroundColor);
310         default:
311             return false;
312     }
313 }
314
315 bool RenderTheme::supportsFocusRing(const RenderStyle* style) const
316 {
317     return (style->hasAppearance() && style->appearance() != TextFieldAppearance && style->appearance() != TextAreaAppearance && style->appearance() != MenulistButtonAppearance && style->appearance() != ListboxAppearance);
318 }
319
320 bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const
321 {
322     // Default implementation assumes the controls dont respond to changes in :hover state
323     if (state == HoverState && !supportsHover(o->style()))
324         return false;
325
326     // Assume pressed state is only responded to if the control is enabled.
327     if (state == PressedState && !isEnabled(o))
328         return false;
329
330     // Repaint the control.
331     o->repaint();
332     return true;
333 }
334
335 bool RenderTheme::isChecked(const RenderObject* o) const
336 {
337     if (!o->element())
338         return false;
339     return o->element()->isChecked();
340 }
341
342 bool RenderTheme::isIndeterminate(const RenderObject* o) const
343 {
344     if (!o->element())
345         return false;
346     return o->element()->isIndeterminate();
347 }
348
349 bool RenderTheme::isEnabled(const RenderObject* o) const
350 {
351     if (!o->element())
352         return true;
353     return o->element()->isEnabled();
354 }
355
356 bool RenderTheme::isFocused(const RenderObject* o) const
357 {
358     Node* node = o->element();
359     if (!node)
360         return false;
361     Document* document = node->document();
362     Frame* frame = document->frame();
363     return node == document->focusedNode() && frame && frame->isActive();
364 }
365
366 bool RenderTheme::isPressed(const RenderObject* o) const
367 {
368     if (!o->element())
369         return false;
370     return o->element()->active();
371 }
372
373 bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
374 {
375     if (!o->element())
376         return false;
377     return o->element()->isReadOnlyControl();
378 }
379
380 bool RenderTheme::isHovered(const RenderObject* o) const
381 {
382     if (!o->element())
383         return false;
384     return o->element()->hovered();
385 }
386
387 void RenderTheme::adjustCheckboxStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
388 {
389     // A summary of the rules for checkbox designed to match WinIE:
390     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
391     // font-size - not honored (control has no text), but we use it to decide which control size to use.
392     setCheckboxSize(style);
393
394     // padding - not honored by WinIE, needs to be removed.
395     style->resetPadding();
396
397     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
398     // for now, we will not honor it.
399     style->resetBorder();
400
401     style->setBoxShadow(0);
402 }
403
404 void RenderTheme::adjustRadioStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
405 {
406     // A summary of the rules for checkbox designed to match WinIE:
407     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
408     // font-size - not honored (control has no text), but we use it to decide which control size to use.
409     setRadioSize(style);
410
411     // padding - not honored by WinIE, needs to be removed.
412     style->resetPadding();
413
414     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
415     // for now, we will not honor it.
416     style->resetBorder();
417
418     style->setBoxShadow(0);
419 }
420
421 void RenderTheme::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
422 {
423     // Most platforms will completely honor all CSS, and so we have no need to adjust the style
424     // at all by default.  We will still allow the theme a crack at setting up a desired vertical size.
425     setButtonSize(style);
426 }
427
428 void RenderTheme::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
429 {
430 }
431
432 void RenderTheme::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
433 {
434 }
435
436 void RenderTheme::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
437 {
438 }
439
440 void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
441 {
442 }
443
444 void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
445 {
446 }
447
448 void RenderTheme::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
449 {
450 }
451
452 void RenderTheme::adjustSliderThumbSize(RenderObject*) const
453 {
454 }
455
456 void RenderTheme::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
457 {
458 }
459
460 void RenderTheme::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
461 {
462 }
463
464 void RenderTheme::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
465 {
466 }
467
468 void RenderTheme::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
469 {
470 }
471
472 void RenderTheme::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
473 {
474 }
475
476 void RenderTheme::platformColorsDidChange()
477 {
478     m_activeSelectionColor = Color();
479     m_inactiveSelectionColor = Color();
480 }
481
482 Color RenderTheme::systemColor(int cssValueId) const
483 {
484     switch (cssValueId) {
485         case CSS_VAL_ACTIVEBORDER:
486             return 0xFFFFFFFF;
487         case CSS_VAL_ACTIVECAPTION:
488             return 0xFFCCCCCC;
489         case CSS_VAL_APPWORKSPACE:
490             return 0xFFFFFFFF;
491         case CSS_VAL_BACKGROUND:
492             return 0xFF6363CE;
493         case CSS_VAL_BUTTONFACE:
494             return 0xFFECECEC;
495         case CSS_VAL_BUTTONHIGHLIGHT:
496             return 0xFFDDDDDD;
497         case CSS_VAL_BUTTONSHADOW:
498             return 0xFF888888;
499         case CSS_VAL_BUTTONTEXT:
500             return 0xFF000000;
501         case CSS_VAL_CAPTIONTEXT:
502             return 0xFF000000;
503         case CSS_VAL_GRAYTEXT:
504             return 0xFF808080;
505         case CSS_VAL_HIGHLIGHT:
506             return 0xFFB5D5FF;
507         case CSS_VAL_HIGHLIGHTTEXT:
508             return 0xFF000000;
509         case CSS_VAL_INACTIVEBORDER:
510             return 0xFFFFFFFF;
511         case CSS_VAL_INACTIVECAPTION:
512             return 0xFFFFFFFF;
513         case CSS_VAL_INACTIVECAPTIONTEXT:
514             return 0xFF7F7F7F;
515         case CSS_VAL_INFOBACKGROUND:
516             return 0xFFFBFCC5;
517         case CSS_VAL_INFOTEXT:
518             return 0xFF000000;
519         case CSS_VAL_MENU:
520             return 0xFFC0C0C0;
521         case CSS_VAL_MENUTEXT:
522             return 0xFF000000;
523         case CSS_VAL_SCROLLBAR:
524             return 0xFFFFFFFF;
525         case CSS_VAL_TEXT:
526             return 0xFF000000;
527         case CSS_VAL_THREEDDARKSHADOW:
528             return 0xFF666666;
529         case CSS_VAL_THREEDFACE:
530             return 0xFFECECEC;
531         case CSS_VAL_THREEDHIGHLIGHT:
532             return 0xFFDDDDDD;
533         case CSS_VAL_THREEDLIGHTSHADOW:
534             return 0xFFC0C0C0;
535         case CSS_VAL_THREEDSHADOW:
536             return 0xFF888888;
537         case CSS_VAL_WINDOW:
538             return 0xFFFFFFFF;
539         case CSS_VAL_WINDOWFRAME:
540             return 0xFFCCCCCC;
541         case CSS_VAL_WINDOWTEXT:
542             return 0xFF000000;
543     }
544     return Color();
545 }
546
547 Color RenderTheme::platformTextSearchHighlightColor() const
548 {
549     return Color(255, 255, 0);
550 }
551
552 } // namespace WebCore