• 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 "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 
getWebFrame(const Node * node)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
drawLineForBoxSide(GraphicsContext * graphicsContext,int x1,int y1,int x2,int y2,BoxSide side,Color color,int adjacentWidth1,int adjacentWidth2)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 
theme()148 RenderTheme* theme()
149 {
150     DEFINE_STATIC_LOCAL(RenderThemeAndroid, androidTheme, ());
151     return &androidTheme;
152 }
153 
themeForPage(Page * page)154 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
155 {
156     static RenderTheme* rt = RenderThemeAndroid::create().releaseRef();
157     return rt;
158 }
159 
create()160 PassRefPtr<RenderTheme> RenderThemeAndroid::create()
161 {
162     return adoptRef(new RenderThemeAndroid());
163 }
164 
RenderThemeAndroid()165 RenderThemeAndroid::RenderThemeAndroid()
166 {
167 }
168 
~RenderThemeAndroid()169 RenderThemeAndroid::~RenderThemeAndroid()
170 {
171 }
172 
close()173 void RenderThemeAndroid::close()
174 {
175 }
176 
stateChanged(RenderObject * obj,ControlState state) const177 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 
platformActiveSelectionBackgroundColor() const186 Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
187 {
188     return Color(selectionColor);
189 }
190 
platformInactiveSelectionBackgroundColor() const191 Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
192 {
193     return Color(Color::transparent);
194 }
195 
platformActiveSelectionForegroundColor() const196 Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
197 {
198     return Color::black;
199 }
200 
platformInactiveSelectionForegroundColor() const201 Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
202 {
203     return Color::black;
204 }
205 
platformTextSearchHighlightColor() const206 Color RenderThemeAndroid::platformTextSearchHighlightColor() const
207 {
208     return Color(Color::transparent);
209 }
210 
platformActiveListBoxSelectionBackgroundColor() const211 Color RenderThemeAndroid::platformActiveListBoxSelectionBackgroundColor() const
212 {
213     return Color(Color::transparent);
214 }
215 
platformInactiveListBoxSelectionBackgroundColor() const216 Color RenderThemeAndroid::platformInactiveListBoxSelectionBackgroundColor() const
217 {
218     return Color(Color::transparent);
219 }
220 
platformActiveListBoxSelectionForegroundColor() const221 Color RenderThemeAndroid::platformActiveListBoxSelectionForegroundColor() const
222 {
223     return Color(Color::transparent);
224 }
225 
platformInactiveListBoxSelectionForegroundColor() const226 Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() const
227 {
228     return Color(Color::transparent);
229 }
230 
platformActiveTextSearchHighlightColor() const231 Color RenderThemeAndroid::platformActiveTextSearchHighlightColor() const
232 {
233     return Color(0x00, 0x99, 0xcc, 0x99); // HOLO_DARK
234 }
235 
platformInactiveTextSearchHighlightColor() const236 Color RenderThemeAndroid::platformInactiveTextSearchHighlightColor() const
237 {
238     return Color(0x33, 0xb5, 0xe5, 0x66); // HOLO_LIGHT
239 }
240 
baselinePosition(const RenderObject * obj) const241 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 
addIntrinsicMargins(RenderStyle * style) const252 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 
supportsFocus(ControlPart appearance)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 
adjustButtonStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const291 void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
292 {
293 }
294 
paintCheckbox(RenderObject * obj,const PaintInfo & info,const IntRect & rect)295 bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
296 {
297     paintRadio(obj, info, rect);
298     return false;
299 }
300 
paintButton(RenderObject * obj,const PaintInfo & info,const IntRect & rect)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 
extraMediaControlsStyleSheet()349 String RenderThemeAndroid::extraMediaControlsStyleSheet()
350 {
351       return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet));
352 }
353 
shouldRenderMediaControlPart(ControlPart part,Element * e)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 
paintMediaFullscreenButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
paintMediaMuteButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
paintMediaPlayButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
paintMediaSeekBackButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
paintMediaSeekForwardButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
paintMediaControlsBackground(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
paintMediaSliderTrack(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
paintMediaSliderThumb(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)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 
adjustSliderThumbSize(RenderObject * o) const462 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 
paintRadio(RenderObject * obj,const PaintInfo & info,const IntRect & rect)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 
setCheckboxSize(RenderStyle * style) const537 void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
538 {
539     style->setWidth(Length(19, Fixed));
540     style->setHeight(Length(19, Fixed));
541 }
542 
setRadioSize(RenderStyle * style) const543 void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
544 {
545     // This is the same as checkboxes.
546     setCheckboxSize(style);
547 }
548 
adjustTextFieldStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const549 void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
550 {
551     addIntrinsicMargins(style);
552 }
553 
paintTextField(RenderObject *,const PaintInfo &,const IntRect &)554 bool RenderThemeAndroid::paintTextField(RenderObject*, const PaintInfo&, const IntRect&)
555 {
556     return true;
557 }
558 
adjustTextAreaStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const559 void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
560 {
561     addIntrinsicMargins(style);
562 }
563 
paintTextArea(RenderObject * obj,const PaintInfo & info,const IntRect & rect)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 
adjustSearchFieldStyle(CSSStyleSelector *,RenderStyle * style,Element *) const571 void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
572 {
573     addIntrinsicMargins(style);
574 }
575 
paintSearchField(RenderObject *,const PaintInfo &,const IntRect &)576 bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const IntRect&)
577 {
578     return true;
579 }
580 
adjustMenuListStyleCommon(RenderStyle * style)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 
adjustListboxStyle(CSSStyleSelector *,RenderStyle * style,Element * e) const595 void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
596 {
597     adjustMenuListButtonStyle(0, style, 0);
598 }
599 
adjustMenuListStyle(CSSStyleSelector *,RenderStyle * style,Element *) const600 void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
601 {
602     adjustMenuListStyleCommon(style);
603     addIntrinsicMargins(style);
604 }
605 
paintCombo(RenderObject * obj,const PaintInfo & info,const IntRect & rect)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 
paintMenuList(RenderObject * obj,const PaintInfo & info,const IntRect & rect)659 bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
660 {
661     return paintCombo(obj, info, rect);
662 }
663 
adjustMenuListButtonStyle(CSSStyleSelector *,RenderStyle * style,Element *) const664 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 
paintMenuListButton(RenderObject * obj,const PaintInfo & info,const IntRect & rect)686 bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
687 {
688     return paintCombo(obj, info, rect);
689 }
690 
paintSliderTrack(RenderObject * o,const PaintInfo & i,const IntRect & r)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 
paintSliderThumb(RenderObject * o,const PaintInfo & i,const IntRect & r)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 
platformFocusRingColor() const709 Color RenderThemeAndroid::platformFocusRingColor() const
710 {
711     static Color focusRingColor(0x33, 0xB5, 0xE5, 0x66);
712     return focusRingColor;
713 }
714 
supportsFocusRing(const RenderStyle * style) const715 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