• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2021 The Chromium Embedded Framework Authors.
2 // Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 
6 #include "libcef/browser/simple_menu_model_impl.h"
7 
8 #include <vector>
9 
10 #include "libcef/browser/thread_util.h"
11 #include "libcef/common/task_runner_impl.h"
12 
13 namespace {
14 
15 // Value based on the documentation on SimpleMenuModel::GetIndexOfCommandId().
16 const int kInvalidIndex = -1;
17 const int kInvalidCommandId = -1;
18 const int kInvalidGroupId = -1;
19 
GetCefItemType(ui::MenuModel::ItemType type)20 cef_menu_item_type_t GetCefItemType(ui::MenuModel::ItemType type) {
21   switch (type) {
22     case ui::MenuModel::TYPE_COMMAND:
23       return MENUITEMTYPE_COMMAND;
24     case ui::MenuModel::TYPE_CHECK:
25       return MENUITEMTYPE_CHECK;
26     case ui::MenuModel::TYPE_RADIO:
27       return MENUITEMTYPE_RADIO;
28     case ui::MenuModel::TYPE_SEPARATOR:
29       return MENUITEMTYPE_SEPARATOR;
30     case ui::MenuModel::TYPE_SUBMENU:
31       return MENUITEMTYPE_SUBMENU;
32     default:
33       return MENUITEMTYPE_NONE;
34   }
35 }
36 
37 }  // namespace
38 
CefSimpleMenuModelImpl(ui::SimpleMenuModel * model,ui::SimpleMenuModel::Delegate * delegate,StateDelegate * state_delegate,bool is_owned,bool is_submenu)39 CefSimpleMenuModelImpl::CefSimpleMenuModelImpl(
40     ui::SimpleMenuModel* model,
41     ui::SimpleMenuModel::Delegate* delegate,
42     StateDelegate* state_delegate,
43     bool is_owned,
44     bool is_submenu)
45     : supported_thread_id_(base::PlatformThread::CurrentId()),
46       model_(model),
47       delegate_(delegate),
48       state_delegate_(state_delegate),
49       is_owned_(is_owned),
50       is_submenu_(is_submenu) {
51   DCHECK(model_);
52   DCHECK(delegate_);
53   DCHECK(state_delegate_);
54 }
55 
~CefSimpleMenuModelImpl()56 CefSimpleMenuModelImpl::~CefSimpleMenuModelImpl() {
57   // Detach() must be called before object destruction.
58   DCHECK(!model_);
59   DCHECK(submenumap_.empty());
60 }
61 
Detach()62 void CefSimpleMenuModelImpl::Detach() {
63   DCHECK(VerifyContext());
64 
65   if (!submenumap_.empty()) {
66     auto it = submenumap_.begin();
67     for (; it != submenumap_.end(); ++it) {
68       it->second->Detach();
69     }
70     submenumap_.clear();
71   }
72 
73   if (is_owned_)
74     delete model_;
75   model_ = nullptr;
76 }
77 
IsSubMenu()78 bool CefSimpleMenuModelImpl::IsSubMenu() {
79   if (!VerifyContext())
80     return false;
81   return is_submenu_;
82 }
83 
Clear()84 bool CefSimpleMenuModelImpl::Clear() {
85   if (!VerifyContext())
86     return false;
87 
88   model_->Clear();
89   return true;
90 }
91 
GetCount()92 int CefSimpleMenuModelImpl::GetCount() {
93   if (!VerifyContext())
94     return 0;
95 
96   return model_->GetItemCount();
97 }
98 
AddSeparator()99 bool CefSimpleMenuModelImpl::AddSeparator() {
100   if (!VerifyContext())
101     return false;
102 
103   model_->AddSeparator(ui::NORMAL_SEPARATOR);
104   return true;
105 }
106 
AddItem(int command_id,const CefString & label)107 bool CefSimpleMenuModelImpl::AddItem(int command_id, const CefString& label) {
108   if (!VerifyContext())
109     return false;
110 
111   model_->AddItem(command_id, label);
112   return true;
113 }
114 
AddCheckItem(int command_id,const CefString & label)115 bool CefSimpleMenuModelImpl::AddCheckItem(int command_id,
116                                           const CefString& label) {
117   if (!VerifyContext())
118     return false;
119 
120   model_->AddCheckItem(command_id, label);
121   return true;
122 }
123 
AddRadioItem(int command_id,const CefString & label,int group_id)124 bool CefSimpleMenuModelImpl::AddRadioItem(int command_id,
125                                           const CefString& label,
126                                           int group_id) {
127   if (!VerifyContext())
128     return false;
129 
130   model_->AddRadioItem(command_id, label, group_id);
131   return true;
132 }
133 
AddSubMenu(int command_id,const CefString & label)134 CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::AddSubMenu(
135     int command_id,
136     const CefString& label) {
137   if (!VerifyContext())
138     return nullptr;
139 
140   auto new_menu = CreateNewSubMenu(nullptr);
141   model_->AddSubMenu(command_id, label, new_menu->model());
142   return new_menu;
143 }
144 
InsertSeparatorAt(int index)145 bool CefSimpleMenuModelImpl::InsertSeparatorAt(int index) {
146   if (!VerifyContext())
147     return false;
148 
149   model_->InsertSeparatorAt(index, ui::NORMAL_SEPARATOR);
150   return true;
151 }
152 
InsertItemAt(int index,int command_id,const CefString & label)153 bool CefSimpleMenuModelImpl::InsertItemAt(int index,
154                                           int command_id,
155                                           const CefString& label) {
156   if (!VerifyContext() || !ValidIndex(index))
157     return false;
158 
159   model_->InsertItemAt(index, command_id, label);
160   return true;
161 }
162 
InsertCheckItemAt(int index,int command_id,const CefString & label)163 bool CefSimpleMenuModelImpl::InsertCheckItemAt(int index,
164                                                int command_id,
165                                                const CefString& label) {
166   if (!VerifyContext() || !ValidIndex(index))
167     return false;
168 
169   model_->InsertCheckItemAt(index, command_id, label);
170   return true;
171 }
172 
InsertRadioItemAt(int index,int command_id,const CefString & label,int group_id)173 bool CefSimpleMenuModelImpl::InsertRadioItemAt(int index,
174                                                int command_id,
175                                                const CefString& label,
176                                                int group_id) {
177   if (!VerifyContext() || !ValidIndex(index))
178     return false;
179 
180   model_->InsertRadioItemAt(index, command_id, label, group_id);
181   return true;
182 }
183 
InsertSubMenuAt(int index,int command_id,const CefString & label)184 CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::InsertSubMenuAt(
185     int index,
186     int command_id,
187     const CefString& label) {
188   if (!VerifyContext() || !ValidIndex(index))
189     return nullptr;
190 
191   auto new_menu = CreateNewSubMenu(nullptr);
192   model_->InsertSubMenuAt(index, command_id, label, new_menu->model());
193   return new_menu;
194 }
195 
Remove(int command_id)196 bool CefSimpleMenuModelImpl::Remove(int command_id) {
197   return RemoveAt(GetIndexOf(command_id));
198 }
199 
RemoveAt(int index)200 bool CefSimpleMenuModelImpl::RemoveAt(int index) {
201   if (!VerifyContext() || !ValidIndex(index))
202     return false;
203 
204   auto* sub_menu =
205       static_cast<ui::SimpleMenuModel*>(model_->GetSubmenuModelAt(index));
206   if (sub_menu) {
207     auto it = submenumap_.find(sub_menu);
208     if (it != submenumap_.end()) {
209       it->second->Detach();
210       submenumap_.erase(it);
211     }
212   }
213 
214   model_->RemoveItemAt(index);
215   return true;
216 }
217 
GetIndexOf(int command_id)218 int CefSimpleMenuModelImpl::GetIndexOf(int command_id) {
219   if (!VerifyContext())
220     return kInvalidIndex;
221 
222   return model_->GetIndexOfCommandId(command_id);
223 }
224 
GetCommandIdAt(int index)225 int CefSimpleMenuModelImpl::GetCommandIdAt(int index) {
226   if (!VerifyContext() || !ValidIndex(index))
227     return kInvalidCommandId;
228 
229   return model_->GetCommandIdAt(index);
230 }
231 
SetCommandIdAt(int index,int command_id)232 bool CefSimpleMenuModelImpl::SetCommandIdAt(int index, int command_id) {
233   NOTIMPLEMENTED();
234   return false;
235 }
236 
GetLabel(int command_id)237 CefString CefSimpleMenuModelImpl::GetLabel(int command_id) {
238   return GetLabelAt(GetIndexOf(command_id));
239 }
240 
GetLabelAt(int index)241 CefString CefSimpleMenuModelImpl::GetLabelAt(int index) {
242   if (!VerifyContext() || !ValidIndex(index))
243     return CefString();
244 
245   return model_->GetLabelAt(index);
246 }
247 
SetLabel(int command_id,const CefString & label)248 bool CefSimpleMenuModelImpl::SetLabel(int command_id, const CefString& label) {
249   return SetLabelAt(GetIndexOf(command_id), label);
250 }
251 
SetLabelAt(int index,const CefString & label)252 bool CefSimpleMenuModelImpl::SetLabelAt(int index, const CefString& label) {
253   if (!VerifyContext() || !ValidIndex(index))
254     return false;
255 
256   model_->SetLabel(index, label);
257   return true;
258 }
259 
GetType(int command_id)260 CefSimpleMenuModelImpl::MenuItemType CefSimpleMenuModelImpl::GetType(
261     int command_id) {
262   return GetTypeAt(GetIndexOf(command_id));
263 }
264 
GetTypeAt(int index)265 CefSimpleMenuModelImpl::MenuItemType CefSimpleMenuModelImpl::GetTypeAt(
266     int index) {
267   if (!VerifyContext() || !ValidIndex(index))
268     return MENUITEMTYPE_NONE;
269 
270   return GetCefItemType(model_->GetTypeAt(index));
271 }
272 
GetGroupId(int command_id)273 int CefSimpleMenuModelImpl::GetGroupId(int command_id) {
274   return GetGroupIdAt(GetIndexOf(command_id));
275 }
276 
GetGroupIdAt(int index)277 int CefSimpleMenuModelImpl::GetGroupIdAt(int index) {
278   if (!VerifyContext() || !ValidIndex(index))
279     return kInvalidGroupId;
280 
281   return model_->GetGroupIdAt(index);
282 }
283 
SetGroupId(int command_id,int group_id)284 bool CefSimpleMenuModelImpl::SetGroupId(int command_id, int group_id) {
285   return SetGroupIdAt(GetIndexOf(command_id), group_id);
286 }
287 
SetGroupIdAt(int index,int group_id)288 bool CefSimpleMenuModelImpl::SetGroupIdAt(int index, int group_id) {
289   NOTIMPLEMENTED();
290   return false;
291 }
292 
GetSubMenu(int command_id)293 CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::GetSubMenu(int command_id) {
294   return GetSubMenuAt(GetIndexOf(command_id));
295 }
296 
GetSubMenuAt(int index)297 CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::GetSubMenuAt(int index) {
298   if (!VerifyContext() || !ValidIndex(index))
299     return nullptr;
300 
301   auto* sub_model =
302       static_cast<ui::SimpleMenuModel*>(model_->GetSubmenuModelAt(index));
303   auto it = submenumap_.find(sub_model);
304   if (it != submenumap_.end())
305     return it->second;
306   return CreateNewSubMenu(sub_model);
307 }
308 
IsVisible(int command_id)309 bool CefSimpleMenuModelImpl::IsVisible(int command_id) {
310   return IsVisibleAt(GetIndexOf(command_id));
311 }
312 
IsVisibleAt(int index)313 bool CefSimpleMenuModelImpl::IsVisibleAt(int index) {
314   if (!VerifyContext() || !ValidIndex(index))
315     return false;
316 
317   return model_->IsVisibleAt(index);
318 }
319 
SetVisible(int command_id,bool visible)320 bool CefSimpleMenuModelImpl::SetVisible(int command_id, bool visible) {
321   return SetVisibleAt(GetIndexOf(command_id), visible);
322 }
323 
SetVisibleAt(int index,bool visible)324 bool CefSimpleMenuModelImpl::SetVisibleAt(int index, bool visible) {
325   if (!VerifyContext() || !ValidIndex(index))
326     return false;
327 
328   model_->SetVisibleAt(index, visible);
329   return true;
330 }
331 
IsEnabled(int command_id)332 bool CefSimpleMenuModelImpl::IsEnabled(int command_id) {
333   return IsEnabledAt(GetIndexOf(command_id));
334 }
335 
IsEnabledAt(int index)336 bool CefSimpleMenuModelImpl::IsEnabledAt(int index) {
337   if (!VerifyContext() || !ValidIndex(index))
338     return false;
339 
340   return model_->IsEnabledAt(index);
341 }
342 
SetEnabled(int command_id,bool enabled)343 bool CefSimpleMenuModelImpl::SetEnabled(int command_id, bool enabled) {
344   return SetEnabledAt(GetIndexOf(command_id), enabled);
345 }
346 
SetEnabledAt(int index,bool enabled)347 bool CefSimpleMenuModelImpl::SetEnabledAt(int index, bool enabled) {
348   if (!VerifyContext() || !ValidIndex(index))
349     return false;
350 
351   model_->SetEnabledAt(index, enabled);
352   return true;
353 }
354 
IsChecked(int command_id)355 bool CefSimpleMenuModelImpl::IsChecked(int command_id) {
356   return IsCheckedAt(GetIndexOf(command_id));
357 }
358 
IsCheckedAt(int index)359 bool CefSimpleMenuModelImpl::IsCheckedAt(int index) {
360   if (!VerifyContext() || !ValidIndex(index))
361     return false;
362 
363   return model_->IsItemCheckedAt(index);
364 }
365 
SetChecked(int command_id,bool checked)366 bool CefSimpleMenuModelImpl::SetChecked(int command_id, bool checked) {
367   if (!VerifyContext() || command_id == kInvalidIndex)
368     return false;
369 
370   state_delegate_->SetChecked(command_id, checked);
371   return true;
372 }
373 
SetCheckedAt(int index,bool checked)374 bool CefSimpleMenuModelImpl::SetCheckedAt(int index, bool checked) {
375   return SetChecked(GetCommandIdAt(index), checked);
376 }
377 
HasAccelerator(int command_id)378 bool CefSimpleMenuModelImpl::HasAccelerator(int command_id) {
379   return HasAcceleratorAt(GetIndexOf(command_id));
380 }
381 
HasAcceleratorAt(int index)382 bool CefSimpleMenuModelImpl::HasAcceleratorAt(int index) {
383   if (!VerifyContext() || !ValidIndex(index))
384     return false;
385 
386   ui::Accelerator accelerator;
387   return model_->GetAcceleratorAt(index, &accelerator);
388 }
389 
SetAccelerator(int command_id,int key_code,bool shift_pressed,bool ctrl_pressed,bool alt_pressed)390 bool CefSimpleMenuModelImpl::SetAccelerator(int command_id,
391                                             int key_code,
392                                             bool shift_pressed,
393                                             bool ctrl_pressed,
394                                             bool alt_pressed) {
395   if (!VerifyContext() || command_id == kInvalidIndex)
396     return false;
397 
398   int modifiers = 0;
399   if (shift_pressed)
400     modifiers |= ui::EF_SHIFT_DOWN;
401   if (ctrl_pressed)
402     modifiers |= ui::EF_CONTROL_DOWN;
403   if (alt_pressed)
404     modifiers |= ui::EF_ALT_DOWN;
405 
406   state_delegate_->SetAccelerator(
407       command_id,
408       ui::Accelerator(static_cast<ui::KeyboardCode>(key_code), modifiers));
409   return true;
410 }
411 
SetAcceleratorAt(int index,int key_code,bool shift_pressed,bool ctrl_pressed,bool alt_pressed)412 bool CefSimpleMenuModelImpl::SetAcceleratorAt(int index,
413                                               int key_code,
414                                               bool shift_pressed,
415                                               bool ctrl_pressed,
416                                               bool alt_pressed) {
417   return SetAccelerator(GetCommandIdAt(index), key_code, shift_pressed,
418                         ctrl_pressed, alt_pressed);
419 }
420 
RemoveAccelerator(int command_id)421 bool CefSimpleMenuModelImpl::RemoveAccelerator(int command_id) {
422   if (!VerifyContext() || command_id == kInvalidIndex)
423     return false;
424   state_delegate_->SetAccelerator(command_id, absl::nullopt);
425   return true;
426 }
427 
RemoveAcceleratorAt(int index)428 bool CefSimpleMenuModelImpl::RemoveAcceleratorAt(int index) {
429   return RemoveAccelerator(GetCommandIdAt(index));
430 }
431 
GetAccelerator(int command_id,int & key_code,bool & shift_pressed,bool & ctrl_pressed,bool & alt_pressed)432 bool CefSimpleMenuModelImpl::GetAccelerator(int command_id,
433                                             int& key_code,
434                                             bool& shift_pressed,
435                                             bool& ctrl_pressed,
436                                             bool& alt_pressed) {
437   return GetAcceleratorAt(GetIndexOf(command_id), key_code, shift_pressed,
438                           ctrl_pressed, alt_pressed);
439 }
440 
GetAcceleratorAt(int index,int & key_code,bool & shift_pressed,bool & ctrl_pressed,bool & alt_pressed)441 bool CefSimpleMenuModelImpl::GetAcceleratorAt(int index,
442                                               int& key_code,
443                                               bool& shift_pressed,
444                                               bool& ctrl_pressed,
445                                               bool& alt_pressed) {
446   if (!VerifyContext() || !ValidIndex(index))
447     return false;
448 
449   ui::Accelerator accel;
450   if (model_->GetAcceleratorAt(index, &accel)) {
451     key_code = accel.key_code();
452     shift_pressed = accel.modifiers() & ui::EF_SHIFT_DOWN;
453     ctrl_pressed = accel.modifiers() & ui::EF_CONTROL_DOWN;
454     alt_pressed = accel.modifiers() & ui::EF_ALT_DOWN;
455     return true;
456   }
457   return false;
458 }
459 
SetColor(int command_id,cef_menu_color_type_t color_type,cef_color_t color)460 bool CefSimpleMenuModelImpl::SetColor(int command_id,
461                                       cef_menu_color_type_t color_type,
462                                       cef_color_t color) {
463   NOTIMPLEMENTED();
464   return false;
465 }
466 
SetColorAt(int index,cef_menu_color_type_t color_type,cef_color_t color)467 bool CefSimpleMenuModelImpl::SetColorAt(int index,
468                                         cef_menu_color_type_t color_type,
469                                         cef_color_t color) {
470   NOTIMPLEMENTED();
471   return false;
472 }
473 
GetColor(int command_id,cef_menu_color_type_t color_type,cef_color_t & color)474 bool CefSimpleMenuModelImpl::GetColor(int command_id,
475                                       cef_menu_color_type_t color_type,
476                                       cef_color_t& color) {
477   NOTIMPLEMENTED();
478   return false;
479 }
480 
GetColorAt(int index,cef_menu_color_type_t color_type,cef_color_t & color)481 bool CefSimpleMenuModelImpl::GetColorAt(int index,
482                                         cef_menu_color_type_t color_type,
483                                         cef_color_t& color) {
484   NOTIMPLEMENTED();
485   return false;
486 }
487 
SetFontList(int command_id,const CefString & font_list)488 bool CefSimpleMenuModelImpl::SetFontList(int command_id,
489                                          const CefString& font_list) {
490   NOTIMPLEMENTED();
491   return false;
492 }
493 
SetFontListAt(int index,const CefString & font_list)494 bool CefSimpleMenuModelImpl::SetFontListAt(int index,
495                                            const CefString& font_list) {
496   NOTIMPLEMENTED();
497   return false;
498 }
499 
VerifyContext()500 bool CefSimpleMenuModelImpl::VerifyContext() {
501   if (base::PlatformThread::CurrentId() != supported_thread_id_) {
502     // This object should only be accessed from the thread that created it.
503     NOTREACHED();
504     return false;
505   }
506 
507   if (!model_)
508     return false;
509 
510   return true;
511 }
512 
ValidIndex(int index)513 bool CefSimpleMenuModelImpl::ValidIndex(int index) {
514   return index > kInvalidIndex && index < model_->GetItemCount();
515 }
516 
CreateNewSubMenu(ui::SimpleMenuModel * model)517 CefRefPtr<CefSimpleMenuModelImpl> CefSimpleMenuModelImpl::CreateNewSubMenu(
518     ui::SimpleMenuModel* model) {
519   bool is_owned = false;
520   if (!model) {
521     model = new ui::SimpleMenuModel(delegate_);
522     is_owned = true;
523   }
524 
525   CefRefPtr<CefSimpleMenuModelImpl> new_impl = new CefSimpleMenuModelImpl(
526       model, delegate_, state_delegate_, is_owned, /*is_submodel=*/true);
527   submenumap_.insert(std::make_pair(model, new_impl));
528   return new_impl;
529 }
530