1 /* 2 * Copyright (C) 2007 Apple Inc. 3 * Copyright (C) 2007 Alp Toker <alp (at) atoker.com> 4 * Copyright (C) 2008 Collabora Ltd. 5 * Copyright (C) 2009 Kenneth Rohde Christiansen 6 * Copyright (C) 2010 Igalia S.L. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 * 23 */ 24 25 #include "config.h" 26 #include "RenderThemeGtk.h" 27 28 #include "CSSValueKeywords.h" 29 #include "GOwnPtr.h" 30 #include "Gradient.h" 31 #include "GraphicsContext.h" 32 #include "GtkVersioning.h" 33 #include "HTMLMediaElement.h" 34 #include "HTMLNames.h" 35 #include "MediaControlElements.h" 36 #include "PaintInfo.h" 37 #include "PlatformContextCairo.h" 38 #include "RenderBox.h" 39 #include "RenderObject.h" 40 #include "TimeRanges.h" 41 #include "UserAgentStyleSheets.h" 42 #include <gdk/gdk.h> 43 #include <gtk/gtk.h> 44 45 #if ENABLE(PROGRESS_TAG) 46 #include "RenderProgress.h" 47 #endif 48 49 namespace WebCore { 50 51 using namespace HTMLNames; 52 53 #if ENABLE(VIDEO) 54 static HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o) 55 { 56 Node* node = o->node(); 57 Node* mediaNode = node ? node->shadowAncestorNode() : 0; 58 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) 59 return 0; 60 61 return static_cast<HTMLMediaElement*>(mediaNode); 62 } 63 64 static GtkIconSize getMediaButtonIconSize(int mediaIconSize) 65 { 66 GtkIconSize iconSize = gtk_icon_size_from_name("webkit-media-button-size"); 67 if (!iconSize) 68 iconSize = gtk_icon_size_register("webkit-media-button-size", mediaIconSize, mediaIconSize); 69 return iconSize; 70 } 71 72 void RenderThemeGtk::initMediaButtons() 73 { 74 static bool iconsInitialized = false; 75 76 if (iconsInitialized) 77 return; 78 79 GRefPtr<GtkIconFactory> iconFactory = adoptGRef(gtk_icon_factory_new()); 80 GtkIconSource* iconSource = gtk_icon_source_new(); 81 const char* icons[] = { "audio-volume-high", "audio-volume-muted" }; 82 83 gtk_icon_factory_add_default(iconFactory.get()); 84 85 for (size_t i = 0; i < G_N_ELEMENTS(icons); ++i) { 86 gtk_icon_source_set_icon_name(iconSource, icons[i]); 87 GtkIconSet* iconSet = gtk_icon_set_new(); 88 gtk_icon_set_add_source(iconSet, iconSource); 89 gtk_icon_factory_add(iconFactory.get(), icons[i], iconSet); 90 gtk_icon_set_unref(iconSet); 91 } 92 93 gtk_icon_source_free(iconSource); 94 95 iconsInitialized = true; 96 } 97 #endif 98 99 PassRefPtr<RenderTheme> RenderThemeGtk::create() 100 { 101 return adoptRef(new RenderThemeGtk()); 102 } 103 104 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 105 { 106 static RenderTheme* rt = RenderThemeGtk::create().releaseRef(); 107 return rt; 108 } 109 110 RenderThemeGtk::RenderThemeGtk() 111 : m_panelColor(Color::white) 112 , m_sliderColor(Color::white) 113 , m_sliderThumbColor(Color::white) 114 , m_mediaIconSize(16) 115 , m_mediaSliderHeight(14) 116 , m_mediaSliderThumbWidth(12) 117 , m_mediaSliderThumbHeight(12) 118 { 119 platformInit(); 120 #if ENABLE(VIDEO) 121 initMediaColors(); 122 initMediaButtons(); 123 #endif 124 } 125 126 static bool supportsFocus(ControlPart appearance) 127 { 128 switch (appearance) { 129 case PushButtonPart: 130 case ButtonPart: 131 case TextFieldPart: 132 case TextAreaPart: 133 case SearchFieldPart: 134 case MenulistPart: 135 case RadioPart: 136 case CheckboxPart: 137 case SliderHorizontalPart: 138 case SliderVerticalPart: 139 return true; 140 default: 141 return false; 142 } 143 } 144 145 bool RenderThemeGtk::supportsFocusRing(const RenderStyle* style) const 146 { 147 return supportsFocus(style->appearance()); 148 } 149 150 bool RenderThemeGtk::controlSupportsTints(const RenderObject* o) const 151 { 152 return isEnabled(o); 153 } 154 155 int RenderThemeGtk::baselinePosition(const RenderObject* o) const 156 { 157 if (!o->isBox()) 158 return 0; 159 160 // FIXME: This strategy is possibly incorrect for the GTK+ port. 161 if (o->style()->appearance() == CheckboxPart 162 || o->style()->appearance() == RadioPart) { 163 const RenderBox* box = toRenderBox(o); 164 return box->marginTop() + box->height() - 2; 165 } 166 167 return RenderTheme::baselinePosition(o); 168 } 169 170 // This is used in RenderThemeGtk2 and RenderThemeGtk3. Normally, it would be in 171 // the RenderThemeGtk header (perhaps as a static method), but we want to avoid 172 // having to include GTK+ headers only for the GtkTextDirection enum. 173 GtkTextDirection gtkTextDirection(TextDirection direction) 174 { 175 switch (direction) { 176 case RTL: 177 return GTK_TEXT_DIR_RTL; 178 case LTR: 179 return GTK_TEXT_DIR_LTR; 180 default: 181 return GTK_TEXT_DIR_NONE; 182 } 183 } 184 185 static GtkStateType gtkIconState(RenderTheme* theme, RenderObject* renderObject) 186 { 187 if (!theme->isEnabled(renderObject)) 188 return GTK_STATE_INSENSITIVE; 189 if (theme->isPressed(renderObject)) 190 return GTK_STATE_ACTIVE; 191 if (theme->isHovered(renderObject)) 192 return GTK_STATE_PRELIGHT; 193 194 return GTK_STATE_NORMAL; 195 } 196 197 void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const 198 { 199 // Some layout tests check explicitly that buttons ignore line-height. 200 if (style->appearance() == PushButtonPart) 201 style->setLineHeight(RenderStyle::initialLineHeight()); 202 } 203 204 void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 205 { 206 // The tests check explicitly that select menu buttons ignore line height. 207 style->setLineHeight(RenderStyle::initialLineHeight()); 208 209 // We cannot give a proper rendering when border radius is active, unfortunately. 210 style->resetBorderRadius(); 211 } 212 213 void RenderThemeGtk::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 214 { 215 adjustMenuListStyle(selector, style, e); 216 } 217 218 bool RenderThemeGtk::paintMenuListButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) 219 { 220 return paintMenuList(object, info, rect); 221 } 222 223 bool RenderThemeGtk::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r) 224 { 225 return paintTextField(o, i, r); 226 } 227 228 static void paintGdkPixbuf(GraphicsContext* context, const GdkPixbuf* icon, const IntRect& iconRect) 229 { 230 IntSize iconSize(gdk_pixbuf_get_width(icon), gdk_pixbuf_get_height(icon)); 231 if (iconRect.size() != iconSize) { 232 // We could use cairo_scale() here but cairo/pixman downscale quality is quite bad. 233 GRefPtr<GdkPixbuf> scaledIcon = gdk_pixbuf_scale_simple(icon, iconRect.width(), iconRect.height(), 234 GDK_INTERP_BILINEAR); 235 icon = scaledIcon.get(); 236 } 237 238 cairo_t* cr = context->platformContext()->cr(); 239 cairo_save(cr); 240 gdk_cairo_set_source_pixbuf(cr, icon, iconRect.x(), iconRect.y()); 241 cairo_paint(cr); 242 cairo_restore(cr); 243 } 244 245 // Defined in GTK+ (gtk/gtkiconfactory.c) 246 static const gint gtkIconSizeMenu = 16; 247 static const gint gtkIconSizeSmallToolbar = 18; 248 static const gint gtkIconSizeButton = 20; 249 static const gint gtkIconSizeLargeToolbar = 24; 250 static const gint gtkIconSizeDnd = 32; 251 static const gint gtkIconSizeDialog = 48; 252 253 static GtkIconSize getIconSizeForPixelSize(gint pixelSize) 254 { 255 if (pixelSize < gtkIconSizeSmallToolbar) 256 return GTK_ICON_SIZE_MENU; 257 if (pixelSize >= gtkIconSizeSmallToolbar && pixelSize < gtkIconSizeButton) 258 return GTK_ICON_SIZE_SMALL_TOOLBAR; 259 if (pixelSize >= gtkIconSizeButton && pixelSize < gtkIconSizeLargeToolbar) 260 return GTK_ICON_SIZE_BUTTON; 261 if (pixelSize >= gtkIconSizeLargeToolbar && pixelSize < gtkIconSizeDnd) 262 return GTK_ICON_SIZE_LARGE_TOOLBAR; 263 if (pixelSize >= gtkIconSizeDnd && pixelSize < gtkIconSizeDialog) 264 return GTK_ICON_SIZE_DND; 265 266 return GTK_ICON_SIZE_DIALOG; 267 } 268 269 void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 270 { 271 adjustSearchFieldCancelButtonStyle(selector, style, e); 272 } 273 274 bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) 275 { 276 return paintSearchFieldResultsDecoration(o, i, rect); 277 } 278 279 static void adjustSearchFieldIconStyle(RenderStyle* style) 280 { 281 style->resetBorder(); 282 style->resetPadding(); 283 284 // Get the icon size based on the font size. 285 int fontSize = style->fontSize(); 286 if (fontSize < gtkIconSizeMenu) { 287 style->setWidth(Length(fontSize, Fixed)); 288 style->setHeight(Length(fontSize, Fixed)); 289 return; 290 } 291 gint width = 0, height = 0; 292 gtk_icon_size_lookup(getIconSizeForPixelSize(fontSize), &width, &height); 293 style->setWidth(Length(width, Fixed)); 294 style->setHeight(Length(height, Fixed)); 295 } 296 297 void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 298 { 299 adjustSearchFieldIconStyle(style); 300 } 301 302 static IntRect centerRectVerticallyInParentInputElement(RenderObject* renderObject, const IntRect& rect) 303 { 304 // Get the renderer of <input> element. 305 Node* input = renderObject->node()->shadowAncestorNode(); 306 if (!input->renderer()->isBox()) 307 return IntRect(); 308 309 // If possible center the y-coordinate of the rect vertically in the parent input element. 310 // We also add one pixel here to ensure that the y coordinate is rounded up for box heights 311 // that are even, which looks in relation to the box text. 312 IntRect inputContentBox = toRenderBox(input->renderer())->absoluteContentBox(); 313 314 // Make sure the scaled decoration stays square and will fit in its parent's box. 315 int iconSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), rect.height())); 316 IntRect scaledRect(rect.x(), inputContentBox.y() + (inputContentBox.height() - iconSize + 1) / 2, iconSize, iconSize); 317 return scaledRect; 318 } 319 320 bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 321 { 322 IntRect iconRect = centerRectVerticallyInParentInputElement(renderObject, rect); 323 if (iconRect.isEmpty()) 324 return false; 325 326 GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_FIND, 327 gtkTextDirection(renderObject->style()->direction()), 328 gtkIconState(this, renderObject), 329 getIconSizeForPixelSize(rect.height())); 330 paintGdkPixbuf(paintInfo.context, icon.get(), iconRect); 331 return false; 332 } 333 334 void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 335 { 336 adjustSearchFieldIconStyle(style); 337 } 338 339 bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 340 { 341 IntRect iconRect = centerRectVerticallyInParentInputElement(renderObject, rect); 342 if (iconRect.isEmpty()) 343 return false; 344 345 GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_CLEAR, 346 gtkTextDirection(renderObject->style()->direction()), 347 gtkIconState(this, renderObject), 348 getIconSizeForPixelSize(rect.height())); 349 paintGdkPixbuf(paintInfo.context, icon.get(), iconRect); 350 return false; 351 } 352 353 void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 354 { 355 // We cannot give a proper rendering when border radius is active, unfortunately. 356 style->resetBorderRadius(); 357 style->setLineHeight(RenderStyle::initialLineHeight()); 358 } 359 360 bool RenderThemeGtk::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& rect) 361 { 362 return paintTextField(o, i, rect); 363 } 364 365 bool RenderThemeGtk::paintCapsLockIndicator(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 366 { 367 // The other paint methods don't need to check whether painting is disabled because RenderTheme already checks it 368 // before calling them, but paintCapsLockIndicator() is called by RenderTextControlSingleLine which doesn't check it. 369 if (paintInfo.context->paintingDisabled()) 370 return true; 371 372 int iconSize = std::min(rect.width(), rect.height()); 373 GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_CAPS_LOCK_WARNING, 374 gtkTextDirection(renderObject->style()->direction()), 375 0, getIconSizeForPixelSize(iconSize)); 376 377 // Only re-scale the icon when it's smaller than the minimum icon size. 378 if (iconSize >= gtkIconSizeMenu) 379 iconSize = gdk_pixbuf_get_height(icon.get()); 380 381 // GTK+ locates the icon right aligned in the entry. The given rectangle is already 382 // centered vertically by RenderTextControlSingleLine. 383 IntRect iconRect(rect.x() + rect.width() - iconSize, 384 rect.y() + (rect.height() - iconSize) / 2, 385 iconSize, iconSize); 386 paintGdkPixbuf(paintInfo.context, icon.get(), iconRect); 387 return true; 388 } 389 390 void RenderThemeGtk::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 391 { 392 style->setBoxShadow(0); 393 } 394 395 void RenderThemeGtk::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 396 { 397 style->setBoxShadow(0); 398 } 399 400 double RenderThemeGtk::caretBlinkInterval() const 401 { 402 GtkSettings* settings = gtk_settings_get_default(); 403 404 gboolean shouldBlink; 405 gint time; 406 407 g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL); 408 409 if (!shouldBlink) 410 return 0; 411 412 return time / 2000.; 413 } 414 415 double RenderThemeGtk::getScreenDPI() 416 { 417 // FIXME: Really this should be the widget's screen. 418 GdkScreen* screen = gdk_screen_get_default(); 419 if (!screen) 420 return 96; // Default to 96 DPI. 421 422 float dpi = gdk_screen_get_resolution(screen); 423 if (dpi <= 0) 424 return 96; 425 return dpi; 426 } 427 428 void RenderThemeGtk::systemFont(int, FontDescription& fontDescription) const 429 { 430 GtkSettings* settings = gtk_settings_get_default(); 431 if (!settings) 432 return; 433 434 // This will be a font selection string like "Sans 10" so we cannot use it as the family name. 435 GOwnPtr<gchar> fontName; 436 g_object_get(settings, "gtk-font-name", &fontName.outPtr(), NULL); 437 438 PangoFontDescription* pangoDescription = pango_font_description_from_string(fontName.get()); 439 if (!pangoDescription) 440 return; 441 442 fontDescription.firstFamily().setFamily(pango_font_description_get_family(pangoDescription)); 443 444 int size = pango_font_description_get_size(pangoDescription) / PANGO_SCALE; 445 // If the size of the font is in points, we need to convert it to pixels. 446 if (!pango_font_description_get_size_is_absolute(pangoDescription)) 447 size = size * (getScreenDPI() / 72.0); 448 449 fontDescription.setSpecifiedSize(size); 450 fontDescription.setIsAbsoluteSize(true); 451 fontDescription.setGenericFamily(FontDescription::NoFamily); 452 fontDescription.setWeight(FontWeightNormal); 453 fontDescription.setItalic(false); 454 pango_font_description_free(pangoDescription); 455 } 456 457 void RenderThemeGtk::platformColorsDidChange() 458 { 459 #if ENABLE(VIDEO) 460 initMediaColors(); 461 #endif 462 RenderTheme::platformColorsDidChange(); 463 } 464 465 #if ENABLE(VIDEO) 466 String RenderThemeGtk::extraMediaControlsStyleSheet() 467 { 468 return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet)); 469 } 470 471 void RenderThemeGtk::adjustMediaSliderThumbSize(RenderObject* renderObject) const 472 { 473 ASSERT(renderObject->style()->appearance() == MediaSliderThumbPart); 474 renderObject->style()->setWidth(Length(m_mediaSliderThumbWidth, Fixed)); 475 renderObject->style()->setHeight(Length(m_mediaSliderThumbHeight, Fixed)); 476 } 477 478 bool RenderThemeGtk::paintMediaButton(RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, const char* iconName) 479 { 480 GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_CONTAINER, iconName, 481 gtkTextDirection(renderObject->style()->direction()), 482 gtkIconState(this, renderObject), 483 getMediaButtonIconSize(m_mediaIconSize)); 484 IntRect iconRect(rect.x() + (rect.width() - m_mediaIconSize) / 2, 485 rect.y() + (rect.height() - m_mediaIconSize) / 2, 486 m_mediaIconSize, m_mediaIconSize); 487 context->fillRect(FloatRect(rect), m_panelColor, ColorSpaceDeviceRGB); 488 paintGdkPixbuf(context, icon.get(), iconRect); 489 return false; 490 } 491 492 bool RenderThemeGtk::paintMediaFullscreenButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 493 { 494 return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_FULLSCREEN); 495 } 496 497 bool RenderThemeGtk::paintMediaMuteButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 498 { 499 HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(renderObject); 500 if (!mediaElement) 501 return false; 502 503 return paintMediaButton(renderObject, paintInfo.context, rect, mediaElement->muted() ? "audio-volume-muted" : "audio-volume-high"); 504 } 505 506 bool RenderThemeGtk::paintMediaPlayButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 507 { 508 Node* node = renderObject->node(); 509 if (!node) 510 return false; 511 512 MediaControlPlayButtonElement* button = static_cast<MediaControlPlayButtonElement*>(node); 513 return paintMediaButton(renderObject, paintInfo.context, rect, button->displayType() == MediaPlayButton ? GTK_STOCK_MEDIA_PLAY : GTK_STOCK_MEDIA_PAUSE); 514 } 515 516 bool RenderThemeGtk::paintMediaSeekBackButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 517 { 518 return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_MEDIA_REWIND); 519 } 520 521 bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 522 { 523 return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_MEDIA_FORWARD); 524 } 525 526 bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 527 { 528 GraphicsContext* context = paintInfo.context; 529 530 context->fillRect(FloatRect(r), m_panelColor, ColorSpaceDeviceRGB); 531 context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2, 532 r.width(), m_mediaSliderHeight)), m_sliderColor, ColorSpaceDeviceRGB); 533 534 RenderStyle* style = o->style(); 535 HTMLMediaElement* mediaElement = toParentMediaElement(o); 536 537 if (!mediaElement) 538 return false; 539 540 // Draw the buffered ranges. This code is highly inspired from 541 // Chrome for the gradient code. 542 float mediaDuration = mediaElement->duration(); 543 RefPtr<TimeRanges> timeRanges = mediaElement->buffered(); 544 IntRect trackRect = r; 545 int totalWidth = trackRect.width(); 546 547 trackRect.inflate(-style->borderLeftWidth()); 548 context->save(); 549 context->setStrokeStyle(NoStroke); 550 551 for (unsigned index = 0; index < timeRanges->length(); ++index) { 552 ExceptionCode ignoredException; 553 float start = timeRanges->start(index, ignoredException); 554 float end = timeRanges->end(index, ignoredException); 555 int width = ((end - start) * totalWidth) / mediaDuration; 556 IntRect rangeRect; 557 if (!index) { 558 rangeRect = trackRect; 559 rangeRect.setWidth(width); 560 } else { 561 rangeRect.setLocation(IntPoint(trackRect.x() + start / mediaDuration* totalWidth, trackRect.y())); 562 rangeRect.setSize(IntSize(width, trackRect.height())); 563 } 564 565 // Don't bother drawing empty range. 566 if (rangeRect.isEmpty()) 567 continue; 568 569 IntPoint sliderTopLeft = rangeRect.location(); 570 IntPoint sliderTopRight = sliderTopLeft; 571 sliderTopRight.move(0, rangeRect.height()); 572 573 RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight); 574 Color startColor = m_panelColor; 575 gradient->addColorStop(0.0, startColor); 576 gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha())); 577 578 context->setFillGradient(gradient); 579 context->fillRect(rangeRect); 580 } 581 582 context->restore(); 583 return false; 584 } 585 586 bool RenderThemeGtk::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) 587 { 588 // Make the thumb nicer with rounded corners. 589 paintInfo.context->fillRoundedRect(r, IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), m_sliderThumbColor, ColorSpaceDeviceRGB); 590 return false; 591 } 592 593 bool RenderThemeGtk::paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo& paintInfo, const IntRect& rect) 594 { 595 GraphicsContext* context = paintInfo.context; 596 context->fillRect(FloatRect(rect), m_panelColor, ColorSpaceDeviceRGB); 597 return false; 598 } 599 600 bool RenderThemeGtk::paintMediaVolumeSliderTrack(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 601 { 602 return paintSliderTrack(renderObject, paintInfo, rect); 603 } 604 605 bool RenderThemeGtk::paintMediaVolumeSliderThumb(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 606 { 607 return paintSliderThumb(renderObject, paintInfo, rect); 608 } 609 610 String RenderThemeGtk::formatMediaControlsCurrentTime(float currentTime, float duration) const 611 { 612 return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration); 613 } 614 615 bool RenderThemeGtk::paintMediaCurrentTime(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) 616 { 617 GraphicsContext* context = paintInfo.context; 618 619 context->fillRect(FloatRect(rect), m_panelColor, ColorSpaceDeviceRGB); 620 return false; 621 } 622 #endif 623 624 #if ENABLE(PROGRESS_TAG) 625 void RenderThemeGtk::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 626 { 627 style->setBoxShadow(0); 628 } 629 630 // These values have been copied from RenderThemeChromiumSkia.cpp 631 static const int progressActivityBlocks = 5; 632 static const int progressAnimationFrames = 10; 633 static const double progressAnimationInterval = 0.125; 634 double RenderThemeGtk::animationRepeatIntervalForProgressBar(RenderProgress*) const 635 { 636 return progressAnimationInterval; 637 } 638 639 double RenderThemeGtk::animationDurationForProgressBar(RenderProgress*) const 640 { 641 return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth; 642 } 643 644 IntRect RenderThemeGtk::calculateProgressRect(RenderObject* renderObject, const IntRect& fullBarRect) 645 { 646 IntRect progressRect(fullBarRect); 647 RenderProgress* renderProgress = toRenderProgress(renderObject); 648 if (renderProgress->isDeterminate()) { 649 int progressWidth = progressRect.width() * renderProgress->position(); 650 if (renderObject->style()->direction() == RTL) 651 progressRect.setX(progressRect.x() + progressRect.width() - progressWidth); 652 progressRect.setWidth(progressWidth); 653 return progressRect; 654 } 655 656 double animationProgress = renderProgress->animationProgress(); 657 658 // Never let the progress rect shrink smaller than 2 pixels. 659 int newWidth = max(2, progressRect.width() / progressActivityBlocks); 660 int movableWidth = progressRect.width() - newWidth; 661 progressRect.setWidth(newWidth); 662 663 // We want the first 0.5 units of the animation progress to represent the 664 // forward motion and the second 0.5 units to represent the backward motion, 665 // thus we multiply by two here to get the full sweep of the progress bar with 666 // each direction. 667 if (animationProgress < 0.5) 668 progressRect.setX(progressRect.x() + (animationProgress * 2 * movableWidth)); 669 else 670 progressRect.setX(progressRect.x() + ((1.0 - animationProgress) * 2 * movableWidth)); 671 return progressRect; 672 } 673 #endif 674 675 } 676