2 * Copyright 2009, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "RenderThemeAndroid.h"
31 #include "GraphicsContext.h"
32 #include "HTMLNames.h"
33 #include "HTMLOptionElement.h"
34 #include "HTMLSelectElement.h"
36 #include "PlatformGraphicsContext.h"
38 #include "RenderMediaControls.h"
40 #include "RenderSkinAndroid.h"
41 #include "RenderSkinButton.h"
42 #include "RenderSkinCombo.h"
43 #include "RenderSkinMediaButton.h"
44 #include "RenderSkinRadio.h"
46 #include "UserAgentStyleSheets.h"
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;
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
63 const RGBA32 selectionColor = makeRGB(181, 224, 136);
65 static SkCanvas* getCanvasFromInfo(const PaintInfo& info)
67 return info.context->platformContext()->mCanvas;
72 DEFINE_STATIC_LOCAL(RenderThemeAndroid, androidTheme, ());
76 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
78 static RenderTheme* rt = RenderThemeAndroid::create().releaseRef();
82 PassRefPtr<RenderTheme> RenderThemeAndroid::create()
84 return adoptRef(new RenderThemeAndroid());
87 RenderThemeAndroid::RenderThemeAndroid()
91 RenderThemeAndroid::~RenderThemeAndroid()
95 void RenderThemeAndroid::close()
99 bool RenderThemeAndroid::stateChanged(RenderObject* obj, ControlState state) const
101 if (CheckedState == state) {
108 Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
110 return Color(selectionColor);
113 Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
115 return Color(Color::transparent);
118 Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
123 Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
128 Color RenderThemeAndroid::platformTextSearchHighlightColor() const
130 return Color(Color::transparent);
133 Color RenderThemeAndroid::platformActiveListBoxSelectionBackgroundColor() const
135 return Color(Color::transparent);
138 Color RenderThemeAndroid::platformInactiveListBoxSelectionBackgroundColor() const
140 return Color(Color::transparent);
143 Color RenderThemeAndroid::platformActiveListBoxSelectionForegroundColor() const
145 return Color(Color::transparent);
148 Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() const
150 return Color(Color::transparent);
153 int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
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.
160 // Our checkboxes and radio buttons need to be offset to line up properly.
161 return RenderTheme::baselinePosition(obj) - 2;
164 void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
166 // Cut out the intrinsic margins completely if we end up using a small font size
167 if (style->fontSize() < 11)
170 // Intrinsic margin value.
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));
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));
189 bool RenderThemeAndroid::supportsFocus(ControlPart appearance)
191 switch (appearance) {
203 void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
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));
211 // Set a min-height so that we can't get smaller than the mini button.
212 style->setMinHeight(Length(15, Fixed));
215 bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
217 RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, true);
221 bool RenderThemeAndroid::paintButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
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);
229 // Store all the important information in the platform context.
230 info.context->platformContext()->storeButtonInfo(node, rect);
232 // We always return false so we do not request to be redrawn.
238 String RenderThemeAndroid::extraMediaControlsStyleSheet()
240 return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet));
243 bool RenderThemeAndroid::shouldRenderMediaControlPart(ControlPart part, Element* e)
245 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(e);
247 case MediaMuteButtonPart:
249 case MediaSeekBackButtonPart:
250 case MediaSeekForwardButtonPart:
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();
265 bool paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
267 bool translucent = false;
268 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
270 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent);
274 bool RenderThemeAndroid::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
276 bool translucent = false;
277 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
279 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::MUTE, translucent);
283 bool RenderThemeAndroid::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
285 bool translucent = false;
286 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
288 if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
289 if (btn->displayType() == MediaPlayButton)
290 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent);
292 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PAUSE, translucent);
298 bool RenderThemeAndroid::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
300 bool translucent = false;
301 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
303 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::REWIND, translucent);
307 bool RenderThemeAndroid::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
309 bool translucent = false;
310 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
312 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FORWARD, translucent);
316 bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
318 bool translucent = false;
319 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
321 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::BACKGROUND_SLIDER, translucent);
325 bool RenderThemeAndroid::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
327 bool translucent = false;
328 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
330 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_TRACK, translucent);
334 bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
336 bool translucent = false;
337 if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
339 RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_THUMB, translucent);
343 void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const
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));
355 bool RenderThemeAndroid::paintRadio(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
357 RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, false);
361 void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
363 style->setWidth(Length(19, Fixed));
364 style->setHeight(Length(19, Fixed));
367 void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
369 // This is the same as checkboxes.
370 setCheckboxSize(style);
373 void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
375 addIntrinsicMargins(style);
378 bool RenderThemeAndroid::paintTextField(RenderObject*, const PaintInfo&, const IntRect&)
383 void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
385 addIntrinsicMargins(style);
388 bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
390 if (obj->isMenuList())
391 paintCombo(obj, info, rect);
395 void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
397 addIntrinsicMargins(style);
400 bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const IntRect&)
405 static void adjustMenuListStyleCommon(RenderStyle* style)
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));
414 void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
416 adjustMenuListButtonStyle(0, style, 0);
419 void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
421 adjustMenuListStyleCommon(style);
422 addIntrinsicMargins(style);
425 bool RenderThemeAndroid::paintCombo(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
427 if (obj->style() && !obj->style()->visitedDependentColor(CSSPropertyBackgroundColor).alpha())
429 return RenderSkinCombo::Draw(getCanvasFromInfo(info), obj->node(), rect.x(), rect.y(), rect.width(), rect.height());
432 bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
434 return paintCombo(obj, info, rect);
437 void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*,
438 RenderStyle* style, Element*) const
440 // Copied from RenderThemeSafari.
441 const float baseFontSize = 11.0f;
442 const int baseBorderRadius = 5;
443 float fontScale = style->fontSize() / baseFontSize;
445 style->resetPadding();
446 style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
448 const int minHeight = 15;
449 style->setMinHeight(Length(minHeight, Fixed));
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);
459 bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
461 return paintCombo(obj, info, rect);
464 bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
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;
481 } // namespace WebCore