Files
palemoon27/embedding/components/commandhandler/nsCommandManager.cpp
T
roytam1 d6926a176f import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1214179 - Provide device Id for non-discoverable controller. r=xeonchen (0c83743144)
- Bug 1194606 - Add gtest for demuxed-only scenario in MediaFormatReader. r=jya (67a5e19042)
- Bug 1154513 - [EME] GMP crash crashes browser in Nightly - Remember if actor is destroyed, so that no messages are sent from subsequent Shutdown() - r=cpearce (36109a68e8)
- Bug 1171499 - Defer processing GMP EncodingComplete() calls until intr shmem allocs are finished. r=jesup (bac114c170)
- Bug 1162358 - Defer processing GMP DecodingComplete() calls until intr shmem allocs are finished. r=jesup (4b91da11f0)
- Bug 1155178 - Part 1: Convert GMPUnique into a template alias; r=cpearce (3f8ba45b9f)
- Bug 1155178 - Part 2: Rename GMPUnique to GMPUniquePtr; r=cpearce (fa1fd17384)
- Bug 1160908 - [EME] Delete GMPRecords that are 0 bytes in size. r=cpearce (3cc4ad2772)
- Bug 1188235 - Make GMPStorage immune to record name hash collisions. r=gerald (ae6c32363b)
- Bug 1187163 - Ensure we send Reset/Drain complete notifications no matter what happens in GMP{Audio,Video}Decoder. r=gerald (5654321861)
- Bug 1194576 - Add more NSPR logging around GMP*Parent actors. r=gerald (7572f82456)
- Bug 1169129 - Change GMP*Parent::ParentId() to a more consistent GMP*Parent::GetPluginId(). r=edwin (ce2dd08740)
- Bug 1208289 - Log outstanding frames in GMP DrainComplete() and detect dropped ResetComplete. r=jwwang (6e29c332a7)
- Bug 1208289 - Add SimpleTimer to make setting timeouts in C++ easy. r=jwwang (b4c179dc5b)
- Bug 1131908 - no IPC calls after GMPDecryptorChild::RecvDecryptingComplete(). r=edwin. (cb3d2df998)
- Bug 1215508: Fix the race in accessing the unopened IPC channels in TabChild::PreloadSlowThings(). r=khuey (c43fcb1530)
- bits of 1216401 (bb15f26885)
- Bug 1205219 - [Presentation WebAPI] Support terminate semantics. Part 1 - WebIDL & implementation changes. r=smaug (8e485cdec8)
- Bug 1205219 - [Presentation WebAPI] Support terminate semantics. Part 2 - Tests. r=smaug (e16de5d102)
- Bug 1178858 - Video would not playback after seek seekbar first if media.autoplay.enabled = false. r=cpearce (68bae0db50)
- Bug 1072150 - Introduce a transitional legacy API that works like things used to. r=bz Bug 1072150 - Use the opt-out for various sloppy consumers. r=bz (703304f396)
2022-11-25 11:08:40 +08:00

