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