1 /** 2 * This file is part of the theme implementation for form controls in WebCore. 3 * 4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Computer, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22 #include "config.h" 23 #include "core/rendering/RenderTheme.h" 24 25 #include "core/CSSValueKeywords.h" 26 #include "core/HTMLNames.h" 27 #include "core/InputTypeNames.h" 28 #include "core/dom/Document.h" 29 #include "core/dom/shadow/ElementShadow.h" 30 #include "core/editing/FrameSelection.h" 31 #include "core/fileapi/FileList.h" 32 #include "core/frame/LocalFrame.h" 33 #include "core/html/HTMLCollection.h" 34 #include "core/html/HTMLDataListElement.h" 35 #include "core/html/HTMLFormControlElement.h" 36 #include "core/html/HTMLInputElement.h" 37 #include "core/html/HTMLMeterElement.h" 38 #include "core/html/HTMLOptionElement.h" 39 #include "core/html/parser/HTMLParserIdioms.h" 40 #include "core/html/shadow/MediaControlElements.h" 41 #include "core/html/shadow/ShadowElementNames.h" 42 #include "core/html/shadow/SpinButtonElement.h" 43 #include "core/html/shadow/TextControlInnerElements.h" 44 #include "core/page/FocusController.h" 45 #include "core/page/Page.h" 46 #include "core/frame/Settings.h" 47 #include "core/rendering/PaintInfo.h" 48 #include "core/rendering/RenderMeter.h" 49 #include "core/rendering/RenderView.h" 50 #include "core/rendering/style/RenderStyle.h" 51 #include "platform/FileMetadata.h" 52 #include "platform/FloatConversion.h" 53 #include "platform/RuntimeEnabledFeatures.h" 54 #include "platform/fonts/FontSelector.h" 55 #include "platform/graphics/GraphicsContextStateSaver.h" 56 #include "platform/text/PlatformLocale.h" 57 #include "platform/text/StringTruncator.h" 58 #include "public/platform/Platform.h" 59 #include "public/platform/WebFallbackThemeEngine.h" 60 #include "public/platform/WebRect.h" 61 #include "wtf/text/StringBuilder.h" 62 63 // The methods in this file are shared by all themes on every platform. 64 65 namespace WebCore { 66 67 using namespace HTMLNames; 68 69 static blink::WebFallbackThemeEngine::State getWebFallbackThemeState(const RenderTheme* theme, const RenderObject* o) 70 { 71 if (!theme->isEnabled(o)) 72 return blink::WebFallbackThemeEngine::StateDisabled; 73 if (theme->isPressed(o)) 74 return blink::WebFallbackThemeEngine::StatePressed; 75 if (theme->isHovered(o)) 76 return blink::WebFallbackThemeEngine::StateHover; 77 78 return blink::WebFallbackThemeEngine::StateNormal; 79 } 80 81 RenderTheme::RenderTheme() 82 : m_hasCustomFocusRingColor(false) 83 #if USE(NEW_THEME) 84 , m_platformTheme(platformTheme()) 85 #endif 86 { 87 } 88 89 void RenderTheme::adjustStyle(RenderStyle* style, Element* e, const CachedUAStyle* uaStyle) 90 { 91 // Force inline and table display styles to be inline-block (except for table- which is block) 92 ControlPart part = style->appearance(); 93 if (style->display() == INLINE || style->display() == INLINE_TABLE || style->display() == TABLE_ROW_GROUP 94 || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_FOOTER_GROUP 95 || style->display() == TABLE_ROW || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_COLUMN 96 || style->display() == TABLE_CELL || style->display() == TABLE_CAPTION) 97 style->setDisplay(INLINE_BLOCK); 98 else if (style->display() == LIST_ITEM || style->display() == TABLE) 99 style->setDisplay(BLOCK); 100 101 if (uaStyle && uaStyle->hasAppearance && isControlStyled(style, uaStyle)) { 102 if (part == MenulistPart) { 103 style->setAppearance(MenulistButtonPart); 104 part = MenulistButtonPart; 105 } else 106 style->setAppearance(NoControlPart); 107 } 108 109 if (!style->hasAppearance()) 110 return; 111 112 if (shouldUseFallbackTheme(style)) { 113 adjustStyleUsingFallbackTheme(style, e); 114 return; 115 } 116 117 #if USE(NEW_THEME) 118 switch (part) { 119 case CheckboxPart: 120 case InnerSpinButtonPart: 121 case RadioPart: 122 case PushButtonPart: 123 case SquareButtonPart: 124 case ButtonPart: { 125 // Border 126 LengthBox borderBox(style->borderTopWidth(), style->borderRightWidth(), style->borderBottomWidth(), style->borderLeftWidth()); 127 borderBox = m_platformTheme->controlBorder(part, style->font().fontDescription(), borderBox, style->effectiveZoom()); 128 if (borderBox.top().value() != static_cast<int>(style->borderTopWidth())) { 129 if (borderBox.top().value()) 130 style->setBorderTopWidth(borderBox.top().value()); 131 else 132 style->resetBorderTop(); 133 } 134 if (borderBox.right().value() != static_cast<int>(style->borderRightWidth())) { 135 if (borderBox.right().value()) 136 style->setBorderRightWidth(borderBox.right().value()); 137 else 138 style->resetBorderRight(); 139 } 140 if (borderBox.bottom().value() != static_cast<int>(style->borderBottomWidth())) { 141 style->setBorderBottomWidth(borderBox.bottom().value()); 142 if (borderBox.bottom().value()) 143 style->setBorderBottomWidth(borderBox.bottom().value()); 144 else 145 style->resetBorderBottom(); 146 } 147 if (borderBox.left().value() != static_cast<int>(style->borderLeftWidth())) { 148 style->setBorderLeftWidth(borderBox.left().value()); 149 if (borderBox.left().value()) 150 style->setBorderLeftWidth(borderBox.left().value()); 151 else 152 style->resetBorderLeft(); 153 } 154 155 // Padding 156 LengthBox paddingBox = m_platformTheme->controlPadding(part, style->font().fontDescription(), style->paddingBox(), style->effectiveZoom()); 157 if (paddingBox != style->paddingBox()) 158 style->setPaddingBox(paddingBox); 159 160 // Whitespace 161 if (m_platformTheme->controlRequiresPreWhiteSpace(part)) 162 style->setWhiteSpace(PRE); 163 164 // Width / Height 165 // The width and height here are affected by the zoom. 166 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. 167 LengthSize controlSize = m_platformTheme->controlSize(part, style->font().fontDescription(), LengthSize(style->width(), style->height()), style->effectiveZoom()); 168 if (controlSize.width() != style->width()) 169 style->setWidth(controlSize.width()); 170 if (controlSize.height() != style->height()) 171 style->setHeight(controlSize.height()); 172 173 // Min-Width / Min-Height 174 LengthSize minControlSize = m_platformTheme->minimumControlSize(part, style->font().fontDescription(), style->effectiveZoom()); 175 if (minControlSize.width() != style->minWidth()) 176 style->setMinWidth(minControlSize.width()); 177 if (minControlSize.height() != style->minHeight()) 178 style->setMinHeight(minControlSize.height()); 179 180 // Font 181 FontDescription controlFont = m_platformTheme->controlFont(part, style->font().fontDescription(), style->effectiveZoom()); 182 if (controlFont != style->font().fontDescription()) { 183 // Reset our line-height 184 style->setLineHeight(RenderStyle::initialLineHeight()); 185 186 // Now update our font. 187 if (style->setFontDescription(controlFont)) 188 style->font().update(nullptr); 189 } 190 } 191 default: 192 break; 193 } 194 #endif 195 196 // Call the appropriate style adjustment method based off the appearance value. 197 switch (style->appearance()) { 198 #if !USE(NEW_THEME) 199 case CheckboxPart: 200 return adjustCheckboxStyle(style, e); 201 case RadioPart: 202 return adjustRadioStyle(style, e); 203 case PushButtonPart: 204 case SquareButtonPart: 205 case ButtonPart: 206 return adjustButtonStyle(style, e); 207 case InnerSpinButtonPart: 208 return adjustInnerSpinButtonStyle(style, e); 209 #endif 210 case MenulistPart: 211 return adjustMenuListStyle(style, e); 212 case MenulistButtonPart: 213 return adjustMenuListButtonStyle(style, e); 214 case SliderThumbHorizontalPart: 215 case SliderThumbVerticalPart: 216 return adjustSliderThumbStyle(style, e); 217 case SearchFieldPart: 218 return adjustSearchFieldStyle(style, e); 219 case SearchFieldCancelButtonPart: 220 return adjustSearchFieldCancelButtonStyle(style, e); 221 case SearchFieldDecorationPart: 222 return adjustSearchFieldDecorationStyle(style, e); 223 case SearchFieldResultsDecorationPart: 224 return adjustSearchFieldResultsDecorationStyle(style, e); 225 default: 226 break; 227 } 228 } 229 230 bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 231 { 232 // If painting is disabled, but we aren't updating control tints, then just bail. 233 // If we are updating control tints, just schedule a repaint if the theme supports tinting 234 // for that control. 235 if (paintInfo.context->updatingControlTints()) { 236 if (controlSupportsTints(o)) 237 o->paintInvalidationForWholeRenderer(); 238 return false; 239 } 240 ControlPart part = o->style()->appearance(); 241 242 if (shouldUseFallbackTheme(o->style())) 243 return paintUsingFallbackTheme(o, paintInfo, r); 244 245 #if USE(NEW_THEME) 246 switch (part) { 247 case CheckboxPart: 248 case RadioPart: 249 case PushButtonPart: 250 case SquareButtonPart: 251 case ButtonPart: 252 case InnerSpinButtonPart: 253 m_platformTheme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView()); 254 return false; 255 default: 256 break; 257 } 258 #endif 259 260 // Call the appropriate paint method based off the appearance value. 261 switch (part) { 262 #if !USE(NEW_THEME) 263 case CheckboxPart: 264 return paintCheckbox(o, paintInfo, r); 265 case RadioPart: 266 return paintRadio(o, paintInfo, r); 267 case PushButtonPart: 268 case SquareButtonPart: 269 case ButtonPart: 270 return paintButton(o, paintInfo, r); 271 case InnerSpinButtonPart: 272 return paintInnerSpinButton(o, paintInfo, r); 273 #endif 274 case MenulistPart: 275 return paintMenuList(o, paintInfo, r); 276 case MeterPart: 277 case RelevancyLevelIndicatorPart: 278 case ContinuousCapacityLevelIndicatorPart: 279 case DiscreteCapacityLevelIndicatorPart: 280 case RatingLevelIndicatorPart: 281 return paintMeter(o, paintInfo, r); 282 case ProgressBarPart: 283 return paintProgressBar(o, paintInfo, r); 284 case SliderHorizontalPart: 285 case SliderVerticalPart: 286 return paintSliderTrack(o, paintInfo, r); 287 case SliderThumbHorizontalPart: 288 case SliderThumbVerticalPart: 289 return paintSliderThumb(o, paintInfo, r); 290 case MediaEnterFullscreenButtonPart: 291 case MediaExitFullscreenButtonPart: 292 return paintMediaFullscreenButton(o, paintInfo, r); 293 case MediaPlayButtonPart: 294 return paintMediaPlayButton(o, paintInfo, r); 295 case MediaOverlayPlayButtonPart: 296 return paintMediaOverlayPlayButton(o, paintInfo, r); 297 case MediaMuteButtonPart: 298 return paintMediaMuteButton(o, paintInfo, r); 299 case MediaToggleClosedCaptionsButtonPart: 300 return paintMediaToggleClosedCaptionsButton(o, paintInfo, r); 301 case MediaSliderPart: 302 return paintMediaSliderTrack(o, paintInfo, r); 303 case MediaSliderThumbPart: 304 return paintMediaSliderThumb(o, paintInfo, r); 305 case MediaVolumeSliderContainerPart: 306 return paintMediaVolumeSliderContainer(o, paintInfo, r); 307 case MediaVolumeSliderPart: 308 return paintMediaVolumeSliderTrack(o, paintInfo, r); 309 case MediaVolumeSliderThumbPart: 310 return paintMediaVolumeSliderThumb(o, paintInfo, r); 311 case MediaFullScreenVolumeSliderPart: 312 return paintMediaFullScreenVolumeSliderTrack(o, paintInfo, r); 313 case MediaFullScreenVolumeSliderThumbPart: 314 return paintMediaFullScreenVolumeSliderThumb(o, paintInfo, r); 315 case MediaTimeRemainingPart: 316 return paintMediaTimeRemaining(o, paintInfo, r); 317 case MediaCurrentTimePart: 318 return paintMediaCurrentTime(o, paintInfo, r); 319 case MediaControlsBackgroundPart: 320 return paintMediaControlsBackground(o, paintInfo, r); 321 case MenulistButtonPart: 322 case TextFieldPart: 323 case TextAreaPart: 324 case ListboxPart: 325 return true; 326 case SearchFieldPart: 327 return paintSearchField(o, paintInfo, r); 328 case SearchFieldCancelButtonPart: 329 return paintSearchFieldCancelButton(o, paintInfo, r); 330 case SearchFieldDecorationPart: 331 return paintSearchFieldDecoration(o, paintInfo, r); 332 case SearchFieldResultsDecorationPart: 333 return paintSearchFieldResultsDecoration(o, paintInfo, r); 334 default: 335 break; 336 } 337 338 return true; // We don't support the appearance, so let the normal background/border paint. 339 } 340 341 bool RenderTheme::paintBorderOnly(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 342 { 343 // Call the appropriate paint method based off the appearance value. 344 switch (o->style()->appearance()) { 345 case TextFieldPart: 346 return paintTextField(o, paintInfo, r); 347 case ListboxPart: 348 case TextAreaPart: 349 return paintTextArea(o, paintInfo, r); 350 case MenulistButtonPart: 351 case SearchFieldPart: 352 return true; 353 case CheckboxPart: 354 case RadioPart: 355 case PushButtonPart: 356 case SquareButtonPart: 357 case ButtonPart: 358 case MenulistPart: 359 case MeterPart: 360 case RelevancyLevelIndicatorPart: 361 case ContinuousCapacityLevelIndicatorPart: 362 case DiscreteCapacityLevelIndicatorPart: 363 case RatingLevelIndicatorPart: 364 case ProgressBarPart: 365 case SliderHorizontalPart: 366 case SliderVerticalPart: 367 case SliderThumbHorizontalPart: 368 case SliderThumbVerticalPart: 369 case SearchFieldCancelButtonPart: 370 case SearchFieldDecorationPart: 371 case SearchFieldResultsDecorationPart: 372 default: 373 break; 374 } 375 376 return false; 377 } 378 379 bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 380 { 381 // Call the appropriate paint method based off the appearance value. 382 switch (o->style()->appearance()) { 383 case MenulistButtonPart: 384 return paintMenuListButton(o, paintInfo, r); 385 case TextFieldPart: 386 case TextAreaPart: 387 case ListboxPart: 388 case CheckboxPart: 389 case RadioPart: 390 case PushButtonPart: 391 case SquareButtonPart: 392 case ButtonPart: 393 case MenulistPart: 394 case MeterPart: 395 case RelevancyLevelIndicatorPart: 396 case ContinuousCapacityLevelIndicatorPart: 397 case DiscreteCapacityLevelIndicatorPart: 398 case RatingLevelIndicatorPart: 399 case ProgressBarPart: 400 case SliderHorizontalPart: 401 case SliderVerticalPart: 402 case SliderThumbHorizontalPart: 403 case SliderThumbVerticalPart: 404 case SearchFieldPart: 405 case SearchFieldCancelButtonPart: 406 case SearchFieldDecorationPart: 407 case SearchFieldResultsDecorationPart: 408 default: 409 break; 410 } 411 412 return false; 413 } 414 415 String RenderTheme::extraDefaultStyleSheet() 416 { 417 StringBuilder runtimeCSS; 418 if (RuntimeEnabledFeatures::dialogElementEnabled()) { 419 runtimeCSS.appendLiteral("dialog:not([open]) { display: none; }"); 420 runtimeCSS.appendLiteral("dialog { position: absolute; left: 0; right: 0; width: -webkit-fit-content; height: -webkit-fit-content; margin: auto; border: solid; padding: 1em; background: white; color: black;}"); 421 runtimeCSS.appendLiteral("dialog::backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0,0,0,0.1); }"); 422 } 423 424 return runtimeCSS.toString(); 425 } 426 427 String RenderTheme::formatMediaControlsTime(float time) const 428 { 429 if (!std::isfinite(time)) 430 time = 0; 431 int seconds = (int)fabsf(time); 432 int hours = seconds / (60 * 60); 433 int minutes = (seconds / 60) % 60; 434 seconds %= 60; 435 if (hours) { 436 if (hours > 9) 437 return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); 438 439 return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); 440 } 441 442 return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds); 443 } 444 445 String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*duration*/) const 446 { 447 return formatMediaControlsTime(currentTime); 448 } 449 450 Color RenderTheme::activeSelectionBackgroundColor() const 451 { 452 return platformActiveSelectionBackgroundColor().blendWithWhite(); 453 } 454 455 Color RenderTheme::inactiveSelectionBackgroundColor() const 456 { 457 return platformInactiveSelectionBackgroundColor().blendWithWhite(); 458 } 459 460 Color RenderTheme::activeSelectionForegroundColor() const 461 { 462 return platformActiveSelectionForegroundColor(); 463 } 464 465 Color RenderTheme::inactiveSelectionForegroundColor() const 466 { 467 return platformInactiveSelectionForegroundColor(); 468 } 469 470 Color RenderTheme::activeListBoxSelectionBackgroundColor() const 471 { 472 return platformActiveListBoxSelectionBackgroundColor(); 473 } 474 475 Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const 476 { 477 return platformInactiveListBoxSelectionBackgroundColor(); 478 } 479 480 Color RenderTheme::activeListBoxSelectionForegroundColor() const 481 { 482 return platformActiveListBoxSelectionForegroundColor(); 483 } 484 485 Color RenderTheme::inactiveListBoxSelectionForegroundColor() const 486 { 487 return platformInactiveListBoxSelectionForegroundColor(); 488 } 489 490 Color RenderTheme::platformActiveSelectionBackgroundColor() const 491 { 492 // Use a blue color by default if the platform theme doesn't define anything. 493 return Color(0, 0, 255); 494 } 495 496 Color RenderTheme::platformActiveSelectionForegroundColor() const 497 { 498 // Use a white color by default if the platform theme doesn't define anything. 499 return Color::white; 500 } 501 502 Color RenderTheme::platformInactiveSelectionBackgroundColor() const 503 { 504 // Use a grey color by default if the platform theme doesn't define anything. 505 // This color matches Firefox's inactive color. 506 return Color(176, 176, 176); 507 } 508 509 Color RenderTheme::platformInactiveSelectionForegroundColor() const 510 { 511 // Use a black color by default. 512 return Color::black; 513 } 514 515 Color RenderTheme::platformActiveListBoxSelectionBackgroundColor() const 516 { 517 return platformActiveSelectionBackgroundColor(); 518 } 519 520 Color RenderTheme::platformActiveListBoxSelectionForegroundColor() const 521 { 522 return platformActiveSelectionForegroundColor(); 523 } 524 525 Color RenderTheme::platformInactiveListBoxSelectionBackgroundColor() const 526 { 527 return platformInactiveSelectionBackgroundColor(); 528 } 529 530 Color RenderTheme::platformInactiveListBoxSelectionForegroundColor() const 531 { 532 return platformInactiveSelectionForegroundColor(); 533 } 534 535 int RenderTheme::baselinePosition(const RenderObject* o) const 536 { 537 if (!o->isBox()) 538 return 0; 539 540 const RenderBox* box = toRenderBox(o); 541 542 #if USE(NEW_THEME) 543 return box->height() + box->marginTop() + m_platformTheme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom(); 544 #else 545 return box->height() + box->marginTop(); 546 #endif 547 } 548 549 bool RenderTheme::isControlContainer(ControlPart appearance) const 550 { 551 // There are more leaves than this, but we'll patch this function as we add support for 552 // more controls. 553 return appearance != CheckboxPart && appearance != RadioPart; 554 } 555 556 static bool isBackgroundOrBorderStyled(const RenderStyle& style, const CachedUAStyle& uaStyle) 557 { 558 // Code below excludes the background-repeat from comparison by resetting it 559 FillLayer backgroundCopy = uaStyle.backgroundLayers; 560 FillLayer backgroundLayersCopy = *style.backgroundLayers(); 561 backgroundCopy.setRepeatX(NoRepeatFill); 562 backgroundCopy.setRepeatY(NoRepeatFill); 563 backgroundLayersCopy.setRepeatX(NoRepeatFill); 564 backgroundLayersCopy.setRepeatY(NoRepeatFill); 565 // Test the style to see if the UA border and background match. 566 return style.border() != uaStyle.border 567 || backgroundLayersCopy != backgroundCopy 568 || style.visitedDependentColor(CSSPropertyBackgroundColor) != uaStyle.backgroundColor; 569 } 570 571 bool RenderTheme::isControlStyled(const RenderStyle* style, const CachedUAStyle* uaStyle) const 572 { 573 ASSERT(uaStyle); 574 575 switch (style->appearance()) { 576 case PushButtonPart: 577 case SquareButtonPart: 578 case ButtonPart: 579 case ProgressBarPart: 580 case MeterPart: 581 case RelevancyLevelIndicatorPart: 582 case ContinuousCapacityLevelIndicatorPart: 583 case DiscreteCapacityLevelIndicatorPart: 584 case RatingLevelIndicatorPart: 585 return isBackgroundOrBorderStyled(*style, *uaStyle); 586 587 case ListboxPart: 588 case MenulistPart: 589 case SearchFieldPart: 590 case TextAreaPart: 591 case TextFieldPart: 592 return isBackgroundOrBorderStyled(*style, *uaStyle) || style->boxShadow(); 593 594 case SliderHorizontalPart: 595 case SliderVerticalPart: 596 return style->boxShadow(); 597 598 default: 599 return false; 600 } 601 } 602 603 void RenderTheme::adjustRepaintRect(const RenderObject* o, IntRect& r) 604 { 605 #if USE(NEW_THEME) 606 m_platformTheme->inflateControlPaintRect(o->style()->appearance(), controlStatesForRenderer(o), r, o->style()->effectiveZoom()); 607 #endif 608 } 609 610 bool RenderTheme::shouldDrawDefaultFocusRing(RenderObject* renderer) const 611 { 612 if (supportsFocusRing(renderer->style())) 613 return false; 614 if (!renderer->style()->hasAppearance()) 615 return true; 616 Node* node = renderer->node(); 617 if (!node) 618 return true; 619 // We can't use RenderTheme::isFocused because outline:auto might be 620 // specified to non-:focus rulesets. 621 if (node->focused() && !node->shouldHaveFocusAppearance()) 622 return false; 623 return true; 624 } 625 626 bool RenderTheme::supportsFocusRing(const RenderStyle* style) const 627 { 628 return (style->hasAppearance() && style->appearance() != TextFieldPart && style->appearance() != TextAreaPart && style->appearance() != MenulistButtonPart && style->appearance() != ListboxPart); 629 } 630 631 bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const 632 { 633 // Default implementation assumes the controls don't respond to changes in :hover state 634 if (state == HoverControlState && !supportsHover(o->style())) 635 return false; 636 637 // Assume pressed state is only responded to if the control is enabled. 638 if (state == PressedControlState && !isEnabled(o)) 639 return false; 640 641 // Repaint the control. 642 o->paintInvalidationForWholeRenderer(); 643 return true; 644 } 645 646 ControlStates RenderTheme::controlStatesForRenderer(const RenderObject* o) const 647 { 648 ControlStates result = 0; 649 if (isHovered(o)) { 650 result |= HoverControlState; 651 if (isSpinUpButtonPartHovered(o)) 652 result |= SpinUpControlState; 653 } 654 if (isPressed(o)) { 655 result |= PressedControlState; 656 if (isSpinUpButtonPartPressed(o)) 657 result |= SpinUpControlState; 658 } 659 if (isFocused(o) && o->style()->outlineStyleIsAuto()) 660 result |= FocusControlState; 661 if (isEnabled(o)) 662 result |= EnabledControlState; 663 if (isChecked(o)) 664 result |= CheckedControlState; 665 if (isReadOnlyControl(o)) 666 result |= ReadOnlyControlState; 667 if (!isActive(o)) 668 result |= WindowInactiveControlState; 669 if (isIndeterminate(o)) 670 result |= IndeterminateControlState; 671 return result; 672 } 673 674 bool RenderTheme::isActive(const RenderObject* o) const 675 { 676 Node* node = o->node(); 677 if (!node) 678 return false; 679 680 Page* page = node->document().page(); 681 if (!page) 682 return false; 683 684 return page->focusController().isActive(); 685 } 686 687 bool RenderTheme::isChecked(const RenderObject* o) const 688 { 689 if (!isHTMLInputElement(o->node())) 690 return false; 691 return toHTMLInputElement(o->node())->shouldAppearChecked(); 692 } 693 694 bool RenderTheme::isIndeterminate(const RenderObject* o) const 695 { 696 if (!isHTMLInputElement(o->node())) 697 return false; 698 return toHTMLInputElement(o->node())->shouldAppearIndeterminate(); 699 } 700 701 bool RenderTheme::isEnabled(const RenderObject* o) const 702 { 703 Node* node = o->node(); 704 if (!node || !node->isElementNode()) 705 return true; 706 return !toElement(node)->isDisabledFormControl(); 707 } 708 709 bool RenderTheme::isFocused(const RenderObject* o) const 710 { 711 Node* node = o->node(); 712 if (!node) 713 return false; 714 715 node = node->focusDelegate(); 716 Document& document = node->document(); 717 LocalFrame* frame = document.frame(); 718 return node == document.focusedElement() && node->focused() && node->shouldHaveFocusAppearance() && frame && frame->selection().isFocusedAndActive(); 719 } 720 721 bool RenderTheme::isPressed(const RenderObject* o) const 722 { 723 if (!o->node()) 724 return false; 725 return o->node()->active(); 726 } 727 728 bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject* o) const 729 { 730 Node* node = o->node(); 731 if (!node || !node->active() || !node->isElementNode() 732 || !toElement(node)->isSpinButtonElement()) 733 return false; 734 SpinButtonElement* element = toSpinButtonElement(node); 735 return element->upDownState() == SpinButtonElement::Up; 736 } 737 738 bool RenderTheme::isReadOnlyControl(const RenderObject* o) const 739 { 740 Node* node = o->node(); 741 if (!node || !node->isElementNode() || !toElement(node)->isFormControlElement()) 742 return false; 743 HTMLFormControlElement* element = toHTMLFormControlElement(node); 744 return element->isReadOnly(); 745 } 746 747 bool RenderTheme::isHovered(const RenderObject* o) const 748 { 749 Node* node = o->node(); 750 if (!node) 751 return false; 752 if (!node->isElementNode() || !toElement(node)->isSpinButtonElement()) 753 return node->hovered(); 754 SpinButtonElement* element = toSpinButtonElement(node); 755 return element->hovered() && element->upDownState() != SpinButtonElement::Indeterminate; 756 } 757 758 bool RenderTheme::isSpinUpButtonPartHovered(const RenderObject* o) const 759 { 760 Node* node = o->node(); 761 if (!node || !node->isElementNode() || !toElement(node)->isSpinButtonElement()) 762 return false; 763 SpinButtonElement* element = toSpinButtonElement(node); 764 return element->upDownState() == SpinButtonElement::Up; 765 } 766 767 #if !USE(NEW_THEME) 768 769 void RenderTheme::adjustCheckboxStyle(RenderStyle* style, Element*) const 770 { 771 // A summary of the rules for checkbox designed to match WinIE: 772 // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.) 773 // font-size - not honored (control has no text), but we use it to decide which control size to use. 774 setCheckboxSize(style); 775 776 // padding - not honored by WinIE, needs to be removed. 777 style->resetPadding(); 778 779 // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme) 780 // for now, we will not honor it. 781 style->resetBorder(); 782 } 783 784 void RenderTheme::adjustRadioStyle(RenderStyle* style, Element*) const 785 { 786 // A summary of the rules for checkbox designed to match WinIE: 787 // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.) 788 // font-size - not honored (control has no text), but we use it to decide which control size to use. 789 setRadioSize(style); 790 791 // padding - not honored by WinIE, needs to be removed. 792 style->resetPadding(); 793 794 // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme) 795 // for now, we will not honor it. 796 style->resetBorder(); 797 } 798 799 void RenderTheme::adjustButtonStyle(RenderStyle* style, Element*) const 800 { 801 } 802 803 void RenderTheme::adjustInnerSpinButtonStyle(RenderStyle*, Element*) const 804 { 805 } 806 #endif 807 808 void RenderTheme::adjustMenuListStyle(RenderStyle*, Element*) const 809 { 810 } 811 812 IntSize RenderTheme::meterSizeForBounds(const RenderMeter*, const IntRect& bounds) const 813 { 814 return bounds.size(); 815 } 816 817 bool RenderTheme::supportsMeter(ControlPart) const 818 { 819 return false; 820 } 821 822 bool RenderTheme::paintMeter(RenderObject*, const PaintInfo&, const IntRect&) 823 { 824 return true; 825 } 826 827 void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect) 828 { 829 Node* node = o->node(); 830 if (!isHTMLInputElement(node)) 831 return; 832 833 HTMLInputElement* input = toHTMLInputElement(node); 834 if (!input->isRangeControl()) 835 return; 836 837 HTMLDataListElement* dataList = input->dataList(); 838 if (!dataList) 839 return; 840 841 double min = input->minimum(); 842 double max = input->maximum(); 843 ControlPart part = o->style()->appearance(); 844 // We don't support ticks on alternate sliders like MediaVolumeSliders. 845 if (part != SliderHorizontalPart && part != SliderVerticalPart) 846 return; 847 bool isHorizontal = part == SliderHorizontalPart; 848 849 IntSize thumbSize; 850 RenderObject* thumbRenderer = input->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderThumb())->renderer(); 851 if (thumbRenderer) { 852 RenderStyle* thumbStyle = thumbRenderer->style(); 853 int thumbWidth = thumbStyle->width().intValue(); 854 int thumbHeight = thumbStyle->height().intValue(); 855 thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight); 856 thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth); 857 } 858 859 IntSize tickSize = sliderTickSize(); 860 float zoomFactor = o->style()->effectiveZoom(); 861 FloatRect tickRect; 862 int tickRegionSideMargin = 0; 863 int tickRegionWidth = 0; 864 IntRect trackBounds; 865 RenderObject* trackRenderer = input->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderTrack())->renderer(); 866 // We can ignoring transforms because transform is handled by the graphics context. 867 if (trackRenderer) 868 trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms(); 869 IntRect sliderBounds = o->absoluteBoundingBoxRectIgnoringTransforms(); 870 871 // Make position relative to the transformed ancestor element. 872 trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x()); 873 trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y()); 874 875 if (isHorizontal) { 876 tickRect.setWidth(floor(tickSize.width() * zoomFactor)); 877 tickRect.setHeight(floor(tickSize.height() * zoomFactor)); 878 tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); 879 tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; 880 tickRegionWidth = trackBounds.width() - thumbSize.width(); 881 } else { 882 tickRect.setWidth(floor(tickSize.height() * zoomFactor)); 883 tickRect.setHeight(floor(tickSize.width() * zoomFactor)); 884 tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); 885 tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; 886 tickRegionWidth = trackBounds.height() - thumbSize.width(); 887 } 888 RefPtrWillBeRawPtr<HTMLCollection> options = dataList->options(); 889 GraphicsContextStateSaver stateSaver(*paintInfo.context); 890 paintInfo.context->setFillColor(o->resolveColor(CSSPropertyColor)); 891 for (unsigned i = 0; Element* element = options->item(i); i++) { 892 ASSERT(isHTMLOptionElement(*element)); 893 HTMLOptionElement& optionElement = toHTMLOptionElement(*element); 894 String value = optionElement.value(); 895 if (!input->isValidValue(value)) 896 continue; 897 double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value)); 898 double tickFraction = (parsedValue - min) / (max - min); 899 double tickRatio = isHorizontal && o->style()->isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction; 900 double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio); 901 if (isHorizontal) 902 tickRect.setX(tickPosition); 903 else 904 tickRect.setY(tickPosition); 905 paintInfo.context->fillRect(tickRect); 906 } 907 } 908 909 double RenderTheme::animationRepeatIntervalForProgressBar(RenderProgress*) const 910 { 911 return 0; 912 } 913 914 double RenderTheme::animationDurationForProgressBar(RenderProgress*) const 915 { 916 return 0; 917 } 918 919 bool RenderTheme::shouldHaveSpinButton(HTMLInputElement* inputElement) const 920 { 921 return inputElement->isSteppable() && !inputElement->isRangeControl(); 922 } 923 924 void RenderTheme::adjustMenuListButtonStyle(RenderStyle*, Element*) const 925 { 926 } 927 928 void RenderTheme::adjustSliderThumbStyle(RenderStyle* style, Element* element) const 929 { 930 adjustSliderThumbSize(style, element); 931 } 932 933 void RenderTheme::adjustSliderThumbSize(RenderStyle*, Element*) const 934 { 935 } 936 937 void RenderTheme::adjustSearchFieldStyle(RenderStyle*, Element*) const 938 { 939 } 940 941 void RenderTheme::adjustSearchFieldCancelButtonStyle(RenderStyle*, Element*) const 942 { 943 } 944 945 void RenderTheme::adjustSearchFieldDecorationStyle(RenderStyle*, Element*) const 946 { 947 } 948 949 void RenderTheme::adjustSearchFieldResultsDecorationStyle(RenderStyle*, Element*) const 950 { 951 } 952 953 void RenderTheme::platformColorsDidChange() 954 { 955 Page::scheduleForcedStyleRecalcForAllPages(); 956 } 957 958 Color RenderTheme::systemColor(CSSValueID cssValueId) const 959 { 960 switch (cssValueId) { 961 case CSSValueActiveborder: 962 return 0xFFFFFFFF; 963 case CSSValueActivecaption: 964 return 0xFFCCCCCC; 965 case CSSValueAppworkspace: 966 return 0xFFFFFFFF; 967 case CSSValueBackground: 968 return 0xFF6363CE; 969 case CSSValueButtonface: 970 return 0xFFC0C0C0; 971 case CSSValueButtonhighlight: 972 return 0xFFDDDDDD; 973 case CSSValueButtonshadow: 974 return 0xFF888888; 975 case CSSValueButtontext: 976 return 0xFF000000; 977 case CSSValueCaptiontext: 978 return 0xFF000000; 979 case CSSValueGraytext: 980 return 0xFF808080; 981 case CSSValueHighlight: 982 return 0xFFB5D5FF; 983 case CSSValueHighlighttext: 984 return 0xFF000000; 985 case CSSValueInactiveborder: 986 return 0xFFFFFFFF; 987 case CSSValueInactivecaption: 988 return 0xFFFFFFFF; 989 case CSSValueInactivecaptiontext: 990 return 0xFF7F7F7F; 991 case CSSValueInfobackground: 992 return 0xFFFBFCC5; 993 case CSSValueInfotext: 994 return 0xFF000000; 995 case CSSValueMenu: 996 return 0xFFC0C0C0; 997 case CSSValueMenutext: 998 return 0xFF000000; 999 case CSSValueScrollbar: 1000 return 0xFFFFFFFF; 1001 case CSSValueText: 1002 return 0xFF000000; 1003 case CSSValueThreeddarkshadow: 1004 return 0xFF666666; 1005 case CSSValueThreedface: 1006 return 0xFFC0C0C0; 1007 case CSSValueThreedhighlight: 1008 return 0xFFDDDDDD; 1009 case CSSValueThreedlightshadow: 1010 return 0xFFC0C0C0; 1011 case CSSValueThreedshadow: 1012 return 0xFF888888; 1013 case CSSValueWindow: 1014 return 0xFFFFFFFF; 1015 case CSSValueWindowframe: 1016 return 0xFFCCCCCC; 1017 case CSSValueWindowtext: 1018 return 0xFF000000; 1019 case CSSValueInternalActiveListBoxSelection: 1020 return activeListBoxSelectionBackgroundColor(); 1021 break; 1022 case CSSValueInternalActiveListBoxSelectionText: 1023 return activeListBoxSelectionForegroundColor(); 1024 break; 1025 case CSSValueInternalInactiveListBoxSelection: 1026 return inactiveListBoxSelectionBackgroundColor(); 1027 break; 1028 case CSSValueInternalInactiveListBoxSelectionText: 1029 return inactiveListBoxSelectionForegroundColor(); 1030 break; 1031 default: 1032 break; 1033 } 1034 ASSERT_NOT_REACHED(); 1035 return Color(); 1036 } 1037 1038 Color RenderTheme::platformActiveTextSearchHighlightColor() const 1039 { 1040 return Color(255, 150, 50); // Orange. 1041 } 1042 1043 Color RenderTheme::platformInactiveTextSearchHighlightColor() const 1044 { 1045 return Color(255, 255, 0); // Yellow. 1046 } 1047 1048 Color RenderTheme::tapHighlightColor() 1049 { 1050 return theme().platformTapHighlightColor(); 1051 } 1052 1053 void RenderTheme::setCustomFocusRingColor(const Color& c) 1054 { 1055 m_customFocusRingColor = c; 1056 m_hasCustomFocusRingColor = true; 1057 } 1058 1059 Color RenderTheme::focusRingColor() const 1060 { 1061 return m_hasCustomFocusRingColor ? m_customFocusRingColor : theme().platformFocusRingColor(); 1062 } 1063 1064 String RenderTheme::fileListNameForWidth(Locale& locale, const FileList* fileList, const Font& font, int width) const 1065 { 1066 if (width <= 0) 1067 return String(); 1068 1069 String string; 1070 if (fileList->isEmpty()) { 1071 string = locale.queryString(blink::WebLocalizedString::FileButtonNoFileSelectedLabel); 1072 } else if (fileList->length() == 1) { 1073 string = fileList->item(0)->name(); 1074 } else { 1075 // FIXME: Localization of fileList->length(). 1076 return StringTruncator::rightTruncate(locale.queryString(blink::WebLocalizedString::MultipleFileUploadText, String::number(fileList->length())), width, font, StringTruncator::EnableRoundingHacks); 1077 } 1078 1079 return StringTruncator::centerTruncate(string, width, font, StringTruncator::EnableRoundingHacks); 1080 } 1081 1082 bool RenderTheme::shouldOpenPickerWithF4Key() const 1083 { 1084 return false; 1085 } 1086 1087 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 1088 bool RenderTheme::supportsCalendarPicker(const AtomicString& type) const 1089 { 1090 return type == InputTypeNames::date 1091 || type == InputTypeNames::datetime 1092 || type == InputTypeNames::datetime_local 1093 || type == InputTypeNames::month 1094 || type == InputTypeNames::week; 1095 } 1096 #endif 1097 1098 bool RenderTheme::shouldUseFallbackTheme(RenderStyle*) const 1099 { 1100 return false; 1101 } 1102 1103 void RenderTheme::adjustStyleUsingFallbackTheme(RenderStyle* style, Element* e) 1104 { 1105 ControlPart part = style->appearance(); 1106 switch (part) { 1107 case CheckboxPart: 1108 return adjustCheckboxStyleUsingFallbackTheme(style, e); 1109 case RadioPart: 1110 return adjustRadioStyleUsingFallbackTheme(style, e); 1111 default: 1112 break; 1113 } 1114 } 1115 1116 bool RenderTheme::paintUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r) 1117 { 1118 ControlPart part = o->style()->appearance(); 1119 switch (part) { 1120 case CheckboxPart: 1121 return paintCheckboxUsingFallbackTheme(o, i, r); 1122 case RadioPart: 1123 return paintRadioUsingFallbackTheme(o, i, r); 1124 default: 1125 break; 1126 } 1127 return true; 1128 } 1129 1130 // static 1131 void RenderTheme::setSizeIfAuto(RenderStyle* style, const IntSize& size) 1132 { 1133 if (style->width().isIntrinsicOrAuto()) 1134 style->setWidth(Length(size.width(), Fixed)); 1135 if (style->height().isAuto()) 1136 style->setHeight(Length(size.height(), Fixed)); 1137 } 1138 1139 bool RenderTheme::paintCheckboxUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r) 1140 { 1141 if (i.context->paintingDisabled()) 1142 return false; 1143 blink::WebFallbackThemeEngine::ExtraParams extraParams; 1144 blink::WebCanvas* canvas = i.context->canvas(); 1145 extraParams.button.checked = isChecked(o); 1146 extraParams.button.indeterminate = isIndeterminate(o); 1147 1148 float zoomLevel = o->style()->effectiveZoom(); 1149 GraphicsContextStateSaver stateSaver(*i.context); 1150 IntRect unzoomedRect = r; 1151 if (zoomLevel != 1) { 1152 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); 1153 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); 1154 i.context->translate(unzoomedRect.x(), unzoomedRect.y()); 1155 i.context->scale(zoomLevel, zoomLevel); 1156 i.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); 1157 } 1158 1159 blink::Platform::current()->fallbackThemeEngine()->paint(canvas, blink::WebFallbackThemeEngine::PartCheckbox, getWebFallbackThemeState(this, o), blink::WebRect(unzoomedRect), &extraParams); 1160 return false; 1161 } 1162 1163 void RenderTheme::adjustCheckboxStyleUsingFallbackTheme(RenderStyle* style, Element*) const 1164 { 1165 // If the width and height are both specified, then we have nothing to do. 1166 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 1167 return; 1168 1169 IntSize size = blink::Platform::current()->fallbackThemeEngine()->getSize(blink::WebFallbackThemeEngine::PartCheckbox); 1170 float zoomLevel = style->effectiveZoom(); 1171 size.setWidth(size.width() * zoomLevel); 1172 size.setHeight(size.height() * zoomLevel); 1173 setSizeIfAuto(style, size); 1174 1175 // padding - not honored by WinIE, needs to be removed. 1176 style->resetPadding(); 1177 1178 // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme) 1179 // for now, we will not honor it. 1180 style->resetBorder(); 1181 } 1182 1183 bool RenderTheme::paintRadioUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r) 1184 { 1185 if (i.context->paintingDisabled()) 1186 return false; 1187 blink::WebFallbackThemeEngine::ExtraParams extraParams; 1188 blink::WebCanvas* canvas = i.context->canvas(); 1189 extraParams.button.checked = isChecked(o); 1190 extraParams.button.indeterminate = isIndeterminate(o); 1191 1192 float zoomLevel = o->style()->effectiveZoom(); 1193 GraphicsContextStateSaver stateSaver(*i.context); 1194 IntRect unzoomedRect = r; 1195 if (zoomLevel != 1) { 1196 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); 1197 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); 1198 i.context->translate(unzoomedRect.x(), unzoomedRect.y()); 1199 i.context->scale(zoomLevel, zoomLevel); 1200 i.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); 1201 } 1202 1203 blink::Platform::current()->fallbackThemeEngine()->paint(canvas, blink::WebFallbackThemeEngine::PartRadio, getWebFallbackThemeState(this, o), blink::WebRect(unzoomedRect), &extraParams); 1204 return false; 1205 } 1206 1207 void RenderTheme::adjustRadioStyleUsingFallbackTheme(RenderStyle* style, Element*) const 1208 { 1209 // If the width and height are both specified, then we have nothing to do. 1210 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 1211 return; 1212 1213 IntSize size = blink::Platform::current()->fallbackThemeEngine()->getSize(blink::WebFallbackThemeEngine::PartRadio); 1214 float zoomLevel = style->effectiveZoom(); 1215 size.setWidth(size.width() * zoomLevel); 1216 size.setHeight(size.height() * zoomLevel); 1217 setSizeIfAuto(style, size); 1218 1219 // padding - not honored by WinIE, needs to be removed. 1220 style->resetPadding(); 1221 1222 // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme) 1223 // for now, we will not honor it. 1224 style->resetBorder(); 1225 } 1226 1227 } // namespace WebCore 1228