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