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