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