Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/commandhandler/nsCommandManager.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsString.h"
8
9
#include "nsIController.h"
10
#include "nsIControllers.h"
11
#include "nsIObserver.h"
12
13
#include "nsIComponentManager.h"
14
15
#include "nsServiceManagerUtils.h"
16
#include "nsIScriptSecurityManager.h"
17
18
#include "nsContentUtils.h"
19
#include "nsIDOMWindow.h"
20
#include "nsPIDOMWindow.h"
21
#include "nsPIWindowRoot.h"
22
#include "nsIFocusManager.h"
23
24
#include "nsCOMArray.h"
25
26
#include "nsCommandManager.h"
27
28
nsCommandManager::nsCommandManager()
29
  : mWindow(nullptr)
30
0
{
31
0
}
32
33
nsCommandManager::~nsCommandManager()
34
0
{
35
0
}
36
37
NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
38
39
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
40
0
  tmp->mObserversTable.Clear();
41
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
42
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager)
43
0
  for (auto iter = tmp->mObserversTable.Iter(); !iter.Done(); iter.Next()) {
44
0
    nsCommandManager::ObserverList* observers = iter.UserData();
45
0
    int32_t numItems = observers->Length();
46
0
    for (int32_t i = 0; i < numItems; ++i) {
47
0
      cb.NoteXPCOMChild(observers->ElementAt(i));
48
0
    }
49
0
  }
50
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
51
52
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)
53
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager)
54
55
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager)
56
0
  NS_INTERFACE_MAP_ENTRY(nsICommandManager)
57
0
  NS_INTERFACE_MAP_ENTRY(nsPICommandUpdater)
58
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
59
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager)
60
0
NS_INTERFACE_MAP_END
61
62
NS_IMETHODIMP
63
nsCommandManager::Init(mozIDOMWindowProxy* aWindow)
64
0
{
65
0
  NS_ENSURE_ARG_POINTER(aWindow);
66
0
67
0
  mWindow = aWindow; // weak ptr
68
0
  return NS_OK;
69
0
}
70
71
NS_IMETHODIMP
72
nsCommandManager::CommandStatusChanged(const char* aCommandName)
73
0
{
74
0
  ObserverList* commandObservers;
75
0
  mObserversTable.Get(aCommandName, &commandObservers);
76
0
77
0
  if (commandObservers) {
78
0
    // XXX Should we worry about observers removing themselves from Observe()?
79
0
    int32_t i, numItems = commandObservers->Length();
80
0
    for (i = 0; i < numItems; ++i) {
81
0
      nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i);
82
0
      // should we get the command state to pass here? This might be expensive.
83
0
      observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this),
84
0
                        aCommandName,
85
0
                        u"command_status_changed");
86
0
    }
87
0
  }
88
0
89
0
  return NS_OK;
90
0
}
91
92
#if 0
93
#pragma mark -
94
#endif
95
96
NS_IMETHODIMP
97
nsCommandManager::AddCommandObserver(nsIObserver* aCommandObserver,
98
                                     const char* aCommandToObserve)
99
0
{
100
0
  NS_ENSURE_ARG(aCommandObserver);
101
0
102
0
  // XXX todo: handle special cases of aCommandToObserve being null, or empty
103
0
104
0
  // for each command in the table, we make a list of observers for that command
105
0
  ObserverList* commandObservers =
106
0
    mObserversTable.LookupForAdd(aCommandToObserve).OrInsert(
107
0
      [] () { return new ObserverList; });
108
0
109
0
  // need to check that this command observer hasn't already been registered
110
0
  int32_t existingIndex = commandObservers->IndexOf(aCommandObserver);
111
0
  if (existingIndex == -1) {
112
0
    commandObservers->AppendElement(aCommandObserver);
113
0
  } else {
114
0
    NS_WARNING("Registering command observer twice on the same command");
115
0
  }
116
0
117
0
  return NS_OK;
118
0
}
119
120
NS_IMETHODIMP
121
nsCommandManager::RemoveCommandObserver(nsIObserver* aCommandObserver,
122
                                        const char* aCommandObserved)
123
0
{
124
0
  NS_ENSURE_ARG(aCommandObserver);
125
0
126
0
  // XXX todo: handle special cases of aCommandToObserve being null, or empty
127
0
128
0
  ObserverList* commandObservers;
129
0
  if (!mObserversTable.Get(aCommandObserved, &commandObservers)) {
130
0
    return NS_ERROR_UNEXPECTED;
131
0
  }
132
0
133
0
  commandObservers->RemoveElement(aCommandObserver);
134
0
135
0
  return NS_OK;
136
0
}
137
138
NS_IMETHODIMP
139
nsCommandManager::IsCommandSupported(const char* aCommandName,
140
                                     mozIDOMWindowProxy* aTargetWindow,
141
                                     bool* aResult)
