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) |
306 | |