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 (at) kde.org> 7 * 2006 Dirk Mueller <mueller (at) kde.org> 8 * 2006 Nikolas Zimmermann <zimmermann (at) 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 84 namespace WebCore { 85 86 using namespace HTMLNames; 87 88 inline 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 101 static const float defaultControlFontPixelSize = 13; 102 static const float defaultCancelButtonSize = 9; 103 static const float minCancelButtonSize = 5; 104 static const float maxCancelButtonSize = 21; 105 static const float defaultSearchFieldResultsDecorationSize = 13; 106 static const float minSearchFieldResultsDecorationSize = 9; 107 static const float maxSearchFieldResultsDecorationSize = 30; 108 static const float defaultSearchFieldResultsButtonWidth = 18; 109 110 #if USE(QT_MOBILE_THEME) 111 namespace { 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 121 StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo) 122 { 123 init(paintInfo.context ? paintInfo.context : 0, theme->qStyle()); 124 } 125 126 StylePainter::StylePainter(ScrollbarThemeQt* theme, GraphicsContext* context) 127 { 128 init(context, theme->style()); 129 } 130 131 void 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 155 StylePainter::~StylePainter() 156 { 157 if (painter) { 158 painter->setBrush(oldBrush); 159 painter->setRenderHints(QPainter::Antialiasing, oldAntialiasing); 160 } 161 } 162 163 PassRefPtr<RenderTheme> RenderThemeQt::create(Page* page) 164 { 165 return adoptRef(new RenderThemeQt(page)); 166 } 167 168 PassRefPtr<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 177 RenderThemeQt::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 198 RenderThemeQt::~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) 207 bool 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 228 int RenderThemeQt::popupInternalPaddingBottom(RenderStyle* style) const 229 { 230 return 1; 231 } 232 #else 233 // Remove this when SearchFieldPart is style-able in RenderTheme::isControlStyled() 234 bool 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 249 QStyle* RenderThemeQt::fallbackStyle() const 250 { 251 return (m_fallbackStyle) ? m_fallbackStyle : QApplication::style(); 252 } 253 254 QStyle* 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 270 String 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 279 bool RenderThemeQt::supportsHover(const RenderStyle*) const 280 { 281 return true; 282 } 283 284 bool 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 312 int 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 322 bool 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 335 bool RenderThemeQt::supportsControlTints() const 336 { 337 return true; 338 } 339 340 int 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 355 static 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 373 void 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 393 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const 394 { 395 QPalette pal = QApplication::palette(); 396 setPaletteFromPageClientIfExists(pal); 397 return pal.brush(QPalette::Active, QPalette::Highlight).color(); 398 } 399 400 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const 401 { 402 QPalette pal = QApplication::palette(); 403 setPaletteFromPageClientIfExists(pal); 404 return pal.brush(QPalette::Inactive, QPalette::Highlight).color(); 405 } 406 407 Color RenderThemeQt::platformActiveSelectionForegroundColor() const 408 { 409 QPalette pal = QApplication::palette(); 410 setPaletteFromPageClientIfExists(pal); 411 return pal.brush(QPalette::Active, QPalette::HighlightedText).color(); 412 } 413 414 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const 415 { 416 QPalette pal = QApplication::palette(); 417 setPaletteFromPageClientIfExists(pal); 418 return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color(); 419 } 420 421 Color RenderThemeQt::platformFocusRingColor() const 422 { 423 QPalette pal = QApplication::palette(); 424 setPaletteFromPageClientIfExists(pal); 425 return pal.brush(QPalette::Active, QPalette::Highlight).color(); 426 } 427 428 void RenderThemeQt::systemFont(int, FontDescription&) const 429 { 430 // no-op 431 } 432 433 Color 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 446 int RenderThemeQt::minimumMenuListSize(RenderStyle*) const 447 { 448 const QFontMetrics &fm = QApplication::fontMetrics(); 449 return 7 * fm.width(QLatin1Char('x')); 450 } 451 452 void 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 535 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const 536 { 537 computeSizeBasedOnStyle(style); 538 } 539 540 bool RenderThemeQt::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r) 541 { 542 return paintButton(o, i, r); 543 } 544 545 void RenderThemeQt::setRadioSize(RenderStyle* style) const 546 { 547 computeSizeBasedOnStyle(style); 548 } 549 550 bool RenderThemeQt::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r) 551 { 552 return paintButton(o, i, r); 553 } 554 555 void 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 591 void RenderThemeQt::setButtonSize(RenderStyle* style) const 592 { 593 computeSizeBasedOnStyle(style); 594 } 595 596 #if !USE(QT_MOBILE_THEME) 597 void 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 632 void 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 643 bool 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 666 void 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 683 bool 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 714 void RenderThemeQt::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const 715 { 716 adjustTextFieldStyle(selector, style, element); 717 } 718 719 bool RenderThemeQt::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r) 720 { 721 return paintTextField(o, i, r); 722 } 723 724 void 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 743 void 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 759 bool 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 789 void 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 811 bool 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) 832 double 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 842 double 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 854 void RenderThemeQt::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 855 { 856 style->setBoxShadow(0); 857 } 858 859 bool 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 902 bool 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 951 void RenderThemeQt::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 952 { 953 style->setBoxShadow(0); 954 } 955 956 bool 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 963 void RenderThemeQt::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 964 { 965 style->setBoxShadow(0); 966 } 967 968 bool RenderThemeQt::paintSearchField(RenderObject* o, const PaintInfo& pi, 969 const IntRect& r) 970 { 971 return paintTextField(o, pi, r); 972 } 973 974 void 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 988 void 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 1000 IntRect 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 1012 bool 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 1040 void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, 1041 Element* e) const 1042 { 1043 notImplemented(); 1044 RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e); 1045 } 1046 1047 bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const PaintInfo& pi, 1048 const IntRect& r) 1049 { 1050 notImplemented(); 1051 return RenderTheme::paintSearchFieldDecoration(o, pi, r); 1052 } 1053 1054 void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, 1055 Element* e) const 1056 { 1057 notImplemented(); 1058 RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e); 1059 } 1060 1061 bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& pi, 1062 const IntRect& r) 1063 { 1064 notImplemented(); 1065 return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r); 1066 } 1067 1068 bool 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 1087 void 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 1109 ControlPart 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 1168 String 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 1179 class WorldMatrixTransformer { 1180 public: 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 1192 private: 1193 QPainter* m_painter; 1194 QTransform m_originalTransform; 1195 }; 1196 1197 double RenderThemeQt::mediaControlsBaselineOpacity() const 1198 { 1199 return 0.4; 1200 } 1201 1202 void 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 1210 QColor 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 1218 bool 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 1242 bool 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 1266 bool 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 1293 bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&) 1294 { 1295 // We don't want to paint this at the moment. 1296 return false; 1297 } 1298 1299 bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&) 1300 { 1301 // We don't want to paint this at the moment. 1302 return false; 1303 } 1304 1305 bool 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 1317 String RenderThemeQt::formatMediaControlsCurrentTime(float currentTime, float duration) const 1318 { 1319 return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration); 1320 } 1321 1322 String RenderThemeQt::formatMediaControlsRemainingTime(float currentTime, float duration) const 1323 { 1324 return String(); 1325 } 1326 1327 bool 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 1375 bool 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 1385 bool 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 1420 bool 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 1436 void 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 1468 double RenderThemeQt::caretBlinkInterval() const 1469 { 1470 return QApplication::cursorFlashTime() / 1000.0 / 2.0; 1471 } 1472 1473 } 1474 1475 // vim: ts=4 sw=4 et 1476