273 lines
8.0 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsString.h"
#include "nsIController.h"
#include "nsIControllers.h"
#include "nsIObserver.h"
#include "nsIComponentManager.h"
#include "nsServiceManagerUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsContentUtils.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowRoot.h"
#include "nsIFocusManager.h"
#include "nsCOMArray.h"
#include "nsCommandManager.h"
nsCommandManager::nsCommandManager()
: mWindow(nullptr)
{
}
nsCommandManager::~nsCommandManager()
{
}
static PLDHashOperator
TraverseCommandObservers(const char* aKey,
nsCommandManager::ObserverList* aObservers,
void* aClosure)
{
nsCycleCollectionTraversalCallback* cb =
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
int32_t i, numItems = aObservers->Length();
for (i = 0; i < numItems; ++i) {
cb->NoteXPCOMChild(aObservers->ElementAt(i));
}
return PL_DHASH_NEXT;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
tmp->mObserversTable.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager)
tmp->mObserversTable.EnumerateRead(TraverseCommandObservers, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager)
NS_INTERFACE_MAP_ENTRY(nsICommandManager)
NS_INTERFACE_MAP_ENTRY(nsPICommandUpdater)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager)
NS_INTERFACE_MAP_END
NS_IMETHODIMP
nsCommandManager::Init(nsIDOMWindow* aWindow)
{
NS_ENSURE_ARG_POINTER(aWindow);
NS_ASSERTION(aWindow, "Need non-null window here");
mWindow = aWindow; // weak ptr
return NS_OK;
}
NS_IMETHODIMP
nsCommandManager::CommandStatusChanged(const char* aCommandName)
{
ObserverList* commandObservers;
mObserversTable.Get(aCommandName, &commandObservers);
if (commandObservers) {
// XXX Should we worry about observers removing themselves from Observe()?
int32_t i, numItems = commandObservers->Length();
for (i = 0; i < numItems; ++i) {
nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i);
// should we get the command state to pass here? This might be expensive.
observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this),
aCommandName,
MOZ_UTF16("command_status_changed"));
}
}
return NS_OK;
}
#if 0
#pragma mark -
#endif
NS_IMETHODIMP
nsCommandManager::AddCommandObserver(nsIObserver* aCommandObserver,
const char* aCommandToObserve)
{
NS_ENSURE_ARG(aCommandObserver);
// XXX todo: handle special cases of aCommandToObserve being null, or empty
// for each command in the table, we make a list of observers for that command
ObserverList* commandObservers;
if (!mObserversTable.Get(aCommandToObserve, &commandObservers)) {
commandObservers = new ObserverList;
mObserversTable.Put(aCommandToObserve, commandObservers);
}
// need to check that this command observer hasn't already been registered
int32_t existingIndex = commandObservers->IndexOf(aCommandObserver);
if (existingIndex == -1) {
commandObservers->AppendElement(aCommandObserver);
} else {
NS_WARNING("Registering command observer twice on the same command");
}
return NS_OK;
}
NS_IMETHODIMP
nsCommandManager::RemoveCommandObserver(nsIObserver* aCommandObserver,
const char* aCommandObserved)
{
NS_ENSURE_ARG(aCommandObserver);
// XXX todo: handle special cases of aCommandToObserve being null, or empty
ObserverList* commandObservers;
if (!mObserversTable.Get(aCommandObserved, &commandObservers)) {
return NS_ERROR_UNEXPECTED;
}
commandObservers->RemoveElement(aCommandObserver);
return NS_OK;
}
NS_IMETHODIMP
nsCommandManager::IsCommandSupported(const char* aCommandName,
nsIDOMWindow* aTargetWindow,
bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsCOMPtr<nsIController> controller;
GetControllerForCommand(aCommandName, aTargetWindow,
getter_AddRefs(controller));
*aResult = (controller.get() != nullptr);
return NS_OK;
}
NS_IMETHODIMP
nsCommandManager::IsCommandEnabled(const char* aCommandName,
nsIDOMWindow* aTargetWindow,
bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
bool commandEnabled = false;
nsCOMPtr<nsIController> controller;
GetControllerForCommand(aCommandName, aTargetWindow,
getter_AddRefs(controller));
if (controller) {
controller->IsCommandEnabled(aCommandName, &commandEnabled);
}
*aResult = commandEnabled;
return NS_OK;
}
NS_IMETHODIMP
nsCommandManager::GetCommandState(const char* aCommandName,
nsIDOMWindow* aTargetWindow,
nsICommandParams* aCommandParams)
{
nsCOMPtr<nsIController> controller;
nsAutoString tValue;
nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
getter_AddRefs(controller));
if (!controller) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsICommandController> commandController =
do_QueryInterface(controller);
if (commandController) {
rv = commandController->GetCommandStateWithParams(aCommandName,
aCommandParams);
} else {
rv = NS_ERROR_NOT_IMPLEMENTED;
}
return rv;
}
NS_IMETHODIMP
nsCommandManager::DoCommand(const char* aCommandName,
nsICommandParams* aCommandParams,
nsIDOMWindow* aTargetWindow)
{
nsCOMPtr<nsIController> controller;
nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
getter_AddRefs(controller));
if (!controller) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsICommandController> commandController =
do_QueryInterface(controller);
if (commandController && aCommandParams) {
rv = commandController->DoCommandWithParams(aCommandName, aCommandParams);
} else {
rv = controller->DoCommand(aCommandName);
}
return rv;
}
nsresult
nsCommandManager::GetControllerForCommand(const char* aCommand,
nsIDOMWindow* aTargetWindow,
nsIController** aResult)
{
nsresult rv = NS_ERROR_FAILURE;
*aResult = nullptr;
// check if we're in content or chrome
// if we're not chrome we must have a target window or we bail
if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
if (!aTargetWindow) {
return rv;
}
// if a target window is specified, it must be the window we expect
if (aTargetWindow != mWindow) {
return NS_ERROR_FAILURE;
}
}
if (aTargetWindow) {
// get the controller for this particular window
nsCOMPtr<nsIControllers> controllers;
rv = aTargetWindow->GetControllers(getter_AddRefs(controllers));
if (NS_FAILED(rv)) {
return rv;
}
if (!controllers) {
return NS_ERROR_FAILURE;
}
// dispatch the command
return controllers->GetControllerForCommand(aCommand, aResult);
}
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mWindow));
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
// no target window; send command to focus controller
return root->GetControllerForCommand(aCommand, aResult);
}