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