Home | History | Annotate | Download | only in gtk
      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