OSDN Git Service

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