RenderThemeAndroid.cpp revision 3718b58e4da76b7025aa5316a51264c5e38f2569
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 "RenderSkinMediaButton.h"
42#include "RenderSlider.h"
43#include "RoundedIntRect.h"
44#include "SkCanvas.h"
45#include "UserAgentStyleSheets.h"
46#include "WebCoreFrameBridge.h"
47
48namespace 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.
53const 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
63const RGBA32 selectionColor = makeRGB(181, 224, 136);
64
65// Colors copied from the holo resources
66const RGBA32 defaultBgColor = makeRGBA(204, 204, 204, 197);
67const RGBA32 defaultBgBright = makeRGBA(213, 213, 213, 221);
68const RGBA32 defaultBgDark = makeRGBA(92, 92, 92, 160);
69const RGBA32 defaultBgMedium = makeRGBA(132, 132, 132, 111);
70const RGBA32 defaultFgColor = makeRGBA(101, 101, 101, 225);
71const RGBA32 defaultCheckColor = makeRGBA(154, 204, 2, 255);
72
73const RGBA32 disabledBgColor = makeRGBA(205, 205, 205, 107);
74const RGBA32 disabledBgBright = makeRGBA(213, 213, 213, 133);
75const RGBA32 disabledBgDark = makeRGBA(92, 92, 92, 96);
76const RGBA32 disabledBgMedium = makeRGBA(132, 132, 132, 111);
77const RGBA32 disabledFgColor = makeRGBA(148, 148, 148, 137);
78
79const int paddingButton = 2;
80const int cornerButton = 2;
81
82// scale factors for various resolutions
83const float scaleFactor[RenderSkinAndroid::ResolutionCount] = {
84    1.0f, // medium res
85    1.5f, // high res
86    2.0f  // extra high res
87};
88
89static android::WebFrame* getWebFrame(const Node* node)
90{
91    if (!node)
92        return 0;
93    return android::WebFrame::getWebFrame(node->document()->frame());
94}
95
96RenderTheme* theme()
97{
98    DEFINE_STATIC_LOCAL(RenderThemeAndroid, androidTheme, ());
99    return &androidTheme;
100}
101
102PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
103{
104    static RenderTheme* rt = RenderThemeAndroid::create().releaseRef();
105    return rt;
106}
107
108PassRefPtr<RenderTheme> RenderThemeAndroid::create()
109{
110    return adoptRef(new RenderThemeAndroid());
111}
112
113RenderThemeAndroid::RenderThemeAndroid()
114{
115}
116
117RenderThemeAndroid::~RenderThemeAndroid()
118{
119}
120
121void RenderThemeAndroid::close()
122{
123}
124
125bool RenderThemeAndroid::stateChanged(RenderObject* obj, ControlState state) const
126{
127    if (CheckedState == state) {
128        obj->repaint();
129        return true;
130    }
131    return false;
132}
133
134Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
135{
136    return Color(selectionColor);
137}
138
139Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
140{
141    return Color(Color::transparent);
142}
143
144Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
145{
146    return Color::black;
147}
148
149Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
150{
151    return Color::black;
152}
153
154Color RenderThemeAndroid::platformTextSearchHighlightColor() const
155{
156    return Color(Color::transparent);
157}
158
159Color RenderThemeAndroid::platformActiveListBoxSelectionBackgroundColor() const
160{
161    return Color(Color::transparent);
162}
163
164Color RenderThemeAndroid::platformInactiveListBoxSelectionBackgroundColor() const
165{
166    return Color(Color::transparent);
167}
168
169Color RenderThemeAndroid::platformActiveListBoxSelectionForegroundColor() const
170{
171    return Color(Color::transparent);
172}
173
174Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() const
175{
176    return Color(Color::transparent);
177}
178
179Color RenderThemeAndroid::platformActiveTextSearchHighlightColor() const
180{
181    return Color(0x00, 0x99, 0xcc, 0x99); // HOLO_DARK
182}
183
184Color RenderThemeAndroid::platformInactiveTextSearchHighlightColor() const
185{
186    return Color(0x33, 0xb5, 0xe5, 0x66); // HOLO_LIGHT
187}
188
189int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
190{
191    // From the description of this function in RenderTheme.h:
192    // A method to obtain the baseline position for a "leaf" control.  This will only be used if a baseline
193    // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
194    // controls that need to do this.
195    //
196    // Our checkboxes and radio buttons need to be offset to line up properly.
197    return RenderTheme::baselinePosition(obj) - 8;
198}
199
200void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
201{
202    // Cut out the intrinsic margins completely if we end up using a small font size
203    if (style->fontSize() < 11)
204        return;
205
206    // Intrinsic margin value.
207    const int m = 2;
208
209    // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
210    if (style->width().isIntrinsicOrAuto()) {
211        if (style->marginLeft().quirk())
212            style->setMarginLeft(Length(m, Fixed));
213        if (style->marginRight().quirk())
214            style->setMarginRight(Length(m, Fixed));
215    }
216
217    if (style->height().isAuto()) {
218        if (style->marginTop().quirk())
219            style->setMarginTop(Length(m, Fixed));
220        if (style->marginBottom().quirk())
221            style->setMarginBottom(Length(m, Fixed));
222    }
223}
224
225bool RenderThemeAndroid::supportsFocus(ControlPart appearance)
226{
227    switch (appearance) {
228    case PushButtonPart:
229    case ButtonPart:
230    case TextFieldPart:
231        return true;
232    default:
233        return false;
234    }
235
236    return false;
237}
238
239void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
240{
241}
242
243bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
244{
245    paintRadio(obj, info, rect);
246    return false;
247}
248
249bool RenderThemeAndroid::paintButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
250{
251    // If it is a disabled button, simply paint it to the master picture.
252    Node* node = obj->node();
253    Element* formControlElement = static_cast<Element*>(node);
254    if (formControlElement) {
255        android::WebFrame* webFrame = getWebFrame(node);
256        if (webFrame) {
257            GraphicsContext *context = info.context;
258            IntRect innerrect = IntRect(rect.x() + paddingButton, rect.y() + paddingButton,
259                    rect.width() - 2 * paddingButton, rect.height() - 2 * paddingButton);
260            IntSize cornerrect = IntSize(cornerButton, cornerButton);
261            Color bg, bright, dark, medium;
262            if (formControlElement->isEnabledFormControl()) {
263                bg = Color(defaultBgColor);
264                bright = Color(defaultBgBright);
265                dark = Color(defaultBgDark);
266                medium = Color(defaultBgMedium);
267            } else {
268                bg = Color(disabledBgColor);
269                bright = Color(disabledBgBright);
270                dark = Color(disabledBgDark);
271                medium = Color(disabledBgMedium);
272            }
273            context->save();
274            context->clip(
275                    IntRect(innerrect.x(), innerrect.y(), innerrect.width(), 1));
276            context->fillRoundedRect(innerrect, cornerrect, cornerrect,
277                    cornerrect, cornerrect, bright, context->fillColorSpace());
278            context->restore();
279            context->save();
280            context->clip(IntRect(innerrect.x(), innerrect.y() + innerrect.height() - 1,
281                    innerrect.width(), 1));
282            context->fillRoundedRect(innerrect, cornerrect, cornerrect,
283                    cornerrect, cornerrect, dark, context->fillColorSpace());
284            context->restore();
285            context->save();
286            context->clip(IntRect(innerrect.x(), innerrect.y() + 1, innerrect.width(),
287                    innerrect.height() - 2));
288            context->fillRoundedRect(innerrect, cornerrect, cornerrect,
289                    cornerrect, cornerrect, bg, context->fillColorSpace());
290            context->restore();
291            context->setStrokeColor(medium, context->strokeColorSpace());
292            context->setStrokeThickness(1.0f);
293            context->drawLine(IntPoint(innerrect.x(), innerrect.y() + cornerButton),
294                    IntPoint(innerrect.x(), innerrect.y() + innerrect.height() - cornerButton));
295            context->drawLine(IntPoint(innerrect.x() + innerrect.width(), innerrect.y() + cornerButton),
296                    IntPoint(innerrect.x() + innerrect.width(), innerrect.y() + innerrect.height() - cornerButton));
297        }
298    }
299
300
301    // We always return false so we do not request to be redrawn.
302    return false;
303}
304
305#if ENABLE(VIDEO)
306
307String RenderThemeAndroid::extraMediaControlsStyleSheet()
308{
309      return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet));
310}
311
312bool RenderThemeAndroid::shouldRenderMediaControlPart(ControlPart part, Element* e)
313{
314      HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(e);
315      switch (part) {
316      case MediaMuteButtonPart:
317          return false;
318      case MediaSeekBackButtonPart:
319      case MediaSeekForwardButtonPart:
320          return false;
321      case MediaRewindButtonPart:
322          return mediaElement->movieLoadType() != MediaPlayer::LiveStream;
323      case MediaReturnToRealtimeButtonPart:
324          return mediaElement->movieLoadType() == MediaPlayer::LiveStream;
325      case MediaFullscreenButtonPart:
326          return mediaElement->supportsFullscreen();
327      case MediaToggleClosedCaptionsButtonPart:
328          return mediaElement->hasClosedCaptions();
329      default:
330          return true;
331      }
332}
333
334bool RenderThemeAndroid::paintMediaFullscreenButton(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      paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::FULLSCREEN, translucent);
340      return false;
341}
342
343bool RenderThemeAndroid::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
344{
345      bool translucent = false;
346      if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
347          translucent = true;
348      paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::MUTE, translucent);
349      return false;
350}
351
352bool RenderThemeAndroid::paintMediaPlayButton(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      if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
358          if (btn->displayType() == MediaPlayButton)
359              paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::PLAY, translucent);
360          else
361              paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::PAUSE, translucent);
362          return false;
363      }
364      return true;
365}
366
367bool RenderThemeAndroid::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
368{
369      bool translucent = false;
370      if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
371          translucent = true;
372      paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::REWIND, translucent);
373      return false;
374}
375
376bool RenderThemeAndroid::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
377{
378      bool translucent = false;
379      if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
380          translucent = true;
381      paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::FORWARD, translucent);
382      return false;
383}
384
385bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
386{
387      bool translucent = false;
388      if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
389          translucent = true;
390      paintInfo.context->platformContext()->drawMediaButton(rect,
391                                  RenderSkinMediaButton::BACKGROUND_SLIDER,
392                                  translucent, false);
393      return false;
394}
395
396bool RenderThemeAndroid::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
397{
398      bool translucent = false;
399      if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
400          translucent = true;
401      IntRect thumb;
402      if (o && o->isSlider())
403          thumb = toRenderSlider(o)->thumbRect();
404      paintInfo.context->platformContext()->drawMediaButton(rect,
405                                  RenderSkinMediaButton::SLIDER_TRACK, translucent, true, thumb);
406      return false;
407}
408
409bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
410{
411      bool translucent = false;
412      if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
413          translucent = true;
414      paintInfo.context->platformContext()->drawMediaButton(rect,
415                                  RenderSkinMediaButton::SLIDER_THUMB,
416                                  translucent, false);
417      return false;
418}
419
420void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const
421{
422    static const int sliderThumbWidth = RenderSkinMediaButton::sliderThumbWidth();
423    static const int sliderThumbHeight = RenderSkinMediaButton::sliderThumbHeight();
424    o->style()->setWidth(Length(sliderThumbWidth, Fixed));
425    o->style()->setHeight(Length(sliderThumbHeight, Fixed));
426}
427
428#endif
429
430bool RenderThemeAndroid::paintRadio(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
431{
432    Node* node = obj->node();
433    Element* element = static_cast<Element*>(node);
434    if (element) {
435        InputElement* input = element->toInputElement();
436        GraphicsContext* context = info.context;
437        if (!element->isEnabledFormControl()) {
438            context->setAlpha(0.5f);
439        }
440        const IntRect inner = IntRect(rect.x() - 2, rect.y() - 2, rect.width() - 4, rect.height() - 4);
441        context->setFillColor(Color(defaultBgBright), context->fillColorSpace());
442        context->setStrokeColor(Color(defaultBgBright), context->strokeColorSpace());
443        context->setStrokeThickness(1.0f);
444        if (input->isCheckbox()) {
445            context->drawRect(inner);
446        } else {
447            context->drawEllipse(inner);
448        }
449        context->setStrokeColor(Color(defaultFgColor), context->strokeColorSpace());
450        if (input->isCheckbox()) {
451            context->drawRect(IntRect(inner.x() + 2, inner.y() + 2, inner.width() -4, inner.height() - 4));
452        } else {
453            context->drawEllipse(IntRect(inner.x() + 2, inner.y() + 2, inner.width() -4, inner.height() - 4));
454        }
455        if (input->isChecked()) {
456            context->setFillColor(Color(defaultCheckColor), context->fillColorSpace());
457            context->setStrokeColor(Color(defaultCheckColor), context->strokeColorSpace());
458            if (input->isCheckbox()) {
459                const float w2 = ((float) rect.width() / 2);
460                const float cx = ((float) rect.x());
461                const float cy = ((float) rect.y());
462                context->save();
463                // magic numbers due to weird scale in context
464                context->translate(cx + w2 / 2.2f, cy + w2 / 1.2f);
465                context->rotate(3.93f); // 225 degrees
466                context->drawRect(IntRect(0, 0, rect.width() / 4, 2));
467                context->rotate(1.57f); // 90 degrees
468                context->drawRect(IntRect(0, 0, rect.width() / 2, 2));
469                context->restore();
470            } else {
471                context->drawEllipse(IntRect(inner.x() + 5, inner.y() + 5, inner.width() - 10, inner.height() - 10));
472            }
473        }
474    }
475    return false;
476}
477
478void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
479{
480    style->setWidth(Length(19, Fixed));
481    style->setHeight(Length(19, Fixed));
482}
483
484void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
485{
486    // This is the same as checkboxes.
487    setCheckboxSize(style);
488}
489
490void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
491{
492    addIntrinsicMargins(style);
493}
494
495bool RenderThemeAndroid::paintTextField(RenderObject*, const PaintInfo&, const IntRect&)
496{
497    return true;
498}
499
500void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
501{
502    addIntrinsicMargins(style);
503}
504
505bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
506{
507    if (obj->isMenuList())
508        paintCombo(obj, info, rect);
509    return true;
510}
511
512void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
513{
514    addIntrinsicMargins(style);
515}
516
517bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const IntRect&)
518{
519    return true;
520}
521
522static void adjustMenuListStyleCommon(RenderStyle* style)
523{
524    // Added to make room for our arrow and make the touch target less cramped.
525    const int padding = (int)(scaleFactor[RenderSkinAndroid::DrawableResolution()] + 0.5f);
526    style->setPaddingLeft(Length(padding,Fixed));
527    style->setPaddingTop(Length(padding, Fixed));
528    style->setPaddingBottom(Length(padding, Fixed));
529    // allocate height as arrow size
530    int arrow = std::max(18, style->fontMetrics().height() + 2 * padding);
531    style->setPaddingRight(Length(arrow, Fixed));
532    style->setMinHeight(Length(arrow, Fixed));
533    style->setHeight(Length(arrow, Fixed));
534}
535
536void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
537{
538    adjustMenuListButtonStyle(0, style, 0);
539}
540
541void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
542{
543    adjustMenuListStyleCommon(style);
544    addIntrinsicMargins(style);
545}
546
547bool RenderThemeAndroid::paintCombo(RenderObject* obj, const PaintInfo& info,  const IntRect& rect)
548{
549  if (obj->style() && !obj->style()->visitedDependentColor(CSSPropertyBackgroundColor).alpha())
550        return true;
551    Node* node = obj->node();
552    Element* element = static_cast<Element*>(node);
553    if (element) {
554        InputElement* input = element->toInputElement();
555        GraphicsContext* context = info.context;
556        if (!element->isEnabledFormControl()) {
557            context->setAlpha(0.5f);
558        }
559        IntRect bounds = IntRect(rect.x(), rect.y(), rect.width(), rect.height());
560        // paint bg color
561        RenderStyle* style = obj->style();
562        context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor),
563                context->fillColorSpace());
564        context->fillRect(FloatRect(bounds));
565        // copied form the original RenderSkinCombo:
566        // If this is an appearance where RenderTheme::paint returns true
567        // without doing anything, this means that
568        // RenderBox::PaintBoxDecorationWithSize will end up painting the
569        // border, so we shouldn't paint a border here.
570        if (style->appearance() != MenulistButtonPart &&
571                style->appearance() != ListboxPart &&
572                style->appearance() != TextFieldPart &&
573                style->appearance() != TextAreaPart) {
574            const int arrowSize = bounds.height();
575            // dropdown button bg
576            context->setFillColor(Color(defaultBgColor), context->fillColorSpace());
577            context->fillRect(FloatRect(bounds.maxX() - arrowSize + 0.5f, bounds.y() + .5f,
578                    arrowSize - 1, bounds.height() - 1));
579            // outline
580            context->setStrokeThickness(1.0f);
581            context->setStrokeColor(Color(defaultBgDark), context->strokeColorSpace());
582            context->strokeRect(bounds, 1.0f);
583            // arrow
584            context->setFillColor(Color(defaultFgColor), context->fillColorSpace());
585            Path tri = Path();
586            tri.clear();
587            const float aw = arrowSize - 10;
588            FloatPoint br = FloatPoint(bounds.maxX() - 4, bounds.maxY() - 4);
589            tri.moveTo(br);
590            tri.addLineTo(FloatPoint(br.x() - aw, br.y()));
591            tri.addLineTo(FloatPoint(br.x(), br.y() - aw));
592            context->fillPath(tri);
593        }
594    }
595    return false;
596}
597
598bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
599{
600    return paintCombo(obj, info, rect);
601}
602
603void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*,
604        RenderStyle* style, Element*) const
605{
606    // Copied from RenderThemeSafari.
607    const float baseFontSize = 11.0f;
608    const int baseBorderRadius = 5;
609    float fontScale = style->fontSize() / baseFontSize;
610
611    style->resetPadding();
612    style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
613
614    const int minHeight = 15;
615    style->setMinHeight(Length(minHeight, Fixed));
616
617    style->setLineHeight(RenderStyle::initialLineHeight());
618    // Found these padding numbers by trial and error.
619    const int padding = 4;
620    style->setPaddingTop(Length(padding, Fixed));
621    style->setPaddingLeft(Length(padding, Fixed));
622    adjustMenuListStyleCommon(style);
623}
624
625bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
626{
627    return paintCombo(obj, info, rect);
628}
629
630bool RenderThemeAndroid::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
631{
632    static const bool translucent = true;
633    i.context->platformContext()->drawMediaButton(r,
634                                RenderSkinMediaButton::SLIDER_TRACK,
635                                translucent, false);
636    return false;
637}
638
639bool RenderThemeAndroid::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
640{
641    static const bool translucent = true;
642    i.context->platformContext()->drawMediaButton(r,
643                                RenderSkinMediaButton::SLIDER_THUMB,
644                                translucent, false);
645    return false;
646}
647
648Color RenderThemeAndroid::platformFocusRingColor() const
649{
650    static Color focusRingColor(0x33, 0xB5, 0xE5, 0x66);
651    return focusRingColor;
652}
653
654bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
655{
656    // Draw the focus ring ourselves unless it is a text area (webkit does borders better)
657    if (!style || !style->hasAppearance())
658        return true;
659    return style->appearance() != TextFieldPart && style->appearance() != TextAreaPart;
660}
661
662} // namespace WebCore
663