0d1726d55122b67fe9a57a28c15574dbc2cc134f
[WebKit-https.git] / Source / WebCore / platform / gtk / RenderThemeWidget.cpp
1 /*
2  * Copyright (C) 2017 Igalia S.L.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "RenderThemeWidget.h"
28
29 #if GTK_CHECK_VERSION(3, 20, 0)
30
31 #include <wtf/HashMap.h>
32 #include <wtf/NeverDestroyed.h>
33
34 namespace WebCore {
35
36 static HashMap<unsigned, std::unique_ptr<RenderThemeWidget>>& widgetMap()
37 {
38     static NeverDestroyed<HashMap<unsigned, std::unique_ptr<RenderThemeWidget>>> map;
39     return map;
40 }
41
42 RenderThemeWidget& RenderThemeWidget::getOrCreate(Type widgetType)
43 {
44     auto addResult = widgetMap().ensure(static_cast<unsigned>(widgetType), [widgetType]() -> std::unique_ptr<RenderThemeWidget> {
45         switch (widgetType) {
46         case RenderThemeWidget::Type::VerticalScrollbarRight:
47             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Full);
48         case RenderThemeWidget::Type::VerticalScrollbarLeft:
49             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Full, RenderThemeScrollbar::VerticalPosition::Left);
50         case RenderThemeWidget::Type::HorizontalScrollbar:
51             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbar::Mode::Full);
52         case RenderThemeWidget::Type::VerticalScrollIndicatorRight:
53             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Indicator);
54         case RenderThemeWidget::Type::VerticalScrollIndicatorLeft:
55             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Indicator, RenderThemeScrollbar::VerticalPosition::Left);
56         case RenderThemeWidget::Type::HorizontalScrollIndicator:
57             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbar::Mode::Indicator);
58         case RenderThemeWidget::Type::CheckButton:
59             return std::make_unique<RenderThemeToggleButton>(RenderThemeToggleButton::Type::Check);
60         case RenderThemeWidget::Type::RadioButton:
61             return std::make_unique<RenderThemeToggleButton>(RenderThemeToggleButton::Type::Radio);
62         case RenderThemeWidget::Type::Button:
63             return std::make_unique<RenderThemeButton>(RenderThemeButton::Default::No);
64         case RenderThemeWidget::Type::ButtonDefault:
65             return std::make_unique<RenderThemeButton>(RenderThemeButton::Default::Yes);
66         case RenderThemeWidget::Type::ComboBox:
67             return std::make_unique<RenderThemeComboBox>();
68         case RenderThemeWidget::Type::Entry:
69             return std::make_unique<RenderThemeEntry>();
70         case RenderThemeWidget::Type::SelectedEntry:
71             return std::make_unique<RenderThemeEntry>(RenderThemeEntry::Selected::Yes);
72         case RenderThemeWidget::Type::SearchEntry:
73             return std::make_unique<RenderThemeSearchEntry>();
74         case RenderThemeWidget::Type::SpinButton:
75             return std::make_unique<RenderThemeSpinButton>();
76         case RenderThemeWidget::Type::VerticalSlider:
77             return std::make_unique<RenderThemeSlider>(GTK_ORIENTATION_VERTICAL);
78         case RenderThemeWidget::Type::HorizontalSlider:
79             return std::make_unique<RenderThemeSlider>(GTK_ORIENTATION_HORIZONTAL);
80         case RenderThemeWidget::Type::ProgressBar:
81             return std::make_unique<RenderThemeProgressBar>(RenderThemeProgressBar::Mode::Determinate);
82         case RenderThemeWidget::Type::IndeterminateProgressBar:
83             return std::make_unique<RenderThemeProgressBar>(RenderThemeProgressBar::Mode::Indeterminate);
84         case RenderThemeWidget::Type::ListView:
85             return std::make_unique<RenderThemeListView>();
86         case RenderThemeWidget::Type::Icon:
87             return std::make_unique<RenderThemeIcon>();
88         case RenderThemeWidget::Type::Window:
89             return std::make_unique<RenderThemeWindow>();
90         }
91         ASSERT_NOT_REACHED();
92         return nullptr;
93     });
94     return *addResult.iterator->value;
95 }
96
97 void RenderThemeWidget::clearCache()
98 {
99     widgetMap().clear();
100 }
101
102 RenderThemeWidget::~RenderThemeWidget() = default;
103
104 RenderThemeScrollbar::RenderThemeScrollbar(GtkOrientation orientation, Mode mode, VerticalPosition verticalPosition)
105 {
106     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Scrollbar, "scrollbar", { } };
107     if (orientation == GTK_ORIENTATION_VERTICAL) {
108         info.classList.append("vertical");
109         info.classList.append(verticalPosition == VerticalPosition::Right ? "right" : "left");
110     } else {
111         info.classList.append("horizontal");
112         info.classList.append("bottom");
113     }
114     static bool usesOverlayScrollbars = g_strcmp0(g_getenv("GTK_OVERLAY_SCROLLING"), "0");
115     if (usesOverlayScrollbars)
116         info.classList.append("overlay-indicator");
117     if (mode == Mode::Full)
118         info.classList.append("hovering");
119     m_scrollbar = RenderThemeGadget::create(info);
120
121     Vector<RenderThemeGadget::Info> children;
122     auto steppers = static_cast<RenderThemeScrollbarGadget*>(m_scrollbar.get())->steppers();
123     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward)) {
124         m_steppersPosition[0] = children.size();
125         children.append({ RenderThemeGadget::Type::Generic, "button", { "up" } });
126     }
127     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) {
128         m_steppersPosition[1] = children.size();
129         children.append({ RenderThemeGadget::Type::Generic, "button", { "down" } });
130     }
131     m_troughPosition = children.size();
132     children.append({ RenderThemeGadget::Type::Generic, "trough", { } });
133     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) {
134         m_steppersPosition[2] = children.size();
135         children.append({ RenderThemeGadget::Type::Generic, "button", { "up" } });
136     }
137     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward)) {
138         m_steppersPosition[3] = children.size();
139         children.append({ RenderThemeGadget::Type::Generic, "button", { "down" } });
140     }
141     info.type = RenderThemeGadget::Type::Generic;
142     info.name = "contents";
143     info.classList.clear();
144     m_contents = std::make_unique<RenderThemeBoxGadget>(info, GTK_ORIENTATION_VERTICAL, children, m_scrollbar.get());
145     info.name = "slider";
146     m_slider = RenderThemeGadget::create(info, m_contents->child(m_troughPosition));
147 }
148
149 RenderThemeGadget* RenderThemeScrollbar::stepper(RenderThemeScrollbarGadget::Steppers scrollbarStepper)
150 {
151     if (!static_cast<RenderThemeScrollbarGadget*>(m_scrollbar.get())->steppers().contains(scrollbarStepper))
152         return nullptr;
153
154     switch (scrollbarStepper) {
155     case RenderThemeScrollbarGadget::Steppers::Backward:
156         return m_contents->child(m_steppersPosition[0]);
157     case RenderThemeScrollbarGadget::Steppers::SecondaryForward:
158         return m_contents->child(m_steppersPosition[1]);
159     case RenderThemeScrollbarGadget::Steppers::SecondaryBackward:
160         return m_contents->child(m_steppersPosition[2]);
161     case RenderThemeScrollbarGadget::Steppers::Forward:
162         return m_contents->child(m_steppersPosition[3]);
163     default:
164         break;
165     }
166
167     return nullptr;
168 }
169
170 RenderThemeToggleButton::RenderThemeToggleButton(Type toggleType)
171 {
172     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, toggleType == Type::Check ? "checkbutton" : "radiobutton", { "text-button" } };
173     m_button = RenderThemeGadget::create(info);
174     if (toggleType == Type::Check) {
175         info.type = RenderThemeGadget::Type::Check;
176         info.name = "check";
177     } else {
178         info.type = RenderThemeGadget::Type::Radio;
179         info.name = "radio";
180     }
181     info.classList.clear();
182     m_toggle = RenderThemeGadget::create(info, m_button.get());
183 }
184
185 RenderThemeButton::RenderThemeButton(Default isDefault)
186 {
187     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Button, "button", { "text-button" } };
188     if (isDefault == Default::Yes)
189         info.classList.append("default");
190     m_button = RenderThemeGadget::create(info);
191 }
192
193 RenderThemeComboBox::RenderThemeComboBox()
194 {
195     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "combobox", { } };
196     m_comboBox = RenderThemeGadget::create(info);
197     Vector<RenderThemeGadget::Info> children = {
198         { RenderThemeGadget::Type::Generic, "button", { "combo" } }
199     };
200     info.name = "box";
201     info.classList = { "horizontal", "linked" };
202     m_box = std::make_unique<RenderThemeBoxGadget>(info, GTK_ORIENTATION_HORIZONTAL, children, m_comboBox.get());
203     RenderThemeGadget* button = m_box->child(0);
204     info.classList.removeLast();
205     m_buttonBox = RenderThemeGadget::create(info, button);
206     info.type = RenderThemeGadget::Type::Arrow;
207     info.name = "arrow";
208     info.classList = { };
209     m_arrow = RenderThemeGadget::create(info, m_buttonBox.get());
210 }
211
212 RenderThemeEntry::RenderThemeEntry(Selected isSelected)
213 {
214     RenderThemeGadget::Info info = { RenderThemeGadget::Type::TextField, "entry", { } };
215     m_entry = RenderThemeGadget::create(info);
216     if (isSelected == Selected::Yes) {
217         info.type = RenderThemeGadget::Type::Generic;
218         info.name = "selection";
219         m_selection = RenderThemeGadget::create(info, m_entry.get());
220     }
221 }
222
223 RenderThemeSearchEntry::RenderThemeSearchEntry()
224 {
225     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Icon, "image", { "left" } };
226     m_leftIcon = RenderThemeGadget::create(info, m_entry.get());
227     static_cast<RenderThemeIconGadget*>(m_leftIcon.get())->setIconName("edit-find-symbolic");
228     info.classList.clear();
229     info.classList.append("right");
230     m_rightIcon = RenderThemeGadget::create(info, m_entry.get());
231     static_cast<RenderThemeIconGadget*>(m_rightIcon.get())->setIconName("edit-clear-symbolic");
232 }
233
234 RenderThemeSpinButton::RenderThemeSpinButton()
235 {
236     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "spinbutton", { "horizontal" } };
237     m_spinButton = RenderThemeGadget::create(info);
238     info.type = RenderThemeGadget::Type::TextField;
239     info.name = "entry";
240     info.classList.clear();
241     m_entry = RenderThemeGadget::create(info, m_spinButton.get());
242     info.type = RenderThemeGadget::Type::Icon;
243     info.name = "button";
244     info.classList.append("up");
245     m_up = RenderThemeGadget::create(info, m_spinButton.get());
246     auto* upIcon = static_cast<RenderThemeIconGadget*>(m_up.get());
247     upIcon->setIconSize(RenderThemeIconGadget::IconSizeGtk::Menu);
248     upIcon->setIconName("list-add-symbolic");
249     info.classList[0] = "down";
250     m_down = RenderThemeGadget::create(info, m_spinButton.get());
251     auto* downIcon = static_cast<RenderThemeIconGadget*>(m_down.get());
252     downIcon->setIconSize(RenderThemeIconGadget::IconSizeGtk::Menu);
253     downIcon->setIconName("list-remove-symbolic");
254 }
255
256 RenderThemeSlider::RenderThemeSlider(GtkOrientation orientation)
257 {
258     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "scale", { } };
259     if (orientation == GTK_ORIENTATION_VERTICAL)
260         info.classList.append("vertical");
261     else
262         info.classList.append("horizontal");
263     m_scale = RenderThemeGadget::create(info);
264     info.name = "contents";
265     info.classList.clear();
266     m_contents = RenderThemeGadget::create(info, m_scale.get());
267     info.name = "trough";
268     m_trough = RenderThemeGadget::create(info, m_contents.get());
269     info.name = "slider";
270     m_slider = RenderThemeGadget::create(info, m_trough.get());
271     info.name = "highlight";
272     m_highlight = RenderThemeGadget::create(info, m_trough.get());
273 }
274
275 RenderThemeProgressBar::RenderThemeProgressBar(Mode mode)
276 {
277     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "progressbar", { "horizontal" } };
278     m_progressBar = RenderThemeGadget::create(info);
279     info.name = "trough";
280     info.classList.clear();
281     m_trough = RenderThemeGadget::create(info, m_progressBar.get());
282     info.name = "progress";
283     if (mode == Mode::Determinate)
284         info.classList.append("pulse");
285     m_progress = RenderThemeGadget::create(info, m_trough.get());
286 }
287
288 RenderThemeListView::RenderThemeListView()
289     : m_treeview(RenderThemeGadget::create({ RenderThemeGadget::Type::Generic, "treeview", { "view" } }))
290 {
291 }
292
293 RenderThemeIcon::RenderThemeIcon()
294     : m_icon(RenderThemeGadget::create({ RenderThemeGadget::Type::Icon, "image", { } }))
295 {
296 }
297
298 RenderThemeWindow::RenderThemeWindow()
299     : m_window(RenderThemeGadget::create({ RenderThemeGadget::Type::Generic, "window", { "background" } }))
300 {
301 }
302
303 } // namepsace WebCore
304
305 #endif // GTK_CHECK_VERSION(3, 20, 0)