4b622eac2ab8b644e159e12582b63e6ed24ca6fa
[WebKit-https.git] / Source / WebCore / rendering / 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 "ExceptionCodePlaceholder.h"
30 #include "FileList.h"
31 #include "FileSystem.h"
32 #include "FontDescription.h"
33 #include "GRefPtrGtk.h"
34 #include "GUniquePtrGtk.h"
35 #include "Gradient.h"
36 #include "GraphicsContext.h"
37 #include "GtkVersioning.h"
38 #include "HTMLInputElement.h"
39 #include "HTMLMediaElement.h"
40 #include "LocalizedStrings.h"
41 #include "MediaControlElements.h"
42 #include "NamedNodeMap.h"
43 #include "Page.h"
44 #include "PaintInfo.h"
45 #include "PlatformContextCairo.h"
46 #include "RenderBox.h"
47 #include "RenderObject.h"
48 #include "RenderProgress.h"
49 #include "ScrollbarThemeGtk.h"
50 #include "StringTruncator.h"
51 #include "TimeRanges.h"
52 #include "UserAgentScripts.h"
53 #include "UserAgentStyleSheets.h"
54 #include <cmath>
55 #include <gdk/gdk.h>
56 #include <glib.h>
57 #include <gtk/gtk.h>
58 #include <wtf/NeverDestroyed.h>
59 #include <wtf/glib/GRefPtr.h>
60 #include <wtf/glib/GUniquePtr.h>
61 #include <wtf/text/CString.h>
62 #include <wtf/text/StringBuilder.h>
63
64 namespace WebCore {
65
66 Ref<RenderTheme> RenderThemeGtk::create()
67 {
68     return adoptRef(*new RenderThemeGtk());
69 }
70
71 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
72 {
73     static RenderTheme& rt = RenderThemeGtk::create().leakRef();
74     return &rt;
75 }
76
77 static double getScreenDPI()
78 {
79     // FIXME: Really this should be the widget's screen.
80     GdkScreen* screen = gdk_screen_get_default();
81     if (!screen)
82         return 96; // Default to 96 DPI.
83
84     float dpi = gdk_screen_get_resolution(screen);
85     if (dpi <= 0)
86         return 96;
87     return dpi;
88 }
89
90 void RenderThemeGtk::updateCachedSystemFontDescription(CSSValueID, FontCascadeDescription& fontDescription) const
91 {
92     GtkSettings* settings = gtk_settings_get_default();
93     if (!settings)
94         return;
95
96     // This will be a font selection string like "Sans 10" so we cannot use it as the family name.
97     GUniqueOutPtr<gchar> fontName;
98     g_object_get(settings, "gtk-font-name", &fontName.outPtr(), nullptr);
99     if (!fontName || !fontName.get()[0])
100         return;
101
102     PangoFontDescription* pangoDescription = pango_font_description_from_string(fontName.get());
103     if (!pangoDescription)
104         return;
105
106     fontDescription.setOneFamily(pango_font_description_get_family(pangoDescription));
107
108     int size = pango_font_description_get_size(pangoDescription) / PANGO_SCALE;
109     // If the size of the font is in points, we need to convert it to pixels.
110     if (!pango_font_description_get_size_is_absolute(pangoDescription))
111         size = size * (getScreenDPI() / 72.0);
112
113     fontDescription.setSpecifiedSize(size);
114     fontDescription.setIsAbsoluteSize(true);
115     fontDescription.setWeight(FontWeightNormal);
116     fontDescription.setItalic(FontItalicOff);
117     pango_font_description_free(pangoDescription);
118 }
119
120 #if ENABLE(DATALIST_ELEMENT)
121 IntSize RenderThemeGtk::sliderTickSize() const
122 {
123     // FIXME: We need to set this to the size of one tick mark.
124     return IntSize(0, 0);
125 }
126
127 int RenderThemeGtk::sliderTickOffsetFromTrackCenter() const
128 {
129     // FIXME: We need to set this to the position of the tick marks.
130     return 0;
131 }
132 #endif
133
134 #ifndef GTK_API_VERSION_2
135
136 // This is the default value defined by GTK+, where it was defined as MIN_ARROW_SIZE in gtkarrow.c.
137 static const int minArrowSize = 15;
138 // This is the default value defined by GTK+, where it was defined as MIN_ARROW_WIDTH in gtkspinbutton.c.
139 static const int minSpinButtonArrowSize = 6;
140
141 enum RenderThemePart {
142     Entry,
143     EntrySelection,
144     EntryIconLeft,
145     EntryIconRight,
146     Button,
147     CheckButton,
148     CheckButtonCheck,
149     RadioButton,
150     RadioButtonRadio,
151     ComboBox,
152     ComboBoxButton,
153     ComboBoxArrow,
154     Scale,
155     ScaleTrough,
156     ScaleSlider,
157     ProgressBar,
158     ProgressBarTrough,
159     ProgressBarProgress,
160     ListBox,
161     ListBoxSelection,
162     SpinButton,
163     SpinButtonUpButton,
164     SpinButtonDownButton,
165 #if ENABLE(VIDEO)
166     MediaButton,
167 #endif
168 };
169
170 static void gtkStyleChangedCallback(GObject*, GParamSpec*)
171 {
172     static_cast<ScrollbarThemeGtk&>(ScrollbarTheme::theme()).themeChanged();
173     Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
174 }
175
176 static GRefPtr<GtkStyleContext> createStyleContext(RenderThemePart themePart, GtkStyleContext* parent = nullptr)
177 {
178     static bool initialized = false;
179     if (!initialized) {
180         GtkSettings* settings = gtk_settings_get_default();
181         g_signal_connect(settings, "notify::gtk-theme-name", G_CALLBACK(gtkStyleChangedCallback), nullptr);
182         g_signal_connect(settings, "notify::gtk-color-scheme", G_CALLBACK(gtkStyleChangedCallback), nullptr);
183         initialized = true;
184     }
185
186     GRefPtr<GtkWidgetPath> path = adoptGRef(parent ? gtk_widget_path_copy(gtk_style_context_get_path(parent)) : gtk_widget_path_new());
187
188     switch (themePart) {
189     case Entry:
190         gtk_widget_path_append_type(path.get(), GTK_TYPE_ENTRY);
191 #if GTK_CHECK_VERSION(3, 19, 2)
192         gtk_widget_path_iter_set_object_name(path.get(), -1, "entry");
193 #else
194         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_ENTRY);
195 #endif
196         break;
197     case EntrySelection:
198         gtk_widget_path_append_type(path.get(), GTK_TYPE_ENTRY);
199 #if GTK_CHECK_VERSION(3, 19, 2)
200         gtk_widget_path_iter_set_object_name(path.get(), -1, "selection");
201 #else
202         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_ENTRY);
203 #endif
204         break;
205     case EntryIconLeft:
206     case EntryIconRight:
207         gtk_widget_path_append_type(path.get(), GTK_TYPE_ENTRY);
208 #if GTK_CHECK_VERSION(3, 19, 2)
209         gtk_widget_path_iter_set_object_name(path.get(), -1, "image");
210         gtk_widget_path_iter_add_class(path.get(), -1, themePart == EntryIconLeft ? "left" : "right");
211 #endif
212         break;
213     case Button:
214         gtk_widget_path_append_type(path.get(), GTK_TYPE_BUTTON);
215 #if GTK_CHECK_VERSION(3, 19, 2)
216         gtk_widget_path_iter_set_object_name(path.get(), -1, "button");
217 #else
218         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_BUTTON);
219 #endif
220         gtk_widget_path_iter_add_class(path.get(), -1, "text-button");
221         break;
222     case CheckButton:
223         gtk_widget_path_append_type(path.get(), GTK_TYPE_CHECK_BUTTON);
224 #if GTK_CHECK_VERSION(3, 19, 2)
225         gtk_widget_path_iter_set_object_name(path.get(), -1, "checkbutton");
226 #else
227         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_CHECK);
228 #endif
229         break;
230     case CheckButtonCheck:
231         gtk_widget_path_append_type(path.get(), GTK_TYPE_CHECK_BUTTON);
232 #if GTK_CHECK_VERSION(3, 19, 2)
233         gtk_widget_path_iter_set_object_name(path.get(), -1, "check");
234 #else
235         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_CHECK);
236 #endif
237         break;
238     case RadioButton:
239         gtk_widget_path_append_type(path.get(), GTK_TYPE_RADIO_BUTTON);
240 #if GTK_CHECK_VERSION(3, 19, 2)
241         gtk_widget_path_iter_set_object_name(path.get(), -1, "radiobutton");
242 #else
243         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_RADIO);
244 #endif
245         break;
246     case RadioButtonRadio:
247         gtk_widget_path_append_type(path.get(), GTK_TYPE_RADIO_BUTTON);
248 #if GTK_CHECK_VERSION(3, 19, 2)
249         gtk_widget_path_iter_set_object_name(path.get(), -1, "radio");
250 #else
251         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_RADIO);
252 #endif
253         break;
254     case ComboBox:
255         gtk_widget_path_append_type(path.get(), GTK_TYPE_COMBO_BOX);
256 #if GTK_CHECK_VERSION(3, 19, 2)
257         gtk_widget_path_iter_set_object_name(path.get(), -1, "combobox");
258 #endif
259         break;
260     case ComboBoxButton:
261         gtk_widget_path_append_type(path.get(), GTK_TYPE_BUTTON);
262 #if GTK_CHECK_VERSION(3, 19, 2)
263         gtk_widget_path_iter_set_object_name(path.get(), -1, "button");
264 #else
265         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_BUTTON);
266 #endif
267         gtk_widget_path_iter_add_class(path.get(), -1, "text-button");
268         gtk_widget_path_iter_add_class(path.get(), -1, "combo");
269         break;
270     case ComboBoxArrow:
271         gtk_widget_path_append_type(path.get(), GTK_TYPE_ARROW);
272 #if GTK_CHECK_VERSION(3, 19, 2)
273         gtk_widget_path_iter_set_object_name(path.get(), -1, "arrow");
274 #else
275         gtk_widget_path_iter_add_class(path.get(), -1, "arrow");
276 #endif
277         break;
278     case Scale:
279         gtk_widget_path_append_type(path.get(), GTK_TYPE_SCALE);
280 #if GTK_CHECK_VERSION(3, 19, 2)
281         gtk_widget_path_iter_set_object_name(path.get(), -1, "scale");
282 #else
283         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SCALE);
284 #endif
285         break;
286     case ScaleTrough:
287         gtk_widget_path_append_type(path.get(), GTK_TYPE_SCALE);
288 #if GTK_CHECK_VERSION(3, 19, 2)
289         gtk_widget_path_iter_set_object_name(path.get(), -1, "trough");
290 #else
291         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SCALE);
292         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_TROUGH);
293 #endif
294         break;
295     case ScaleSlider:
296         gtk_widget_path_append_type(path.get(), GTK_TYPE_SCALE);
297 #if GTK_CHECK_VERSION(3, 19, 2)
298         gtk_widget_path_iter_set_object_name(path.get(), -1, "slider");
299 #else
300         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SCALE);
301         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SLIDER);
302 #endif
303         break;
304     case ProgressBar:
305         gtk_widget_path_append_type(path.get(), GTK_TYPE_PROGRESS_BAR);
306 #if GTK_CHECK_VERSION(3, 19, 2)
307         gtk_widget_path_iter_set_object_name(path.get(), -1, "progressbar");
308 #else
309         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_PROGRESSBAR);
310 #endif
311         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_HORIZONTAL);
312         break;
313     case ProgressBarTrough:
314         gtk_widget_path_append_type(path.get(), GTK_TYPE_PROGRESS_BAR);
315 #if GTK_CHECK_VERSION(3, 19, 2)
316         gtk_widget_path_iter_set_object_name(path.get(), -1, "trough");
317 #else
318         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_PROGRESSBAR);
319         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_TROUGH);
320 #endif
321         break;
322     case ProgressBarProgress:
323         gtk_widget_path_append_type(path.get(), GTK_TYPE_PROGRESS_BAR);
324 #if GTK_CHECK_VERSION(3, 19, 2)
325         gtk_widget_path_iter_set_object_name(path.get(), -1, "progress");
326 #else
327         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_PROGRESSBAR);
328 #endif
329         break;
330     case ListBox:
331         gtk_widget_path_append_type(path.get(), GTK_TYPE_TREE_VIEW);
332 #if GTK_CHECK_VERSION(3, 19, 2)
333         gtk_widget_path_iter_set_object_name(path.get(), -1, "treeview");
334 #endif
335         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_VIEW);
336         break;
337     case ListBoxSelection:
338         gtk_widget_path_append_type(path.get(), GTK_TYPE_TREE_VIEW);
339 #if GTK_CHECK_VERSION(3, 19, 2)
340         gtk_widget_path_iter_set_object_name(path.get(), -1, "selection");
341 #else
342         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_VIEW);
343 #endif
344         break;
345     case SpinButton:
346         gtk_widget_path_append_type(path.get(), GTK_TYPE_SPIN_BUTTON);
347 #if GTK_CHECK_VERSION(3, 19, 2)
348         gtk_widget_path_iter_set_object_name(path.get(), -1, "spinbutton");
349 #else
350         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SPINBUTTON);
351 #endif
352         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_HORIZONTAL);
353         break;
354     case SpinButtonUpButton:
355     case SpinButtonDownButton:
356         gtk_widget_path_append_type(path.get(), GTK_TYPE_SPIN_BUTTON);
357 #if GTK_CHECK_VERSION(3, 19, 2)
358         gtk_widget_path_iter_set_object_name(path.get(), -1, "button");
359         gtk_widget_path_iter_add_class(path.get(), -1, themePart == SpinButtonUpButton ? "up" : "down");
360 #else
361         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SPINBUTTON);
362         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_BUTTON);
363 #endif
364         break;
365 #if ENABLE(VIDEO)
366     case MediaButton:
367         gtk_widget_path_append_type(path.get(), GTK_TYPE_IMAGE);
368 #if GTK_CHECK_VERSION(3, 19, 2)
369         gtk_widget_path_iter_set_object_name(path.get(), -1, "image");
370 #else
371         gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_IMAGE);
372 #endif
373         break;
374 #endif // ENABLE(VIDEO)
375     }
376
377     GRefPtr<GtkStyleContext> context = adoptGRef(gtk_style_context_new());
378     gtk_style_context_set_path(context.get(), path.get());
379     gtk_style_context_set_parent(context.get(), parent);
380     return context;
381 }
382
383 static GRefPtr<GdkPixbuf> loadThemedIcon(GtkStyleContext* context, const char* iconName, GtkIconSize iconSize)
384 {
385     GRefPtr<GIcon> icon = adoptGRef(g_themed_icon_new(iconName));
386     unsigned lookupFlags = GTK_ICON_LOOKUP_USE_BUILTIN | GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_FORCE_SVG;
387     GtkTextDirection direction = gtk_style_context_get_direction(context);
388     if (direction & GTK_TEXT_DIR_LTR)
389         lookupFlags |= GTK_ICON_LOOKUP_DIR_LTR;
390     else if (direction & GTK_TEXT_DIR_RTL)
391         lookupFlags |= GTK_ICON_LOOKUP_DIR_RTL;
392     int width, height;
393     gtk_icon_size_lookup(iconSize, &width, &height);
394     GRefPtr<GtkIconInfo> iconInfo = adoptGRef(gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(), icon.get(), std::min(width, height), static_cast<GtkIconLookupFlags>(lookupFlags)));
395     if (!iconInfo)
396         return nullptr;
397
398     return adoptGRef(gtk_icon_info_load_symbolic_for_context(iconInfo.get(), context, nullptr, nullptr));
399 }
400
401 static bool nodeHasPseudo(Node* node, const char* pseudo)
402 {
403     RefPtr<Node> attributeNode = node->attributes()->getNamedItem("pseudo");
404
405     return attributeNode ? attributeNode->nodeValue() == pseudo : false;
406 }
407
408 static bool nodeHasClass(Node* node, const char* className)
409 {
410     if (!is<Element>(*node))
411         return false;
412
413     Element& element = downcast<Element>(*node);
414
415     if (!element.hasClass())
416         return false;
417
418     return element.classNames().contains(className);
419 }
420
421 RenderThemeGtk::~RenderThemeGtk()
422 {
423 }
424
425 static bool supportsFocus(ControlPart appearance)
426 {
427     switch (appearance) {
428     case PushButtonPart:
429     case ButtonPart:
430     case TextFieldPart:
431     case TextAreaPart:
432     case SearchFieldPart:
433     case MenulistPart:
434     case RadioPart:
435     case CheckboxPart:
436     case SliderHorizontalPart:
437     case SliderVerticalPart:
438         return true;
439     default:
440         return false;
441     }
442 }
443
444 bool RenderThemeGtk::supportsFocusRing(const RenderStyle& style) const
445 {
446     return supportsFocus(style.appearance());
447 }
448
449 bool RenderThemeGtk::controlSupportsTints(const RenderObject& o) const
450 {
451     return isEnabled(o);
452 }
453
454 int RenderThemeGtk::baselinePosition(const RenderBox& box) const
455 {
456     // FIXME: This strategy is possibly incorrect for the GTK+ port.
457     if (box.style().appearance() == CheckboxPart || box.style().appearance() == RadioPart)
458         return box.marginTop() + box.height() - 2;
459     return RenderTheme::baselinePosition(box);
460 }
461
462 static GtkTextDirection gtkTextDirection(TextDirection direction)
463 {
464     switch (direction) {
465     case RTL:
466         return GTK_TEXT_DIR_RTL;
467     case LTR:
468         return GTK_TEXT_DIR_LTR;
469     default:
470         return GTK_TEXT_DIR_NONE;
471     }
472 }
473
474 static GtkStateFlags gtkIconStateFlags(RenderTheme* theme, const RenderObject& renderObject)
475 {
476     if (!theme->isEnabled(renderObject))
477         return GTK_STATE_FLAG_INSENSITIVE;
478     if (theme->isPressed(renderObject))
479         return GTK_STATE_FLAG_ACTIVE;
480     if (theme->isHovered(renderObject))
481         return GTK_STATE_FLAG_PRELIGHT;
482
483     return GTK_STATE_FLAG_NORMAL;
484 }
485
486 static void adjustRectForFocus(GtkStyleContext* context, FloatRect& rect)
487 {
488     gint focusWidth, focusPad;
489     gtk_style_context_get_style(context, "focus-line-width", &focusWidth, "focus-padding", &focusPad, nullptr);
490     rect.inflate(focusWidth + focusPad);
491 }
492
493 void RenderThemeGtk::adjustRepaintRect(const RenderObject& renderObject, FloatRect& rect)
494 {
495     GRefPtr<GtkStyleContext> context;
496     bool checkInteriorFocus = false;
497     ControlPart part = renderObject.style().appearance();
498     switch (part) {
499     case CheckboxPart:
500     case RadioPart:
501         context = createStyleContext(part == CheckboxPart ? CheckButton : RadioButton);
502
503         gint indicatorSpacing;
504         gtk_style_context_get_style(context.get(), "indicator-spacing", &indicatorSpacing, nullptr);
505         rect.inflate(indicatorSpacing);
506
507         return;
508     case SliderVerticalPart:
509     case SliderHorizontalPart:
510         context = createStyleContext(ScaleSlider);
511         break;
512     case ButtonPart:
513     case MenulistButtonPart:
514     case MenulistPart:
515         context = createStyleContext(Button);
516         checkInteriorFocus = true;
517         break;
518     case TextFieldPart:
519     case TextAreaPart:
520         context = createStyleContext(Entry);
521         checkInteriorFocus = true;
522         break;
523     default:
524         return;
525     }
526
527     ASSERT(context);
528     if (checkInteriorFocus) {
529         gboolean interiorFocus;
530         gtk_style_context_get_style(context.get(), "interior-focus", &interiorFocus, nullptr);
531         if (interiorFocus)
532             return;
533     }
534     adjustRectForFocus(context.get(), rect);
535 }
536
537 void RenderThemeGtk::adjustButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
538 {
539     // Some layout tests check explicitly that buttons ignore line-height.
540     if (style.appearance() == PushButtonPart)
541         style.setLineHeight(RenderStyle::initialLineHeight());
542 }
543
544 static void setToggleSize(RenderThemePart themePart, RenderStyle& style)
545 {
546     // The width and height are both specified, so we shouldn't change them.
547     if (!style.width().isIntrinsicOrAuto() && !style.height().isAuto())
548         return;
549
550     GRefPtr<GtkStyleContext> context = createStyleContext(themePart);
551     // Other ports hard-code this to 13. GTK+ users tend to demand the native look.
552     gint indicatorSize;
553     gtk_style_context_get_style(context.get(), "indicator-size", &indicatorSize, nullptr);
554
555     if (style.width().isIntrinsicOrAuto())
556         style.setWidth(Length(indicatorSize, Fixed));
557
558     if (style.height().isAuto())
559         style.setHeight(Length(indicatorSize, Fixed));
560 }
561
562 static void paintToggle(const RenderThemeGtk* theme, RenderThemePart themePart, const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& fullRect)
563 {
564     GRefPtr<GtkStyleContext> parentContext = createStyleContext(themePart);
565     GRefPtr<GtkStyleContext> context = createStyleContext(themePart == CheckButton ? CheckButtonCheck : RadioButtonRadio, parentContext.get());
566     gtk_style_context_set_direction(context.get(), static_cast<GtkTextDirection>(gtkTextDirection(renderObject.style().direction())));
567
568     unsigned flags = 0;
569     if (!theme->isEnabled(renderObject))
570         flags |= GTK_STATE_FLAG_INSENSITIVE;
571     else if (theme->isHovered(renderObject))
572         flags |= GTK_STATE_FLAG_PRELIGHT;
573     if (theme->isIndeterminate(renderObject))
574         flags |= GTK_STATE_FLAG_INCONSISTENT;
575     else if (theme->isChecked(renderObject))
576 #if GTK_CHECK_VERSION(3, 13, 7)
577         flags |= GTK_STATE_FLAG_CHECKED;
578 #else
579         flags |= GTK_STATE_FLAG_ACTIVE;
580 #endif
581     if (theme->isPressed(renderObject))
582         flags |= GTK_STATE_FLAG_SELECTED;
583     gtk_style_context_set_state(context.get(), static_cast<GtkStateFlags>(flags));
584
585     // Some themes do not render large toggle buttons properly, so we simply
586     // shrink the rectangle back down to the default size and then center it
587     // in the full toggle button region. The reason for not simply forcing toggle
588     // buttons to be a smaller size is that we don't want to break site layouts.
589     gint indicatorSize;
590     gtk_style_context_get_style(context.get(), "indicator-size", &indicatorSize, nullptr);
591     IntRect rect(fullRect);
592     if (rect.width() > indicatorSize) {
593         rect.inflateX(-(rect.width() - indicatorSize) / 2);
594         rect.setWidth(indicatorSize); // In case rect.width() was equal to indicatorSize + 1.
595     }
596
597     if (rect.height() > indicatorSize) {
598         rect.inflateY(-(rect.height() - indicatorSize) / 2);
599         rect.setHeight(indicatorSize); // In case rect.height() was equal to indicatorSize + 1.
600     }
601
602     gtk_render_background(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
603     gtk_render_frame(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
604
605     if (themePart == CheckButton)
606         gtk_render_check(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
607     else
608         gtk_render_option(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
609
610     if (theme->isFocused(renderObject)) {
611         IntRect indicatorRect(rect);
612         gint indicatorSpacing;
613         gtk_style_context_get_style(context.get(), "indicator-spacing", &indicatorSpacing, nullptr);
614         indicatorRect.inflate(indicatorSpacing);
615         gtk_render_focus(context.get(), paintInfo.context().platformContext()->cr(), indicatorRect.x(), indicatorRect.y(),
616             indicatorRect.width(), indicatorRect.height());
617     }
618 }
619
620 void RenderThemeGtk::setCheckboxSize(RenderStyle& style) const
621 {
622     setToggleSize(CheckButton, style);
623 }
624
625 bool RenderThemeGtk::paintCheckbox(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
626 {
627     paintToggle(this, CheckButton, renderObject, paintInfo, rect);
628     return false;
629 }
630
631 void RenderThemeGtk::setRadioSize(RenderStyle& style) const
632 {
633     setToggleSize(RadioButton, style);
634 }
635
636 bool RenderThemeGtk::paintRadio(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
637 {
638     paintToggle(this, RadioButton, renderObject, paintInfo, rect);
639     return false;
640 }
641
642 static void renderButton(RenderTheme* theme, GtkStyleContext* context, const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
643 {
644     IntRect buttonRect(rect);
645
646     guint flags = 0;
647     if (!theme->isEnabled(renderObject))
648         flags |= GTK_STATE_FLAG_INSENSITIVE;
649     else if (theme->isHovered(renderObject))
650         flags |= GTK_STATE_FLAG_PRELIGHT;
651     if (theme->isPressed(renderObject))
652         flags |= GTK_STATE_FLAG_ACTIVE;
653     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
654
655     if (theme->isDefault(renderObject)) {
656         GtkBorder* borderPtr = 0;
657         GtkBorder border = { 1, 1, 1, 1 };
658
659         gtk_style_context_get_style(context, "default-border", &borderPtr, nullptr);
660         if (borderPtr) {
661             border = *borderPtr;
662             gtk_border_free(borderPtr);
663         }
664
665         buttonRect.move(border.left, border.top);
666         buttonRect.setWidth(buttonRect.width() - (border.left + border.right));
667         buttonRect.setHeight(buttonRect.height() - (border.top + border.bottom));
668
669         gtk_style_context_add_class(context, GTK_STYLE_CLASS_DEFAULT);
670     }
671
672     gtk_render_background(context, paintInfo.context().platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
673     gtk_render_frame(context, paintInfo.context().platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
674
675     if (theme->isFocused(renderObject)) {
676         gint focusWidth, focusPad;
677         gboolean displaceFocus, interiorFocus;
678         gtk_style_context_get_style(
679             context,
680             "focus-line-width", &focusWidth,
681             "focus-padding", &focusPad,
682             "interior-focus", &interiorFocus,
683             "displace-focus", &displaceFocus,
684             nullptr);
685
686         if (interiorFocus) {
687             GtkBorder borderWidth;
688             gtk_style_context_get_border(context, gtk_style_context_get_state(context), &borderWidth);
689
690             buttonRect = IntRect(
691                 buttonRect.x() + borderWidth.left + focusPad,
692                 buttonRect.y() + borderWidth.top + focusPad,
693                 buttonRect.width() - (2 * focusPad + borderWidth.left + borderWidth.right),
694                 buttonRect.height() - (2 * focusPad + borderWidth.top + borderWidth.bottom));
695         } else
696             buttonRect.inflate(focusWidth + focusPad);
697
698         if (displaceFocus && theme->isPressed(renderObject)) {
699             gint childDisplacementX;
700             gint childDisplacementY;
701             gtk_style_context_get_style(context, "child-displacement-x", &childDisplacementX, "child-displacement-y", &childDisplacementY, nullptr);
702             buttonRect.move(childDisplacementX, childDisplacementY);
703         }
704
705         gtk_render_focus(context, paintInfo.context().platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
706     }
707 }
708 bool RenderThemeGtk::paintButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
709 {
710     GRefPtr<GtkStyleContext> context = createStyleContext(Button);
711     gtk_style_context_set_direction(context.get(), static_cast<GtkTextDirection>(gtkTextDirection(renderObject.style().direction())));
712     renderButton(this, context.get(), renderObject, paintInfo, rect);
713     return false;
714 }
715
716 void RenderThemeGtk::adjustMenuListStyle(StyleResolver&, RenderStyle& style, Element*) const
717 {
718     // The tests check explicitly that select menu buttons ignore line height.
719     style.setLineHeight(RenderStyle::initialLineHeight());
720
721     // We cannot give a proper rendering when border radius is active, unfortunately.
722     style.resetBorderRadius();
723 }
724
725 void RenderThemeGtk::adjustMenuListButtonStyle(StyleResolver& styleResolver, RenderStyle& style, Element* e) const
726 {
727     adjustMenuListStyle(styleResolver, style, e);
728 }
729
730 static void getComboBoxMetrics(RenderStyle& style, GtkBorder& border, int& focus)
731 {
732     // If this menu list button isn't drawn using the native theme, we
733     // don't add any extra padding beyond what WebCore already uses.
734     if (style.appearance() == NoControlPart)
735         return;
736
737     GRefPtr<GtkStyleContext> parentContext = createStyleContext(ComboBox);
738     GRefPtr<GtkStyleContext> context = createStyleContext(ComboBoxButton, parentContext.get());
739     gtk_style_context_set_direction(context.get(), static_cast<GtkTextDirection>(gtkTextDirection(style.direction())));
740     gtk_style_context_set_state(context.get(), static_cast<GtkStateFlags>(0));
741     gtk_style_context_get_border(context.get(), gtk_style_context_get_state(context.get()), &border);
742
743     gboolean interiorFocus;
744     gint focusWidth, focusPad;
745     gtk_style_context_get_style(context.get(), "interior-focus", &interiorFocus, "focus-line-width", &focusWidth, "focus-padding", &focusPad, nullptr);
746     focus = interiorFocus ? focusWidth + focusPad : 0;
747 }
748
749 int RenderThemeGtk::popupInternalPaddingLeft(RenderStyle& style) const
750 {
751     GtkBorder borderWidth = { 0, 0, 0, 0 };
752     int focusWidth = 0;
753     getComboBoxMetrics(style, borderWidth, focusWidth);
754     int left = borderWidth.left + focusWidth;
755     if (style.direction() == RTL)
756         left += minArrowSize;
757     return left;
758 }
759
760 int RenderThemeGtk::popupInternalPaddingRight(RenderStyle& style) const
761 {
762     GtkBorder borderWidth = { 0, 0, 0, 0 };
763     int focusWidth = 0;
764     getComboBoxMetrics(style, borderWidth, focusWidth);
765     int right = borderWidth.right + focusWidth;
766     if (style.direction() == LTR)
767         right += minArrowSize;
768     return right;
769 }
770
771 int RenderThemeGtk::popupInternalPaddingTop(RenderStyle& style) const
772 {
773     GtkBorder borderWidth = { 0, 0, 0, 0 };
774     int focusWidth = 0;
775     getComboBoxMetrics(style, borderWidth, focusWidth);
776     return borderWidth.top + focusWidth;
777 }
778
779 int RenderThemeGtk::popupInternalPaddingBottom(RenderStyle& style) const
780 {
781     GtkBorder borderWidth = { 0, 0, 0, 0 };
782     int focusWidth = 0;
783     getComboBoxMetrics(style, borderWidth, focusWidth);
784     return borderWidth.bottom + focusWidth;
785 }
786
787 bool RenderThemeGtk::paintMenuList(const RenderObject& renderObject, const PaintInfo& paintInfo, const FloatRect& r)
788 {
789     // FIXME: adopt subpixel themes.
790     IntRect rect = IntRect(r);
791
792     cairo_t* cairoContext = paintInfo.context().platformContext()->cr();
793     GtkTextDirection direction = static_cast<GtkTextDirection>(gtkTextDirection(renderObject.style().direction()));
794
795     GRefPtr<GtkStyleContext> parentStyleContext = createStyleContext(ComboBox);
796
797     // Paint the button.
798     GRefPtr<GtkStyleContext> buttonStyleContext = createStyleContext(ComboBoxButton, parentStyleContext.get());
799     gtk_style_context_set_direction(buttonStyleContext.get(), direction);
800     renderButton(this, buttonStyleContext.get(), renderObject, paintInfo, rect);
801
802     // Get the inner rectangle.
803     gint focusWidth, focusPad;
804     GtkBorder* innerBorderPtr = 0;
805     GtkBorder innerBorder = { 1, 1, 1, 1 };
806     gtk_style_context_get_style(buttonStyleContext.get(), "inner-border", &innerBorderPtr, "focus-line-width", &focusWidth, "focus-padding", &focusPad, nullptr);
807     if (innerBorderPtr) {
808         innerBorder = *innerBorderPtr;
809         gtk_border_free(innerBorderPtr);
810     }
811
812     GtkBorder borderWidth;
813     GtkStateFlags state = gtk_style_context_get_state(buttonStyleContext.get());
814     gtk_style_context_get_border(buttonStyleContext.get(), state, &borderWidth);
815
816     focusWidth += focusPad;
817     IntRect innerRect(
818         rect.x() + innerBorder.left + borderWidth.left + focusWidth,
819         rect.y() + innerBorder.top + borderWidth.top + focusWidth,
820         rect.width() - borderWidth.left - borderWidth.right - innerBorder.left - innerBorder.right - (2 * focusWidth),
821         rect.height() - borderWidth.top - borderWidth.bottom - innerBorder.top - innerBorder.bottom - (2 * focusWidth));
822
823     if (isPressed(renderObject)) {
824         gint childDisplacementX;
825         gint childDisplacementY;
826         gtk_style_context_get_style(buttonStyleContext.get(), "child-displacement-x", &childDisplacementX, "child-displacement-y", &childDisplacementY, nullptr);
827         innerRect.move(childDisplacementX, childDisplacementY);
828     }
829     innerRect.setWidth(std::max(1, innerRect.width()));
830     innerRect.setHeight(std::max(1, innerRect.height()));
831
832     // Paint the arrow.
833     GRefPtr<GtkStyleContext> arrowStyleContext = createStyleContext(ComboBoxArrow, buttonStyleContext.get());
834     gtk_style_context_set_direction(arrowStyleContext.get(), direction);
835
836 #if GTK_CHECK_VERSION(3, 19, 2)
837     // arrow-scaling style property is now deprecated and ignored.
838     gfloat arrowScaling = 1.;
839 #else
840     gfloat arrowScaling;
841     gtk_style_context_get_style(parentStyleContext.get(), "arrow-scaling", &arrowScaling, nullptr);
842 #endif
843
844     IntSize arrowSize(minArrowSize, innerRect.height());
845     FloatPoint arrowPosition(innerRect.location());
846     if (direction == GTK_TEXT_DIR_LTR)
847         arrowPosition.move(innerRect.width() - arrowSize.width(), 0);
848
849     // GTK+ actually fetches the xalign and valign values from the widget, but since we
850     // don't have a widget here, we are just using the default xalign and valign values of 0.5.
851     gint extent = std::min(arrowSize.width(), arrowSize.height()) * arrowScaling;
852     arrowPosition.move((arrowSize.width() - extent) / 2, (arrowSize.height() - extent) / 2);
853
854     gtk_style_context_set_state(arrowStyleContext.get(), state);
855     gtk_render_arrow(arrowStyleContext.get(), cairoContext, G_PI, arrowPosition.x(), arrowPosition.y(), extent);
856
857     return false;
858 }
859
860 bool RenderThemeGtk::paintMenuListButtonDecorations(const RenderBox& object, const PaintInfo& info, const FloatRect& rect)
861 {
862     return paintMenuList(object, info, rect);
863 }
864
865 bool RenderThemeGtk::paintTextField(const RenderObject& renderObject, const PaintInfo& paintInfo, const FloatRect& rect)
866 {
867     GRefPtr<GtkStyleContext> context = createStyleContext(Entry);
868     gtk_style_context_set_direction(context.get(), static_cast<GtkTextDirection>(gtkTextDirection(renderObject.style().direction())));
869
870     guint flags = 0;
871     if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
872         flags |= GTK_STATE_FLAG_INSENSITIVE;
873     else if (isFocused(renderObject))
874         flags |= GTK_STATE_FLAG_FOCUSED;
875     gtk_style_context_set_state(context.get(), static_cast<GtkStateFlags>(flags));
876
877     gtk_render_background(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
878     gtk_render_frame(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
879
880     if (isFocused(renderObject) && isEnabled(renderObject)) {
881         gboolean interiorFocus;
882         gint focusWidth, focusPad;
883         gtk_style_context_get_style(context.get(), "interior-focus", &interiorFocus, "focus-line-width", &focusWidth, "focus-padding", &focusPad, nullptr);
884         if (!interiorFocus) {
885             IntRect focusRect(rect);
886             focusRect.inflate(focusWidth + focusPad);
887             gtk_render_focus(context.get(), paintInfo.context().platformContext()->cr(), focusRect.x(), focusRect.y(), focusRect.width(), focusRect.height());
888         }
889     }
890
891     return false;
892 }
893
894 bool RenderThemeGtk::paintTextArea(const RenderObject& o, const PaintInfo& i, const FloatRect& r)
895 {
896     return paintTextField(o, i, r);
897 }
898
899 // Defined in GTK+ (gtk/gtkiconfactory.c)
900 static const gint gtkIconSizeMenu = 16;
901 static const gint gtkIconSizeSmallToolbar = 18;
902 static const gint gtkIconSizeButton = 20;
903 static const gint gtkIconSizeLargeToolbar = 24;
904 static const gint gtkIconSizeDnd = 32;
905 static const gint gtkIconSizeDialog = 48;
906
907 static GtkIconSize getIconSizeForPixelSize(gint pixelSize)
908 {
909     if (pixelSize < gtkIconSizeSmallToolbar)
910         return GTK_ICON_SIZE_MENU;
911     if (pixelSize >= gtkIconSizeSmallToolbar && pixelSize < gtkIconSizeButton)
912         return GTK_ICON_SIZE_SMALL_TOOLBAR;
913     if (pixelSize >= gtkIconSizeButton && pixelSize < gtkIconSizeLargeToolbar)
914         return GTK_ICON_SIZE_BUTTON;
915     if (pixelSize >= gtkIconSizeLargeToolbar && pixelSize < gtkIconSizeDnd)
916         return GTK_ICON_SIZE_LARGE_TOOLBAR;
917     if (pixelSize >= gtkIconSizeDnd && pixelSize < gtkIconSizeDialog)
918         return GTK_ICON_SIZE_DND;
919
920     return GTK_ICON_SIZE_DIALOG;
921 }
922
923 void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(StyleResolver& styleResolver, RenderStyle& style, Element* e) const
924 {
925     adjustSearchFieldCancelButtonStyle(styleResolver, style, e);
926 }
927
928 bool RenderThemeGtk::paintSearchFieldResultsButton(const RenderBox& o, const PaintInfo& i, const IntRect& rect)
929 {
930     return paintSearchFieldResultsDecorationPart(o, i, rect);
931 }
932
933 static void adjustSearchFieldIconStyle(RenderThemePart themePart, RenderStyle& style)
934 {
935     style.resetBorder();
936     style.resetPadding();
937
938     GRefPtr<GtkStyleContext> parentContext = createStyleContext(Entry);
939     GRefPtr<GtkStyleContext> context = createStyleContext(themePart, parentContext.get());
940
941     GtkBorder padding;
942     gtk_style_context_get_padding(context.get(), gtk_style_context_get_state(context.get()), &padding);
943
944     // Get the icon size based on the font size.
945     int fontSize = style.fontSize();
946     if (fontSize < gtkIconSizeMenu) {
947         style.setWidth(Length(fontSize + (padding.left + padding.right), Fixed));
948         style.setHeight(Length(fontSize + (padding.top + padding.bottom), Fixed));
949         return;
950     }
951     gint width = 0, height = 0;
952     gtk_icon_size_lookup(getIconSizeForPixelSize(fontSize), &width, &height);
953     style.setWidth(Length(width + (padding.left + padding.right), Fixed));
954     style.setHeight(Length(height + (padding.top + padding.bottom), Fixed));
955 }
956
957 void RenderThemeGtk::adjustSearchFieldResultsDecorationPartStyle(StyleResolver&, RenderStyle& style, Element*) const
958 {
959     adjustSearchFieldIconStyle(EntryIconLeft, style);
960 }
961
962 static IntRect centerRectVerticallyInParentInputElement(const RenderObject& renderObject, const IntRect& rect)
963 {
964     if (!renderObject.node())
965         return IntRect();
966
967     // Get the renderer of <input> element.
968     Node* input = renderObject.node()->shadowHost();
969     if (!input)
970         input = renderObject.node();
971     if (!is<RenderBox>(*input->renderer()))
972         return IntRect();
973
974     // If possible center the y-coordinate of the rect vertically in the parent input element.
975     // We also add one pixel here to ensure that the y coordinate is rounded up for box heights
976     // that are even, which looks in relation to the box text.
977     IntRect inputContentBox = downcast<RenderBox>(*input->renderer()).absoluteContentBox();
978
979     // Make sure the scaled decoration stays square and will fit in its parent's box.
980     int iconSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), rect.height()));
981     IntRect scaledRect(rect.x(), inputContentBox.y() + (inputContentBox.height() - iconSize + 1) / 2, iconSize, iconSize);
982     return scaledRect;
983 }
984
985 static bool paintIcon(GtkStyleContext* context, GraphicsContext& graphicsContext, const IntRect& rect, const char* iconName)
986 {
987     GRefPtr<GdkPixbuf> icon = loadThemedIcon(context, iconName, getIconSizeForPixelSize(rect.height()));
988     if (!icon)
989         return false;
990
991     if (gdk_pixbuf_get_width(icon.get()) > rect.width() || gdk_pixbuf_get_height(icon.get()) > rect.height())
992         icon = adoptGRef(gdk_pixbuf_scale_simple(icon.get(), rect.width(), rect.height(), GDK_INTERP_BILINEAR));
993
994     gtk_render_icon(context, graphicsContext.platformContext()->cr(), icon.get(), rect.x(), rect.y());
995     return true;
996 }
997
998 static bool paintEntryIcon(RenderThemePart themePart, const char* iconName, GraphicsContext& graphicsContext, const IntRect& rect, GtkTextDirection direction, GtkStateFlags state)
999 {
1000     GRefPtr<GtkStyleContext> parentContext = createStyleContext(Entry);
1001     GRefPtr<GtkStyleContext> context = createStyleContext(themePart, parentContext.get());
1002     gtk_style_context_set_direction(context.get(), direction);
1003     gtk_style_context_set_state(context.get(), state);
1004     return paintIcon(context.get(), graphicsContext, rect, iconName);
1005 }
1006
1007 bool RenderThemeGtk::paintSearchFieldResultsDecorationPart(const RenderBox& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1008 {
1009     IntRect iconRect = centerRectVerticallyInParentInputElement(renderObject, rect);
1010     if (iconRect.isEmpty())
1011         return true;
1012
1013     return !paintEntryIcon(EntryIconLeft, "edit-find-symbolic", paintInfo.context(), iconRect, gtkTextDirection(renderObject.style().direction()),
1014         gtkIconStateFlags(this, renderObject));
1015 }
1016
1017 void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1018 {
1019     adjustSearchFieldIconStyle(EntryIconRight, style);
1020 }
1021
1022 bool RenderThemeGtk::paintSearchFieldCancelButton(const RenderBox& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1023 {
1024     IntRect iconRect = centerRectVerticallyInParentInputElement(renderObject, rect);
1025     if (iconRect.isEmpty())
1026         return true;
1027
1028     return !paintEntryIcon(EntryIconRight, "edit-clear-symbolic", paintInfo.context(), iconRect, gtkTextDirection(renderObject.style().direction()),
1029         gtkIconStateFlags(this, renderObject));
1030 }
1031
1032 void RenderThemeGtk::adjustSearchFieldStyle(StyleResolver&, RenderStyle& style, Element*) const
1033 {
1034     // We cannot give a proper rendering when border radius is active, unfortunately.
1035     style.resetBorderRadius();
1036     style.setLineHeight(RenderStyle::initialLineHeight());
1037 }
1038
1039 bool RenderThemeGtk::paintSearchField(const RenderObject& o, const PaintInfo& i, const IntRect& rect)
1040 {
1041     return paintTextField(o, i, rect);
1042 }
1043
1044 bool RenderThemeGtk::shouldHaveCapsLockIndicator(HTMLInputElement& element) const
1045 {
1046     return element.isPasswordField();
1047 }
1048
1049 void RenderThemeGtk::adjustSliderTrackStyle(StyleResolver&, RenderStyle& style, Element*) const
1050 {
1051     style.setBoxShadow(nullptr);
1052 }
1053
1054 void RenderThemeGtk::adjustSliderThumbStyle(StyleResolver& styleResolver, RenderStyle& style, Element* element) const
1055 {
1056     RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
1057     style.setBoxShadow(nullptr);
1058 }
1059
1060 bool RenderThemeGtk::paintSliderTrack(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1061 {
1062     ControlPart part = renderObject.style().appearance();
1063     ASSERT_UNUSED(part, part == SliderHorizontalPart || part == SliderVerticalPart);
1064
1065     GRefPtr<GtkStyleContext> parentContext = createStyleContext(Scale);
1066     gtk_style_context_add_class(parentContext.get(), part == SliderHorizontalPart ? GTK_STYLE_CLASS_HORIZONTAL : GTK_STYLE_CLASS_VERTICAL);
1067     GRefPtr<GtkStyleContext> context = createStyleContext(ScaleTrough, parentContext.get());
1068     gtk_style_context_set_direction(context.get(), gtkTextDirection(renderObject.style().direction()));
1069
1070     if (!isEnabled(renderObject))
1071         gtk_style_context_set_state(context.get(), GTK_STATE_FLAG_INSENSITIVE);
1072
1073     gtk_render_background(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
1074     gtk_render_frame(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
1075
1076     if (isFocused(renderObject)) {
1077         gint focusWidth, focusPad;
1078         gtk_style_context_get_style(context.get(), "focus-line-width", &focusWidth, "focus-padding", &focusPad, nullptr);
1079         IntRect focusRect(rect);
1080         focusRect.inflate(focusWidth + focusPad);
1081         gtk_render_focus(context.get(), paintInfo.context().platformContext()->cr(), focusRect.x(), focusRect.y(), focusRect.width(), focusRect.height());
1082     }
1083
1084     return false;
1085 }
1086
1087 bool RenderThemeGtk::paintSliderThumb(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1088 {
1089     ControlPart part = renderObject.style().appearance();
1090     ASSERT(part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart);
1091
1092     // FIXME: The entire slider is too wide, stretching the thumb into an oval rather than a circle.
1093     GRefPtr<GtkStyleContext> parentContext = createStyleContext(Scale);
1094     gtk_style_context_add_class(parentContext.get(), part == SliderThumbHorizontalPart ? GTK_STYLE_CLASS_HORIZONTAL : GTK_STYLE_CLASS_VERTICAL);
1095     GRefPtr<GtkStyleContext> troughContext = createStyleContext(ScaleTrough, parentContext.get());
1096     GRefPtr<GtkStyleContext> context = createStyleContext(ScaleSlider, troughContext.get());
1097     gtk_style_context_set_direction(context.get(), gtkTextDirection(renderObject.style().direction()));
1098
1099     guint flags = 0;
1100     if (!isEnabled(renderObject))
1101         flags |= GTK_STATE_FLAG_INSENSITIVE;
1102     else if (isHovered(renderObject))
1103         flags |= GTK_STATE_FLAG_PRELIGHT;
1104     if (isPressed(renderObject))
1105         flags |= GTK_STATE_FLAG_ACTIVE;
1106     gtk_style_context_set_state(context.get(), static_cast<GtkStateFlags>(flags));
1107
1108     gtk_render_slider(context.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height(),
1109         part == SliderThumbHorizontalPart ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
1110
1111     return false;
1112 }
1113
1114 void RenderThemeGtk::adjustSliderThumbSize(RenderStyle& style, Element*) const
1115 {
1116     ControlPart part = style.appearance();
1117     if (part != SliderThumbHorizontalPart && part != SliderThumbVerticalPart)
1118         return;
1119
1120     GRefPtr<GtkStyleContext> context = createStyleContext(Scale);
1121     gint sliderWidth, sliderLength;
1122     gtk_style_context_get_style(context.get(), "slider-width", &sliderWidth, "slider-length", &sliderLength, nullptr);
1123     if (part == SliderThumbHorizontalPart) {
1124         style.setWidth(Length(sliderLength, Fixed));
1125         style.setHeight(Length(sliderWidth, Fixed));
1126         return;
1127     }
1128     ASSERT(part == SliderThumbVerticalPart);
1129     style.setWidth(Length(sliderWidth, Fixed));
1130     style.setHeight(Length(sliderLength, Fixed));
1131 }
1132
1133 bool RenderThemeGtk::paintProgressBar(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1134 {
1135     if (!renderObject.isProgress())
1136         return true;
1137
1138     GRefPtr<GtkStyleContext> parentContext = createStyleContext(ProgressBar);
1139     GRefPtr<GtkStyleContext> troughContext = createStyleContext(ProgressBarTrough, parentContext.get());
1140     GRefPtr<GtkStyleContext> context = createStyleContext(ProgressBarProgress, troughContext.get());
1141
1142     gtk_render_background(troughContext.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
1143     gtk_render_frame(troughContext.get(), paintInfo.context().platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
1144
1145     gtk_style_context_set_state(context.get(), static_cast<GtkStateFlags>(0));
1146
1147     GtkBorder padding;
1148     gtk_style_context_get_padding(context.get(), gtk_style_context_get_state(context.get()), &padding);
1149     IntRect progressRect(
1150         rect.x() + padding.left,
1151         rect.y() + padding.top,
1152         rect.width() - (padding.left + padding.right),
1153         rect.height() - (padding.top + padding.bottom));
1154     progressRect = RenderThemeGtk::calculateProgressRect(renderObject, progressRect);
1155
1156     if (!progressRect.isEmpty()) {
1157 #if GTK_CHECK_VERSION(3, 13, 7)
1158         gtk_render_background(context.get(), paintInfo.context().platformContext()->cr(), progressRect.x(), progressRect.y(), progressRect.width(), progressRect.height());
1159         gtk_render_frame(context.get(), paintInfo.context().platformContext()->cr(), progressRect.x(), progressRect.y(), progressRect.width(), progressRect.height());
1160 #else
1161         gtk_render_activity(context.get(), paintInfo.context().platformContext()->cr(), progressRect.x(), progressRect.y(), progressRect.width(), progressRect.height());
1162 #endif
1163     }
1164
1165     return false;
1166 }
1167
1168 static gint spinButtonArrowSize(GtkStyleContext* context)
1169 {
1170     PangoFontDescription* fontDescription;
1171     gtk_style_context_get(context, gtk_style_context_get_state(context), "font", &fontDescription, nullptr);
1172     gint fontSize = pango_font_description_get_size(fontDescription);
1173     gint arrowSize = std::max(PANGO_PIXELS(fontSize), minSpinButtonArrowSize);
1174     pango_font_description_free(fontDescription);
1175
1176     return arrowSize - arrowSize % 2; // Force even.
1177 }
1178
1179 void RenderThemeGtk::adjustInnerSpinButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1180 {
1181     GRefPtr<GtkStyleContext> context = createStyleContext(SpinButton);
1182
1183     GtkBorder padding;
1184     gtk_style_context_get_padding(context.get(), gtk_style_context_get_state(context.get()), &padding);
1185
1186     int width = spinButtonArrowSize(context.get()) + padding.left + padding.right;
1187     style.setWidth(Length(width, Fixed));
1188     style.setMinWidth(Length(width, Fixed));
1189 }
1190
1191 static void paintSpinArrowButton(RenderTheme* theme, GtkStyleContext* parentContext, const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect, GtkArrowType arrowType)
1192 {
1193     ASSERT(arrowType == GTK_ARROW_UP || arrowType == GTK_ARROW_DOWN);
1194
1195     GRefPtr<GtkStyleContext> context = createStyleContext(arrowType == GTK_ARROW_UP ? SpinButtonUpButton : SpinButtonDownButton, parentContext);
1196     GtkTextDirection direction = gtk_style_context_get_direction(context.get());
1197     guint state = static_cast<guint>(gtk_style_context_get_state(context.get()));
1198     if (!(state & GTK_STATE_FLAG_INSENSITIVE)) {
1199         if (theme->isPressed(renderObject)) {
1200             if ((arrowType == GTK_ARROW_UP && theme->isSpinUpButtonPartPressed(renderObject))
1201                 || (arrowType == GTK_ARROW_DOWN && !theme->isSpinUpButtonPartPressed(renderObject)))
1202                 state |= GTK_STATE_FLAG_ACTIVE;
1203         } else if (theme->isHovered(renderObject)) {
1204             if ((arrowType == GTK_ARROW_UP && theme->isSpinUpButtonPartHovered(renderObject))
1205                 || (arrowType == GTK_ARROW_DOWN && !theme->isSpinUpButtonPartHovered(renderObject)))
1206                 state |= GTK_STATE_FLAG_PRELIGHT;
1207         }
1208     }
1209     gtk_style_context_set_state(context.get(), static_cast<GtkStateFlags>(state));
1210
1211     // Paint button.
1212     IntRect buttonRect(rect);
1213     guint junction = gtk_style_context_get_junction_sides(context.get());
1214     if (arrowType == GTK_ARROW_UP)
1215         junction |= GTK_JUNCTION_BOTTOM;
1216     else {
1217         junction |= GTK_JUNCTION_TOP;
1218         buttonRect.move(0, rect.height() / 2);
1219     }
1220     buttonRect.setHeight(rect.height() / 2);
1221     gtk_style_context_set_junction_sides(context.get(), static_cast<GtkJunctionSides>(junction));
1222
1223     gtk_render_background(context.get(), paintInfo.context().platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
1224     gtk_render_frame(context.get(), paintInfo.context().platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
1225
1226     // Paint arrow centered inside button.
1227     // This code is based on gtkspinbutton.c code.
1228     IntRect arrowRect;
1229     gdouble angle;
1230     if (arrowType == GTK_ARROW_UP) {
1231         angle = 0;
1232         arrowRect.setY(rect.y());
1233         arrowRect.setHeight(rect.height() / 2 - 2);
1234     } else {
1235         angle = G_PI;
1236         arrowRect.setY(rect.y() + buttonRect.y());
1237         arrowRect.setHeight(rect.height() - arrowRect.y() - 2);
1238     }
1239     arrowRect.setWidth(rect.width() - 3);
1240     if (direction == GTK_TEXT_DIR_LTR)
1241         arrowRect.setX(rect.x() + 1);
1242     else
1243         arrowRect.setX(rect.x() + 2);
1244
1245     gint width = arrowRect.width() / 2;
1246     width -= width % 2 - 1; // Force odd.
1247     gint height = (width + 1) / 2;
1248
1249     arrowRect.move((arrowRect.width() - width) / 2, (arrowRect.height() - height) / 2);
1250     gtk_render_arrow(context.get(), paintInfo.context().platformContext()->cr(), angle, arrowRect.x(), arrowRect.y(), width);
1251 }
1252
1253 bool RenderThemeGtk::paintInnerSpinButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1254 {
1255     GRefPtr<GtkStyleContext> context = createStyleContext(SpinButton);
1256     gtk_style_context_set_direction(context.get(), gtkTextDirection(renderObject.style().direction()));
1257
1258     guint flags = 0;
1259     if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
1260         flags |= GTK_STATE_FLAG_INSENSITIVE;
1261     else if (isFocused(renderObject))
1262         flags |= GTK_STATE_FLAG_FOCUSED;
1263     gtk_style_context_set_state(context.get(), static_cast<GtkStateFlags>(flags));
1264
1265     paintSpinArrowButton(this, context.get(), renderObject, paintInfo, rect, GTK_ARROW_UP);
1266     paintSpinArrowButton(this, context.get(), renderObject, paintInfo, rect, GTK_ARROW_DOWN);
1267
1268     return false;
1269 }
1270
1271 double RenderThemeGtk::caretBlinkInterval() const
1272 {
1273     GtkSettings* settings = gtk_settings_get_default();
1274
1275     gboolean shouldBlink;
1276     gint time;
1277
1278     g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, nullptr);
1279
1280     if (!shouldBlink)
1281         return 0;
1282
1283     return time / 2000.;
1284 }
1285
1286 enum StyleColorType { StyleColorBackground, StyleColorForeground };
1287
1288 static Color styleColor(RenderThemePart themePart, GtkStateFlags state, StyleColorType colorType)
1289 {
1290     GRefPtr<GtkStyleContext> parentContext;
1291     RenderThemePart part = themePart;
1292     if (state & GTK_STATE_FLAG_SELECTED) {
1293         parentContext = createStyleContext(themePart);
1294         ASSERT(themePart == Entry || themePart == ListBox);
1295         part = themePart == Entry ? EntrySelection : ListBoxSelection;
1296     }
1297
1298     GRefPtr<GtkStyleContext> context = createStyleContext(part, parentContext.get());
1299     gtk_style_context_set_state(context.get(), state);
1300
1301     GdkRGBA gdkRGBAColor;
1302     if (colorType == StyleColorBackground)
1303         gtk_style_context_get_background_color(context.get(), state, &gdkRGBAColor);
1304     else
1305         gtk_style_context_get_color(context.get(), state, &gdkRGBAColor);
1306     return gdkRGBAColor;
1307 }
1308
1309 Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const
1310 {
1311     return styleColor(Entry, static_cast<GtkStateFlags>(GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED), StyleColorBackground);
1312 }
1313
1314 Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const
1315 {
1316     return styleColor(Entry, GTK_STATE_FLAG_SELECTED, StyleColorBackground);
1317 }
1318
1319 Color RenderThemeGtk::platformActiveSelectionForegroundColor() const
1320 {
1321     return styleColor(Entry, static_cast<GtkStateFlags>(GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED), StyleColorForeground);
1322 }
1323
1324 Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const
1325 {
1326     return styleColor(Entry, GTK_STATE_FLAG_SELECTED, StyleColorForeground);
1327 }
1328
1329 Color RenderThemeGtk::platformActiveListBoxSelectionBackgroundColor() const
1330 {
1331     return styleColor(ListBox, static_cast<GtkStateFlags>(GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED), StyleColorBackground);
1332 }
1333
1334 Color RenderThemeGtk::platformInactiveListBoxSelectionBackgroundColor() const
1335 {
1336     return styleColor(ListBox, GTK_STATE_FLAG_SELECTED, StyleColorBackground);
1337 }
1338
1339 Color RenderThemeGtk::platformActiveListBoxSelectionForegroundColor() const
1340 {
1341     return styleColor(ListBox, static_cast<GtkStateFlags>(GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED), StyleColorForeground);
1342 }
1343
1344 Color RenderThemeGtk::platformInactiveListBoxSelectionForegroundColor() const
1345 {
1346     return styleColor(ListBox, GTK_STATE_FLAG_SELECTED, StyleColorForeground);
1347 }
1348
1349 Color RenderThemeGtk::systemColor(CSSValueID cssValueId) const
1350 {
1351     switch (cssValueId) {
1352     case CSSValueButtontext:
1353         return styleColor(Button, GTK_STATE_FLAG_ACTIVE, StyleColorForeground);
1354     case CSSValueCaptiontext:
1355         return styleColor(Entry, GTK_STATE_FLAG_ACTIVE, StyleColorForeground);
1356     default:
1357         return RenderTheme::systemColor(cssValueId);
1358     }
1359 }
1360
1361 void RenderThemeGtk::platformColorsDidChange()
1362 {
1363     RenderTheme::platformColorsDidChange();
1364 }
1365
1366 #if ENABLE(VIDEO)
1367 String RenderThemeGtk::extraMediaControlsStyleSheet()
1368 {
1369     return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet));
1370 }
1371
1372 #if ENABLE(FULLSCREEN_API)
1373 String RenderThemeGtk::extraFullScreenStyleSheet()
1374 {
1375     return String();
1376 }
1377 #endif
1378
1379 bool RenderThemeGtk::paintMediaButton(const RenderObject& renderObject, GraphicsContext& graphicsContext, const IntRect& rect, const char* iconName)
1380 {
1381     GRefPtr<GtkStyleContext> context = createStyleContext(MediaButton);
1382     gtk_style_context_set_direction(context.get(), gtkTextDirection(renderObject.style().direction()));
1383     gtk_style_context_set_state(context.get(), gtkIconStateFlags(this, renderObject));
1384     static const unsigned mediaIconSize = 16;
1385     IntRect iconRect(rect.x() + (rect.width() - mediaIconSize) / 2, rect.y() + (rect.height() - mediaIconSize) / 2, mediaIconSize, mediaIconSize);
1386     return !paintIcon(context.get(), graphicsContext, iconRect, iconName);
1387 }
1388
1389 bool RenderThemeGtk::hasOwnDisabledStateHandlingFor(ControlPart part) const
1390 {
1391     return (part != MediaMuteButtonPart);
1392 }
1393
1394 bool RenderThemeGtk::paintMediaFullscreenButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1395 {
1396     return paintMediaButton(renderObject, paintInfo.context(), rect, "view-fullscreen-symbolic");
1397 }
1398
1399 bool RenderThemeGtk::paintMediaMuteButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1400 {
1401     Node* node = renderObject.node();
1402     if (!node)
1403         return true;
1404     Node* mediaNode = node->shadowHost();
1405     if (!is<HTMLMediaElement>(mediaNode))
1406         return true;
1407
1408     HTMLMediaElement* mediaElement = downcast<HTMLMediaElement>(mediaNode);
1409     return paintMediaButton(renderObject, paintInfo.context(), rect, mediaElement->muted() ? "audio-volume-muted-symbolic" : "audio-volume-high-symbolic");
1410 }
1411
1412 bool RenderThemeGtk::paintMediaPlayButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1413 {
1414     Node* node = renderObject.node();
1415     if (!node)
1416         return true;
1417     if (!nodeHasPseudo(node, "-webkit-media-controls-play-button"))
1418         return true;
1419
1420     return paintMediaButton(renderObject, paintInfo.context(), rect, nodeHasClass(node, "paused") ? "media-playback-start-symbolic" : "media-playback-pause-symbolic");
1421 }
1422
1423 bool RenderThemeGtk::paintMediaSeekBackButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1424 {
1425     return paintMediaButton(renderObject, paintInfo.context(), rect, "media-seek-backward-symbolic");
1426 }
1427
1428 bool RenderThemeGtk::paintMediaSeekForwardButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1429 {
1430     return paintMediaButton(renderObject, paintInfo.context(), rect, "media-seek-forward-symbolic");
1431 }
1432
1433 #if ENABLE(VIDEO_TRACK)
1434 bool RenderThemeGtk::paintMediaToggleClosedCaptionsButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1435 {
1436     return paintMediaButton(renderObject, paintInfo.context(), rect, "media-view-subtitles-symbolic");
1437 }
1438 #endif
1439
1440 static FloatRoundedRect::Radii borderRadiiFromStyle(RenderStyle& style)
1441 {
1442     return FloatRoundedRect::Radii(
1443         IntSize(style.borderTopLeftRadius().width().intValue(), style.borderTopLeftRadius().height().intValue()),
1444         IntSize(style.borderTopRightRadius().width().intValue(), style.borderTopRightRadius().height().intValue()),
1445         IntSize(style.borderBottomLeftRadius().width().intValue(), style.borderBottomLeftRadius().height().intValue()),
1446         IntSize(style.borderBottomRightRadius().width().intValue(), style.borderBottomRightRadius().height().intValue()));
1447 }
1448
1449 bool RenderThemeGtk::paintMediaSliderTrack(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1450 {
1451     HTMLMediaElement* mediaElement = parentMediaElement(o);
1452     if (!mediaElement)
1453         return true;
1454
1455     GraphicsContext& context = paintInfo.context();
1456     context.save();
1457     context.setStrokeStyle(NoStroke);
1458
1459     float mediaDuration = mediaElement->duration();
1460     float totalTrackWidth = r.width();
1461     RenderStyle& style = o.style();
1462     RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
1463     for (unsigned index = 0; index < timeRanges->length(); ++index) {
1464         float start = timeRanges->start(index, IGNORE_EXCEPTION);
1465         float end = timeRanges->end(index, IGNORE_EXCEPTION);
1466         float startRatio = start / mediaDuration;
1467         float lengthRatio = (end - start) / mediaDuration;
1468         if (!lengthRatio)
1469             continue;
1470
1471         IntRect rangeRect(r);
1472         rangeRect.setWidth(lengthRatio * totalTrackWidth);
1473         if (index)
1474             rangeRect.move(startRatio * totalTrackWidth, 0);
1475         context.fillRoundedRect(FloatRoundedRect(rangeRect, borderRadiiFromStyle(style)), style.visitedDependentColor(CSSPropertyColor));
1476     }
1477
1478     context.restore();
1479     return false;
1480 }
1481
1482 bool RenderThemeGtk::paintMediaSliderThumb(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1483 {
1484     RenderStyle& style = o.style();
1485     paintInfo.context().fillRoundedRect(FloatRoundedRect(r, borderRadiiFromStyle(style)), style.visitedDependentColor(CSSPropertyColor));
1486     return false;
1487 }
1488
1489 bool RenderThemeGtk::paintMediaVolumeSliderTrack(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1490 {
1491     HTMLMediaElement* mediaElement = parentMediaElement(renderObject);
1492     if (!mediaElement)
1493         return true;
1494
1495     float volume = mediaElement->muted() ? 0.0f : mediaElement->volume();
1496     if (!volume)
1497         return true;
1498
1499     GraphicsContext& context = paintInfo.context();
1500     context.save();
1501     context.setStrokeStyle(NoStroke);
1502
1503     int rectHeight = rect.height();
1504     float trackHeight = rectHeight * volume;
1505     RenderStyle& style = renderObject.style();
1506     IntRect volumeRect(rect);
1507     volumeRect.move(0, rectHeight - trackHeight);
1508     volumeRect.setHeight(ceil(trackHeight));
1509
1510     context.fillRoundedRect(FloatRoundedRect(volumeRect, borderRadiiFromStyle(style)), style.visitedDependentColor(CSSPropertyColor));
1511     context.restore();
1512
1513     return false;
1514 }
1515
1516 bool RenderThemeGtk::paintMediaVolumeSliderThumb(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1517 {
1518     return paintMediaSliderThumb(renderObject, paintInfo, rect);
1519 }
1520
1521 String RenderThemeGtk::formatMediaControlsCurrentTime(float currentTime, float duration) const
1522 {
1523     return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
1524 }
1525
1526 bool RenderThemeGtk::paintMediaCurrentTime(const RenderObject&, const PaintInfo&, const IntRect&)
1527 {
1528     return false;
1529 }
1530 #endif
1531
1532 void RenderThemeGtk::adjustProgressBarStyle(StyleResolver&, RenderStyle& style, Element*) const
1533 {
1534     style.setBoxShadow(nullptr);
1535 }
1536
1537 // These values have been copied from RenderThemeChromiumSkia.cpp
1538 static const int progressActivityBlocks = 5;
1539 static const int progressAnimationFrames = 10;
1540 static const double progressAnimationInterval = 0.125;
1541 double RenderThemeGtk::animationRepeatIntervalForProgressBar(RenderProgress&) const
1542 {
1543     return progressAnimationInterval;
1544 }
1545
1546 double RenderThemeGtk::animationDurationForProgressBar(RenderProgress&) const
1547 {
1548     return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth;
1549 }
1550
1551 IntRect RenderThemeGtk::calculateProgressRect(const RenderObject& renderObject, const IntRect& fullBarRect)
1552 {
1553     IntRect progressRect(fullBarRect);
1554     const auto& renderProgress = downcast<RenderProgress>(renderObject);
1555     if (renderProgress.isDeterminate()) {
1556         int progressWidth = progressRect.width() * renderProgress.position();
1557         if (renderObject.style().direction() == RTL)
1558             progressRect.setX(progressRect.x() + progressRect.width() - progressWidth);
1559         progressRect.setWidth(progressWidth);
1560         return progressRect;
1561     }
1562
1563     double animationProgress = renderProgress.animationProgress();
1564
1565     // Never let the progress rect shrink smaller than 2 pixels.
1566     int newWidth = std::max(2, progressRect.width() / progressActivityBlocks);
1567     int movableWidth = progressRect.width() - newWidth;
1568     progressRect.setWidth(newWidth);
1569
1570     // We want the first 0.5 units of the animation progress to represent the
1571     // forward motion and the second 0.5 units to represent the backward motion,
1572     // thus we multiply by two here to get the full sweep of the progress bar with
1573     // each direction.
1574     if (animationProgress < 0.5)
1575         progressRect.setX(progressRect.x() + (animationProgress * 2 * movableWidth));
1576     else
1577         progressRect.setX(progressRect.x() + ((1.0 - animationProgress) * 2 * movableWidth));
1578     return progressRect;
1579 }
1580
1581 String RenderThemeGtk::fileListNameForWidth(const FileList* fileList, const FontCascade& font, int width, bool multipleFilesAllowed) const
1582 {
1583     if (width <= 0)
1584         return String();
1585
1586     if (fileList->length() > 1)
1587         return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
1588
1589     String string;
1590     if (fileList->length())
1591         string = pathGetFileName(fileList->item(0)->path());
1592     else if (multipleFilesAllowed)
1593         string = fileButtonNoFilesSelectedLabel();
1594     else
1595         string = fileButtonNoFileSelectedLabel();
1596
1597     return StringTruncator::centerTruncate(string, width, font, StringTruncator::EnableRoundingHacks);
1598 }
1599
1600 #if ENABLE(VIDEO)
1601 String RenderThemeGtk::mediaControlsScript()
1602 {
1603     StringBuilder scriptBuilder;
1604     scriptBuilder.append(mediaControlsLocalizedStringsJavaScript, sizeof(mediaControlsLocalizedStringsJavaScript));
1605     scriptBuilder.append(mediaControlsBaseJavaScript, sizeof(mediaControlsBaseJavaScript));
1606     scriptBuilder.append(mediaControlsGtkJavaScript, sizeof(mediaControlsGtkJavaScript));
1607     return scriptBuilder.toString();
1608 }
1609 #endif // ENABLE(VIDEO)
1610
1611 #endif // GTK_API_VERSION_2
1612 }