• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "RenderThemeAndroid.h"
28 
29 #include "Color.h"
30 #include "Element.h"
31 #include "GraphicsContext.h"
32 #include "HTMLNames.h"
33 #include "HTMLOptionElement.h"
34 #include "HTMLSelectElement.h"
35 #include "Node.h"
36 #include "PlatformGraphicsContext.h"
37 #if ENABLE(VIDEO)
38 #include "RenderMediaControls.h"
39 #endif
40 #include "RenderSkinAndroid.h"
41 #include "RenderSkinMediaButton.h"
42 #include "RoundedIntRect.h"
43 #include "SkCanvas.h"
44 #include "UserAgentStyleSheets.h"
45 #include "WebCoreFrameBridge.h"
46 
47 namespace WebCore {
48 
49 // Add padding to the fontSize of ListBoxes to get their maximum sizes.
50 // Listboxes often have a specified size.  Since we change them into
51 // dropdowns, we want a much smaller height, which encompasses the text.
52 const int listboxPadding = 5;
53 
54 // This is the color of selection in a textfield.  It was computed from
55 // frameworks/base/core/res/res/values/colors.xml, which uses #9983CC39
56 // (decimal a = 153, r = 131, g = 204, b = 57)
57 // for all four highlighted text values. Blending this with white yields:
58 // R = (131 * 153 + 255 * (255 - 153)) / 255  -> 180.6
59 // G = (204 * 153 + 255 * (255 - 153)) / 255  -> 224.4
60 // B = ( 57 * 153 + 255 * (255 - 153)) / 255  -> 136.2
61 
62 const RGBA32 selectionColor = makeRGB(181, 224, 136);
63 
64 // Colors copied from the holo resources
65 const RGBA32 defaultBgColor = makeRGBA(204, 204, 204, 197);
66 const RGBA32 defaultBgBright = makeRGBA(213, 213, 213, 221);
67 const RGBA32 defaultBgDark = makeRGBA(92, 92, 92, 160);
68 const RGBA32 defaultBgMedium = makeRGBA(132, 132, 132, 111);
69 const RGBA32 defaultFgColor = makeRGBA(101, 101, 101, 225);
70 const RGBA32 defaultCheckColor = makeRGBA(154, 204, 2, 255);
71 
72 const RGBA32 disabledBgColor = makeRGBA(205, 205, 205, 107);
73 const RGBA32 disabledBgBright = makeRGBA(213, 213, 213, 133);
74 const RGBA32 disabledBgDark = makeRGBA(92, 92, 92, 96);
75 const RGBA32 disabledBgMedium = makeRGBA(132, 132, 132, 111);
76 const RGBA32 disabledFgColor = makeRGBA(148, 148, 148, 137);
77 
78 const int paddingButton = 2;
79 const int cornerButton = 2;
80 
81 // scale factors for various resolutions
82 const float scaleFactor[RenderSkinAndroid::ResolutionCount] = {
83     1.0f, // medium res
84     1.5f, // high res
85     2.0f  // extra high res
86 };
87 
88 
getCanvasFromInfo(const PaintInfo & info)89 static SkCanvas* getCanvasFromInfo(const PaintInfo& info)
90 {
91     return info.context->platformContext()->getCanvas();
92 }
93 
getWebFrame(const Node * node)94 static android::WebFrame* getWebFrame(const Node* node)
95 {
96     if (!node)
97         return 0;
98     return android::WebFrame::getWebFrame(node->document()->frame());
99 }
100 
theme()101 RenderTheme* theme()
102 {
103     DEFINE_STATIC_LOCAL(RenderThemeAndroid, androidTheme, ());
104     return &androidTheme;
105 }
106 
themeForPage(Page * page)107 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
108 {
109     static RenderTheme* rt = RenderThemeAndroid::create().releaseRef();
110     return rt;
111 }
112 
create()113 PassRefPtr<RenderTheme> RenderThemeAndroid::create()
114 {
115     return adoptRef(new RenderThemeAndroid());
116 }
117 
RenderThemeAndroid()118 RenderThemeAndroid::RenderThemeAndroid()
119 {
120 }
121 
~RenderThemeAndroid()122 RenderThemeAndroid::~RenderThemeAndroid()
123 {
124 }
125 
close()126 void RenderThemeAndroid::close()
127 {
128 }
129 
stateChanged(RenderObject * obj,ControlState state) const130 bool RenderThemeAndroid::stateChanged(RenderObject* obj, ControlState state) const
131 {
132     if (CheckedState == state) {
133         obj->repaint();
134         return true;
135     }
136     return false;
137 }
138 
platformActiveSelectionBackgroundColor() const139 Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
140 {
141     return Color(selectionColor);
142 }
143 
platformInactiveSelectionBackgroundColor() const144 Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
145 {
146     return Color(Color::transparent);
147 }
148 
platformActiveSelectionForegroundColor() const149 Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
150 {
151     return Color::black;
152 }
153 
platformInactiveSelectionForegroundColor() const154 Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
155 {
156     return Color::black;
157 }
158 
platformTextSearchHighlightColor() const159 Color RenderThemeAndroid::platformTextSearchHighlightColor() const
160 {
161     return Color(Color::transparent);
162 }
163 
platformActiveListBoxSelectionBackgroundColor() const164 Color RenderThemeAndroid::platformActiveListBoxSelectionBackgroundColor() const
165 {
166     return Color(Color::transparent);
167 }
168 
platformInactiveListBoxSelectionBackgroundColor() const169 Color RenderThemeAndroid::platformInactiveListBoxSelectionBackgroundColor() const
170 {
171     return Color(Color::transparent);
172 }
173 
platformActiveListBoxSelectionForegroundColor() const174 Color RenderThemeAndroid::platformActiveListBoxSelectionForegroundColor() const
175 {
176     return Color(Color::transparent);
177 }
178 
platformInactiveListBoxSelectionForegroundColor() const179 Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() const
180 {
181     return Color(Color::transparent);
182 }
183 
platformActiveTextSearchHighlightColor() const184 Color RenderThemeAndroid::platformActiveTextSearchHighlightColor() const
185 {
186     return Color(0x00, 0x99, 0xcc, 0x99); // HOLO_DARK
187 }
188 
platformInactiveTextSearchHighlightColor() const189 Color RenderThemeAndroid::platformInactiveTextSearchHighlightColor() const
190 {
191     return Color(0x33, 0xb5, 0xe5, 0x66); // HOLO_LIGHT
192 }
193 
baselinePosition(const RenderObject * obj) const194 int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
195 {
196     // From the description of this function in RenderTheme.h:
197     // A method to obtain the baseline position for a "leaf" control.  This will only be used if a baseline
198     // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
199     // controls that need to do this.
200     //
201     // Our checkboxes and radio buttons need to be offset to line up properly.
202     return RenderTheme::baselinePosition(obj) - 8;
203 }
204 
addIntrinsicMargins(RenderStyle * style) const205 void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
206 {
207     // Cut out the intrinsic margins completely if we end up using a small font size
208     if (style->fontSize() < 11)
209         return;
210 
211     // Intrinsic margin value.
212     const int m = 2;
213 
214     // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
215     if (style->width().isIntrinsicOrAuto()) {
216         if (style->marginLeft().quirk())
217             style->setMarginLeft(Length(m, Fixed));
218         if (style->marginRight().quirk())
219             style->setMarginRight(Length(m, Fixed));
220     }
221 
222     if (style->height().isAuto()) {
223         if (style->marginTop().quirk())
224             style->setMarginTop(Length(m, Fixed));
225         if (style->marginBottom().quirk())
226             style->setMarginBottom(Length(m, Fixed));
227     }
228 }
229 
supportsFocus(ControlPart appearance)230 bool RenderThemeAndroid::supportsFocus(ControlPart appearance)
231 {
232     switch (appearance) {
233     case PushButtonPart:
234     case ButtonPart:
235     case TextFieldPart:
236         return true;
237     default:
238         return false;
239     }
240 
241     return false;
242 }
243 
adjustButtonStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const244 void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
245 {
246 }
247 
paintCheckbox(RenderObject * obj,const PaintInfo & info,const IntRect & rect)248 bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
249 {
250     paintRadio(obj, info, rect);
251     return false;
252 }
253 
paintButton(RenderObject * obj,const PaintInfo & info,const IntRect & rect)254 bool RenderThemeAndroid::paintButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
255 {
256     // If it is a disabled button, simply paint it to the master picture.
257     Node* node = obj->node();
258     Element* formControlElement = static_cast<Element*>(node);
259     if (formControlElement) {
260         android::WebFrame* webFrame = getWebFrame(node);
261         if (webFrame) {
262             GraphicsContext *context = info.context;
263             IntRect innerrect = IntRect(rect.x() + paddingButton, rect.y() + paddingButton,
264                     rect.width() - 2 * paddingButton, rect.height() - 2 * paddingButton);
265             IntSize cornerrect = IntSize(cornerButton, cornerButton);
266             Color bg, bright, dark, medium;
267             if (formControlElement->isEnabledFormControl()) {
268                 bg = Color(defaultBgColor);
269                 bright = Color(defaultBgBright);
270                 dark = Color(defaultBgDark);
271                 medium = Color(defaultBgMedium);
272             } else {
273                 bg = Color(disabledBgColor);
274                 bright = Color(disabledBgBright);
275                 dark = Color(disabledBgDark);
276                 medium = Color(disabledBgMedium);
277             }
278             context->save();
279             context->clip(
280                     IntRect(innerrect.x(), innerrect.y(), innerrect.width(), 1));
281             context->fillRoundedRect(innerrect, cornerrect, cornerrect,
282                     cornerrect, cornerrect, bright, context->fillColorSpace());
283             context->restore();
284             context->save();
285             context->clip(IntRect(innerrect.x(), innerrect.y() + innerrect.height() - 1,
286                     innerrect.width(), 1));
287             context->fillRoundedRect(innerrect, cornerrect, cornerrect,
288                     cornerrect, cornerrect, dark, context->fillColorSpace());
289             context->restore();
290             context->save();
291             context->clip(IntRect(innerrect.x(), innerrect.y() + 1, innerrect.width(),
292                     innerrect.height() - 2));
293             context->fillRoundedRect(innerrect, cornerrect, cornerrect,
294                     cornerrect, cornerrect, bg, context->fillColorSpace());
295             context->restore();
296             context->setStrokeColor(medium, context->strokeColorSpace());
297             context->setStrokeThickness(1.0f);
298             context->drawLine(IntPoint(innerrect.x(), innerrect.y() + cornerButton),
299                     IntPoint(innerrect.x(), innerrect.y() + innerrect.height() - cornerButton));
300             context->drawLine(IntPoint(innerrect.x() + innerrect.width(), innerrect.y() + cornerButton),
301                     IntPoint(innerrect.x() + innerrect.width(), innerrect.y() + innerrect.height() - cornerButton));
302         }
303     }
304 
305 
306     // We always return false so we do not request to be redrawn.
307     return false;
308 }
309 
310 #if ENABLE(VIDEO)
311 
extraMediaControlsStyleSheet()312 String RenderThemeAndroid::extraMediaControlsStyleSheet()
313 {
314       return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet));
315 }
316 
shouldRenderMediaControlPart(ControlPart part,Element * e)317 bool RenderThemeAndroid::shouldRenderMediaControlPart(ControlPart part, Element* e)
318 {
319       HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(e);
320       switch (part) {
321       case MediaMuteButtonPart:
322           return false;
323       case MediaSeekBackButtonPart:
324       case MediaSeekForwardButtonPart:
325           return false;
326       case MediaRewindButtonPart:
327           return mediaElement->movieLoadType() != MediaPlayer::LiveStream;
328       case MediaReturnToRealtimeButtonPart:
329           return mediaElement->movieLoadType() == MediaPlayer::LiveStream;
330       case MediaFullscreenButtonPart:
331           return mediaElement->supportsFullscreen();
332       case MediaToggleClosedCaptionsButtonPart:
333           return mediaElement->hasClosedCaptions();
334       default:
335           return true;
336       }
337 }
338 
paintMediaFullscreenButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)339 bool RenderThemeAndroid::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
340 {
341       bool translucent = false;
342       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
343           translucent = true;
344       if (!getCanvasFromInfo(paintInfo))
345           return true;
346       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FULLSCREEN, translucent);
347       return false;
348 }
349 
paintMediaMuteButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)350 bool RenderThemeAndroid::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
351 {
352       bool translucent = false;
353       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
354           translucent = true;
355       if (!getCanvasFromInfo(paintInfo))
356           return true;
357       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::MUTE, translucent);
358       return false;
359 }
360 
paintMediaPlayButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)361 bool RenderThemeAndroid::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
362 {
363       bool translucent = false;
364       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
365           translucent = true;
366       if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
367           if (!getCanvasFromInfo(paintInfo))
368               return true;
369           if (btn->displayType() == MediaPlayButton)
370               RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent);
371           else
372               RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PAUSE, translucent);
373           return false;
374       }
375       return true;
376 }
377 
paintMediaSeekBackButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)378 bool RenderThemeAndroid::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
379 {
380       bool translucent = false;
381       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
382           translucent = true;
383       if (!getCanvasFromInfo(paintInfo))
384           return true;
385       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::REWIND, translucent);
386       return false;
387 }
388 
paintMediaSeekForwardButton(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)389 bool RenderThemeAndroid::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
390 {
391       bool translucent = false;
392       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
393           translucent = true;
394       if (!getCanvasFromInfo(paintInfo))
395           return true;
396       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FORWARD, translucent);
397       return false;
398 }
399 
paintMediaControlsBackground(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)400 bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
401 {
402       bool translucent = false;
403       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
404           translucent = true;
405       if (!getCanvasFromInfo(paintInfo))
406           return true;
407       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect,
408                                   RenderSkinMediaButton::BACKGROUND_SLIDER,
409                                   translucent, 0, false);
410       return false;
411 }
412 
paintMediaSliderTrack(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)413 bool RenderThemeAndroid::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
414 {
415       bool translucent = false;
416       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
417           translucent = true;
418       if (!getCanvasFromInfo(paintInfo))
419           return true;
420       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect,
421                                   RenderSkinMediaButton::SLIDER_TRACK, translucent, o);
422       return false;
423 }
424 
paintMediaSliderThumb(RenderObject * o,const PaintInfo & paintInfo,const IntRect & rect)425 bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
426 {
427       bool translucent = false;
428       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
429           translucent = true;
430       if (!getCanvasFromInfo(paintInfo))
431           return true;
432       RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect,
433                                   RenderSkinMediaButton::SLIDER_THUMB,
434                                   translucent, 0, false);
435       return false;
436 }
437 
adjustSliderThumbSize(RenderObject * o) const438 void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const
439 {
440     static const int sliderThumbWidth = RenderSkinMediaButton::sliderThumbWidth();
441     static const int sliderThumbHeight = RenderSkinMediaButton::sliderThumbHeight();
442     o->style()->setWidth(Length(sliderThumbWidth, Fixed));
443     o->style()->setHeight(Length(sliderThumbHeight, Fixed));
444 }
445 
446 #endif
447 
paintRadio(RenderObject * obj,const PaintInfo & info,const IntRect & rect)448 bool RenderThemeAndroid::paintRadio(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
449 {
450     Node* node = obj->node();
451     Element* element = static_cast<Element*>(node);
452     if (element) {
453         InputElement* input = element->toInputElement();
454         GraphicsContext* context = info.context;
455         if (!element->isEnabledFormControl()) {
456             context->setAlpha(0.5f);
457         }
458         const IntRect inner = IntRect(rect.x() - 2, rect.y() - 2, rect.width() - 4, rect.height() - 4);
459         context->setFillColor(Color(defaultBgBright), context->fillColorSpace());
460         context->setStrokeColor(Color(defaultBgBright), context->strokeColorSpace());
461         context->setStrokeThickness(1.0f);
462         if (input->isCheckbox()) {
463             context->drawRect(inner);
464         } else {
465             context->drawEllipse(inner);
466         }
467         context->setStrokeColor(Color(defaultFgColor), context->strokeColorSpace());
468         if (input->isCheckbox()) {
469             context->drawRect(IntRect(inner.x() + 2, inner.y() + 2, inner.width() -4, inner.height() - 4));
470         } else {
471             context->drawEllipse(IntRect(inner.x() + 2, inner.y() + 2, inner.width() -4, inner.height() - 4));
472         }
473         if (input->isChecked()) {
474             context->setFillColor(Color(defaultCheckColor), context->fillColorSpace());
475             context->setStrokeColor(Color(defaultCheckColor), context->strokeColorSpace());
476             if (input->isCheckbox()) {
477                 const float w2 = ((float) rect.width() / 2);
478                 const float cx = ((float) rect.x());
479                 const float cy = ((float) rect.y());
480                 context->save();
481                 // magic numbers due to weird scale in context
482                 context->translate(cx + w2 / 2.2f, cy + w2 / 1.2f);
483                 context->rotate(3.93f); // 225 degrees
484                 context->drawRect(IntRect(0, 0, rect.width() / 4, 2));
485                 context->rotate(1.57f); // 90 degrees
486                 context->drawRect(IntRect(0, 0, rect.width() / 2, 2));
487                 context->restore();
488             } else {
489                 context->drawEllipse(IntRect(inner.x() + 5, inner.y() + 5, inner.width() - 10, inner.height() - 10));
490             }
491         }
492     }
493     return false;
494 }
495 
setCheckboxSize(RenderStyle * style) const496 void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
497 {
498     style->setWidth(Length(19, Fixed));
499     style->setHeight(Length(19, Fixed));
500 }
501 
setRadioSize(RenderStyle * style) const502 void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
503 {
504     // This is the same as checkboxes.
505     setCheckboxSize(style);
506 }
507 
adjustTextFieldStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const508 void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
509 {
510     addIntrinsicMargins(style);
511 }
512 
paintTextField(RenderObject *,const PaintInfo &,const IntRect &)513 bool RenderThemeAndroid::paintTextField(RenderObject*, const PaintInfo&, const IntRect&)
514 {
515     return true;
516 }
517 
adjustTextAreaStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const518 void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
519 {
520     addIntrinsicMargins(style);
521 }
522 
paintTextArea(RenderObject * obj,const PaintInfo & info,const IntRect & rect)523 bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
524 {
525     if (obj->isMenuList())
526         paintCombo(obj, info, rect);
527     return true;
528 }
529 
adjustSearchFieldStyle(CSSStyleSelector *,RenderStyle * style,Element *) const530 void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
531 {
532     addIntrinsicMargins(style);
533 }
534 
paintSearchField(RenderObject *,const PaintInfo &,const IntRect &)535 bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const IntRect&)
536 {
537     return true;
538 }
539 
adjustMenuListStyleCommon(RenderStyle * style)540 static void adjustMenuListStyleCommon(RenderStyle* style)
541 {
542     // Added to make room for our arrow and make the touch target less cramped.
543     const int padding = (int)(scaleFactor[RenderSkinAndroid::DrawableResolution()] + 0.5f);
544     style->setPaddingLeft(Length(padding,Fixed));
545     style->setPaddingTop(Length(padding, Fixed));
546     style->setPaddingBottom(Length(padding, Fixed));
547     // allocate height as arrow size
548     int arrow = std::max(18, style->fontMetrics().height() + 2 * padding);
549     style->setPaddingRight(Length(arrow, Fixed));
550     style->setMinHeight(Length(arrow, Fixed));
551     style->setHeight(Length(arrow, Fixed));
552 }
553 
adjustListboxStyle(CSSStyleSelector *,RenderStyle * style,Element * e) const554 void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
555 {
556     adjustMenuListButtonStyle(0, style, 0);
557 }
558 
adjustMenuListStyle(CSSStyleSelector *,RenderStyle * style,Element *) const559 void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
560 {
561     adjustMenuListStyleCommon(style);
562     addIntrinsicMargins(style);
563 }
564 
paintCombo(RenderObject * obj,const PaintInfo & info,const IntRect & rect)565 bool RenderThemeAndroid::paintCombo(RenderObject* obj, const PaintInfo& info,  const IntRect& rect)
566 {
567   if (obj->style() && !obj->style()->visitedDependentColor(CSSPropertyBackgroundColor).alpha())
568         return true;
569     Node* node = obj->node();
570     Element* element = static_cast<Element*>(node);
571     if (element) {
572         InputElement* input = element->toInputElement();
573         GraphicsContext* context = info.context;
574         if (!element->isEnabledFormControl()) {
575             context->setAlpha(0.5f);
576         }
577         IntRect bounds = IntRect(rect.x(), rect.y(), rect.width(), rect.height());
578         // paint bg color
579         RenderStyle* style = obj->style();
580         context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor),
581                 context->fillColorSpace());
582         context->fillRect(FloatRect(bounds));
583         // copied form the original RenderSkinCombo:
584         // If this is an appearance where RenderTheme::paint returns true
585         // without doing anything, this means that
586         // RenderBox::PaintBoxDecorationWithSize will end up painting the
587         // border, so we shouldn't paint a border here.
588         if (style->appearance() != MenulistButtonPart &&
589                 style->appearance() != ListboxPart &&
590                 style->appearance() != TextFieldPart &&
591                 style->appearance() != TextAreaPart) {
592             const int arrowSize = bounds.height();
593             // dropdown button bg
594             context->setFillColor(Color(defaultBgColor), context->fillColorSpace());
595             context->fillRect(FloatRect(bounds.maxX() - arrowSize + 0.5f, bounds.y() + .5f,
596                     arrowSize - 1, bounds.height() - 1));
597             // outline
598             context->setStrokeThickness(1.0f);
599             context->setStrokeColor(Color(defaultBgDark), context->strokeColorSpace());
600             context->strokeRect(bounds, 1.0f);
601             // arrow
602             context->setFillColor(Color(defaultFgColor), context->fillColorSpace());
603             Path tri = Path();
604             tri.clear();
605             const float aw = arrowSize - 10;
606             FloatPoint br = FloatPoint(bounds.maxX() - 4, bounds.maxY() - 4);
607             tri.moveTo(br);
608             tri.addLineTo(FloatPoint(br.x() - aw, br.y()));
609             tri.addLineTo(FloatPoint(br.x(), br.y() - aw));
610             context->fillPath(tri);
611         }
612     }
613     return false;
614 }
615 
paintMenuList(RenderObject * obj,const PaintInfo & info,const IntRect & rect)616 bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
617 {
618     return paintCombo(obj, info, rect);
619 }
620 
adjustMenuListButtonStyle(CSSStyleSelector *,RenderStyle * style,Element *) const621 void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*,
622         RenderStyle* style, Element*) const
623 {
624     // Copied from RenderThemeSafari.
625     const float baseFontSize = 11.0f;
626     const int baseBorderRadius = 5;
627     float fontScale = style->fontSize() / baseFontSize;
628 
629     style->resetPadding();
630     style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
631 
632     const int minHeight = 15;
633     style->setMinHeight(Length(minHeight, Fixed));
634 
635     style->setLineHeight(RenderStyle::initialLineHeight());
636     // Found these padding numbers by trial and error.
637     const int padding = 4;
638     style->setPaddingTop(Length(padding, Fixed));
639     style->setPaddingLeft(Length(padding, Fixed));
640     adjustMenuListStyleCommon(style);
641 }
642 
paintMenuListButton(RenderObject * obj,const PaintInfo & info,const IntRect & rect)643 bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
644 {
645     return paintCombo(obj, info, rect);
646 }
647 
paintSliderTrack(RenderObject * o,const PaintInfo & i,const IntRect & r)648 bool RenderThemeAndroid::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
649 {
650     SkCanvas* canvas = getCanvasFromInfo(i);
651     if (!canvas)
652         return true;
653     static const bool translucent = true;
654     RenderSkinMediaButton::Draw(canvas, r,
655                                 RenderSkinMediaButton::SLIDER_TRACK,
656                                 translucent, o, false);
657     return false;
658 }
659 
paintSliderThumb(RenderObject * o,const PaintInfo & i,const IntRect & r)660 bool RenderThemeAndroid::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
661 {
662     SkCanvas* canvas = getCanvasFromInfo(i);
663     if (!canvas)
664         return true;
665     static const bool translucent = true;
666     RenderSkinMediaButton::Draw(canvas, r,
667                                 RenderSkinMediaButton::SLIDER_THUMB,
668                                 translucent, 0, false);
669     return false;
670 }
671 
platformFocusRingColor() const672 Color RenderThemeAndroid::platformFocusRingColor() const
673 {
674     static Color focusRingColor(0x33, 0xB5, 0xE5, 0x66);
675     return focusRingColor;
676 }
677 
supportsFocusRing(const RenderStyle * style) const678 bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
679 {
680     // Draw the focus ring ourselves unless it is a text area (webkit does borders better)
681     if (!style || !style->hasAppearance())
682         return true;
683     return style->appearance() != TextFieldPart && style->appearance() != TextAreaPart;
684 }
685 
686 } // namespace WebCore
687