bbd6649a848608a60ba8fbe0a2c0ed77dbdff370
[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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include "RenderTheme.h"
24
25 #include "Document.h"
26 #include "GraphicsContext.h"
27 #include "HTMLInputElement.h"
28 #include "HTMLNames.h"
29 #include "RenderStyle.h"
30
31 // The methods in this file are shared by all themes on every platform.
32
33 namespace WebCore {
34
35 using namespace HTMLNames;
36
37 void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e, 
38                               bool UAHasAppearance, const BorderData& border, const BackgroundLayer& background, const Color& backgroundColor)
39 {
40
41     // Force inline and table display styles to be inline-block (except for table- which is block)
42     if (style->display() == INLINE || style->display() == INLINE_TABLE || style->display() == TABLE_ROW_GROUP || 
43         style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_FOOTER_GROUP ||
44         style->display() == TABLE_ROW || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_COLUMN || 
45         style->display() == TABLE_CELL || style->display() == TABLE_CAPTION)
46         style->setDisplay(INLINE_BLOCK);
47     else if (style->display() == COMPACT || style->display() == RUN_IN || style->display() == LIST_ITEM || style->display() == TABLE)
48         style->setDisplay(BLOCK);
49     
50     if (UAHasAppearance && theme()->isControlStyled(style, border, background, backgroundColor)) {
51         if (style->appearance() == MenulistAppearance)
52             style->setAppearance(MenulistButtonAppearance);
53         else
54             style->setAppearance(NoAppearance);
55     }
56
57     // Call the appropriate style adjustment method based off the appearance value.
58     switch (style->appearance()) {
59         case CheckboxAppearance:
60             return adjustCheckboxStyle(selector, style, e);
61         case RadioAppearance:
62             return adjustRadioStyle(selector, style, e);
63         case PushButtonAppearance:
64         case SquareButtonAppearance:
65         case ButtonAppearance:
66             return adjustButtonStyle(selector, style, e);
67         case TextFieldAppearance:
68             return adjustTextFieldStyle(selector, style, e);
69         case TextAreaAppearance:
70             return adjustTextAreaStyle(selector, style, e);
71         case MenulistAppearance:
72             return adjustMenuListStyle(selector, style, e);
73         case MenulistButtonAppearance:
74             return adjustMenuListButtonStyle(selector, style, e);
75         case SliderHorizontalAppearance:
76         case SliderVerticalAppearance:
77             return adjustSliderTrackStyle(selector, style, e);
78         case SliderThumbHorizontalAppearance:
79         case SliderThumbVerticalAppearance:
80             return adjustSliderThumbStyle(selector, style, e);
81         default:
82             break;
83     }
84 }
85
86 bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
87 {
88     // If painting is disabled, but we aren't updating control tints, then just bail.
89     // If we are updating control tints, just schedule a repaint if the theme supports tinting
90     // for that control.
91     if (paintInfo.context->updatingControlTints()) {
92         if (controlSupportsTints(o))
93             o->repaint();
94         return false;
95     }
96     if (paintInfo.context->paintingDisabled())
97         return false;
98
99     // Call the appropriate paint method based off the appearance value.
100     switch (o->style()->appearance()) {
101         case CheckboxAppearance:
102             return paintCheckbox(o, paintInfo, r);
103         case RadioAppearance:
104             return paintRadio(o, paintInfo, r);
105         case PushButtonAppearance:
106         case SquareButtonAppearance:
107         case ButtonAppearance:
108             return paintButton(o, paintInfo, r);
109         case MenulistAppearance:
110             return paintMenuList(o, paintInfo, r);
111         case SliderHorizontalAppearance:
112         case SliderVerticalAppearance:
113             return paintSliderTrack(o, paintInfo, r);
114         case SliderThumbHorizontalAppearance:
115         case SliderThumbVerticalAppearance:
116             return paintSliderThumb(o, paintInfo, r);
117         case MenulistButtonAppearance:
118         case TextFieldAppearance:
119         case TextAreaAppearance:
120         case ListboxAppearance:
121             return true;
122         default:
123             break;
124     }
125
126     return true; // We don't support the appearance, so let the normal background/border paint.
127 }
128
129 bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
130 {
131     if (paintInfo.context->paintingDisabled())
132         return false;
133
134     // Call the appropriate paint method based off the appearance value.
135     switch (o->style()->appearance()) {
136         case TextFieldAppearance:
137             return paintTextField(o, paintInfo, r);
138         case ListboxAppearance:
139         case TextAreaAppearance:
140             return paintTextArea(o, paintInfo, r);
141         case MenulistButtonAppearance:
142             return true;
143         case CheckboxAppearance:
144         case RadioAppearance:
145         case PushButtonAppearance:
146         case SquareButtonAppearance:
147         case ButtonAppearance:
148         case MenulistAppearance:
149         case SliderHorizontalAppearance:
150         case SliderVerticalAppearance:
151         case SliderThumbHorizontalAppearance:
152         case SliderThumbVerticalAppearance:
153         default:
154             break;
155     }
156
157     return false;
158 }
159
160 bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
161 {
162     if (paintInfo.context->paintingDisabled())
163         return false;
164
165     // Call the appropriate paint method based off the appearance value.
166     switch (o->style()->appearance()) {
167         case MenulistButtonAppearance:
168             return paintMenuListButton(o, paintInfo, r);
169         case TextFieldAppearance:
170         case TextAreaAppearance:
171         case ListboxAppearance:
172         case CheckboxAppearance:
173         case RadioAppearance:
174         case PushButtonAppearance:
175         case SquareButtonAppearance:
176         case ButtonAppearance:
177         case MenulistAppearance:
178         case SliderHorizontalAppearance:
179         case SliderVerticalAppearance:
180         case SliderThumbHorizontalAppearance:
181         case SliderThumbVerticalAppearance:
182         default:
183             break;
184     }
185
186     return false;
187 }
188
189 Color RenderTheme::activeSelectionBackgroundColor() const
190 {
191     static Color activeSelectionColor;
192     if (!activeSelectionColor.isValid())
193         activeSelectionColor = platformActiveSelectionBackgroundColor().blendWithWhite();
194     return activeSelectionColor;
195 }
196
197 Color RenderTheme::inactiveSelectionBackgroundColor() const
198 {
199     static Color inactiveSelectionColor;
200     if (!inactiveSelectionColor.isValid())
201         inactiveSelectionColor = platformInactiveSelectionBackgroundColor().blendWithWhite();
202     return inactiveSelectionColor;
203 }
204
205 Color RenderTheme::platformActiveSelectionBackgroundColor() const
206 {
207     // Use a blue color by default if the platform theme doesn't define anything.
208     return Color(0, 0, 255);
209 }
210     
211 Color RenderTheme::platformInactiveSelectionBackgroundColor() const
212 {
213     // Use a grey color by default if the platform theme doesn't define anything.
214     return Color(128, 128, 128);
215 }
216    
217 Color RenderTheme::platformActiveSelectionForegroundColor() const
218 {
219     return Color();
220 }
221     
222 Color RenderTheme::platformInactiveSelectionForegroundColor() const
223 {
224     return Color();
225 }
226
227 Color RenderTheme::activeListBoxSelectionBackgroundColor() const
228 {
229     return activeSelectionBackgroundColor();
230 }
231
232 Color RenderTheme::activeListBoxSelectionForegroundColor() const
233 {
234     // Use a white color by default if the platform theme doesn't define anything.
235     return Color(255, 255, 255);
236 }
237
238 Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const
239 {
240     return inactiveSelectionBackgroundColor();
241 }
242
243 Color RenderTheme::inactiveListBoxSelectionForegroundColor() const
244 {
245     // Use a black color by default if the platform theme doesn't define anything.
246     return Color(0, 0, 0);
247 }
248
249 short RenderTheme::baselinePosition(const RenderObject* o) const
250 {
251     return o->height() + o->marginTop();
252 }
253
254 bool RenderTheme::isControlContainer(EAppearance appearance) const
255 {
256     // There are more leaves than this, but we'll patch this function as we add support for
257     // more controls.
258     return appearance != CheckboxAppearance && appearance != RadioAppearance;
259 }
260
261 bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& border, const BackgroundLayer& background,
262                                   const Color& backgroundColor) const
263 {
264     switch (style->appearance()) {
265         case PushButtonAppearance:
266         case SquareButtonAppearance:
267         case ButtonAppearance:
268         case ListboxAppearance:
269         case MenulistAppearance:
270         case TextFieldAppearance:
271         case TextAreaAppearance: {
272             // Test the style to see if the UA border and background match.
273             return (style->border() != border ||
274                     *style->backgroundLayers() != background ||
275                     style->backgroundColor() != backgroundColor);
276         }
277         default:
278             return false;
279     }
280     
281     return false;
282 }
283
284 bool RenderTheme::supportsFocusRing(const RenderStyle* style) const
285 {
286     return (style->hasAppearance() && style->appearance() != TextFieldAppearance && style->appearance() != TextAreaAppearance && style->appearance() != MenulistButtonAppearance && style->appearance() != ListboxAppearance);
287 }
288
289 bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const
290 {
291     // Default implementation assumes the controls dont respond to changes in :hover state
292     if (state == HoverState && !supportsHover(o->style()))
293         return false;
294         
295     // Assume pressed state is only responded to if the control is enabled.
296     if (state == PressedState && !isEnabled(o))
297         return false;
298     
299     // Repaint the control.
300     o->repaint();
301     return true;
302 }
303
304 bool RenderTheme::isChecked(const RenderObject* o) const
305 {
306     if (!o->element())
307         return false;
308     return o->element()->isChecked();
309 }
310
311 bool RenderTheme::isIndeterminate(const RenderObject* o) const
312 {
313     if (!o->element())
314         return false;
315     return o->element()->isIndeterminate();
316 }
317
318 bool RenderTheme::isEnabled(const RenderObject* o) const
319 {
320     if (!o->element())
321         return true;
322     return o->element()->isEnabled();
323 }
324
325 bool RenderTheme::isFocused(const RenderObject* o) const
326 {
327     if (!o->element())
328         return false;
329     return o->element() == o->element()->document()->focusNode();
330 }
331
332 bool RenderTheme::isPressed(const RenderObject* o) const
333 {
334     if (!o->element())
335         return false;
336     return o->element()->active();
337 }
338
339 bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
340 {
341     if (!o->element())
342         return false;
343     return o->element()->isReadOnlyControl();
344 }
345
346 bool RenderTheme::isHovered(const RenderObject* o) const
347 {
348     if (!o->element())
349         return false;
350     return o->element()->hovered();
351 }
352
353 void RenderTheme::adjustCheckboxStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
354 {
355     // A summary of the rules for checkbox designed to match WinIE:
356     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
357     // font-size - not honored (control has no text), but we use it to decide which control size to use.
358     setCheckboxSize(style);
359     
360     // padding - not honored by WinIE, needs to be removed.
361     style->resetPadding();
362     
363     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
364     // for now, we will not honor it.
365     style->resetBorder();
366 }
367
368 void RenderTheme::adjustRadioStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
369 {
370     // A summary of the rules for checkbox designed to match WinIE:
371     // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
372     // font-size - not honored (control has no text), but we use it to decide which control size to use.
373     setRadioSize(style);
374     
375     // padding - not honored by WinIE, needs to be removed.
376     style->resetPadding();
377     
378     // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
379     // for now, we will not honor it.
380     style->resetBorder();
381 }
382
383 void RenderTheme::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
384 {
385     // Most platforms will completely honor all CSS, and so we have no need to adjust the style
386     // at all by default.  We will still allow the theme a crack at setting up a desired vertical size.
387     setButtonSize(style);
388 }
389
390 void RenderTheme::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
391 {
392 }
393
394 void RenderTheme::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
395 {
396 }
397
398 void RenderTheme::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
399 {
400 }
401
402 void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
403 {
404 }
405
406 void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
407 {
408 }
409
410 void RenderTheme::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
411 {
412 }
413
414 }