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 "Chrome.h" 36 #include "ChromeClientQt.h" 37 #include "Color.h" 38 #include "Document.h" 39 #include "Font.h" 40 #include "FontSelector.h" 41 #include "GraphicsContext.h" 42 #include "HTMLMediaElement.h" 43 #include "HTMLNames.h" 44 #include "NotImplemented.h" 45 #include "Page.h" 46 #include "QWebPageClient.h" 47 #include "RenderBox.h" 48 #include "RenderSlider.h" 49 #include "RenderTheme.h" 50 #include "ScrollbarThemeQt.h" 51 #include "UserAgentStyleSheets.h" 52 #include "qwebpage.h" 53 54 #include <QApplication> 55 #include <QColor> 56 #include <QDebug> 57 #include <QFile> 58 #include <QLineEdit> 59 #include <QPainter> 60 #include <QPushButton> 61 #include <QStyleFactory> 62 #include <QStyleOptionButton> 63 #include <QStyleOptionFrameV2> 64 #include <QStyleOptionSlider> 65 #include <QWidget> 66 67 68 namespace WebCore { 69 70 using namespace HTMLNames; 71 72 73 StylePainter::StylePainter(RenderThemeQt* theme, const RenderObject::PaintInfo& paintInfo) 74 { 75 init(paintInfo.context ? paintInfo.context : 0, theme->qStyle()); 76 } 77 78 StylePainter::StylePainter(ScrollbarThemeQt* theme, GraphicsContext* context) 79 { 80 init(context, theme->style()); 81 } 82 83 void StylePainter::init(GraphicsContext* context, QStyle* themeStyle) 84 { 85 painter = static_cast<QPainter*>(context->platformContext()); 86 widget = 0; 87 QPaintDevice* dev = 0; 88 if (painter) 89 dev = painter->device(); 90 if (dev && dev->devType() == QInternal::Widget) 91 widget = static_cast<QWidget*>(dev); 92 style = themeStyle; 93 94 if (painter) { 95 // the styles often assume being called with a pristine painter where no brush is set, 96 // so reset it manually 97 oldBrush = painter->brush(); 98 painter->setBrush(Qt::NoBrush); 99 100 // painting the widget with anti-aliasing will make it blurry 101 // disable it here and restore it later 102 oldAntialiasing = painter->testRenderHint(QPainter::Antialiasing); 103 painter->setRenderHint(QPainter::Antialiasing, false); 104 } 105 } 106 107 StylePainter::~StylePainter() 108 { 109 if (painter) { 110 painter->setBrush(oldBrush); 111 painter->setRenderHints(QPainter::Antialiasing, oldAntialiasing); 112 } 113 } 114 115 PassRefPtr<RenderTheme> RenderThemeQt::create(Page* page) 116 { 117 return adoptRef(new RenderThemeQt(page)); 118 } 119 120 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 121 { 122 if (page) 123 return RenderThemeQt::create(page); 124 125 static RenderTheme* fallback = RenderThemeQt::create(0).releaseRef(); 126 return fallback; 127 } 128 129 RenderThemeQt::RenderThemeQt(Page* page) 130 : RenderTheme() 131 , m_page(page) 132 { 133 QPushButton button; 134 button.setAttribute(Qt::WA_MacSmallSize); 135 QFont defaultButtonFont = QApplication::font(&button); 136 QFontInfo fontInfo(defaultButtonFont); 137 m_buttonFontFamily = defaultButtonFont.family(); 138 #ifdef Q_WS_MAC 139 m_buttonFontPixelSize = fontInfo.pixelSize(); 140 #endif 141 142 m_fallbackStyle = QStyleFactory::create(QLatin1String("windows")); 143 } 144 145 RenderThemeQt::~RenderThemeQt() 146 { 147 delete m_fallbackStyle; 148 } 149 150 // for some widget painting, we need to fallback to Windows style 151 QStyle* RenderThemeQt::fallbackStyle() const 152 { 153 return (m_fallbackStyle) ? m_fallbackStyle : QApplication::style(); 154 } 155 156 QStyle* RenderThemeQt::qStyle() const 157 { 158 #ifdef Q_WS_MAEMO_5 159 return fallbackStyle(); 160 #endif 161 162 if (m_page) { 163 QWebPageClient* pageClient = m_page->chrome()->client()->platformPageClient(); 164 165 if (pageClient) 166 return pageClient->style(); 167 } 168 169 return QApplication::style(); 170 } 171 172 bool RenderThemeQt::supportsHover(const RenderStyle*) const 173 { 174 return true; 175 } 176 177 bool RenderThemeQt::supportsFocusRing(const RenderStyle*) const 178 { 179 return true; // Qt provides this through the style 180 } 181 182 int RenderThemeQt::baselinePosition(const RenderObject* o) const 183 { 184 if (!o->isBox()) 185 return 0; 186 187 if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) 188 return toRenderBox(o)->marginTop() + toRenderBox(o)->height() - 2; // Same as in old khtml 189 return RenderTheme::baselinePosition(o); 190 } 191 192 bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const 193 { 194 if (!isEnabled(o)) 195 return false; 196 197 // Checkboxes only have tint when checked. 198 if (o->style()->appearance() == CheckboxPart) 199 return isChecked(o); 200 201 // For now assume other controls have tint if enabled. 202 return true; 203 } 204 205 bool RenderThemeQt::supportsControlTints() const 206 { 207 return true; 208 } 209 210 static int findFrameLineWidth(QStyle* style) 211 { 212 QLineEdit lineEdit; 213 QStyleOptionFrameV2 opt; 214 return style->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, &lineEdit); 215 } 216 217 static QRect inflateButtonRect(const QRect& originalRect, QStyle* style) 218 { 219 QStyleOptionButton option; 220 option.state |= QStyle::State_Small; 221 option.rect = originalRect; 222 223 QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem, &option, 0); 224 if (!layoutRect.isNull()) { 225 int paddingLeft = layoutRect.left() - originalRect.left(); 226 int paddingRight = originalRect.right() - layoutRect.right(); 227 int paddingTop = layoutRect.top() - originalRect.top(); 228 int paddingBottom = originalRect.bottom() - layoutRect.bottom(); 229 230 return originalRect.adjusted(-paddingLeft, -paddingTop, paddingRight, paddingBottom); 231 } 232 return originalRect; 233 } 234 235 void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& rect) 236 { 237 switch (o->style()->appearance()) { 238 case CheckboxPart: 239 break; 240 case RadioPart: 241 break; 242 case PushButtonPart: 243 case ButtonPart: { 244 QRect inflatedRect = inflateButtonRect(rect, qStyle()); 245 rect = IntRect(inflatedRect.x(), inflatedRect.y(), inflatedRect.width(), inflatedRect.height()); 246 break; 247 } 248 case MenulistPart: 249 break; 250 default: 251 break; 252 } 253 } 254 255 Color RenderThemeQt::platformActiveSelectionBackgroundColor() const 256 { 257 QPalette pal = QApplication::palette(); 258 return pal.brush(QPalette::Active, QPalette::Highlight).color(); 259 } 260 261 Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const 262 { 263 QPalette pal = QApplication::palette(); 264 return pal.brush(QPalette::Inactive, QPalette::Highlight).color(); 265 } 266 267 Color RenderThemeQt::platformActiveSelectionForegroundColor() const 268 { 269 QPalette pal = QApplication::palette(); 270 return pal.brush(QPalette::Active, QPalette::HighlightedText).color(); 271 } 272 273 Color RenderThemeQt::platformInactiveSelectionForegroundColor() const 274 { 275 QPalette pal = QApplication::palette(); 276 return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color(); 277 } 278 279 void RenderThemeQt::systemFont(int, FontDescription&) const 280 { 281 // no-op 282 } 283 284 int RenderThemeQt::minimumMenuListSize(RenderStyle*) const 285 { 286 const QFontMetrics &fm = QApplication::fontMetrics(); 287 return 7 * fm.width(QLatin1Char('x')); 288 } 289 290 void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const 291 { 292 // If the width and height are both specified, then we have nothing to do. 293 if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto()) 294 return; 295 296 QSize size(0, 0); 297 const QFontMetrics fm(renderStyle->font().font()); 298 QStyle* style = qStyle(); 299 300 switch (renderStyle->appearance()) { 301 case CheckboxPart: { 302 QStyleOption styleOption; 303 styleOption.state |= QStyle::State_Small; 304 int checkBoxWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &styleOption); 305 size = QSize(checkBoxWidth, checkBoxWidth); 306 break; 307 } 308 case RadioPart: { 309 QStyleOption styleOption; 310 styleOption.state |= QStyle::State_Small; 311 int radioWidth = style->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, &styleOption); 312 size = QSize(radioWidth, radioWidth); 313 break; 314 } 315 case PushButtonPart: 316 case ButtonPart: { 317 QStyleOptionButton styleOption; 318 styleOption.state |= QStyle::State_Small; 319 QSize contentSize = fm.size(Qt::TextShowMnemonic, QString::fromLatin1("X")); 320 QSize pushButtonSize = style->sizeFromContents(QStyle::CT_PushButton, 321 &styleOption, contentSize, 0); 322 styleOption.rect = QRect(0, 0, pushButtonSize.width(), pushButtonSize.height()); 323 QRect layoutRect = style->subElementRect(QStyle::SE_PushButtonLayoutItem, 324 &styleOption, 0); 325 326 // If the style supports layout rects we use that, and compensate accordingly 327 // in paintButton() below. 328 if (!layoutRect.isNull()) 329 size.setHeight(layoutRect.height()); 330 else 331 size.setHeight(pushButtonSize.height()); 332 333 break; 334 } 335 case MenulistPart: { 336 QStyleOptionComboBox styleOption; 337 styleOption.state |= QStyle::State_Small; 338 int contentHeight = qMax(fm.lineSpacing(), 14) + 2; 339 QSize menuListSize = style->sizeFromContents(QStyle::CT_ComboBox, 340 &styleOption, QSize(0, contentHeight), 0); 341 size.setHeight(menuListSize.height()); 342 break; 343 } 344 case TextFieldPart: { 345 const int verticalMargin = 1; 346 const int horizontalMargin = 2; 347 int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin; 348 int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin; 349 QStyleOptionFrameV2 opt; 350 opt.lineWidth = findFrameLineWidth(style); 351 QSize sz = style->sizeFromContents(QStyle::CT_LineEdit, 352 &opt, 353 QSize(w, h).expandedTo(QApplication::globalStrut()), 354 0); 355 size.setHeight(sz.height()); 356 357 renderStyle->setPaddingLeft(Length(opt.lineWidth, Fixed)); 358 renderStyle->setPaddingRight(Length(opt.lineWidth, Fixed)); 359 break; 360 } 361 default: 362 break; 363 } 364 365 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. 366 if (renderStyle->width().isIntrinsicOrAuto() && size.width() > 0) 367 renderStyle->setWidth(Length(size.width(), Fixed)); 368 if (renderStyle->height().isAuto() && size.height() > 0) 369 renderStyle->setHeight(Length(size.height(), Fixed)); 370 } 371 372 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const 373 { 374 computeSizeBasedOnStyle(style); 375 } 376 377 bool RenderThemeQt::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 378 { 379 return paintButton(o, i, r); 380 } 381 382 void RenderThemeQt::setRadioSize(RenderStyle* style) const 383 { 384 computeSizeBasedOnStyle(style); 385 } 386 387 bool RenderThemeQt::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 388 { 389 return paintButton(o, i, r); 390 } 391 392 void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const 393 { 394 // Ditch the border. 395 style->resetBorder(); 396 397 #ifdef Q_WS_MAC 398 if (style->appearance() == PushButtonPart) { 399 // The Mac ports ignore the specified height for <input type="button"> elements 400 // unless a border and/or background CSS property is also specified. 401 style->setHeight(Length(Auto)); 402 } 403 #endif 404 405 // White-space is locked to pre 406 style->setWhiteSpace(PRE); 407 408 FontDescription fontDescription = style->fontDescription(); 409 fontDescription.setIsAbsoluteSize(true); 410 411 #ifdef Q_WS_MAC // Use fixed font size and family on Mac (like Safari does) 412 fontDescription.setSpecifiedSize(m_buttonFontPixelSize); 413 fontDescription.setComputedSize(m_buttonFontPixelSize); 414 #else 415 fontDescription.setSpecifiedSize(style->fontSize()); 416 fontDescription.setComputedSize(style->fontSize()); 417 #endif 418 419 FontFamily fontFamily; 420 fontFamily.setFamily(m_buttonFontFamily); 421 fontDescription.setFamily(fontFamily); 422 style->setFontDescription(fontDescription); 423 style->font().update(selector->fontSelector()); 424 style->setLineHeight(RenderStyle::initialLineHeight()); 425 426 setButtonSize(style); 427 setButtonPadding(style); 428 } 429 430 void RenderThemeQt::setButtonSize(RenderStyle* style) const 431 { 432 computeSizeBasedOnStyle(style); 433 } 434 435 void RenderThemeQt::setButtonPadding(RenderStyle* style) const 436 { 437 QStyleOptionButton styleOption; 438 styleOption.state |= QStyle::State_Small; 439 440 // Fake a button rect here, since we're just computing deltas 441 QRect originalRect = QRect(0, 0, 100, 30); 442 styleOption.rect = originalRect; 443 444 // Default padding is based on the button margin pixel metric 445 int buttonMargin = qStyle()->pixelMetric(QStyle::PM_ButtonMargin, &styleOption, 0); 446 int paddingLeft = buttonMargin; 447 int paddingRight = buttonMargin; 448 int paddingTop = 1; 449 int paddingBottom = 0; 450 451 // Then check if the style uses layout margins 452 QRect layoutRect = qStyle()->subElementRect(QStyle::SE_PushButtonLayoutItem, 453 &styleOption, 0); 454 if (!layoutRect.isNull()) { 455 QRect contentsRect = qStyle()->subElementRect(QStyle::SE_PushButtonContents, 456 &styleOption, 0); 457 paddingLeft = contentsRect.left() - layoutRect.left(); 458 paddingRight = layoutRect.right() - contentsRect.right(); 459 paddingTop = contentsRect.top() - layoutRect.top(); 460 461 // Can't use this right now because we don't have the baseline to compensate 462 // paddingBottom = layoutRect.bottom() - contentsRect.bottom(); 463 } 464 465 style->setPaddingLeft(Length(paddingLeft, Fixed)); 466 style->setPaddingRight(Length(paddingRight, Fixed)); 467 style->setPaddingTop(Length(paddingTop, Fixed)); 468 style->setPaddingBottom(Length(paddingBottom, Fixed)); 469 } 470 471 bool RenderThemeQt::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 472 { 473 StylePainter p(this, i); 474 if (!p.isValid()) 475 return true; 476 477 QStyleOptionButton option; 478 if (p.widget) 479 option.initFrom(p.widget); 480 481 option.rect = r; 482 option.state |= QStyle::State_Small; 483 484 ControlPart appearance = initializeCommonQStyleOptions(option, o); 485 if (appearance == PushButtonPart || appearance == ButtonPart) { 486 option.rect = inflateButtonRect(option.rect, qStyle()); 487 p.drawControl(QStyle::CE_PushButton, option); 488 } else if (appearance == RadioPart) 489 p.drawControl(QStyle::CE_RadioButton, option); 490 else if (appearance == CheckboxPart) 491 p.drawControl(QStyle::CE_CheckBox, option); 492 493 return false; 494 } 495 496 void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 497 { 498 style->setBackgroundColor(Color::transparent); 499 style->resetBorder(); 500 style->resetPadding(); 501 computeSizeBasedOnStyle(style); 502 } 503 504 bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 505 { 506 StylePainter p(this, i); 507 if (!p.isValid()) 508 return true; 509 510 QStyleOptionFrameV2 panel; 511 if (p.widget) 512 panel.initFrom(p.widget); 513 514 panel.rect = r; 515 panel.lineWidth = findFrameLineWidth(qStyle()); 516 panel.state |= QStyle::State_Sunken; 517 panel.features = QStyleOptionFrameV2::None; 518 519 // Get the correct theme data for a text field 520 ControlPart appearance = initializeCommonQStyleOptions(panel, o); 521 if (appearance != TextFieldPart 522 && appearance != SearchFieldPart 523 && appearance != TextAreaPart 524 && appearance != ListboxPart) 525 return true; 526 527 // Now paint the text field. 528 p.drawPrimitive(QStyle::PE_PanelLineEdit, panel); 529 530 return false; 531 } 532 533 void RenderThemeQt::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const 534 { 535 adjustTextFieldStyle(selector, style, element); 536 } 537 538 bool RenderThemeQt::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 539 { 540 return paintTextField(o, i, r); 541 } 542 543 void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 544 { 545 style->resetBorder(); 546 547 // Height is locked to auto. 548 style->setHeight(Length(Auto)); 549 550 // White-space is locked to pre 551 style->setWhiteSpace(PRE); 552 553 computeSizeBasedOnStyle(style); 554 555 // Add in the padding that we'd like to use. 556 setPopupPadding(style); 557 } 558 559 void RenderThemeQt::setPopupPadding(RenderStyle* style) const 560 { 561 const int padding = 8; 562 style->setPaddingLeft(Length(padding, Fixed)); 563 564 QStyleOptionComboBox opt; 565 int w = qStyle()->pixelMetric(QStyle::PM_ButtonIconSize, &opt, 0); 566 style->setPaddingRight(Length(padding + w, Fixed)); 567 568 style->setPaddingTop(Length(2, Fixed)); 569 style->setPaddingBottom(Length(0, Fixed)); 570 } 571 572 573 bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 574 { 575 StylePainter p(this, i); 576 if (!p.isValid()) 577 return true; 578 579 QStyleOptionComboBox opt; 580 if (p.widget) 581 opt.initFrom(p.widget); 582 initializeCommonQStyleOptions(opt, o); 583 584 const QPoint topLeft = r.topLeft(); 585 p.painter->translate(topLeft); 586 opt.rect.moveTo(QPoint(0, 0)); 587 opt.rect.setSize(r.size()); 588 589 p.drawComplexControl(QStyle::CC_ComboBox, opt); 590 p.painter->translate(-topLeft); 591 return false; 592 } 593 594 void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 595 { 596 // WORKAROUND because html.css specifies -webkit-border-radius for <select> so we override it here 597 // see also http://bugs.webkit.org/show_bug.cgi?id=18399 598 style->resetBorderRadius(); 599 600 // Height is locked to auto. 601 style->setHeight(Length(Auto)); 602 603 // White-space is locked to pre 604 style->setWhiteSpace(PRE); 605 606 computeSizeBasedOnStyle(style); 607 608 // Add in the padding that we'd like to use. 609 setPopupPadding(style); 610 } 611 612 bool RenderThemeQt::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, 613 const IntRect& r) 614 { 615 StylePainter p(this, i); 616 if (!p.isValid()) 617 return true; 618 619 QStyleOptionComboBox option; 620 if (p.widget) 621 option.initFrom(p.widget); 622 initializeCommonQStyleOptions(option, o); 623 option.rect = r; 624 625 // for drawing the combo box arrow, rely only on the fallback style 626 p.style = fallbackStyle(); 627 option.subControls = QStyle::SC_ComboBoxArrow; 628 p.drawComplexControl(QStyle::CC_ComboBox, option); 629 630 return false; 631 } 632 633 bool RenderThemeQt::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& pi, 634 const IntRect& r) 635 { 636 StylePainter p(this, pi); 637 if (!p.isValid()) 638 return true; 639 640 QStyleOptionSlider option; 641 if (p.widget) 642 option.initFrom(p.widget); 643 ControlPart appearance = initializeCommonQStyleOptions(option, o); 644 645 RenderSlider* renderSlider = toRenderSlider(o); 646 IntRect thumbRect = renderSlider->thumbRect(); 647 648 option.rect = r; 649 650 int value; 651 if (appearance == SliderVerticalPart) { 652 option.maximum = r.height() - thumbRect.height(); 653 value = thumbRect.y(); 654 } else { 655 option.maximum = r.width() - thumbRect.width(); 656 value = thumbRect.x(); 657 } 658 659 value = QStyle::sliderValueFromPosition(0, option.maximum, value, option.maximum); 660 661 option.sliderValue = value; 662 option.sliderPosition = value; 663 if (appearance == SliderVerticalPart) 664 option.orientation = Qt::Vertical; 665 666 if (renderSlider->inDragMode()) { 667 option.activeSubControls = QStyle::SC_SliderHandle; 668 option.state |= QStyle::State_Sunken; 669 } 670 671 const QPoint topLeft = r.topLeft(); 672 p.painter->translate(topLeft); 673 option.rect.moveTo(QPoint(0, 0)); 674 option.rect.setSize(r.size()); 675 676 p.drawComplexControl(QStyle::CC_Slider, option); 677 p.painter->translate(-topLeft); 678 679 return false; 680 } 681 682 void RenderThemeQt::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 683 { 684 style->setBoxShadow(0); 685 } 686 687 bool RenderThemeQt::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& pi, 688 const IntRect& r) 689 { 690 // We've already painted it in paintSliderTrack(), no need to do anything here. 691 return false; 692 } 693 694 void RenderThemeQt::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 695 { 696 style->setBoxShadow(0); 697 } 698 699 bool RenderThemeQt::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& pi, 700 const IntRect& r) 701 { 702 return true; 703 } 704 705 void RenderThemeQt::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, 706 Element* e) const 707 { 708 notImplemented(); 709 RenderTheme::adjustSearchFieldStyle(selector, style, e); 710 } 711 712 void RenderThemeQt::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, 713 Element* e) const 714 { 715 notImplemented(); 716 RenderTheme::adjustSearchFieldCancelButtonStyle(selector, style, e); 717 } 718 719 bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& pi, 720 const IntRect& r) 721 { 722 notImplemented(); 723 return RenderTheme::paintSearchFieldCancelButton(o, pi, r); 724 } 725 726 void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, 727 Element* e) const 728 { 729 notImplemented(); 730 RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e); 731 } 732 733 bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& pi, 734 const IntRect& r) 735 { 736 notImplemented(); 737 return RenderTheme::paintSearchFieldDecoration(o, pi, r); 738 } 739 740 void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, 741 Element* e) const 742 { 743 notImplemented(); 744 RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e); 745 } 746 747 bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& pi, 748 const IntRect& r) 749 { 750 notImplemented(); 751 return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r); 752 } 753 754 bool RenderThemeQt::supportsFocus(ControlPart appearance) const 755 { 756 switch (appearance) { 757 case PushButtonPart: 758 case ButtonPart: 759 case TextFieldPart: 760 case TextAreaPart: 761 case ListboxPart: 762 case MenulistPart: 763 case RadioPart: 764 case CheckboxPart: 765 case SliderHorizontalPart: 766 case SliderVerticalPart: 767 return true; 768 default: // No for all others... 769 return false; 770 } 771 } 772 773 void RenderThemeQt::setPaletteFromPageClientIfExists(QPalette& palette) const 774 { 775 #ifdef Q_WS_MAEMO_5 776 static QPalette lightGrayPalette(Qt::lightGray); 777 palette = lightGrayPalette; 778 return; 779 #endif 780 // If the webview has a custom palette, use it 781 if (!m_page) 782 return; 783 Chrome* chrome = m_page->chrome(); 784 if (!chrome) 785 return; 786 ChromeClient* chromeClient = chrome->client(); 787 if (!chromeClient) 788 return; 789 QWebPageClient* pageClient = chromeClient->platformPageClient(); 790 if (!pageClient) 791 return; 792 palette = pageClient->palette(); 793 } 794 795 ControlPart RenderThemeQt::initializeCommonQStyleOptions(QStyleOption& option, RenderObject* o) const 796 { 797 // Default bits: no focus, no mouse over 798 option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver); 799 800 if (!isEnabled(o)) 801 option.state &= ~QStyle::State_Enabled; 802 803 if (isReadOnlyControl(o)) 804 // Readonly is supported on textfields. 805 option.state |= QStyle::State_ReadOnly; 806 807 option.direction = Qt::LeftToRight; 808 809 if (isHovered(o)) 810 option.state |= QStyle::State_MouseOver; 811 812 setPaletteFromPageClientIfExists(option.palette); 813 RenderStyle* style = o->style(); 814 if (!style) 815 return NoControlPart; 816 817 ControlPart result = style->appearance(); 818 if (supportsFocus(result) && isFocused(o)) { 819 option.state |= QStyle::State_HasFocus; 820 option.state |= QStyle::State_KeyboardFocusChange; 821 } 822 823 if (style->direction() == WebCore::RTL) 824 option.direction = Qt::RightToLeft; 825 826 switch (result) { 827 case PushButtonPart: 828 case SquareButtonPart: 829 case ButtonPart: 830 case ButtonBevelPart: 831 case ListItemPart: 832 case MenulistButtonPart: 833 case SearchFieldResultsButtonPart: 834 case SearchFieldCancelButtonPart: { 835 if (isPressed(o)) 836 option.state |= QStyle::State_Sunken; 837 else if (result == PushButtonPart) 838 option.state |= QStyle::State_Raised; 839 break; 840 } 841 case RadioPart: 842 case CheckboxPart: 843 option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off); 844 } 845 846 return result; 847 } 848 849 #if ENABLE(VIDEO) 850 851 String RenderThemeQt::extraMediaControlsStyleSheet() 852 { 853 return String(mediaControlsQtUserAgentStyleSheet, sizeof(mediaControlsQtUserAgentStyleSheet)); 854 } 855 856 // Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100 857 class WorldMatrixTransformer { 858 public: 859 WorldMatrixTransformer(QPainter* painter, RenderObject* renderObject, const IntRect& r) : m_painter(painter) 860 { 861 RenderStyle* style = renderObject->style(); 862 m_originalTransform = m_painter->transform(); 863 m_painter->translate(r.x() + style->paddingLeft().value(), r.y() + style->paddingTop().value()); 864 m_painter->scale((r.width() - style->paddingLeft().value() - style->paddingRight().value()) / 100.0, 865 (r.height() - style->paddingTop().value() - style->paddingBottom().value()) / 100.0); 866 } 867 868 ~WorldMatrixTransformer() { m_painter->setTransform(m_originalTransform); } 869 870 private: 871 QPainter* m_painter; 872 QTransform m_originalTransform; 873 }; 874 875 HTMLMediaElement* RenderThemeQt::getMediaElementFromRenderObject(RenderObject* o) const 876 { 877 Node* node = o->node(); 878 Node* mediaNode = node ? node->shadowAncestorNode() : 0; 879 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) 880 return 0; 881 882 return static_cast<HTMLMediaElement*>(mediaNode); 883 } 884 885 void RenderThemeQt::paintMediaBackground(QPainter* painter, const IntRect& r) const 886 { 887 painter->setPen(Qt::NoPen); 888 static QColor transparentBlack(0, 0, 0, 100); 889 painter->setBrush(transparentBlack); 890 painter->drawRoundedRect(r.x(), r.y(), r.width(), r.height(), 5.0, 5.0); 891 } 892 893 QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const 894 { 895 QColor fgColor = platformActiveSelectionBackgroundColor(); 896 if (o && o->node()->active()) 897 fgColor = fgColor.lighter(); 898 return fgColor; 899 } 900 901 bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 902 { 903 return RenderTheme::paintMediaFullscreenButton(o, paintInfo, r); 904 } 905 906 bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 907 { 908 HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); 909 if (!mediaElement) 910 return false; 911 912 StylePainter p(this, paintInfo); 913 if (!p.isValid()) 914 return true; 915 916 p.painter->setRenderHint(QPainter::Antialiasing, true); 917 918 paintMediaBackground(p.painter, r); 919 920 WorldMatrixTransformer transformer(p.painter, o, r); 921 const QPointF speakerPolygon[6] = { QPointF(20, 30), QPointF(50, 30), QPointF(80, 0), 922 QPointF(80, 100), QPointF(50, 70), QPointF(20, 70)}; 923 924 p.painter->setBrush(getMediaControlForegroundColor(o)); 925 p.painter->drawPolygon(speakerPolygon, 6); 926 927 if (mediaElement->muted()) { 928 p.painter->setPen(Qt::red); 929 p.painter->drawLine(0, 100, 100, 0); 930 } 931 932 return false; 933 } 934 935 bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 936 { 937 HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); 938 if (!mediaElement) 939 return false; 940 941 StylePainter p(this, paintInfo); 942 if (!p.isValid()) 943 return true; 944 945 p.painter->setRenderHint(QPainter::Antialiasing, true); 946 947 paintMediaBackground(p.painter, r); 948 949 WorldMatrixTransformer transformer(p.painter, o, r); 950 p.painter->setBrush(getMediaControlForegroundColor(o)); 951 if (mediaElement->canPlay()) { 952 const QPointF playPolygon[3] = { QPointF(0, 0), QPointF(100, 50), QPointF(0, 100)}; 953 p.painter->drawPolygon(playPolygon, 3); 954 } else { 955 p.painter->drawRect(0, 0, 30, 100); 956 p.painter->drawRect(70, 0, 30, 100); 957 } 958 959 return false; 960 } 961 962 bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) 963 { 964 // We don't want to paint this at the moment. 965 return false; 966 } 967 968 bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) 969 { 970 // We don't want to paint this at the moment. 971 return false; 972 } 973 974 bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 975 { 976 HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); 977 if (!mediaElement) 978 return false; 979 980 StylePainter p(this, paintInfo); 981 if (!p.isValid()) 982 return true; 983 984 p.painter->setRenderHint(QPainter::Antialiasing, true); 985 986 paintMediaBackground(p.painter, r); 987 988 return false; 989 } 990 991 bool RenderThemeQt::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 992 { 993 HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o->parent()); 994 if (!mediaElement) 995 return false; 996 997 StylePainter p(this, paintInfo); 998 if (!p.isValid()) 999 return true; 1000 1001 p.painter->setRenderHint(QPainter::Antialiasing, true); 1002 1003 p.painter->setPen(Qt::NoPen); 1004 p.painter->setBrush(getMediaControlForegroundColor(o)); 1005 p.painter->drawRect(r.x(), r.y(), r.width(), r.height()); 1006 1007 return false; 1008 } 1009 #endif 1010 1011 void RenderThemeQt::adjustSliderThumbSize(RenderObject* o) const 1012 { 1013 ControlPart part = o->style()->appearance(); 1014 1015 if (part == MediaSliderThumbPart) { 1016 RenderStyle* parentStyle = o->parent()->style(); 1017 Q_ASSERT(parentStyle); 1018 1019 int parentHeight = parentStyle->height().value(); 1020 o->style()->setWidth(Length(parentHeight / 3, Fixed)); 1021 o->style()->setHeight(Length(parentHeight, Fixed)); 1022 } else if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) { 1023 QStyleOptionSlider option; 1024 if (part == SliderThumbVerticalPart) 1025 option.orientation = Qt::Vertical; 1026 1027 QStyle* style = qStyle(); 1028 1029 int width = style->pixelMetric(QStyle::PM_SliderLength, &option); 1030 int height = style->pixelMetric(QStyle::PM_SliderThickness, &option); 1031 o->style()->setWidth(Length(width, Fixed)); 1032 o->style()->setHeight(Length(height, Fixed)); 1033 } 1034 } 1035 1036 double RenderThemeQt::caretBlinkInterval() const 1037 { 1038 return QApplication::cursorFlashTime() / 1000.0 / 2.0; 1039 } 1040 1041 } 1042 1043 // vim: ts=4 sw=4 et 1044