OSDN Git Service

5253219309f64e5664c452088c4ef0e38b58c550
[android-x86/external-webkit.git] / WebCore / platform / android / RenderThemeAndroid.cpp
1 /*
2  * Copyright 2009, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "RenderThemeAndroid.h"
28
29 #include "Color.h"
30 #include "Element.h"
31 #include "GraphicsContext.h"
32 #include "HTMLNames.h"
33 #include "HTMLOptionElement.h"
34 #include "HTMLSelectElement.h"
35 #include "Node.h"
36 #include "PlatformGraphicsContext.h"
37 #if ENABLE(VIDEO)
38 #include "RenderMediaControls.h"
39 #endif
40 #include "RenderSkinAndroid.h"
41 #include "RenderSkinButton.h"
42 #include "RenderSkinCombo.h"
43 #include "RenderSkinMediaButton.h"
44 #include "RenderSkinRadio.h"
45 #include "SkCanvas.h"
46 #include "UserAgentStyleSheets.h"
47
48 namespace WebCore {
49
50 // Add padding to the fontSize of ListBoxes to get their maximum sizes.
51 // Listboxes often have a specified size.  Since we change them into
52 // dropdowns, we want a much smaller height, which encompasses the text.
53 const int listboxPadding = 5;
54
55 // This is the color of selection in a textfield.  It was computed from
56 // frameworks/base/core/res/res/values/colors.xml, which uses #9983CC39
57 // (decimal a = 153, r = 131, g = 204, b = 57)
58 // for all four highlighted text values. Blending this with white yields:
59 // R = (131 * 153 + 255 * (255 - 153)) / 255  -> 180.6
60 // G = (204 * 153 + 255 * (255 - 153)) / 255  -> 224.4
61 // B = ( 57 * 153 + 255 * (255 - 153)) / 255  -> 136.2
62
63 const RGBA32 selectionColor = makeRGB(181, 224, 136);
64
65 static SkCanvas* getCanvasFromInfo(const PaintInfo& info)
66 {
67     return info.context->platformContext()->mCanvas;
68 }
69
70 RenderTheme* theme()
71 {
72     DEFINE_STATIC_LOCAL(RenderThemeAndroid, androidTheme, ());
73     return &androidTheme;
74 }
75
76 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
77 {
78     static RenderTheme* rt = RenderThemeAndroid::create().releaseRef();
79     return rt;
80 }
81
82 PassRefPtr<RenderTheme> RenderThemeAndroid::create()
83 {
84     return adoptRef(new RenderThemeAndroid());
85 }
86
87 RenderThemeAndroid::RenderThemeAndroid()
88 {
89 }
90
91 RenderThemeAndroid::~RenderThemeAndroid()
92 {
93 }
94
95 void RenderThemeAndroid::close()
96 {
97 }
98
99 bool RenderThemeAndroid::stateChanged(RenderObject* obj, ControlState state) const
100 {
101     if (CheckedState == state) {
102         obj->repaint();
103         return true;
104     }
105     return false;
106 }
107
108 Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
109 {
110     return Color(selectionColor);
111 }
112
113 Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
114 {
115     return Color(Color::transparent);
116 }
117
118 Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
119 {
120     return Color::black;
121 }
122
123 Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
124 {
125     return Color::black;
126 }
127
128 Color RenderThemeAndroid::platformTextSearchHighlightColor() const
129 {
130     return Color(Color::transparent);
131 }
132
133 Color RenderThemeAndroid::platformActiveListBoxSelectionBackgroundColor() const
134 {
135     return Color(Color::transparent);
136 }
137
138 Color RenderThemeAndroid::platformInactiveListBoxSelectionBackgroundColor() const
139 {
140     return Color(Color::transparent);
141 }
142
143 Color RenderThemeAndroid::platformActiveListBoxSelectionForegroundColor() const
144 {
145     return Color(Color::transparent);
146 }
147
148 Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() const
149 {
150     return Color(Color::transparent);
151 }
152
153 int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
154 {
155     // From the description of this function in RenderTheme.h:
156     // A method to obtain the baseline position for a "leaf" control.  This will only be used if a baseline
157     // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
158     // controls that need to do this.
159     //
160     // Our checkboxes and radio buttons need to be offset to line up properly.
161     return RenderTheme::baselinePosition(obj) - 2;
162 }
163
164 void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
165 {
166     // Cut out the intrinsic margins completely if we end up using a small font size
167     if (style->fontSize() < 11)
168         return;
169     
170     // Intrinsic margin value.
171     const int m = 2;
172     
173     // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
174     if (style->width().isIntrinsicOrAuto()) {
175         if (style->marginLeft().quirk())
176             style->setMarginLeft(Length(m, Fixed));
177         if (style->marginRight().quirk())
178             style->setMarginRight(Length(m, Fixed));
179     }
180
181     if (style->height().isAuto()) {
182         if (style->marginTop().quirk())
183             style->setMarginTop(Length(m, Fixed));
184         if (style->marginBottom().quirk())
185             style->setMarginBottom(Length(m, Fixed));
186     }
187 }
188
189 bool RenderThemeAndroid::supportsFocus(ControlPart appearance)
190 {
191     switch (appearance) {
192     case PushButtonPart:
193     case ButtonPart:
194     case TextFieldPart:
195         return true;
196     default:
197         return false;
198     }
199
200     return false;
201 }
202
203 void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
204 {
205     // Code is taken from RenderThemeSafari.cpp
206     // It makes sure we have enough space for the button text.
207     const int padding = 8;
208     style->setPaddingLeft(Length(padding, Fixed));
209     style->setPaddingRight(Length(padding, Fixed));
210
211     // Set a min-height so that we can't get smaller than the mini button.
212     style->setMinHeight(Length(15, Fixed));
213 }
214
215 bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
216 {
217     RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, true);
218     return false;
219 }
220
221 bool RenderThemeAndroid::paintButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
222 {
223     // If it is a disabled button, simply paint it to the master picture.
224     Node* node = obj->node();
225     Element* formControlElement = static_cast<Element*>(node);
226     if (formControlElement && !formControlElement->isEnabledFormControl())
227         RenderSkinButton::Draw(getCanvasFromInfo(info), rect, RenderSkinAndroid::kDisabled);
228     else
229         // Store all the important information in the platform context.
230         info.context->platformContext()->storeButtonInfo(node, rect);
231
232     // We always return false so we do not request to be redrawn.
233     return false;
234 }
235
236 #if ENABLE(VIDEO)
237
238 String RenderThemeAndroid::extraMediaControlsStyleSheet()
239 {
240       return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet));
241 }
242
243 bool RenderThemeAndroid::shouldRenderMediaControlPart(ControlPart part, Element* e)
244 {
245       HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(e);
246       switch (part) {
247       case MediaMuteButtonPart:
248           return false;
249       case MediaSeekBackButtonPart:
250       case MediaSeekForwardButtonPart:
251           return false;
252       case MediaRewindButtonPart:
253           return mediaElement->movieLoadType() != MediaPlayer::LiveStream;
254       case MediaReturnToRealtimeButtonPart:
255           return mediaElement->movieLoadType() == MediaPlayer::LiveStream;
256       case MediaFullscreenButtonPart:
257           return mediaElement->supportsFullscreen();
258       case MediaToggleClosedCaptionsButtonPart:
259           return mediaElement->hasClosedCaptions();
260       default:
261           return true;
262       }
263 }
264
265 bool paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
266 {
267       bool translucent = false;
268       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
269           translucent = true;
270       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent);
271       return false;
272 }
273
274 bool RenderThemeAndroid::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
275 {
276       bool translucent = false;
277       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
278           translucent = true;
279       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::MUTE, translucent);
280       return false;
281 }
282
283 bool RenderThemeAndroid::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
284 {
285       bool translucent = false;
286       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
287           translucent = true;
288       if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
289           if (btn->displayType() == MediaPlayButton)
290               RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent);
291           else
292               RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PAUSE, translucent);
293           return false;
294       }
295       return true;
296 }
297
298 bool RenderThemeAndroid::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
299 {
300       bool translucent = false;
301       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
302           translucent = true;
303       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::REWIND, translucent);
304       return false;
305 }
306
307 bool RenderThemeAndroid::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
308 {
309       bool translucent = false;
310       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
311           translucent = true;
312       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FORWARD, translucent);
313       return false;
314 }
315
316 bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
317 {
318       bool translucent = false;
319       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
320           translucent = true;
321       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::BACKGROUND_SLIDER, translucent);
322       return false;
323 }
324
325 bool RenderThemeAndroid::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
326 {
327       bool translucent = false;
328       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
329           translucent = true;
330       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_TRACK, translucent);
331       return false;
332 }
333
334 bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
335 {
336       bool translucent = false;
337       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
338           translucent = true;
339       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_THUMB, translucent);
340       return false;
341 }
342
343 void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const
344 {
345     static const int sliderThumbWidth = RenderSkinMediaButton::sliderThumbWidth();
346     static const int sliderThumbHeight = RenderSkinMediaButton::sliderThumbHeight();
347     if (o->style()->appearance() == MediaSliderThumbPart) {
348         o->style()->setWidth(Length(sliderThumbWidth, Fixed));
349         o->style()->setHeight(Length(sliderThumbHeight, Fixed));
350     }
351 }
352
353 #endif
354
355 bool RenderThemeAndroid::paintRadio(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
356 {
357     RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, false);
358     return false;
359 }
360
361 void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
362 {
363     style->setWidth(Length(19, Fixed));
364     style->setHeight(Length(19, Fixed));
365 }
366
367 void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
368 {
369     // This is the same as checkboxes.
370     setCheckboxSize(style);
371 }
372
373 void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
374 {
375     addIntrinsicMargins(style);
376 }
377
378 bool RenderThemeAndroid::paintTextField(RenderObject*, const PaintInfo&, const IntRect&)
379 {
380     return true;    
381 }
382
383 void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
384 {
385     addIntrinsicMargins(style);
386 }
387
388 bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
389 {
390     if (obj->isMenuList())
391         paintCombo(obj, info, rect);
392     return true;
393 }
394
395 void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
396 {
397     addIntrinsicMargins(style);
398 }
399
400 bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const IntRect&)
401 {
402     return true;    
403 }
404
405 static void adjustMenuListStyleCommon(RenderStyle* style)
406 {
407     // Added to make room for our arrow and make the touch target less cramped.
408     style->setPaddingLeft(Length(RenderSkinCombo::padding(), Fixed));
409     style->setPaddingTop(Length(RenderSkinCombo::padding(), Fixed));
410     style->setPaddingBottom(Length(RenderSkinCombo::padding(), Fixed));
411     style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
412 }
413
414 void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
415 {
416     adjustMenuListButtonStyle(0, style, 0);
417 }
418
419 void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
420 {
421     adjustMenuListStyleCommon(style);
422     addIntrinsicMargins(style);
423 }
424
425 bool RenderThemeAndroid::paintCombo(RenderObject* obj, const PaintInfo& info,  const IntRect& rect)
426 {
427   if (obj->style() && !obj->style()->visitedDependentColor(CSSPropertyBackgroundColor).alpha())
428         return true;
429     return RenderSkinCombo::Draw(getCanvasFromInfo(info), obj->node(), rect.x(), rect.y(), rect.width(), rect.height());
430 }
431
432 bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect) 
433
434     return paintCombo(obj, info, rect);
435 }
436
437 void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*,
438         RenderStyle* style, Element*) const
439 {
440     // Copied from RenderThemeSafari.
441     const float baseFontSize = 11.0f;
442     const int baseBorderRadius = 5;
443     float fontScale = style->fontSize() / baseFontSize;
444     
445     style->resetPadding();
446     style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
447
448     const int minHeight = 15;
449     style->setMinHeight(Length(minHeight, Fixed));
450     
451     style->setLineHeight(RenderStyle::initialLineHeight());
452     // Found these padding numbers by trial and error.
453     const int padding = 4;
454     style->setPaddingTop(Length(padding, Fixed));
455     style->setPaddingLeft(Length(padding, Fixed));
456     adjustMenuListStyleCommon(style);
457 }
458
459 bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect) 
460 {
461     return paintCombo(obj, info, rect);
462 }
463
464 bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
465 {
466     return style->opacity() > 0
467         && style->hasAppearance() 
468         && style->appearance() != TextFieldPart 
469         && style->appearance() != SearchFieldPart 
470         && style->appearance() != TextAreaPart 
471         && style->appearance() != CheckboxPart
472         && style->appearance() != RadioPart
473         && style->appearance() != PushButtonPart
474         && style->appearance() != SquareButtonPart
475         && style->appearance() != ButtonPart
476         && style->appearance() != ButtonBevelPart
477         && style->appearance() != MenulistPart
478         && style->appearance() != MenulistButtonPart;
479 }
480
481 } // namespace WebCore