d85dca1853d105b9819315d382c085ec65b47385
[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/Environment.h>
32 #include <wtf/HashMap.h>
33 #include <wtf/NeverDestroyed.h>
34
35 namespace WebCore {
36
37 static HashMap<unsigned, std::unique_ptr<RenderThemeWidget>>& widgetMap()
38 {
39     static NeverDestroyed<HashMap<unsigned, std::unique_ptr<RenderThemeWidget>>> map;
40     return map;
41 }
42
43 RenderThemeWidget& RenderThemeWidget::getOrCreate(Type widgetType)
44 {
45     auto addResult = widgetMap().ensure(static_cast<unsigned>(widgetType), [widgetType]() -> std::unique_ptr<RenderThemeWidget> {
46         switch (widgetType) {
47         case RenderThemeWidget::Type::VerticalScrollbarRight:
48             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Full);
49         case RenderThemeWidget::Type::VerticalScrollbarLeft:
50             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Full, RenderThemeScrollbar::VerticalPosition::Left);
51         case RenderThemeWidget::Type::HorizontalScrollbar:
52             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbar::Mode::Full);
53         case RenderThemeWidget::Type::VerticalScrollIndicatorRight:
54             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Indicator);
55         case RenderThemeWidget::Type::VerticalScrollIndicatorLeft:
56             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Indicator, RenderThemeScrollbar::VerticalPosition::Left);
57         case RenderThemeWidget::Type::HorizontalScrollIndicator:
58             return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbar::Mode::Indicator);
59         case RenderThemeWidget::Type::CheckButton:
60             return std::make_unique<RenderThemeToggleButton>(RenderThemeToggleButton::Type::Check);
61         case RenderThemeWidget::Type::RadioButton:
62             return std::make_unique<RenderThemeToggleButton>(RenderThemeToggleButton::Type::Radio);
63         case RenderThemeWidget::Type::Button:
64             return std::make_unique<RenderThemeButton>(RenderThemeButton::Default::No);
65         case RenderThemeWidget::Type::ButtonDefault:
66             return std::make_unique<RenderThemeButton>(RenderThemeButton::Default::Yes);
67         case RenderThemeWidget::Type::ComboBox:
68             return std::make_unique<RenderThemeComboBox>();
69         case RenderThemeWidget::Type::Entry:
70             return std::make_unique<RenderThemeEntry>();
71         case RenderThemeWidget::Type::SelectedEntry:
72             return std::make_unique<RenderThemeEntry>(RenderThemeEntry::Selected::Yes);
73         case RenderThemeWidget::Type::SearchEntry:
74             return std::make_unique<RenderThemeSearchEntry>();
75         case RenderThemeWidget::Type::SpinButton:
76             return std::make_unique<RenderThemeSpinButton>();
77         case RenderThemeWidget::Type::VerticalSlider:
78             return std::make_unique<RenderThemeSlider>(GTK_ORIENTATION_VERTICAL);
79         case RenderThemeWidget::Type::HorizontalSlider:
80             return std::make_unique<RenderThemeSlider>(GTK_ORIENTATION_HORIZONTAL);
81         case RenderThemeWidget::Type::ProgressBar:
82             return std::make_unique<RenderThemeProgressBar>(RenderThemeProgressBar::Mode::Determinate);
83         case RenderThemeWidget::Type::IndeterminateProgressBar:
84             return std::make_unique<RenderThemeProgressBar>(RenderThemeProgressBar::Mode::Indeterminate);
85         case RenderThemeWidget::Type::ListView:
86             return std::make_unique<RenderThemeListView>();
87         case RenderThemeWidget::Type::Icon:
88             return std::make_unique<RenderThemeIcon>();
89         }
90         ASSERT_NOT_REACHED();
91         return nullptr;
92     });
93     return *addResult.iterator->value;
94 }
95
96 void RenderThemeWidget::clearCache()
97 {
98     widgetMap().clear();
99 }
100
101 RenderThemeWidget::~RenderThemeWidget() = default;
102
103 RenderThemeScrollbar::RenderThemeScrollbar(GtkOrientation orientation, Mode mode, VerticalPosition verticalPosition)
104 {
105     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Scrollbar, "scrollbar", { } };
106     if (orientation == GTK_ORIENTATION_VERTICAL) {
107         info.classList.append("vertical");
108         info.classList.append(verticalPosition == VerticalPosition::Right ? "right" : "left");
109     } else {
110         info.classList.append("horizontal");
111         info.classList.append("bottom");
112     }
113     static bool usesOverlayScrollbars = !Environment::hasValue("GTK_OVERLAY_SCROLLING", "0");
114     if (usesOverlayScrollbars)
115         info.classList.append("overlay-indicator");
116     if (mode == Mode::Full)
117         info.classList.append("hovering");
118     m_scrollbar = RenderThemeGadget::create(info);
119
120     Vector<RenderThemeGadget::Info> children;
121     auto steppers = static_cast<RenderThemeScrollbarGadget*>(m_scrollbar.get())->steppers();
122     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward)) {
123         m_steppersPosition[0] = children.size();
124         children.append({ RenderThemeGadget::Type::Generic, "button", { "up" } });
125     }
126     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) {
127         m_steppersPosition[1] = children.size();
128         children.append({ RenderThemeGadget::Type::Generic, "button", { "down" } });
129     }
130     m_troughPosition = children.size();
131     children.append({ RenderThemeGadget::Type::Generic, "trough", { } });
132     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) {
133         m_steppersPosition[2] = children.size();
134         children.append({ RenderThemeGadget::Type::Generic, "button", { "up" } });
135     }
136     if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward)) {
137         m_steppersPosition[3] = children.size();
138         children.append({ RenderThemeGadget::Type::Generic, "button", { "down" } });
139     }
140     info.type = RenderThemeGadget::Type::Generic;
141     info.name = "contents";
142     info.classList.clear();
143     m_contents = std::make_unique<RenderThemeBoxGadget>(info, GTK_ORIENTATION_VERTICAL, children, m_scrollbar.get());
144     info.name = "slider";
145     m_slider = RenderThemeGadget::create(info, m_contents->child(m_troughPosition));
146 }
147
148 RenderThemeGadget* RenderThemeScrollbar::stepper(RenderThemeScrollbarGadget::Steppers scrollbarStepper)
149 {
150     if (!static_cast<RenderThemeScrollbarGadget*>(m_scrollbar.get())->steppers().contains(scrollbarStepper))
151         return nullptr;
152
153     switch (scrollbarStepper) {
154     case RenderThemeScrollbarGadget::Steppers::Backward:
155         return m_contents->child(m_steppersPosition[0]);
156     case RenderThemeScrollbarGadget::Steppers::SecondaryForward:
157         return m_contents->child(m_steppersPosition[1]);
158     case RenderThemeScrollbarGadget::Steppers::SecondaryBackward:
159         return m_contents->child(m_steppersPosition[2]);
160     case RenderThemeScrollbarGadget::Steppers::Forward:
161         return m_contents->child(m_steppersPosition[3]);
162     default:
163         break;
164     }
165
166     return nullptr;
167 }
168
169 RenderThemeToggleButton::RenderThemeToggleButton(Type toggleType)
170 {
171     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, toggleType == Type::Check ? "checkbutton" : "radiobutton", { "text-button" } };
172     m_button = RenderThemeGadget::create(info);
173     if (toggleType == Type::Check) {
174         info.type = RenderThemeGadget::Type::Check;
175         info.name = "check";
176     } else {
177         info.type = RenderThemeGadget::Type::Radio;
178         info.name = "radio";
179     }
180     info.classList.clear();
181     m_toggle = RenderThemeGadget::create(info, m_button.get());
182 }
183
184 RenderThemeButton::RenderThemeButton(Default isDefault)
185 {
186     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Button, "button", { "text-button" } };
187     if (isDefault == Default::Yes)
188         info.classList.append("default");
189     m_button = RenderThemeGadget::create(info);
190 }
191
192 RenderThemeComboBox::RenderThemeComboBox()
193 {
194     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "combobox", { } };
195     m_comboBox = RenderThemeGadget::create(info);
196     Vector<RenderThemeGadget::Info> children = {
197         { RenderThemeGadget::Type::Generic, "button", { "combo" } }
198     };
199     info.name = "box";
200     info.classList = { "horizontal", "linked" };
201     m_box = std::make_unique<RenderThemeBoxGadget>(info, GTK_ORIENTATION_HORIZONTAL, children, m_comboBox.get());
202     RenderThemeGadget* button = m_box->child(0);
203     info.classList.removeLast();
204     m_buttonBox = RenderThemeGadget::create(info, button);
205     info.type = RenderThemeGadget::Type::Arrow;
206     info.name = "arrow";
207     info.classList = { };
208     m_arrow = RenderThemeGadget::create(info, m_buttonBox.get());
209 }
210
211 RenderThemeEntry::RenderThemeEntry(Selected isSelected)
212 {
213     RenderThemeGadget::Info info = { RenderThemeGadget::Type::TextField, "entry", { } };
214     m_entry = RenderThemeGadget::create(info);
215     if (isSelected == Selected::Yes) {
216         info.type = RenderThemeGadget::Type::Generic;
217         info.name = "selection";
218         m_selection = RenderThemeGadget::create(info, m_entry.get());
219     }
220 }
221
222 RenderThemeSearchEntry::RenderThemeSearchEntry()
223 {
224     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Icon, "image", { "left" } };
225     m_leftIcon = RenderThemeGadget::create(info, m_entry.get());
226     static_cast<RenderThemeIconGadget*>(m_leftIcon.get())->setIconName("edit-find-symbolic");
227     info.classList.clear();
228     info.classList.append("right");
229     m_rightIcon = RenderThemeGadget::create(info, m_entry.get());
230     static_cast<RenderThemeIconGadget*>(m_rightIcon.get())->setIconName("edit-clear-symbolic");
231 }
232
233 RenderThemeSpinButton::RenderThemeSpinButton()
234 {
235     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "spinbutton", { "horizontal" } };
236     m_spinButton = RenderThemeGadget::create(info);
237     info.type = RenderThemeGadget::Type::TextField;
238     info.name = "entry";
239     info.classList.clear();
240     m_entry = RenderThemeGadget::create(info, m_spinButton.get());
241     info.type = RenderThemeGadget::Type::Icon;
242     info.name = "button";
243     info.classList.append("up");
244     m_up = RenderThemeGadget::create(info, m_spinButton.get());
245     auto* upIcon = static_cast<RenderThemeIconGadget*>(m_up.get());
246     upIcon->setIconSize(RenderThemeIconGadget::IconSizeGtk::Menu);
247     upIcon->setIconName("list-add-symbolic");
248     info.classList[0] = "down";
249     m_down = RenderThemeGadget::create(info, m_spinButton.get());
250     auto* downIcon = static_cast<RenderThemeIconGadget*>(m_down.get());
251     downIcon->setIconSize(RenderThemeIconGadget::IconSizeGtk::Menu);
252     downIcon->setIconName("list-remove-symbolic");
253 }
254
255 RenderThemeSlider::RenderThemeSlider(GtkOrientation orientation)
256 {
257     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "scale", { } };
258     if (orientation == GTK_ORIENTATION_VERTICAL)
259         info.classList.append("vertical");
260     else
261         info.classList.append("horizontal");
262     m_scale = RenderThemeGadget::create(info);
263     info.name = "contents";
264     info.classList.clear();
265     m_contents = RenderThemeGadget::create(info, m_scale.get());
266     info.name = "trough";
267     m_trough = RenderThemeGadget::create(info, m_contents.get());
268     info.name = "slider";
269     m_slider = RenderThemeGadget::create(info, m_trough.get());
270     info.name = "highlight";
271     m_highlight = RenderThemeGadget::create(info, m_trough.get());
272 }
273
274 RenderThemeProgressBar::RenderThemeProgressBar(Mode mode)
275 {
276     RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "progressbar", { "horizontal" } };
277     m_progressBar = RenderThemeGadget::create(info);
278     info.name = "trough";
279     info.classList.clear();
280     m_trough = RenderThemeGadget::create(info, m_progressBar.get());
281     info.name = "progress";
282     if (mode == Mode::Determinate)
283         info.classList.append("pulse");
284     m_progress = RenderThemeGadget::create(info, m_trough.get());
285 }
286
287 RenderThemeListView::RenderThemeListView()
288     : m_treeview(RenderThemeGadget::create({ RenderThemeGadget::Type::Generic, "treeview", { "view" } }))
289 {
290 }
291
292 RenderThemeIcon::RenderThemeIcon()
293     : m_icon(RenderThemeGadget::create({ RenderThemeGadget::Type::Icon, "image", { } }))
294 {
295 }
296
297 } // namepsace WebCore
298
299 #endif // GTK_CHECK_VERSION(3, 20, 0)