142
0
{
143
0
  NS_ENSURE_ARG_POINTER(aResult);
144
0
145
0
  nsCOMPtr<nsIController> controller;
146
0
  GetControllerForCommand(aCommandName, aTargetWindow,
147
0
                          getter_AddRefs(controller));
148
0
  *aResult = (controller.get() != nullptr);
149
0
  return NS_OK;
150
0
}
151
152
NS_IMETHODIMP
153
nsCommandManager::IsCommandEnabled(const char* aCommandName,
154
                                   mozIDOMWindowProxy* aTargetWindow,
155
                                   bool* aResult)
156
0
{
157
0
  NS_ENSURE_ARG_POINTER(aResult);
158
0
159
0
  bool commandEnabled = false;
160
0
161
0
  nsCOMPtr<nsIController> controller;
162
0
  GetControllerForCommand(aCommandName, aTargetWindow,
163
0
                          getter_AddRefs(controller));
164
0
  if (controller) {
165
0
    controller->IsCommandEnabled(aCommandName, &commandEnabled);
166
0
  }
167
0
  *aResult = commandEnabled;
168
0
  return NS_OK;
169
0
}
170
171
NS_IMETHODIMP
172
nsCommandManager::GetCommandState(const char* aCommandName,
173
                                  mozIDOMWindowProxy* aTargetWindow,
174
                                  nsICommandParams* aCommandParams)
175
0
{
176
0
  nsCOMPtr<nsIController> controller;
177
0
  nsAutoString tValue;
178
0
  nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
179
0
                                        getter_AddRefs(controller));
180
0
  if (!controller) {
181
0
    return NS_ERROR_FAILURE;
182
0
  }
183
0
184
0
  nsCOMPtr<nsICommandController> commandController =
185
0
    do_QueryInterface(controller);
186
0
  if (commandController) {
187
0
    rv = commandController->GetCommandStateWithParams(aCommandName,
188
0
                                                      aCommandParams);
189
0
  } else {
190
0
    rv = NS_ERROR_NOT_IMPLEMENTED;
191
0
  }
192
0
  return rv;
193
0
}
194
195
NS_IMETHODIMP
196
nsCommandManager::DoCommand(const char* aCommandName,
197
                            nsICommandParams* aCommandParams,
198
                            mozIDOMWindowProxy* aTargetWindow)
199
0
{
200
0
  nsCOMPtr<nsIController> controller;
201
0
  nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
202
0
                                        getter_AddRefs(controller));
203
0
  if (!controller) {
204
0
    return NS_ERROR_FAILURE;
205
0
  }
206
0
207
0
  nsCOMPtr<nsICommandController> commandController =
208
0
    do_QueryInterface(controller);
209
0
  if (commandController && aCommandParams) {
210
0
    rv = commandController->DoCommandWithParams(aCommandName, aCommandParams);
211
0
  } else {
212
0
    rv = controller->DoCommand(aCommandName);
213
0
  }
214
0
  return rv;
215
0
}
216
217
nsresult
218
nsCommandManager::GetControllerForCommand(const char* aCommand,
219
                                          mozIDOMWindowProxy* aTargetWindow,
220
                                          nsIController** aResult)
221
0
{
222
0
  nsresult rv = NS_ERROR_FAILURE;
223
0
  *aResult = nullptr;
224
0
225
0
  // check if we're in content or chrome
226
0
  // if we're not chrome we must have a target window or we bail
227
0
  if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
228
0
    if (!aTargetWindow) {
229
0
      return rv;
230
0
    }
231
0
232
0
    // if a target window is specified, it must be the window we expect
233
0
    if (aTargetWindow != mWindow) {
234
0
      return NS_ERROR_FAILURE;
235
0
    }
236
0
  }
237
0
238
0
  if (auto* targetWindow = nsPIDOMWindowOuter::From(aTargetWindow)) {
239
0
    // get the controller for this particular window
240
0
    nsCOMPtr<nsIControllers> controllers;
241
0
    rv = targetWindow->GetControllers(getter_AddRefs(controllers));
242
0
    if (NS_FAILED(rv)) {
243
0
      return rv;
244
0
    }
245
0
    if (!controllers) {
246
0
      return NS_ERROR_FAILURE;
247
0
    }
248
0
249
0
    // dispatch the command
250
0
    return controllers->GetControllerForCommand(aCommand, aResult);
251
0
  }
252
0
253
0
  auto* window = nsPIDOMWindowOuter::From(mWindow);
254
0
  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
255
0
  nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
256
0
  NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
257
0
258
0
  // no target window; send command to focus controller
259
0
  return root->GetControllerForCommand(aCommand, false /* for any window */,
260
0
                                       aResult);
261
0
}