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