• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "WebCoreFrameBridge.h"
48 
49 namespace WebCore {
50 
51 // Add padding to the fontSize of ListBoxes to get their maximum sizes.
52 // Listboxes often have a specified size.  Since we change them into
53 // dropdowns, we want a much smaller height, which encompasses the text.
54 const int listboxPadding = 5;
55 
56 // This is the color of selection in a textfield.  It was computed from
57 // frameworks/base/core/res/res/values/colors.xml, which uses #9983CC39
58 // (decimal a = 153, r = 131, g = 204, b = 57)
59 // for all four highlighted text values. Blending this with white yields:
60 // R = (131 * 153 + 255 * (255 - 153)) / 255  -> 180.6
61 // G = (204 * 153 + 255 * (255 - 153)) / 255  -> 224.4
62 // B = ( 57 * 153 + 255 * (255 - 153)) / 255  -> 136.2
63 
64 const RGBA32 selectionColor = makeRGB(181, 224, 136);
65 
getCanvasFromInfo(const PaintInfo & info)66 static SkCanvas* getCanvasFromInfo(const PaintInfo& info)
67 {
68     return info.context->platformContext()->mCanvas;
69 }
70 
getWebFrame(const Node * node)71 static android::WebFrame* getWebFrame(const Node* node)
72 {
73     if (!node)
74         return 0;
75     return android::WebFrame::getWebFrame(node->document()->frame());
76 }
77 
theme()78 RenderTheme* theme()
79 {
80     DEFINE_STATIC_LOCAL(RenderThemeAndroid, androidTheme, ());
81     return &androidTheme;
82 }
83 
themeForPage(Page * page)84 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
85 {
86     static RenderTheme* rt = RenderThemeAndroid::create().releaseRef();
87     return rt;
88 }
89 
create()90 PassRefPtr<RenderTheme> RenderThemeAndroid::create()
91 {
92     return adoptRef(new RenderThemeAndroid());
93 }
94 
RenderThemeAndroid()95 RenderThemeAndroid::RenderThemeAndroid()
96 {
97 }
98 
~RenderThemeAndroid()99 RenderThemeAndroid::~RenderThemeAndroid()
100 {
101 }
102 
close()103 void RenderThemeAndroid::close()
104 {
105 }
106 
stateChanged(RenderObject * obj,ControlState state) const107 bool RenderThemeAndroid::stateChanged(RenderObject* obj, ControlState state) const
108 {
109     if (CheckedState == state) {
110         obj->repaint();
111         return true;
112     }
113     return false;
114 }
115 
platformActiveSelectionBackgroundColor() const116 Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
117 {
118     return Color(selectionColor);
119 }
120 
platformInactiveSelectionBackgroundColor() const121 Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
122 {
123     return Color(Color::transparent);
124 }
125 
platformActiveSelectionForegroundColor() const126 Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
127 {
128     return Color::black;
129 }
130 
platformInactiveSelectionForegroundColor() const131 Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
132 {
133     return Color::black;
134 }
135 
platformTextSearchHighlightColor() const136 Color RenderThemeAndroid::platformTextSearchHighlightColor() const
137 {
138     return Color(Color::transparent);
139 }
140 
platformActiveListBoxSelectionBackgroundColor() const141 Color RenderThemeAndroid::platformActiveListBoxSelectionBackgroundColor() const
142 {
143     return Color(Color::transparent);
144 }
145 
platformInactiveListBoxSelectionBackgroundColor() const146 Color RenderThemeAndroid::platformInactiveListBoxSelectionBackgroundColor() const
147 {
148     return Color(Color::transparent);
149 }
150 
platformActiveListBoxSelectionForegroundColor() const151 Color RenderThemeAndroid::platformActiveListBoxSelectionForegroundColor() const
152 {
153     return Color(Color::transparent);
154 }
155 
platformInactiveListBoxSelectionForegroundColor() const156 Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() const
157 {
158     return Color(Color::transparent);
159 }
160 
baselinePosition(const RenderObject * obj) const161 int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
162 {
163     // From the description of this function in RenderTheme.h:
164     // A method to obtain the baseline position for a "leaf" control.  This will only be used if a baseline
165     // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
166     // controls that need to do this.
167     //
168     // Our checkboxes and radio buttons need to be offset to line up properly.
169     return RenderTheme::baselinePosition(obj) - 2;
170 }
171 
addIntrinsicMargins(RenderStyle * style) const172 void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
173 {
174     // Cut out the intrinsic margins completely if we end up using a small font size
175     if (style->fontSize() < 11)
176         return;
177 
178     // Intrinsic margin value.
179     const int m = 2;
180 
181     // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
182     if (style->width().isIntrinsicOrAuto()) {
183         if (style->marginLeft().quirk())
184             style->setMarginLeft(Length(m, Fixed));
185         if (style->marginRight().quirk())
186             style->setMarginRight(Length(m, Fixed));
187     }
188 
189     if (style->height().isAuto()) {
190         if (style->marginTop().quirk())
191             style->setMarginTop(Length(m, Fixed));
192         if (style->marginBottom().quirk())
193             style->setMarginBottom(Length(m, Fixed));
194     }
195 }
196 
supportsFocus(ControlPart appearance)197 bool RenderThemeAndroid::supportsFocus(ControlPart appearance)
198 {
199     switch (appearance) {
200     case PushButtonPart:
201     case ButtonPart:
202     case TextFieldPart:
203         return true;
204     default:
205         return false;
206     }
207 
208     return false;
209 }
210 
adjustButtonStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const211 void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
212 {
213     // Code is taken from RenderThemeSafari.cpp
214     // It makes sure we have enough space for the button text.
215     const int paddingHoriz = 12;
216     const int paddingVert = 8;
217     style->setPaddingLeft(Length(paddingHoriz, Fixed));
218     style->setPaddingRight(Length(paddingHoriz, Fixed));
219     style->setPaddingTop(Length(paddingVert, Fixed));
220     style->setPaddingBottom(Length(paddingVert, Fixed));
221 
222     // Set a min-height so that we can't get smaller than the mini button.
223     style->setMinHeight(Length(15, Fixed));
224 }
225 
paintCheckbox(RenderObject * obj,const PaintInfo & info,const IntRect & rect)226 bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
227 {
228     RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, true);
229     return false;
230 }
231 
paintButton(RenderObject * obj,const PaintInfo & info,const IntRect & rect)232 bool RenderThemeAndroid::paintButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
233 {
234     // If it is a disabled button, simply paint it to the master picture.
235     Node* node = obj->node();
236     Element* formControlElement = static_cast<Element*>(node);
237     if (formControlElement && !formControlElement->isEnabledFormControl()) {
238         android::WebFrame* webFrame = getWebFrame(node);
239         if (webFrame) {
240             RenderSkinAndroid* skins = webFrame->renderSkins();
241             if (skins)
242                 skins->renderSkinButton()->draw(getCanvasFromInfo(info), rect,
243                                                 RenderSkinAndroid::kDisabled);
244         }
245     } else
246         // Store all the important information in the platform context.
247         info.context->platformContext()->storeButtonInfo(node, rect);
248 
249     // We always return false so we do not request to be redrawn.
250     return false;
251 }
252 
253 #if ENABLE(VIDEO)
254 
extraMediaControlsStyleSheet()255 String RenderThemeAndroid::extraMediaControlsStyleSheet()
256 {
257       return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet));
258 }
259 
shouldRenderMediaControlPart(ControlPart part,Element * e)260 bool RenderThemeAndroid::shouldRenderMediaControlPart(ControlPart part, Element* e)
261 {
262       HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(e);
263       switch (part) {
264       case MediaMuteButtonPart:
265           return false;
266       case MediaSeekBackButtonPart:
267       case MediaSeekForwardButtonPart:
268           return false;
269       case MediaRewindButtonPart:
270           return mediaElement->movieLoadType() != MediaPlayer::LiveStream;
271       case MediaReturnToRealtimeButtonPart:
272           return mediaElement->movieLoadType() == MediaPlayer::LiveStream;
273       case MediaFullscreenButtonPart:
274           return mediaElement->supportsFullscreen();
275       case MediaToggleClosedCaptionsButtonPart:
276           return mediaElement->hasClosedCaptions();
277       default:
278           return true;
279       }
280 }
281 
paintMediaFullscreenButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)282 bool RenderThemeAndroid::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
283 {
284       bool translucent = false;
285       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
286           translucent = true;
287       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FULLSCREEN, translucent);
288       return false;
289 }
290 
paintMediaMuteButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)291 bool RenderThemeAndroid::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
292 {
293       bool translucent = false;
294       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
295           translucent = true;
296       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::MUTE, translucent);
297       return false;
298 }
299 
paintMediaPlayButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)300 bool RenderThemeAndroid::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
301 {
302       bool translucent = false;
303       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
304           translucent = true;
305       if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
306           if (btn->displayType() == MediaPlayButton)
307               RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent);
308           else
309               RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PAUSE, translucent);
310           return false;
311       }
312       return true;
313 }
314 
paintMediaSeekBackButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)315 bool RenderThemeAndroid::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
316 {
317       bool translucent = false;
318       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
319           translucent = true;
320       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::REWIND, translucent);
321       return false;
322 }
323 
paintMediaSeekForwardButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)324 bool RenderThemeAndroid::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
325 {
326       bool translucent = false;
327       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
328           translucent = true;
329       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FORWARD, translucent);
330       return false;
331 }
332 
paintMediaControlsBackground(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)333 bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
334 {
335       bool translucent = false;
336       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
337           translucent = true;
338       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::BACKGROUND_SLIDER, translucent);
339       return false;
340 }
341 
paintMediaSliderTrack(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)342 bool RenderThemeAndroid::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
343 {
344       bool translucent = false;
345       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
346           translucent = true;
347       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect,
348                                   RenderSkinMediaButton::SLIDER_TRACK, translucent, o);
349       return false;
350 }
351 
paintMediaSliderThumb(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)352 bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
353 {
354       bool translucent = false;
355       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
356           translucent = true;
357       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_THUMB, translucent);
358       return false;
359 }
360 
adjustSliderThumbSize(RenderObject * o) const361 void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const
362 {
363     static const int sliderThumbWidth = RenderSkinMediaButton::sliderThumbWidth();
364     static const int sliderThumbHeight = RenderSkinMediaButton::sliderThumbHeight();
365     if (o->style()->appearance() == MediaSliderThumbPart) {
366         o->style()->setWidth(Length(sliderThumbWidth, Fixed));
367         o->style()->setHeight(Length(sliderThumbHeight, Fixed));
368     }
369 }
370 
371 #endif
372 
paintRadio(RenderObject * obj,const PaintInfo & info,const IntRect & rect)373 bool RenderThemeAndroid::paintRadio(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
374 {
375     RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, false);
376     return false;
377 }
378 
setCheckboxSize(RenderStyle * style) const379 void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
380 {
381     style->setWidth(Length(19, Fixed));
382     style->setHeight(Length(19, Fixed));
383 }
384 
setRadioSize(RenderStyle * style) const385 void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
386 {
387     // This is the same as checkboxes.
388     setCheckboxSize(style);
389 }
390 
adjustTextFieldStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const391 void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
392 {
393     addIntrinsicMargins(style);
394 }
395 
paintTextField(RenderObject *,const PaintInfo &,const IntRect &)396 bool RenderThemeAndroid::paintTextField(RenderObject*, const PaintInfo&, const IntRect&)
397 {
398     return true;
399 }
400 
adjustTextAreaStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const401 void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
402 {
403     addIntrinsicMargins(style);
404 }
405 
paintTextArea(RenderObject * obj,const PaintInfo & info,const IntRect & rect)406 bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
407 {
408     if (obj->isMenuList())
409         paintCombo(obj, info, rect);
410     return true;
411 }
412 
adjustSearchFieldStyle(CSSStyleSelector *,RenderStyle * style,Element *) const413 void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
414 {
415     addIntrinsicMargins(style);
416 }
417 
paintSearchField(RenderObject *,const PaintInfo &,const IntRect &)418 bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const IntRect&)
419 {
420     return true;
421 }
422 
adjustMenuListStyleCommon(RenderStyle * style)423 static void adjustMenuListStyleCommon(RenderStyle* style)
424 {
425     // Added to make room for our arrow and make the touch target less cramped.
426     style->setPaddingLeft(Length(RenderSkinCombo::padding(), Fixed));
427     style->setPaddingTop(Length(RenderSkinCombo::padding(), Fixed));
428     style->setPaddingBottom(Length(RenderSkinCombo::padding(), Fixed));
429     style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
430 }
431 
adjustListboxStyle(CSSStyleSelector *,RenderStyle * style,Element *) const432 void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
433 {
434     adjustMenuListButtonStyle(0, style, 0);
435 }
436 
adjustMenuListStyle(CSSStyleSelector *,RenderStyle * style,Element * e) const437 void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
438 {
439     adjustMenuListStyleCommon(style);
440     addIntrinsicMargins(style);
441 }
442 
paintCombo(RenderObject * obj,const PaintInfo & info,const IntRect & rect)443 bool RenderThemeAndroid::paintCombo(RenderObject* obj, const PaintInfo& info,  const IntRect& rect)
444 {
445   if (obj->style() && !obj->style()->visitedDependentColor(CSSPropertyBackgroundColor).alpha())
446         return true;
447     return RenderSkinCombo::Draw(getCanvasFromInfo(info), obj->node(), rect.x(), rect.y(), rect.width(), rect.height());
448 }
449 
paintMenuList(RenderObject * obj,const PaintInfo & info,const IntRect & rect)450 bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
451 {
452     return paintCombo(obj, info, rect);
453 }
454 
adjustMenuListButtonStyle(CSSStyleSelector *,RenderStyle * style,Element *) const455 void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*,
456         RenderStyle* style, Element*) const
457 {
458     // Copied from RenderThemeSafari.
459     const float baseFontSize = 11.0f;
460     const int baseBorderRadius = 5;
461     float fontScale = style->fontSize() / baseFontSize;
462 
463     style->resetPadding();
464     style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
465 
466     const int minHeight = 15;
467     style->setMinHeight(Length(minHeight, Fixed));
468 
469     style->setLineHeight(RenderStyle::initialLineHeight());
470     // Found these padding numbers by trial and error.
471     const int padding = 4;
472     style->setPaddingTop(Length(padding, Fixed));
473     style->setPaddingLeft(Length(padding, Fixed));
474     adjustMenuListStyleCommon(style);
475 }
476 
paintMenuListButton(RenderObject * obj,const PaintInfo & info,const IntRect & rect)477 bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
478 {
479     return paintCombo(obj, info, rect);
480 }
481 
supportsFocusRing(const RenderStyle * style) const482 bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
483 {
484     return style->opacity() > 0
485         && style->hasAppearance()
486         && style->appearance() != TextFieldPart
487         && style->appearance() != SearchFieldPart
488         && style->appearance() != TextAreaPart
489         && style->appearance() != CheckboxPart
490         && style->appearance() != RadioPart
491         && style->appearance() != PushButtonPart
492         && style->appearance() != SquareButtonPart
493         && style->appearance() != ButtonPart
494         && style->appearance() != ButtonBevelPart
495         && style->appearance() != MenulistPart
496         && style->appearance() != MenulistButtonPart;
497 }
498 
499 } // namespace WebCore
500