1/* 2 * This file is part of the WebKit project. 3 * 4 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 5 * 6 * Copyright (C) 2006 Zack Rusin <zack@kde.org> 7 * 2006 Dirk Mueller <mueller@kde.org> 8 * 2006 Nikolas Zimmermann <zimmermann@kde.org> 9 * Copyright (C) 2008 Holger Hans Peter Freyther 10 * 11 * All rights reserved. 12 * 13 * This library is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU Library General Public 15 * License as published by the Free Software Foundation; either 16 * version 2 of the License, or (at your option) any later version. 17 * 18 * This library is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * Library General Public License for more details. 22 * 23 * You should have received a copy of the GNU Library General Public License 24 * along with this library; see the file COPYING.LIB. If not, write to 25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 * Boston, MA 02110-1301, USA. 27 * 28 */ 29 30#include "config.h" 31#include "RenderThemeQt.h" 32 33#include "CSSStyleSelector.h" 34#include "CSSStyleSheet.h" 35#include "CSSValueKeywords.h" 36#include "Chrome.h" 37#include "ChromeClientQt.h" 38#include "Color.h" 39#include "Document.h" 40#include "Font.h" 41#include "FontSelector.h" 42#include "GraphicsContext.h" 43#include "HTMLInputElement.h" 44#include "HTMLMediaElement.h" 45#include "HTMLNames.h" 46#if USE(QT_MOBILE_THEME) 47#include "QtMobileWebStyle.h" 48#endif 49#if ENABLE(VIDEO) 50#include "MediaControlElements.h" 51#endif 52#include "NotImplemented.h" 53#include "PaintInfo.h" 54#include "Page.h" 55#include "QWebPageClient.h" 56#include "QtStyleOptionWebComboBox.h" 57#include "qwebsettings.h" 58#include "RenderBox.h" 59#if ENABLE(PROGRESS_TAG) 60#include "RenderProgress.h" 61#endif 62#include "RenderSlider.h" 63#include "RenderTheme.h" 64#include "ScrollbarThemeQt.h" 65#include "TimeRanges.h" 66#include "UserAgentStyleSheets.h" 67 68#include <QApplication> 69#include <QColor> 70#include <QFile> 71#include <QLineEdit> 72#include <QMacStyle> 73#include <QPainter> 74#include <QPushButton> 75#include <QStyleFactory> 76#include <QStyleOptionButton> 77#include <QStyleOptionFrameV2> 78#if ENABLE(PROGRESS_TAG) 79#include <QStyleOptionProgressBarV2> 80#endif 81#include <QStyleOptionSlider> 82#include <QWidget> 83 84namespace WebCore { 85 86using namespace HTMLNames; 87 88inline static void initStyleOption(QWidget *widget, QStyleOption& option) 89{ 90 if (widget) 91 option.initFrom(widget); 92 else { 93 /* 94 If a widget is not directly available for rendering, we fallback to default 95 value for an active widget. 96 */ 97 option.state = QStyle::State_Active | QStyle::State_Enabled; 98 } 99} 100// These values all match Safari/Win/Chromium 101static const float defaultControlFontPixelSize = 13; 102static const float defaultCancelButtonSize = 9; 103static const float minCancelButtonSize = 5; 104static const float maxCancelButtonSize = 21; 105static const float defaultSearchFieldResultsDecorationSize = 13; 106static const float minSearchFieldResultsDecorationSize = 9; 107static const float maxSearchFieldResultsDecorationSize = 30; 108static const float defaultSearchFieldResultsButtonWidth = 18; 109 110#if USE(QT_MOBILE_THEME) 111namespace { 112 float buttonPaddingLeft = 18; 113 float buttonPaddingRight = 18; 114 float buttonPaddingTop = 2; 115 float buttonPaddingBottom = 3; 116 float menuListPadding = 9; 117 float textFieldPadding = 5; 118} 119#endif 120 121StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo) 122{ 123 init(paintInfo.context ? paintInfo.context : 0, theme->qStyle()); 124} 125 126StylePainter::StylePainter(ScrollbarThemeQt* theme, GraphicsContext* context) 127{ 128 init(context, theme->style()); 129} 130 131void StylePainter::init(GraphicsContext* context, QStyle* themeStyle) 132{ 133 painter = static_cast<QPainter*>(context->platformContext()); 134 widget = 0; 135 QPaintDevice* dev = 0; 136 if (painter) 137 dev = painter->device(); 138 if (dev && dev->devType() == QInternal::Widget) 139 widget = static_cast<QWidget*>(dev); 140 style = themeStyle; 141 142 if (painter) { 143 // the styles often assume being called with a pristine painter where no brush is set, 144 // so reset it manually 145 oldBrush = painter->brush(); 146 painter->setBrush(Qt::NoBrush); 147 148 // painting the widget with anti-aliasing will make it blurry 149 // disable it here and restore it later 150 oldAntialiasing = painter->testRenderHint(QPainter::Antialiasing); 151 painter->setRenderHint(QPainter::Antialiasing, false); 152 } 153} 154 155StylePainter::~StylePainter() 156{ 157 if (painter) { 158 painter->setBrush(oldBrush); 159 painter->setRenderHints(QPainter::Antialiasing, oldAntialiasing); 160 } 161} 162 163PassRefPtr<RenderTheme> RenderThemeQt::create(Page* page) 164{ 165 return adoptRef(new RenderThemeQt(page)); 166} 167 168PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 169{ 170 if (page) 171 return RenderThemeQt::create(page); 172 173 static RenderTheme* fallback = RenderThemeQt::create(0).releaseRef(); 174 return fallback; 175} 176 177RenderThemeQt::RenderThemeQt(Page* page) 178 : RenderTheme() 179 , m_page(page) 180 , m_lineEdit(0) 181{ 182 QPushButton button; 183 button.setAttribute(Qt::WA_MacSmallSize); 184 QFont defaultButtonFont = QApplication::font(&button); 185 QFontInfo fontInfo(defaultButtonFont); 186 m_buttonFontFamily = defaultButtonFont.family(); 187#ifdef Q_WS_MAC 188 m_buttonFontPixelSize = fontInfo.pixelSize(); 189#endif 190 191#if USE(QT_MOBILE_THEME) 192 m_fallbackStyle = new QtMobileWebStyle; 193#else 194 m_fallbackStyle = QStyleFactory::create(QLatin1String("windows")); 195#endif 196} 197 198RenderThemeQt::~RenderThemeQt() 199{ 200 delete m_fallbackStyle; 201#ifndef QT_NO_LINEEDIT 202 delete m_lineEdit; 203#endif 204} 205 206#if USE(QT_MOBILE_THEME) 207bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& fill, const Color& backgroundColor) const 208{ 209 switch (style->appearance()) { 210 case PushButtonPart: 211 case ButtonPart: 212 case MenulistPart: 213 case SearchFieldPart: 214 case TextFieldPart: 215 case TextAreaPart: 216 // Test the style to see if the UA border and background match. 217 return (style->border() != border 218 || *style->backgroundLayers() != fill 219 || style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor); 220 case CheckboxPart: 221 case RadioPart: 222 return false; 223 default: 224 return RenderTheme::isControlStyled(style, border, fill, backgroundColor); 225 } 226} 227 228int RenderThemeQt::popupInternalPaddingBottom(RenderStyle* style) const 229{ 230 return 1; 231} 232#else 233// Remove this when SearchFieldPart is style-able in RenderTheme::isControlStyled() 234bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& fill, const Color& backgroundColor) const 235{ 236 switch (style->appearance()) { 237 case SearchFieldPart: 238 // Test the style to see if the UA border and background match. 239 return (style->border() != border 240 || *style->backgroundLayers() != fill 241 || style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor); 242 default: 243 return RenderTheme::isControlStyled(style, border, fill, backgroundColor); 244 } 245} 246#endif 247 248// for some widget painting, we need to fallback to Windows style 249QStyle* RenderThemeQt::fallbackStyle() const 250{ 251 return (m_fallbackStyle) ? m_fallbackStyle : QApplication::style(); 252} 253 254QStyle* RenderThemeQt::qStyle() const 255{ 256#if USE(QT_MOBILE_THEME) 257 return fallbackStyle(); 258#endif 259 260 if (m_page) { 261 QWebPageClient* pageClient = m_page->chrome()->client()->platformPageClient(); 262 263 if (pageClient) 264 return pageClient->style(); 265 } 266 267 return QApplication::style(); 268} 269 270String RenderThemeQt::extraDefaultStyleSheet() 271{ 272 String result = RenderTheme::extraDefaultStyleSheet(); 273#if ENABLE(NO_LISTBOX_RENDERING) 274 result += String(themeQtNoListboxesUserAgentStyleSheet, sizeof(themeQtNoListboxesUserAgentStyleSheet)); 275#endif 276 return result; 277} 278 279bool RenderThemeQt::supportsHover(const RenderStyle*) const 280{ 281 return true; 282} 283 284bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const 285{ 286 switch (style->appearance()) { 287 case CheckboxPart: 288 case RadioPart: 289 case PushButtonPart: 290 case SquareButtonPart: 291 case ButtonPart: 292 case ButtonBevelPart: 293 case ListboxPart: 294 case ListItemPart: 295 case MenulistPart: 296 case MenulistButtonPart: 297 case SliderHorizontalPart: 298 case SliderVerticalPart: 299 case SliderThumbHorizontalPart: 300 case SliderThumbVerticalPart: 301 case SearchFieldPart: 302 case SearchFieldResultsButtonPart: 303 case SearchFieldCancelButtonPart: 304 case TextFieldPart: 305 case TextAreaPart: 306 return true; 307 default: 308 return false; 309 } 310} 311 312int RenderThemeQt::baselinePosition(const RenderObject* o) const 313{ 314 if (!o->isBox()) 315 return 0; 316 317 if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) 318 return toRenderBox(o)->marginTop() + toRenderBox(o)->height() - 2; // Same as in old khtml 319 return RenderTheme::baselinePosition(o); 320} 321 322bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const 323{ 324 if (!isEnabled(o)) 325 return false; 326 327 // Checkboxes only have tint when checked. 328 if (o->style()->appearance() == CheckboxPart) 329 return isChecked(o); 330 331 // For now assume other controls have tint if enabled. 332 return true; 333} 334 335bool RenderThemeQt::supportsControlTints() const 336{ 337 return true; 338} 339 340int RenderThemeQt::findFrameLineWidth(QStyle* style) const 341{ 342#ifndef QT_NO_LINEEDIT 343 if (!m_lineEdit) 344 m_lineEdit = new QLineEdit(); 345#endif 346 347 QStyleOptionFrameV2 opt; 348 QWidget* widget = 0; 349#ifndef QT_NO_LINEEDIT 350 widget = m_lineEdit; 351#endif 352 return style->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, widget); 353} 354 355static QRect inflateButtonRect(const QRect& originalRect, QStyle* style) 356{ 357 QStyleOptionButton option; 358 option.state |= QStyle::State_Small; 359 option.rect = originalRect; 360 361 QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem, &option, 0); 362 if (!layoutRect.isNull()) { 363 int paddingLeft = layoutRect.left() - originalRect.left(); 364 int paddingRight = originalRect.right() - layoutRect.right(); 365 int paddingTop = layoutRect.top() - originalRect.top(); 366 int paddingBottom = originalRect.bottom() - layoutRect.bottom(); 367 368 return originalRect.adjusted(-paddingLeft, -paddingTop, paddingRight, paddingBottom); 369 } 370 return originalRect; 371} 372 373void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& rect) 374{ 375 switch (o->style()->appearance()) { 376 case CheckboxPart: 377 break; 378 case RadioPart: 379 break; 380 case PushButtonPart: 381 case ButtonPart: { 382 QRect inflatedRect = inflateButtonRect(rect, qStyle()); 383 rect = IntRect(inflatedRect.x(), inflatedRect.y(), inflatedRect.width(), inflatedRect.height()); 384 break; 385 } 386 case MenulistPart: 387 break; 388 default: 389 break; 390 } 391} 392 393Color RenderThemeQt::platformActiveSelectionBackgroundColor() const 394{ 395 QPalette pal = QApplication::palette(); 396 setPaletteFromPageClientIfExists(pal); 397 return pal.brush(QPalette::Active, QPalette::Highlight).color(); 398} 399 400Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const 401{ 402 QPalette pal = QApplication::palette(); 403 setPaletteFromPageClientIfExists(pal); 404 return pal.brush(QPalette::Inactive, QPalette::Highlight).color(); 405} 406 407Color RenderThemeQt::platformActiveSelectionForegroundColor() const 408{ 409 QPalette pal = QApplication::palette(); 410 setPaletteFromPageClientIfExists(pal); 411 return pal.brush(QPalette::Active, QPalette::HighlightedText).color(); 412} 413 414Color RenderThemeQt::platformInactiveSelectionForegroundColor() const 415{ 416 QPalette pal = QApplication::palette(); 417 setPaletteFromPageClientIfExists(pal); 418 return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color(); 419} 420 421Color RenderThemeQt::platformFocusRingColor() const 422{ 423 QPalette pal = QApplication::palette(); 424 setPaletteFromPageClientIfExists(pal); 425 return pal.brush(QPalette::Active, QPalette::Highlight).color(); 426} 427 428void RenderThemeQt::systemFont(int, FontDescription&) const 429{ 430 // no-op 431} 432 433Color RenderThemeQt::systemColor(int cssValueId) const 434{ 435 QPalette pal = QApplication::palette(); 436 switch (cssValueId) { 437 case CSSValueButtontext: 438 return pal.brush(QPalette::Active, QPalette::ButtonText).color(); 439 case CSSValueCaptiontext: 440 return pal.brush(QPalette::Active, QPalette::Text).color(); 441 default: 442 return RenderTheme::systemColor(cssValueId); 443 } 444} 445 446int RenderThemeQt::minimumMenuListSize(RenderStyle*) const 447{ 448 const QFontMetrics &fm = QApplication::fontMetrics(); 449 return 7 * fm.width(QLatin1Char('x')); 450} 451 452void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const 453{ 454 QSize size(0, 0); 455 const QFontMetrics fm(renderStyle->font().font()); 456 QStyle* style = qStyle(); 457 458 switch (renderStyle->appearance()) { 459 case TextAreaPart: 460 case SearchFieldPart: 461 case TextFieldPart: { 462 int padding = findFrameLineWidth(style); 463 renderStyle->setPaddingLeft(Length(padding, Fixed)); 464 renderStyle->setPaddingRight(Length(padding, Fixed)); 465 renderStyle->setPaddingTop(Length(padding, Fixed)); 466 renderStyle->setPaddingBottom(Length(padding, Fixed)); 467 break; 468 } 469 default: 470 break; 471 } 472 // If the width and height are both specified, then we have nothing to do. 473 if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto()) 474 return; 475 476 switch (renderStyle->appearance()) { 477 case CheckboxPart: { 478 QStyleOption styleOption; 479 styleOption.state |= QStyle::State_Small; 480 int checkBoxWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &styleOption); 481 checkBoxWidth *= renderStyle->effectiveZoom(); 482 size = QSize(checkBoxWidth, checkBoxWidth); 483 break; 484 } 485 case RadioPart: { 486 QStyleOption styleOption; 487 styleOption.state |= QStyle::State_Small; 488 int radioWidth = style->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, &styleOption); 489 radioWidth *= renderStyle->effectiveZoom(); 490 size = QSize(radioWidth, radioWidth); 491 break; 492 } 493#if !USE(QT_MOBILE_THEME) 494 case PushButtonPart: 495 case ButtonPart: { 496 QStyleOptionButton styleOption; 497 styleOption.state |= QStyle::State_Small; 498 QSize contentSize = fm.size(Qt::TextShowMnemonic, QString::fromLatin1("X")); 499 QSize pushButtonSize = style->sizeFromContents(QStyle::CT_PushButton, 500 &styleOption, contentSize, 0); 501 styleOption.rect = QRect(0, 0, pushButtonSize.width(), pushButtonSize.height()); 502 QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem, 503 &styleOption, 0); 504 505 // If the style supports layout rects we use that, and compensate accordingly 506 // in paintButton() below. 507 if (!layoutRect.isNull()) 508 size.setHeight(layoutRect.height()); 509 else 510 size.setHeight(pushButtonSize.height()); 511 512 break; 513 } 514 case MenulistPart: { 515 QStyleOptionComboBox styleOption; 516 styleOption.state |= QStyle::State_Small; 517 int contentHeight = qMax(fm.lineSpacing(), 14) + 2; 518 QSize menuListSize = style->sizeFromContents(QStyle::CT_ComboBox, 519 &styleOption, QSize(0, contentHeight), 0); 520 size.setHeight(menuListSize.height()); 521 break; 522 } 523#endif 524 default: 525 break; 526 } 527 528 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. 529 if (renderStyle->width().isIntrinsicOrAuto() && size.width() > 0) 530 renderStyle->setWidth(Length(size.width(), Fixed)); 531 if (renderStyle->height().isAuto() && size.height() > 0) 532 renderStyle->setHeight(Length(size.height(), Fixed)); 533} 534 535void RenderThemeQt::setCheckboxSize(RenderStyle* style) const 536{ 537 computeSizeBasedOnStyle(style); 538} 539 540bool RenderThemeQt::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r) 541{ 542 return paintButton(o, i, r); 543} 544 545void RenderThemeQt::setRadioSize(RenderStyle* style) const 546{ 547 computeSizeBasedOnStyle(style); 548} 549 550bool RenderThemeQt::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r) 551{ 552 return paintButton(o, i, r); 553} 554 555void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const 556{ 557 // Ditch the border. 558 style->resetBorder(); 559 560#ifdef Q_WS_MAC 561 if (style->appearance() == PushButtonPart) { 562 // The Mac ports ignore the specified height for <input type="button"> elements 563 // unless a border and/or background CSS property is also specified. 564 style->setHeight(Length(Auto)); 565 } 566#endif 567 568 FontDescription fontDescription = style->fontDescription(); 569 fontDescription.setIsAbsoluteSize(true); 570 571#ifdef Q_WS_MAC // Use fixed font size and family on Mac (like Safari does) 572 fontDescription.setSpecifiedSize(m_buttonFontPixelSize); 573 fontDescription.setComputedSize(m_buttonFontPixelSize); 574#else 575 fontDescription.setSpecifiedSize(style->fontSize()); 576 fontDescription.setComputedSize(style->fontSize()); 577#endif 578 579#if !USE(QT_MOBILE_THEME) 580 FontFamily fontFamily; 581 fontFamily.setFamily(m_buttonFontFamily); 582 fontDescription.setFamily(fontFamily); 583 style->setFontDescription(fontDescription); 584 style->font().update(selector->fontSelector()); 585#endif 586 style->setLineHeight(RenderStyle::initialLineHeight()); 587 setButtonSize(style); 588 setButtonPadding(style); 589} 590 591void RenderThemeQt::setButtonSize(RenderStyle* style) const 592{ 593 computeSizeBasedOnStyle(style); 594} 595 596#if !USE(QT_MOBILE_THEME) 597void RenderThemeQt::setButtonPadding(RenderStyle* style) const 598{ 599 QStyleOptionButton styleOption; 600 styleOption.state |= QStyle::State_Small; 601 602 // Fake a button rect here, since we're just computing deltas 603 QRect originalRect = QRect(0, 0, 100, 30); 604 styleOption.rect = originalRect; 605 606 // Default padding is based on the button margin pixel metric 607 int buttonMargin = qStyle()->pixelMetric(QStyle::PM_ButtonMargin, &styleOption, 0); 608 int paddingLeft = buttonMargin; 609 int paddingRight = buttonMargin; 610 int paddingTop = 1; 611 int paddingBottom = 0; 612 613 // Then check if the style uses layout margins 614 QRect layoutRect = qStyle()->subElementRect(QStyle::SE_PushButtonLayoutItem, 615 &styleOption, 0); 616 if (!layoutRect.isNull()) { 617 QRect contentsRect = qStyle()->subElementRect(QStyle::SE_PushButtonContents, 618 &styleOption, 0); 619 paddingLeft = contentsRect.left() - layoutRect.left(); 620 paddingRight = layoutRect.right() - contentsRect.right(); 621 paddingTop = contentsRect.top() - layoutRect.top(); 622 623 // Can't use this right now because we don't have the baseline to compensate 624 // paddingBottom = layoutRect.bottom() - contentsRect.bottom(); 625 } 626 style->setPaddingLeft(Length(paddingLeft, Fixed)); 627 style->setPaddingRight(Length(paddingRight, Fixed)); 628 style->setPaddingTop(Length(paddingTop, Fixed)); 629 style->setPaddingBottom(Length(paddingBottom, Fixed)); 630} 631#else 632void RenderThemeQt::setButtonPadding(RenderStyle* style) const 633{ 634 if (!style) 635 return; 636 style->setPaddingLeft(Length(buttonPaddingLeft, Fixed)); 637 style->setPaddingRight(Length(buttonPaddingRight, Fixed)); 638 style->setPaddingTop(Length(buttonPaddingTop, Fixed)); 639 style->setPaddingBottom(Length(buttonPaddingBottom, Fixed)); 640} 641#endif 642 643bool RenderThemeQt::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r) 644{ 645 StylePainter p(this, i); 646 if (!p.isValid()) 647 return true; 648 649 QStyleOptionButton option; 650 initStyleOption(p.widget, option); 651 option.rect = r; 652 option.state |= QStyle::State_Small; 653 654 ControlPart appearance = initializeCommonQStyleOptions(option, o); 655 if (appearance == PushButtonPart || appearance == ButtonPart) { 656 option.rect = inflateButtonRect(option.rect, qStyle()); 657 p.drawControl(QStyle::CE_PushButton, option); 658 } else if (appearance == RadioPart) 659 p.drawControl(QStyle::CE_RadioButton, option); 660 else if (appearance == CheckboxPart) 661 p.drawControl(QStyle::CE_CheckBox, option); 662 663 return false; 664} 665 666void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 667{ 668 // Resetting the style like this leads to differences like: 669 // - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)] 670 // + RenderTextControl {INPUT} at (2,2) size 166x26 671 // in layout tests when a CSS style is applied that doesn't affect background color, border or 672 // padding. Just worth keeping in mind! 673 style->setBackgroundColor(Color::transparent); 674 style->resetBorder(); 675 style->resetPadding(); 676 computeSizeBasedOnStyle(style); 677#if USE(QT_MOBILE_THEME) 678 style->setPaddingLeft(Length(textFieldPadding, Fixed)); 679 style->setPaddingRight(Length(textFieldPadding, Fixed)); 680#endif 681} 682 683bool RenderThemeQt::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r) 684{ 685 StylePainter p(this, i); 686 if (!p.isValid()) 687 return true; 688 689 QStyleOptionFrameV2 panel; 690 initStyleOption(p.widget, panel); 691 panel.rect = r; 692 panel.lineWidth = findFrameLineWidth(qStyle()); 693#if USE(QT_MOBILE_THEME) 694 if (isPressed(o)) 695 panel.state |= QStyle::State_Sunken; 696#else 697 panel.state |= QStyle::State_Sunken; 698#endif 699 panel.features = QStyleOptionFrameV2::None; 700 701 // Get the correct theme data for a text field 702 ControlPart appearance = initializeCommonQStyleOptions(panel, o); 703 if (appearance != TextFieldPart 704 && appearance != SearchFieldPart 705 && appearance != TextAreaPart 706 && appearance != ListboxPart) 707 return true; 708 709 // Now paint the text field. 710 p.drawPrimitive(QStyle::PE_PanelLineEdit, panel); 711 return false; 712} 713 714void RenderThemeQt::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const 715{ 716 adjustTextFieldStyle(selector, style, element); 717} 718 719bool RenderThemeQt::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r) 720{ 721 return paintTextField(o, i, r); 722} 723 724void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 725{ 726 style->resetBorder(); 727 728 // Height is locked to auto. 729 style->setHeight(Length(Auto)); 730 731 // White-space is locked to pre 732 style->setWhiteSpace(PRE); 733 734 computeSizeBasedOnStyle(style); 735 736 // Add in the padding that we'd like to use. 737 setPopupPadding(style); 738#if USE(QT_MOBILE_THEME) 739 style->setPaddingLeft(Length(menuListPadding, Fixed)); 740#endif 741} 742 743void RenderThemeQt::setPopupPadding(RenderStyle* style) const 744{ 745 const int paddingLeft = 4; 746 const int paddingRight = style->width().isFixed() || style->width().isPercent() ? 5 : 8; 747 748 style->setPaddingLeft(Length(paddingLeft, Fixed)); 749 750 QStyleOptionComboBox opt; 751 int w = qStyle()->pixelMetric(QStyle::PM_ButtonIconSize, &opt, 0); 752 style->setPaddingRight(Length(paddingRight + w, Fixed)); 753 754 style->setPaddingTop(Length(2, Fixed)); 755 style->setPaddingBottom(Length(2, Fixed)); 756} 757 758 759bool RenderThemeQt::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r) 760{ 761 StylePainter p(this, i); 762 if (!p.isValid()) 763 return true; 764 765 QtStyleOptionWebComboBox opt(o); 766 initStyleOption(p.widget, opt); 767 initializeCommonQStyleOptions(opt, o); 768 769 IntRect rect = r; 770 771#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) 772 // QMacStyle makes the combo boxes a little bit smaller to leave space for the focus rect. 773 // Because of it, the combo button is drawn at a point to the left of where it was expect to be and may end up 774 // overlapped with the text. This will force QMacStyle to draw the combo box with the expected width. 775 if (qobject_cast<QMacStyle*>(p.style)) 776 rect.inflateX(3); 777#endif 778 779 const QPoint topLeft = rect.location(); 780 p.painter->translate(topLeft); 781 opt.rect.moveTo(QPoint(0, 0)); 782 opt.rect.setSize(rect.size()); 783 784 p.drawComplexControl(QStyle::CC_ComboBox, opt); 785 p.painter->translate(-topLeft); 786 return false; 787} 788 789void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 790{ 791#if USE(QT_MOBILE_THEME) 792 // Mobile theme uses border radius. 793#else 794 // WORKAROUND because html.css specifies -webkit-border-radius for <select> so we override it here 795 // see also http://bugs.webkit.org/show_bug.cgi?id=18399 796 style->resetBorderRadius(); 797#endif 798 799 // Height is locked to auto. 800 style->setHeight(Length(Auto)); 801 802 // White-space is locked to pre 803 style->setWhiteSpace(PRE); 804 805 computeSizeBasedOnStyle(style); 806 807 // Add in the padding that we'd like to use. 808 setPopupPadding(style); 809} 810 811bool RenderThemeQt::paintMenuListButton(RenderObject* o, const PaintInfo& i, 812 const IntRect& r) 813{ 814 StylePainter p(this, i); 815 if (!p.isValid()) 816 return true; 817 818 QtStyleOptionWebComboBox option(o); 819 initStyleOption(p.widget, option); 820 initializeCommonQStyleOptions(option, o); 821 option.rect = r; 822 823 // for drawing the combo box arrow, rely only on the fallback style 824 p.style = fallbackStyle(); 825 option.subControls = QStyle::SC_ComboBoxArrow; 826 p.drawComplexControl(QStyle::CC_ComboBox, option); 827 828 return false; 829} 830 831#if ENABLE(PROGRESS_TAG) 832double RenderThemeQt::animationRepeatIntervalForProgressBar(RenderProgress* renderProgress) const 833{ 834 if (renderProgress->position() >= 0) 835 return 0; 836 837 // FIXME: Use hard-coded value until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed. 838 // Use the value from windows style which is 10 fps. 839 return 0.1; 840} 841 842double RenderThemeQt::animationDurationForProgressBar(RenderProgress* renderProgress) const 843{ 844 if (renderProgress->position() >= 0) 845 return 0; 846 847 QStyleOptionProgressBarV2 option; 848 option.rect.setSize(renderProgress->size()); 849 // FIXME: Until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed, 850 // we simulate one square animating across the progress bar. 851 return (option.rect.width() / qStyle()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option)) * animationRepeatIntervalForProgressBar(renderProgress); 852} 853 854void RenderThemeQt::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 855{ 856 style->setBoxShadow(0); 857} 858 859bool RenderThemeQt::paintProgressBar(RenderObject* o, const PaintInfo& pi, const IntRect& r) 860{ 861 if (!o->isProgress()) 862 return true; 863 864 StylePainter p(this, pi); 865 if (!p.isValid()) 866 return true; 867 868 QStyleOptionProgressBarV2 option; 869 initStyleOption(p.widget, option); 870 initializeCommonQStyleOptions(option, o); 871 872 RenderProgress* renderProgress = toRenderProgress(o); 873 option.rect = r; 874 option.maximum = std::numeric_limits<int>::max(); 875 option.minimum = 0; 876 option.progress = (renderProgress->position() * std::numeric_limits<int>::max()); 877 878 const QPoint topLeft = r.location(); 879 p.painter->translate(topLeft); 880 option.rect.moveTo(QPoint(0, 0)); 881 option.rect.setSize(r.size()); 882 883 if (option.progress < 0) { 884 // FIXME: Until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed, 885 // we simulate one square animating across the progress bar. 886 p.drawControl(QStyle::CE_ProgressBarGroove, option); 887 int chunkWidth = qStyle()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option); 888 QColor color = (option.palette.highlight() == option.palette.background()) ? option.palette.color(QPalette::Active, QPalette::Highlight) : option.palette.color(QPalette::Highlight); 889 if (renderProgress->style()->direction() == RTL) 890 p.painter->fillRect(option.rect.right() - chunkWidth - renderProgress->animationProgress() * option.rect.width(), 0, chunkWidth, option.rect.height(), color); 891 else 892 p.painter->fillRect(renderProgress->animationProgress() * option.rect.width(), 0, chunkWidth, option.rect.height(), color); 893 } else 894 p.drawControl(QStyle::CE_ProgressBar, option); 895 896 p.painter->translate(-topLeft); 897 898 return false; 899} 900#endif 901 902bool RenderThemeQt::paintSliderTrack(RenderObject* o, const PaintInfo& pi, 903 const IntRect& r) 904{ 905 StylePainter p(this, pi); 906 if (!p.isValid()) 907 return true; 908 909 QStyleOptionSlider option; 910 initStyleOption(p.widget, option); 911 option.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle; 912 ControlPart appearance = initializeCommonQStyleOptions(option, o); 913 914 RenderSlider* renderSlider = toRenderSlider(o); 915 IntRect thumbRect = renderSlider->thumbRect(); 916 917 option.rect = r; 918 919 int value; 920 if (appearance == SliderVerticalPart) { 921 option.maximum = r.height() - thumbRect.height(); 922 value = thumbRect.y(); 923 } else { 924 option.maximum = r.width() - thumbRect.width(); 925 value = thumbRect.x(); 926 } 927 928 value = QStyle::sliderValueFromPosition(0, option.maximum, value, option.maximum); 929 930 option.sliderValue = value; 931 option.sliderPosition = value; 932 if (appearance == SliderVerticalPart) 933 option.orientation = Qt::Vertical; 934 935 if (renderSlider->inDragMode()) { 936 option.activeSubControls = QStyle::SC_SliderHandle; 937 option.state |= QStyle::State_Sunken; 938 } 939 940 const QPoint topLeft = r.location(); 941 p.painter->translate(topLeft); 942 option.rect.moveTo(QPoint(0, 0)); 943 option.rect.setSize(r.size()); 944 945 p.drawComplexControl(QStyle::CC_Slider, option); 946 p.painter->translate(-topLeft); 947 948 return false; 949} 950 951void RenderThemeQt::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 952{ 953 style->setBoxShadow(0); 954} 955 956bool RenderThemeQt::paintSliderThumb(RenderObject* o, const PaintInfo& pi, 957 const IntRect& r) 958{ 959 // We've already painted it in paintSliderTrack(), no need to do anything here. 960 return false; 961} 962 963void RenderThemeQt::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 964{ 965 style->setBoxShadow(0); 966} 967 968bool RenderThemeQt::paintSearchField(RenderObject* o, const PaintInfo& pi, 969 const IntRect& r) 970{ 971 return paintTextField(o, pi, r); 972} 973 974void RenderThemeQt::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, 975 Element* e) const 976{ 977 // Resetting the style like this leads to differences like: 978 // - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)] 979 // + RenderTextControl {INPUT} at (2,2) size 166x26 980 // in layout tests when a CSS style is applied that doesn't affect background color, border or 981 // padding. Just worth keeping in mind! 982 style->setBackgroundColor(Color::transparent); 983 style->resetBorder(); 984 style->resetPadding(); 985 computeSizeBasedOnStyle(style); 986} 987 988void RenderThemeQt::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, 989 Element* e) const 990{ 991 // Logic taken from RenderThemeChromium.cpp. 992 // Scale the button size based on the font size. 993 float fontScale = style->fontSize() / defaultControlFontPixelSize; 994 int cancelButtonSize = lroundf(qMin(qMax(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize)); 995 style->setWidth(Length(cancelButtonSize, Fixed)); 996 style->setHeight(Length(cancelButtonSize, Fixed)); 997} 998 999// Function taken from RenderThemeChromium.cpp 1000IntRect RenderThemeQt::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, IntRect partRect, const IntRect& localOffset) const 1001{ 1002 // Compute an offset between the part renderer and the input renderer. 1003 IntSize offsetFromInputRenderer = -(partRenderer->offsetFromAncestorContainer(inputRenderer)); 1004 // Move the rect into partRenderer's coords. 1005 partRect.move(offsetFromInputRenderer); 1006 // Account for the local drawing offset. 1007 partRect.move(localOffset.x(), localOffset.y()); 1008 1009 return partRect; 1010} 1011 1012bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& pi, 1013 const IntRect& r) 1014{ 1015 // Logic copied from RenderThemeChromium.cpp. 1016 1017 // Get the renderer of <input> element. 1018 Node* input = o->node()->shadowAncestorNode(); 1019 if (!input->renderer()->isBox()) 1020 return false; 1021 RenderBox* inputRenderBox = toRenderBox(input->renderer()); 1022 IntRect inputContentBox = inputRenderBox->contentBoxRect(); 1023 1024 // Make sure the scaled button stays square and will fit in its parent's box. 1025 int cancelButtonSize = qMin(inputContentBox.width(), qMin(inputContentBox.height(), r.height())); 1026 // Calculate cancel button's coordinates relative to the input element. 1027 // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will 1028 // be one pixel closer to the bottom of the field. This tends to look better with the text. 1029 IntRect cancelButtonRect(o->offsetFromAncestorContainer(inputRenderBox).width(), 1030 inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2, 1031 cancelButtonSize, cancelButtonSize); 1032 IntRect paintingRect = convertToPaintingRect(inputRenderBox, o, cancelButtonRect, r); 1033 static Image* cancelImage = Image::loadPlatformResource("searchCancelButton").releaseRef(); 1034 static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelButtonPressed").releaseRef(); 1035 pi.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, 1036 o->style()->colorSpace(), paintingRect); 1037 return false; 1038} 1039 1040void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, 1041 Element* e) const 1042{ 1043 notImplemented(); 1044 RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e); 1045} 1046 1047bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const PaintInfo& pi, 1048 const IntRect& r) 1049{ 1050 notImplemented(); 1051 return RenderTheme::paintSearchFieldDecoration(o, pi, r); 1052} 1053 1054void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, 1055 Element* e) const 1056{ 1057 notImplemented(); 1058 RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e); 1059} 1060 1061bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& pi, 1062 const IntRect& r) 1063{ 1064 notImplemented(); 1065 return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r); 1066} 1067 1068bool RenderThemeQt::supportsFocus(ControlPart appearance) const 1069{ 1070 switch (appearance) { 1071 case PushButtonPart: 1072 case ButtonPart: 1073 case TextFieldPart: 1074 case TextAreaPart: 1075 case ListboxPart: 1076 case MenulistPart: 1077 case RadioPart: 1078 case CheckboxPart: 1079 case SliderHorizontalPart: 1080 case SliderVerticalPart: 1081 return true; 1082 default: // No for all others... 1083 return false; 1084 } 1085} 1086 1087void RenderThemeQt::setPaletteFromPageClientIfExists(QPalette& palette) const 1088{ 1089#if USE(QT_MOBILE_THEME) 1090 static QPalette lightGrayPalette(Qt::lightGray); 1091 palette = lightGrayPalette; 1092 return; 1093#endif 1094 // If the webview has a custom palette, use it 1095 if (!m_page) 1096 return; 1097 Chrome* chrome = m_page->chrome(); 1098 if (!chrome) 1099 return; 1100 ChromeClient* chromeClient = chrome->client(); 1101 if (!chromeClient) 1102 return; 1103 QWebPageClient* pageClient = chromeClient->platformPageClient(); 1104 if (!pageClient) 1105 return; 1106 palette = pageClient->palette(); 1107} 1108 1109ControlPart RenderThemeQt::initializeCommonQStyleOptions(QStyleOption& option, RenderObject* o) const 1110{ 1111 // Default bits: no focus, no mouse over 1112 option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver); 1113 1114 if (isReadOnlyControl(o)) 1115 // Readonly is supported on textfields. 1116 option.state |= QStyle::State_ReadOnly; 1117 1118 option.direction = Qt::LeftToRight; 1119 1120 if (isHovered(o)) 1121 option.state |= QStyle::State_MouseOver; 1122 1123 setPaletteFromPageClientIfExists(option.palette); 1124 1125 if (!isEnabled(o)) { 1126 option.palette.setCurrentColorGroup(QPalette::Disabled); 1127 option.state &= ~QStyle::State_Enabled; 1128 } 1129 1130 RenderStyle* style = o->style(); 1131 if (!style) 1132 return NoControlPart; 1133 1134 ControlPart result = style->appearance(); 1135 if (supportsFocus(result) && isFocused(o)) { 1136 option.state |= QStyle::State_HasFocus; 1137 option.state |= QStyle::State_KeyboardFocusChange; 1138 } 1139 1140 if (style->direction() == WebCore::RTL) 1141 option.direction = Qt::RightToLeft; 1142 1143 switch (result) { 1144 case PushButtonPart: 1145 case SquareButtonPart: 1146 case ButtonPart: 1147 case ButtonBevelPart: 1148 case ListItemPart: 1149 case MenulistButtonPart: 1150 case SearchFieldResultsButtonPart: 1151 case SearchFieldCancelButtonPart: { 1152 if (isPressed(o)) 1153 option.state |= QStyle::State_Sunken; 1154 else if (result == PushButtonPart || result == ButtonPart) 1155 option.state |= QStyle::State_Raised; 1156 break; 1157 } 1158 case RadioPart: 1159 case CheckboxPart: 1160 option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off); 1161 } 1162 1163 return result; 1164} 1165 1166#if ENABLE(VIDEO) 1167 1168String RenderThemeQt::extraMediaControlsStyleSheet() 1169{ 1170 String result = String(mediaControlsQtUserAgentStyleSheet, sizeof(mediaControlsQtUserAgentStyleSheet)); 1171 1172 if (m_page && m_page->chrome()->requiresFullscreenForVideoPlayback()) 1173 result += String(mediaControlsQtFullscreenUserAgentStyleSheet, sizeof(mediaControlsQtFullscreenUserAgentStyleSheet)); 1174 1175 return result; 1176} 1177 1178// Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100 1179class WorldMatrixTransformer { 1180public: 1181 WorldMatrixTransformer(QPainter* painter, RenderObject* renderObject, const IntRect& r) : m_painter(painter) 1182 { 1183 RenderStyle* style = renderObject->style(); 1184 m_originalTransform = m_painter->transform(); 1185 m_painter->translate(r.x() + style->paddingLeft().value(), r.y() + style->paddingTop().value()); 1186 m_painter->scale((r.width() - style->paddingLeft().value() - style->paddingRight().value()) / 100.0, 1187 (r.height() - style->paddingTop().value() - style->paddingBottom().value()) / 100.0); 1188 } 1189 1190 ~WorldMatrixTransformer() { m_painter->setTransform(m_originalTransform); } 1191 1192private: 1193 QPainter* m_painter; 1194 QTransform m_originalTransform; 1195}; 1196 1197double RenderThemeQt::mediaControlsBaselineOpacity() const 1198{ 1199 return 0.4; 1200} 1201 1202void RenderThemeQt::paintMediaBackground(QPainter* painter, const IntRect& r) const 1203{ 1204 painter->setPen(Qt::NoPen); 1205 static QColor transparentBlack(0, 0, 0, mediaControlsBaselineOpacity() * 255); 1206 painter->setBrush(transparentBlack); 1207 painter->drawRoundedRect(r.x(), r.y(), r.width(), r.height(), 5.0, 5.0); 1208} 1209 1210QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const 1211{ 1212 QColor fgColor = platformActiveSelectionBackgroundColor(); 1213 if (o && o->node()->active()) 1214 fgColor = fgColor.lighter(); 1215 return fgColor; 1216} 1217 1218bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 1219{ 1220 HTMLMediaElement* mediaElement = toParentMediaElement(o); 1221 if (!mediaElement) 1222 return false; 1223 1224 StylePainter p(this, paintInfo); 1225 if (!p.isValid()) 1226 return true; 1227 1228 p.painter->setRenderHint(QPainter::Antialiasing, true); 1229 1230 paintMediaBackground(p.painter, r); 1231 1232 WorldMatrixTransformer transformer(p.painter, o, r); 1233 const QPointF arrowPolygon[9] = { QPointF(20, 0), QPointF(100, 0), QPointF(100, 80), 1234 QPointF(80, 80), QPointF(80, 30), QPointF(10, 100), QPointF(0, 90), QPointF(70, 20), QPointF(20, 20)}; 1235 1236 p.painter->setBrush(getMediaControlForegroundColor(o)); 1237 p.painter->drawPolygon(arrowPolygon, 9); 1238 1239 return false; 1240} 1241 1242bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 1243{ 1244 HTMLMediaElement* mediaElement = toParentMediaElement(o); 1245 if (!mediaElement) 1246 return false; 1247 1248 StylePainter p(this, paintInfo); 1249 if (!p.isValid()) 1250 return true; 1251 1252 p.painter->setRenderHint(QPainter::Antialiasing, true); 1253 1254 paintMediaBackground(p.painter, r); 1255 1256 WorldMatrixTransformer transformer(p.painter, o, r); 1257 const QPointF speakerPolygon[6] = { QPointF(20, 30), QPointF(50, 30), QPointF(80, 0), 1258 QPointF(80, 100), QPointF(50, 70), QPointF(20, 70)}; 1259 1260 p.painter->setBrush(mediaElement->muted() ? Qt::darkRed : getMediaControlForegroundColor(o)); 1261 p.painter->drawPolygon(speakerPolygon, 6); 1262 1263 return false; 1264} 1265 1266bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 1267{ 1268 HTMLMediaElement* mediaElement = toParentMediaElement(o); 1269 if (!mediaElement) 1270 return false; 1271 1272 StylePainter p(this, paintInfo); 1273 if (!p.isValid()) 1274 return true; 1275 1276 p.painter->setRenderHint(QPainter::Antialiasing, true); 1277 1278 paintMediaBackground(p.painter, r); 1279 1280 WorldMatrixTransformer transformer(p.painter, o, r); 1281 p.painter->setBrush(getMediaControlForegroundColor(o)); 1282 if (mediaElement->canPlay()) { 1283 const QPointF playPolygon[3] = { QPointF(0, 0), QPointF(100, 50), QPointF(0, 100)}; 1284 p.painter->drawPolygon(playPolygon, 3); 1285 } else { 1286 p.painter->drawRect(0, 0, 30, 100); 1287 p.painter->drawRect(70, 0, 30, 100); 1288 } 1289 1290 return false; 1291} 1292 1293bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&) 1294{ 1295 // We don't want to paint this at the moment. 1296 return false; 1297} 1298 1299bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&) 1300{ 1301 // We don't want to paint this at the moment. 1302 return false; 1303} 1304 1305bool RenderThemeQt::paintMediaCurrentTime(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 1306{ 1307 StylePainter p(this, paintInfo); 1308 if (!p.isValid()) 1309 return true; 1310 1311 p.painter->setRenderHint(QPainter::Antialiasing, true); 1312 paintMediaBackground(p.painter, r); 1313 1314 return false; 1315} 1316 1317String RenderThemeQt::formatMediaControlsCurrentTime(float currentTime, float duration) const 1318{ 1319 return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration); 1320} 1321 1322String RenderThemeQt::formatMediaControlsRemainingTime(float currentTime, float duration) const 1323{ 1324 return String(); 1325} 1326 1327bool RenderThemeQt::paintMediaVolumeSliderTrack(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r) 1328{ 1329 StylePainter p(this, paintInfo); 1330 if (!p.isValid()) 1331 return true; 1332 1333 p.painter->setRenderHint(QPainter::Antialiasing, true); 1334 1335 paintMediaBackground(p.painter, r); 1336 1337 if (!o->isSlider()) 1338 return false; 1339 1340 IntRect b = toRenderBox(o)->contentBoxRect(); 1341 1342 // Position the outer rectangle 1343 int top = r.y() + b.y(); 1344 int left = r.x() + b.x(); 1345 int width = b.width(); 1346 int height = b.height(); 1347 1348 // Get the scale color from the page client 1349 QPalette pal = QApplication::palette(); 1350 setPaletteFromPageClientIfExists(pal); 1351 const QColor highlightText = pal.brush(QPalette::Active, QPalette::HighlightedText).color(); 1352 const QColor scaleColor(highlightText.red(), highlightText.green(), highlightText.blue(), mediaControlsBaselineOpacity() * 255); 1353 1354 // Draw the outer rectangle 1355 p.painter->setBrush(scaleColor); 1356 p.painter->drawRect(left, top, width, height); 1357 1358 if (!o->node() || !o->node()->hasTagName(inputTag)) 1359 return false; 1360 1361 HTMLInputElement* slider = static_cast<HTMLInputElement*>(o->node()); 1362 1363 // Position the inner rectangle 1364 height = height * slider->valueAsNumber(); 1365 top += b.height() - height; 1366 1367 // Draw the inner rectangle 1368 p.painter->setPen(Qt::NoPen); 1369 p.painter->setBrush(getMediaControlForegroundColor(o)); 1370 p.painter->drawRect(left, top, width, height); 1371 1372 return false; 1373} 1374 1375bool RenderThemeQt::paintMediaVolumeSliderThumb(RenderObject *o, const PaintInfo &paintInfo, const IntRect &r) 1376{ 1377 StylePainter p(this, paintInfo); 1378 if (!p.isValid()) 1379 return true; 1380 1381 // Nothing to draw here, this is all done in the track 1382 return false; 1383} 1384 1385bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 1386{ 1387 HTMLMediaElement* mediaElement = toParentMediaElement(o); 1388 if (!mediaElement) 1389 return false; 1390 1391 StylePainter p(this, paintInfo); 1392 if (!p.isValid()) 1393 return true; 1394 1395 p.painter->setRenderHint(QPainter::Antialiasing, true); 1396 1397 paintMediaBackground(p.painter, r); 1398 1399 if (MediaPlayer* player = mediaElement->player()) { 1400 // Get the buffered parts of the media 1401 PassRefPtr<TimeRanges> buffered = player->buffered(); 1402 if (buffered->length() > 0 && player->duration() < std::numeric_limits<float>::infinity()) { 1403 // Set the transform and brush 1404 WorldMatrixTransformer transformer(p.painter, o, r); 1405 p.painter->setBrush(getMediaControlForegroundColor()); 1406 1407 // Paint each buffered section 1408 ExceptionCode ex; 1409 for (int i = 0; i < buffered->length(); i++) { 1410 float startX = (buffered->start(i, ex) / player->duration()) * 100; 1411 float width = ((buffered->end(i, ex) / player->duration()) * 100) - startX; 1412 p.painter->drawRect(startX, 37, width, 26); 1413 } 1414 } 1415 } 1416 1417 return false; 1418} 1419 1420bool RenderThemeQt::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 1421{ 1422 StylePainter p(this, paintInfo); 1423 if (!p.isValid()) 1424 return true; 1425 1426 p.painter->setRenderHint(QPainter::Antialiasing, true); 1427 1428 p.painter->setPen(Qt::NoPen); 1429 p.painter->setBrush(getMediaControlForegroundColor(o)); 1430 p.painter->drawRect(r.x(), r.y(), r.width(), r.height()); 1431 1432 return false; 1433} 1434#endif 1435 1436void RenderThemeQt::adjustSliderThumbSize(RenderObject* o) const 1437{ 1438 ControlPart part = o->style()->appearance(); 1439 1440 if (part == MediaSliderThumbPart) { 1441 RenderStyle* parentStyle = o->parent()->style(); 1442 Q_ASSERT(parentStyle); 1443 1444 int parentHeight = parentStyle->height().value(); 1445 o->style()->setWidth(Length(parentHeight / 3, Fixed)); 1446 o->style()->setHeight(Length(parentHeight, Fixed)); 1447 } else if (part == MediaVolumeSliderThumbPart) { 1448 RenderStyle* parentStyle = o->parent()->style(); 1449 Q_ASSERT(parentStyle); 1450 1451 int parentWidth = parentStyle->width().value(); 1452 o->style()->setHeight(Length(parentWidth / 3, Fixed)); 1453 o->style()->setWidth(Length(parentWidth, Fixed)); 1454 } else if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) { 1455 QStyleOptionSlider option; 1456 if (part == SliderThumbVerticalPart) 1457 option.orientation = Qt::Vertical; 1458 1459 QStyle* style = qStyle(); 1460 1461 int width = style->pixelMetric(QStyle::PM_SliderLength, &option); 1462 int height = style->pixelMetric(QStyle::PM_SliderThickness, &option); 1463 o->style()->setWidth(Length(width, Fixed)); 1464 o->style()->setHeight(Length(height, Fixed)); 1465 } 1466} 1467 1468double RenderThemeQt::caretBlinkInterval() const 1469{ 1470 return QApplication::cursorFlashTime() / 1000.0 / 2.0; 1471} 1472 1473} 1474 1475// vim: ts=4 sw=4 et 1476