source: webkit/trunk/Source/WebCore/platform/gtk/RenderThemeGtk.cpp @ 143463

Last change on this file since 143463 was 143463, checked in by commit-queue@webkit.org, 10 years ago

[Gtk] HTML5 Media controls require a design refresh
https://bugs.webkit.org/show_bug.cgi?id=83869

Source/WebCore:

Created new controls that depend less on Gtk and more in CSS.

Patch by Xabier Rodriguez Calvar <calvaris@igalia.com> and Martin Robinson <mrobinson@igalia.com> on 2013-02-20
Reviewed by Philippe Normand.

  • GNUmakefile.list.am: Added compilation for MediaControlsGtk.cpp

and MediaControlsGtk.h

  • css/mediaControlsGtk.css: Taken from Chromium and adapted for

WebKitGtk+.

  • html/shadow/MediaControlsGtk.cpp: Added.

(WebCore): Added MediaControlsGtk class.
(WebCore::MediaControlsGtk::MediaControlsGtk): Class constructor
(WebCore::MediaControls::create): Creates the Gtk+ controls
components.
(WebCore::MediaControlsGtk::createControls): Creates the Gtk+
controls components.
(WebCore::MediaControlsGtk::initializeControls): Initializes all
media controls.
(WebCore::MediaControlsGtk::setMediaController): Sets the media
controller.
(WebCore::MediaControlsGtk::reset): Resets the controllers.
(WebCore::MediaControlsGtk::playbackStarted): Invoked when the
playback starts
(WebCore::MediaControlsGtk::updateCurrentTimeDisplay): Updates the
controls when the current time shall be updated.
(WebCore::MediaControlsGtk::changedMute): Updates the controls
then the mute changes.
(WebCore::MediaControlsGtk::showVolumeSlider): Invoked when the
volume slider is meant to be shown.
(WebCore::MediaControlsGtk::createTextTrackDisplay): Creates the
track display. Though it is not used by us, it needs to be created
to prevent immediate crashes when loading a video.

  • html/shadow/MediaControlsGtk.h: Added.

(WebCore): Added the MediaControlsGtk class.
(MediaControlsGtk): Added the MediaControlsGtk class.

  • platform/gtk/RenderThemeGtk.cpp:

(WebCore): Added getStockSymbolicIconForWidgetType function
signature to load symbolic icons.
(WebCore::supportsFocus): Added media control widgets to support
focus so that the focus ring is not painted by WebCore.
(WebCore::RenderThemeGtk::paintMediaButton): Added the symbolic
icon support. It supports now normal and symbolic icons at the
same time.
(WebCore::RenderThemeGtk::paintMediaFullscreenButton): Added the
symbolic icon support.
(WebCore::RenderThemeGtk::paintMediaMuteButton): Added the
symbolic icon support.
(WebCore::RenderThemeGtk::paintMediaPlayButton): Added the
symbolic icon support.
(WebCore::RenderThemeGtk::paintMediaSeekBackButton): Added the
symbolic icon support.
(WebCore::RenderThemeGtk::paintMediaSeekForwardButton): Added the
symbolic icon support.
(WebCore::borderRadiiFromStyle): Created the radii info from the
style.
(WebCore::RenderThemeGtk::paintMediaSliderTrack): Removed the
background and the Gtk widget support as it is painted with
CSS. Also paint the time ranges with the CSS style.
(WebCore::RenderThemeGtk::paintMediaSliderThumb): Paint slider
thumb according to the CSS parameters.
(WebCore::RenderThemeGtk::paintMediaVolumeSliderContainer):
Delegates in the CSS.
(WebCore::RenderThemeGtk::paintMediaVolumeSliderTrack): Fills the
track up to the volume level and delegates the border in the CSS.
(WebCore::RenderThemeGtk::paintMediaVolumeSliderThumb): Delegates
in the paintMediaSliderThumb method so the thumb is painted the
same with the CSS parameters.
(WebCore::RenderThemeGtk::paintMediaCurrentTime): Removed the Gtk
background to use only CSS.

  • platform/gtk/RenderThemeGtk.h:

(RenderThemeGtk): Changed paintMediaButton to support the symbolic
and normal icons at the same time.

  • platform/gtk/RenderThemeGtk2.cpp:

(WebCore::RenderThemeGtk::adjustSliderThumbSize): Not adjusting
the thumb size and letting the CSS decide that for media slider.
(WebCore::getStockSymbolicIconForWidgetType): Implemented as a
fallback to the normal stock icons.

  • platform/gtk/RenderThemeGtk3.cpp:

(WebCore):
(WebCore::RenderThemeGtk::adjustSliderThumbSize): Not adjusting
the thumb size and letting the CSS decide that for the media
sliders.
(WebCore::getStockSymbolicIconForWidgetType): Added this function
to load symbolic icons. It falls back to normal icons if the
symbolic is not found.

Tools:

Patch by Xabier Rodriguez Calvar <calvaris@igalia.com> on 2013-02-20
Reviewed by Philippe Normand.

  • DumpRenderTree/gtk/DumpRenderTree.cpp:

(initializeGtkFontSettings): Added gnome as default icon theme for
the DRT.

  • WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp:

(WTR::initializeGtkSettings): Added gnome as default icon theme for
the WTR.

  • gtk/jhbuild.modules: Added gnome-icon-theme-symbolic as external

dependency.

LayoutTests:

Tests flagged and rebaselines.

Patch by Xabier Rodriguez Calvar <calvaris@igalia.com> on 2013-02-20
Reviewed by Philippe Normand.

  • platform/gtk/TestExpectations: Tests flagged and removed some

other flags.

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