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