зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
415f86e41d
|
@ -73,10 +73,10 @@ this.ContentWebRTC = {
|
||||||
let devices = contentWindow.pendingGetUserMediaRequests.get(callID);
|
let devices = contentWindow.pendingGetUserMediaRequests.get(callID);
|
||||||
forgetGUMRequest(contentWindow, callID);
|
forgetGUMRequest(contentWindow, callID);
|
||||||
|
|
||||||
let allowedDevices = Cc["@mozilla.org/array;1"]
|
let allowedDevices = Cc["@mozilla.org/supports-array;1"]
|
||||||
.createInstance(Ci.nsIMutableArray);
|
.createInstance(Ci.nsISupportsArray);
|
||||||
for (let deviceIndex of aMessage.data.devices)
|
for (let deviceIndex of aMessage.data.devices)
|
||||||
allowedDevices.appendElement(devices[deviceIndex], /*weak =*/ false);
|
allowedDevices.AppendElement(devices[deviceIndex]);
|
||||||
|
|
||||||
Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", callID);
|
Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", callID);
|
||||||
break;
|
break;
|
||||||
|
@ -261,8 +261,8 @@ function forgetPendingListsEventually(aContentWindow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateIndicators() {
|
function updateIndicators() {
|
||||||
let contentWindowArray = MediaManagerService.activeMediaCaptureWindows;
|
let contentWindowSupportsArray = MediaManagerService.activeMediaCaptureWindows;
|
||||||
let count = contentWindowArray.length;
|
let count = contentWindowSupportsArray.Count();
|
||||||
|
|
||||||
let state = {
|
let state = {
|
||||||
showGlobalIndicator: count > 0,
|
showGlobalIndicator: count > 0,
|
||||||
|
@ -280,7 +280,7 @@ function updateIndicators() {
|
||||||
// sending duplicate notifications.
|
// sending duplicate notifications.
|
||||||
let contentWindows = new Set();
|
let contentWindows = new Set();
|
||||||
for (let i = 0; i < count; ++i) {
|
for (let i = 0; i < count; ++i) {
|
||||||
contentWindows.add(contentWindowArray.queryElementAt(i, Ci.nsISupports).top);
|
contentWindows.add(contentWindowSupportsArray.GetElementAt(i).top);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let contentWindow of contentWindows) {
|
for (let contentWindow of contentWindows) {
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include "mozilla/dom/MediaStreamTrack.h"
|
#include "mozilla/dom/MediaStreamTrack.h"
|
||||||
#include "GetUserMediaRequest.h"
|
#include "GetUserMediaRequest.h"
|
||||||
#include "MediaStreamListener.h"
|
#include "MediaStreamListener.h"
|
||||||
#include "nsArray.h"
|
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsHashPropertyBag.h"
|
#include "nsHashPropertyBag.h"
|
||||||
#ifdef MOZ_WIDGET_GONK
|
#ifdef MOZ_WIDGET_GONK
|
||||||
|
@ -21,6 +20,7 @@
|
||||||
#include "nsIScriptGlobalObject.h"
|
#include "nsIScriptGlobalObject.h"
|
||||||
#include "nsIPermissionManager.h"
|
#include "nsIPermissionManager.h"
|
||||||
#include "nsIPopupWindowManager.h"
|
#include "nsIPopupWindowManager.h"
|
||||||
|
#include "nsISupportsArray.h"
|
||||||
#include "nsIDocShell.h"
|
#include "nsIDocShell.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "nsISupportsPrimitives.h"
|
#include "nsISupportsPrimitives.h"
|
||||||
|
@ -2406,10 +2406,14 @@ if (privileged) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIMutableArray> devicesCopy = nsArray::Create(); // before we give up devices below
|
nsCOMPtr<nsISupportsArray> devicesCopy; // before we give up devices below
|
||||||
if (!askPermission) {
|
if (!askPermission) {
|
||||||
|
nsresult rv = NS_NewISupportsArray(getter_AddRefs(devicesCopy));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (auto& device : **devices) {
|
for (auto& device : **devices) {
|
||||||
nsresult rv = devicesCopy->AppendElement(device, /*weak =*/ false);
|
rv = devicesCopy->AppendElement(device);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3027,15 +3031,15 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
||||||
if (aSubject) {
|
if (aSubject) {
|
||||||
// A particular device or devices were chosen by the user.
|
// A particular device or devices were chosen by the user.
|
||||||
// NOTE: does not allow setting a device to null; assumes nullptr
|
// NOTE: does not allow setting a device to null; assumes nullptr
|
||||||
nsCOMPtr<nsIArray> array(do_QueryInterface(aSubject));
|
nsCOMPtr<nsISupportsArray> array(do_QueryInterface(aSubject));
|
||||||
MOZ_ASSERT(array);
|
MOZ_ASSERT(array);
|
||||||
uint32_t len = 0;
|
uint32_t len = 0;
|
||||||
array->GetLength(&len);
|
array->Count(&len);
|
||||||
bool videoFound = false, audioFound = false;
|
bool videoFound = false, audioFound = false;
|
||||||
for (uint32_t i = 0; i < len; i++) {
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
nsCOMPtr<nsIMediaDevice> device;
|
nsCOMPtr<nsISupports> supports;
|
||||||
array->QueryElementAt(i, NS_GET_IID(nsIMediaDevice),
|
array->GetElementAt(i,getter_AddRefs(supports));
|
||||||
getter_AddRefs(device));
|
nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supports));
|
||||||
MOZ_ASSERT(device); // shouldn't be returning anything else...
|
MOZ_ASSERT(device); // shouldn't be returning anything else...
|
||||||
if (device) {
|
if (device) {
|
||||||
nsString type;
|
nsString type;
|
||||||
|
@ -3129,11 +3133,14 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
MediaManager::GetActiveMediaCaptureWindows(nsIArray** aArray)
|
MediaManager::GetActiveMediaCaptureWindows(nsISupportsArray** aArray)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aArray);
|
MOZ_ASSERT(aArray);
|
||||||
|
nsISupportsArray* array;
|
||||||
nsCOMPtr<nsIMutableArray> array = nsArray::Create();
|
nsresult rv = NS_NewISupportsArray(&array); // AddRefs
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto iter = mActiveWindows.Iter(); !iter.Done(); iter.Next()) {
|
for (auto iter = mActiveWindows.Iter(); !iter.Done(); iter.Next()) {
|
||||||
const uint64_t& id = iter.Key();
|
const uint64_t& id = iter.Key();
|
||||||
|
@ -3164,11 +3171,11 @@ MediaManager::GetActiveMediaCaptureWindows(nsIArray** aArray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (capturing) {
|
if (capturing) {
|
||||||
array->AppendElement(window, /*weak =*/ false);
|
array->AppendElement(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
array.forget(aArray);
|
*aArray = array;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3327,14 +3334,14 @@ MediaManager::IterateWindowListeners(nsPIDOMWindowInner* aWindow,
|
||||||
void
|
void
|
||||||
MediaManager::StopMediaStreams()
|
MediaManager::StopMediaStreams()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIArray> array;
|
nsCOMPtr<nsISupportsArray> array;
|
||||||
GetActiveMediaCaptureWindows(getter_AddRefs(array));
|
GetActiveMediaCaptureWindows(getter_AddRefs(array));
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
array->GetLength(&len);
|
array->Count(&len);
|
||||||
for (uint32_t i = 0; i < len; i++) {
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
nsCOMPtr<nsPIDOMWindowInner> win;
|
nsCOMPtr<nsISupports> window;
|
||||||
array->QueryElementAt(i, NS_GET_IID(nsPIDOMWindowInner),
|
array->GetElementAt(i, getter_AddRefs(window));
|
||||||
getter_AddRefs(win));
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(window));
|
||||||
if (win) {
|
if (win) {
|
||||||
OnNavigation(win->WindowID());
|
OnNavigation(win->WindowID());
|
||||||
}
|
}
|
||||||
|
@ -3346,14 +3353,14 @@ MediaManager::IsActivelyCapturingOrHasAPermission(uint64_t aWindowId)
|
||||||
{
|
{
|
||||||
// Does page currently have a gUM stream active?
|
// Does page currently have a gUM stream active?
|
||||||
|
|
||||||
nsCOMPtr<nsIArray> array;
|
nsCOMPtr<nsISupportsArray> array;
|
||||||
GetActiveMediaCaptureWindows(getter_AddRefs(array));
|
GetActiveMediaCaptureWindows(getter_AddRefs(array));
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
array->GetLength(&len);
|
array->Count(&len);
|
||||||
for (uint32_t i = 0; i < len; i++) {
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
nsCOMPtr<nsPIDOMWindowInner> win;
|
nsCOMPtr<nsISupports> window;
|
||||||
array->QueryElementAt(i, NS_GET_IID(nsPIDOMWindowInner),
|
array->GetElementAt(i, getter_AddRefs(window));
|
||||||
getter_AddRefs(win));
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(window));
|
||||||
if (win && win->WindowID() == aWindowId) {
|
if (win && win->WindowID() == aWindowId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
#include "MediaManager.h"
|
#include "MediaManager.h"
|
||||||
#include "MediaPermissionGonk.h"
|
#include "MediaPermissionGonk.h"
|
||||||
|
|
||||||
#include "nsArray.h"
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIContentPermissionPrompt.h"
|
#include "nsIContentPermissionPrompt.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "nsIDOMNavigatorUserMedia.h"
|
#include "nsIDOMNavigatorUserMedia.h"
|
||||||
#include "nsIStringEnumerator.h"
|
#include "nsIStringEnumerator.h"
|
||||||
|
#include "nsISupportsArray.h"
|
||||||
#include "nsJSUtils.h"
|
#include "nsJSUtils.h"
|
||||||
#include "nsQueryObject.h"
|
#include "nsQueryObject.h"
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
|
@ -67,10 +67,12 @@ static nsresult
|
||||||
NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
|
NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsIMutableArray> array = nsArray::Create();
|
nsCOMPtr<nsISupportsArray> array;
|
||||||
|
rv = NS_NewISupportsArray(getter_AddRefs(array));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
|
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
|
||||||
rv = array->AppendElement(aDevices.ElementAt(i), /*weak =*/ false);
|
rv = array->AppendElement(aDevices.ElementAt(i));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface nsIArray;
|
interface nsISupportsArray;
|
||||||
interface nsIDOMWindow;
|
interface nsIDOMWindow;
|
||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
|
@ -16,7 +16,7 @@ interface nsIDOMWindow;
|
||||||
interface nsIMediaManagerService : nsISupports
|
interface nsIMediaManagerService : nsISupports
|
||||||
{
|
{
|
||||||
/* return a array of inner windows that have active captures */
|
/* return a array of inner windows that have active captures */
|
||||||
readonly attribute nsIArray activeMediaCaptureWindows;
|
readonly attribute nsISupportsArray activeMediaCaptureWindows;
|
||||||
|
|
||||||
/* Get the capture state for the given window and all descendant windows (iframes, etc) */
|
/* Get the capture state for the given window and all descendant windows (iframes, etc) */
|
||||||
void mediaCaptureWindowState(in nsIDOMWindow aWindow, out boolean aVideo, out boolean aAudio,
|
void mediaCaptureWindowState(in nsIDOMWindow aWindow, out boolean aVideo, out boolean aAudio,
|
||||||
|
|
|
@ -58,7 +58,7 @@ var WebrtcUI = {
|
||||||
|
|
||||||
notify: function() {
|
notify: function() {
|
||||||
let windows = MediaManagerService.activeMediaCaptureWindows;
|
let windows = MediaManagerService.activeMediaCaptureWindows;
|
||||||
let count = windows.length;
|
let count = windows.Count();
|
||||||
let msg = {};
|
let msg = {};
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
if (this._notificationId) {
|
if (this._notificationId) {
|
||||||
|
@ -76,7 +76,7 @@ var WebrtcUI = {
|
||||||
let cameraActive = false;
|
let cameraActive = false;
|
||||||
let audioActive = false;
|
let audioActive = false;
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
let win = windows.queryElementAt(i, Ci.nsIDOMWindow);
|
let win = windows.GetElementAt(i);
|
||||||
let hasAudio = {};
|
let hasAudio = {};
|
||||||
let hasVideo = {};
|
let hasVideo = {};
|
||||||
MediaManagerService.mediaCaptureWindowState(win, hasVideo, hasAudio);
|
MediaManagerService.mediaCaptureWindowState(win, hasVideo, hasAudio);
|
||||||
|
@ -150,19 +150,19 @@ var WebrtcUI = {
|
||||||
{
|
{
|
||||||
label: Strings.browser.GetStringFromName("getUserMedia.shareRequest.label"),
|
label: Strings.browser.GetStringFromName("getUserMedia.shareRequest.label"),
|
||||||
callback: function(checked /* ignored */, inputs) {
|
callback: function(checked /* ignored */, inputs) {
|
||||||
let allowedDevices = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
let allowedDevices = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
|
||||||
|
|
||||||
let audioId = 0;
|
let audioId = 0;
|
||||||
if (inputs && inputs.audioDevice != undefined)
|
if (inputs && inputs.audioDevice != undefined)
|
||||||
audioId = inputs.audioDevice;
|
audioId = inputs.audioDevice;
|
||||||
if (audioDevices[audioId])
|
if (audioDevices[audioId])
|
||||||
allowedDevices.appendElement(audioDevices[audioId], /*weak =*/ false);
|
allowedDevices.AppendElement(audioDevices[audioId]);
|
||||||
|
|
||||||
let videoId = 0;
|
let videoId = 0;
|
||||||
if (inputs && inputs.videoSource != undefined)
|
if (inputs && inputs.videoSource != undefined)
|
||||||
videoId = inputs.videoSource;
|
videoId = inputs.videoSource;
|
||||||
if (videoDevices[videoId]) {
|
if (videoDevices[videoId]) {
|
||||||
allowedDevices.appendElement(videoDevices[videoId], /*weak =*/ false);
|
allowedDevices.AppendElement(videoDevices[videoId]);
|
||||||
let perms = Services.perms;
|
let perms = Services.perms;
|
||||||
// Although the lifetime is "session" it will be removed upon
|
// Although the lifetime is "session" it will be removed upon
|
||||||
// use so it's more of a one-shot.
|
// use so it's more of a one-shot.
|
||||||
|
|
|
@ -33,11 +33,17 @@ class nsISupportsArray;
|
||||||
[scriptable, uuid(241addc8-3608-4e73-8083-2fd6fa09eba2)]
|
[scriptable, uuid(241addc8-3608-4e73-8083-2fd6fa09eba2)]
|
||||||
interface nsISupportsArray : nsICollection {
|
interface nsISupportsArray : nsICollection {
|
||||||
|
|
||||||
|
[notxpcom] boolean Equals([const] in nsISupportsArray other);
|
||||||
|
|
||||||
[notxpcom] long IndexOf([const] in nsISupports aPossibleElement);
|
[notxpcom] long IndexOf([const] in nsISupports aPossibleElement);
|
||||||
|
[notxpcom] long IndexOfStartingAt([const] in nsISupports aPossibleElement,
|
||||||
|
in unsigned long aStartIndex);
|
||||||
[notxpcom] long LastIndexOf([const] in nsISupports aPossibleElement);
|
[notxpcom] long LastIndexOf([const] in nsISupports aPossibleElement);
|
||||||
|
|
||||||
// xpcom-compatible versions
|
// xpcom-compatible versions
|
||||||
long GetIndexOf(in nsISupports aPossibleElement);
|
long GetIndexOf(in nsISupports aPossibleElement);
|
||||||
|
long GetIndexOfStartingAt(in nsISupports aPossibleElement,
|
||||||
|
in unsigned long aStartIndex);
|
||||||
long GetLastIndexOf(in nsISupports aPossibleElement);
|
long GetLastIndexOf(in nsISupports aPossibleElement);
|
||||||
|
|
||||||
[notxpcom] boolean InsertElementAt(in nsISupports aElement,
|
[notxpcom] boolean InsertElementAt(in nsISupports aElement,
|
||||||
|
@ -46,14 +52,25 @@ interface nsISupportsArray : nsICollection {
|
||||||
in unsigned long aIndex);
|
in unsigned long aIndex);
|
||||||
|
|
||||||
[notxpcom] boolean RemoveElementAt(in unsigned long aIndex);
|
[notxpcom] boolean RemoveElementAt(in unsigned long aIndex);
|
||||||
|
[notxpcom] boolean RemoveLastElement([const] in nsISupports aElement);
|
||||||
|
|
||||||
// xpcom-compatible versions
|
// xpcom-compatible versions
|
||||||
|
void DeleteLastElement(in nsISupports aElement);
|
||||||
void DeleteElementAt(in unsigned long aIndex);
|
void DeleteElementAt(in unsigned long aIndex);
|
||||||
|
|
||||||
void Compact();
|
void Compact();
|
||||||
|
|
||||||
|
|
||||||
nsISupportsArray clone();
|
nsISupportsArray clone();
|
||||||
|
|
||||||
|
[notxpcom] boolean MoveElement(in long aFrom,
|
||||||
|
in long aTo);
|
||||||
|
|
||||||
|
[notxpcom] boolean RemoveElementsAt(in unsigned long aIndex,
|
||||||
|
in unsigned long aCount);
|
||||||
|
|
||||||
|
[notxpcom] boolean SizeTo(in long aSize);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
|
|
|
@ -6,11 +6,79 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "nsIObjectInputStream.h"
|
#include "mozilla/MathAlgorithms.h"
|
||||||
#include "nsIObjectOutputStream.h"
|
|
||||||
#include "nsSupportsArray.h"
|
#include "nsSupportsArray.h"
|
||||||
#include "nsSupportsArrayEnumerator.h"
|
#include "nsSupportsArrayEnumerator.h"
|
||||||
|
#include "nsIObjectInputStream.h"
|
||||||
|
#include "nsIObjectOutputStream.h"
|
||||||
|
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
#define MAXSUPPORTS 20
|
||||||
|
|
||||||
|
class SupportsStats
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SupportsStats();
|
||||||
|
~SupportsStats();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sizesUsed; // number of the elements of the arrays used
|
||||||
|
static int sizesAlloced[MAXSUPPORTS]; // sizes of the allocations. sorted
|
||||||
|
static int NumberOfSize[MAXSUPPORTS]; // number of this allocation size (1 per array)
|
||||||
|
static int AllocedOfSize[MAXSUPPORTS]; // number of this allocation size (each size for array used)
|
||||||
|
static int GrowInPlace[MAXSUPPORTS];
|
||||||
|
|
||||||
|
// these are per-allocation
|
||||||
|
static int MaxElements[3000];
|
||||||
|
|
||||||
|
// very evil
|
||||||
|
#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
|
||||||
|
{ \
|
||||||
|
if (sizesAlloced[i] == (int)(size)) \
|
||||||
|
{ ((x)[i])++; break; } \
|
||||||
|
} \
|
||||||
|
if (i >= sizesUsed && sizesUsed < MAXSUPPORTS) \
|
||||||
|
{ sizesAlloced[sizesUsed] = (size); \
|
||||||
|
((x)[sizesUsed++])++; break; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
|
||||||
|
{ \
|
||||||
|
if (sizesAlloced[i] == (int)(size)) \
|
||||||
|
{ ((x)[i])--; break; } \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
|
||||||
|
SupportsStats::SupportsStats()
|
||||||
|
{
|
||||||
|
sizesUsed = 1;
|
||||||
|
sizesAlloced[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SupportsStats::~SupportsStats()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < sizesUsed; ++i) {
|
||||||
|
printf("Size %d:\n", sizesAlloced[i]);
|
||||||
|
printf("\tNumber of SupportsArrays this size (max): %d\n", NumberOfSize[i]);
|
||||||
|
printf("\tNumber of allocations this size (total): %d\n", AllocedOfSize[i]);
|
||||||
|
printf("\tNumber of GrowsInPlace this size (total): %d\n", GrowInPlace[i]);
|
||||||
|
}
|
||||||
|
printf("Max Size of SupportsArray:\n");
|
||||||
|
for (i = 0; i < (int)(sizeof(MaxElements) / sizeof(MaxElements[0])); ++i) {
|
||||||
|
if (MaxElements[i]) {
|
||||||
|
printf("\t%d: %d\n", i, MaxElements[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just so constructor/destructor get called
|
||||||
|
SupportsStats gSupportsStats;
|
||||||
|
#endif
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryElementAt::operator()(const nsIID& aIID, void** aResult) const
|
nsQueryElementAt::operator()(const nsIID& aIID, void** aResult) const
|
||||||
|
@ -28,11 +96,88 @@ nsQueryElementAt::operator()(const nsIID& aIID, void** aResult) const
|
||||||
|
|
||||||
nsSupportsArray::nsSupportsArray()
|
nsSupportsArray::nsSupportsArray()
|
||||||
{
|
{
|
||||||
|
mArray = mAutoArray;
|
||||||
|
mArraySize = kAutoArraySize;
|
||||||
|
mCount = 0;
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
mMaxCount = 0;
|
||||||
|
mMaxSize = 0;
|
||||||
|
ADD_TO_STATS(NumberOfSize, kAutoArraySize * sizeof(mArray[0]));
|
||||||
|
MaxElements[0]++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSupportsArray::~nsSupportsArray()
|
nsSupportsArray::~nsSupportsArray()
|
||||||
{
|
{
|
||||||
Clear();
|
DeleteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsSupportsArray::GrowArrayBy(uint32_t aGrowBy)
|
||||||
|
{
|
||||||
|
const uint32_t kGrowArrayBy = 8;
|
||||||
|
const uint32_t kLinearThreshold = 16 * sizeof(nsISupports*);
|
||||||
|
|
||||||
|
// We have to grow the array. Grow by kGrowArrayBy slots if we're smaller
|
||||||
|
// than kLinearThreshold bytes, or a power of two if we're larger.
|
||||||
|
// This is much more efficient with most memory allocators, especially
|
||||||
|
// if it's very large, or of the allocator is binned.
|
||||||
|
if (aGrowBy < kGrowArrayBy) {
|
||||||
|
aGrowBy = kGrowArrayBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckedUint32 newCount(mArraySize);
|
||||||
|
newCount += aGrowBy; // Minimum increase
|
||||||
|
CheckedUint32 newSize(sizeof(mArray[0]));
|
||||||
|
newSize *= newCount;
|
||||||
|
|
||||||
|
if (!newSize.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSize.value() >= kLinearThreshold) {
|
||||||
|
// newCount includes enough space for at least kGrowArrayBy new slots.
|
||||||
|
// Select the next power-of-two size in bytes above that if newSize is
|
||||||
|
// not a power of two.
|
||||||
|
if (newSize.value() & (newSize.value() - 1)) {
|
||||||
|
newSize = UINT64_C(1) << mozilla::CeilingLog2(newSize.value());
|
||||||
|
if (!newSize.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newCount = newSize / sizeof(mArray[0]);
|
||||||
|
}
|
||||||
|
// XXX This would be far more efficient in many allocators if we used
|
||||||
|
// XXX PR_Realloc(), etc
|
||||||
|
nsISupports** oldArray = mArray;
|
||||||
|
|
||||||
|
mArray = new nsISupports*[newCount.value()];
|
||||||
|
mArraySize = newCount.value();
|
||||||
|
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
if (oldArray == mArray) { // can't happen without use of realloc
|
||||||
|
ADD_TO_STATS(GrowInPlace, mCount);
|
||||||
|
}
|
||||||
|
ADD_TO_STATS(AllocedOfSize, mArraySize * sizeof(mArray[0]));
|
||||||
|
if (mArraySize > mMaxSize) {
|
||||||
|
ADD_TO_STATS(NumberOfSize, mArraySize * sizeof(mArray[0]));
|
||||||
|
if (oldArray != &(mAutoArray[0])) {
|
||||||
|
SUB_FROM_STATS(NumberOfSize, mCount * sizeof(mArray[0]));
|
||||||
|
}
|
||||||
|
mMaxSize = mArraySize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (oldArray) { // need to move old data
|
||||||
|
if (0 < mCount) {
|
||||||
|
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||||
|
}
|
||||||
|
if (oldArray != &(mAutoArray[0])) {
|
||||||
|
delete[] oldArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -53,8 +198,6 @@ NS_IMPL_ISUPPORTS(nsSupportsArray, nsISupportsArray, nsICollection,
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSupportsArray::Read(nsIObjectInputStream* aStream)
|
nsSupportsArray::Read(nsIObjectInputStream* aStream)
|
||||||
{
|
{
|
||||||
// TODO(ER): This used to leak when resizing the array. Not sure if that was
|
|
||||||
// intentional, I'm guessing not.
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
uint32_t newArraySize;
|
uint32_t newArraySize;
|
||||||
|
@ -63,40 +206,43 @@ nsSupportsArray::Read(nsIObjectInputStream* aStream)
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t count;
|
if (newArraySize <= kAutoArraySize) {
|
||||||
rv = aStream->Read32(&count);
|
if (mArray != mAutoArray) {
|
||||||
|
delete[] mArray;
|
||||||
|
mArray = mAutoArray;
|
||||||
|
}
|
||||||
|
newArraySize = kAutoArraySize;
|
||||||
|
} else {
|
||||||
|
if (newArraySize <= mArraySize) {
|
||||||
|
// Keep non-default-size mArray, it's more than big enough.
|
||||||
|
newArraySize = mArraySize;
|
||||||
|
} else {
|
||||||
|
nsISupports** array = new nsISupports*[newArraySize];
|
||||||
|
if (mArray != mAutoArray) {
|
||||||
|
delete[] mArray;
|
||||||
|
}
|
||||||
|
mArray = array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mArraySize = newArraySize;
|
||||||
|
|
||||||
|
rv = aStream->Read32(&mCount);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ASSERTION(count <= newArraySize, "overlarge mCount!");
|
NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!");
|
||||||
if (count > newArraySize) {
|
if (mCount > mArraySize) {
|
||||||
count = newArraySize;
|
mCount = mArraySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't clear out our array until we know we have enough space for the new
|
for (uint32_t i = 0; i < mCount; i++) {
|
||||||
// one and have successfully copied everything out of the stream.
|
rv = aStream->ReadObject(true, &mArray[i]);
|
||||||
ISupportsArray tmp;
|
|
||||||
if (!tmp.SetCapacity(newArraySize, mozilla::fallible)) {
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto elems = tmp.AppendElements(count, mozilla::fallible);
|
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
|
||||||
rv = aStream->ReadObject(true, &elems[i]);
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now clear out existing refs and replace with the new array.
|
|
||||||
for (auto& item : mArray) {
|
|
||||||
NS_IF_RELEASE(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
mArray.Clear();
|
|
||||||
mArray.SwapElements(tmp);
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,18 +251,18 @@ nsSupportsArray::Write(nsIObjectOutputStream* aStream)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
rv = aStream->Write32(mArray.Capacity());
|
rv = aStream->Write32(mArraySize);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = aStream->Write32(mArray.Length());
|
rv = aStream->Write32(mCount);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& item : mArray) {
|
for (uint32_t i = 0; i < mCount; i++) {
|
||||||
rv = aStream->WriteObject(item, true);
|
rv = aStream->WriteObject(mArray[i], true);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -125,42 +271,141 @@ nsSupportsArray::Write(nsIObjectOutputStream* aStream)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsSupportsArray::DeleteArray(void)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
if (mArray != &(mAutoArray[0])) {
|
||||||
|
delete[] mArray;
|
||||||
|
mArray = mAutoArray;
|
||||||
|
mArraySize = kAutoArraySize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(bool)
|
||||||
|
nsSupportsArray::Equals(const nsISupportsArray* aOther)
|
||||||
|
{
|
||||||
|
if (aOther) {
|
||||||
|
uint32_t countOther;
|
||||||
|
nsISupportsArray* other = const_cast<nsISupportsArray*>(aOther);
|
||||||
|
nsresult rv = other->Count(&countOther);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCount == countOther) {
|
||||||
|
uint32_t index = mCount;
|
||||||
|
nsCOMPtr<nsISupports> otherElem;
|
||||||
|
while (index--) {
|
||||||
|
if (NS_FAILED(other->GetElementAt(index, getter_AddRefs(otherElem)))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mArray[index] != otherElem) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSupportsArray::GetElementAt(uint32_t aIndex, nsISupports** aOutPtr)
|
nsSupportsArray::GetElementAt(uint32_t aIndex, nsISupports** aOutPtr)
|
||||||
{
|
{
|
||||||
NS_IF_ADDREF(*aOutPtr = mArray.SafeElementAt(aIndex, nullptr));
|
*aOutPtr = nullptr;
|
||||||
|
if (aIndex < mCount) {
|
||||||
|
NS_IF_ADDREF(*aOutPtr = mArray[aIndex]);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(int32_t)
|
NS_IMETHODIMP_(int32_t)
|
||||||
nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
|
nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
|
||||||
{
|
{
|
||||||
return mArray.IndexOf(aPossibleElement);
|
return IndexOfStartingAt(aPossibleElement, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(int32_t)
|
||||||
|
nsSupportsArray::IndexOfStartingAt(const nsISupports* aPossibleElement,
|
||||||
|
uint32_t aStartIndex)
|
||||||
|
{
|
||||||
|
if (aStartIndex < mCount) {
|
||||||
|
const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
|
||||||
|
const nsISupports** ep = (start + aStartIndex);
|
||||||
|
const nsISupports** end = (start + mCount);
|
||||||
|
while (ep < end) {
|
||||||
|
if (aPossibleElement == *ep) {
|
||||||
|
return (ep - start);
|
||||||
|
}
|
||||||
|
ep++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(int32_t)
|
NS_IMETHODIMP_(int32_t)
|
||||||
nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement)
|
nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement)
|
||||||
{
|
{
|
||||||
return mArray.LastIndexOf(aPossibleElement);
|
if (0 < mCount) {
|
||||||
|
const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
|
||||||
|
const nsISupports** ep = (start + mCount);
|
||||||
|
while (start <= --ep) {
|
||||||
|
if (aPossibleElement == *ep) {
|
||||||
|
return (ep - start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(bool)
|
NS_IMETHODIMP_(bool)
|
||||||
nsSupportsArray::InsertElementAt(nsISupports* aElement, uint32_t aIndex)
|
nsSupportsArray::InsertElementAt(nsISupports* aElement, uint32_t aIndex)
|
||||||
{
|
{
|
||||||
|
if (aIndex <= mCount) {
|
||||||
|
CheckedUint32 newCount(mCount);
|
||||||
|
newCount += 1;
|
||||||
|
if (!newCount.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (aIndex > mArray.Length() ||
|
if (mArraySize < newCount.value()) {
|
||||||
!mArray.InsertElementAt(aIndex, aElement, mozilla::fallible)) {
|
// need to grow the array
|
||||||
return false;
|
if (!GrowArrayBy(1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could be slightly more efficient if GrowArrayBy knew about the
|
||||||
|
// split, but the difference is trivial.
|
||||||
|
uint32_t slide = (mCount - aIndex);
|
||||||
|
if (0 < slide) {
|
||||||
|
::memmove(mArray + aIndex + 1, mArray + aIndex,
|
||||||
|
slide * sizeof(nsISupports*));
|
||||||
|
}
|
||||||
|
|
||||||
|
mArray[aIndex] = aElement;
|
||||||
|
NS_IF_ADDREF(aElement);
|
||||||
|
mCount++;
|
||||||
|
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
if (mCount > mMaxCount &&
|
||||||
|
mCount < (int32_t)(sizeof(MaxElements) / sizeof(MaxElements[0]))) {
|
||||||
|
MaxElements[mCount]++;
|
||||||
|
MaxElements[mMaxCount]--;
|
||||||
|
mMaxCount = mCount;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
NS_IF_ADDREF(aElement);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(bool)
|
NS_IMETHODIMP_(bool)
|
||||||
nsSupportsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex)
|
nsSupportsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex)
|
||||||
{
|
{
|
||||||
if (aIndex < mArray.Length()) {
|
if (aIndex < mCount) {
|
||||||
NS_IF_ADDREF(aElement); // addref first in case it's the same object!
|
NS_IF_ADDREF(aElement); // addref first in case it's the same object!
|
||||||
NS_IF_RELEASE(mArray[aIndex]);
|
NS_IF_RELEASE(mArray[aIndex]);
|
||||||
mArray[aIndex] = aElement;
|
mArray[aIndex] = aElement;
|
||||||
|
@ -170,11 +415,18 @@ nsSupportsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(bool)
|
NS_IMETHODIMP_(bool)
|
||||||
nsSupportsArray::RemoveElementAt(uint32_t aIndex)
|
nsSupportsArray::RemoveElementsAt(uint32_t aIndex, uint32_t aCount)
|
||||||
{
|
{
|
||||||
if (aIndex + 1 <= mArray.Length()) {
|
if (aIndex + aCount <= mCount) {
|
||||||
NS_IF_RELEASE(mArray[aIndex]);
|
for (uint32_t i = 0; i < aCount; i++) {
|
||||||
mArray.RemoveElementAt(aIndex);
|
NS_IF_RELEASE(mArray[aIndex + i]);
|
||||||
|
}
|
||||||
|
mCount -= aCount;
|
||||||
|
int32_t slide = (mCount - aIndex);
|
||||||
|
if (0 < slide) {
|
||||||
|
::memmove(mArray + aIndex, mArray + aIndex + aCount,
|
||||||
|
slide * sizeof(nsISupports*));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -183,7 +435,7 @@ nsSupportsArray::RemoveElementAt(uint32_t aIndex)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSupportsArray::RemoveElement(nsISupports* aElement)
|
nsSupportsArray::RemoveElement(nsISupports* aElement)
|
||||||
{
|
{
|
||||||
int32_t theIndex = IndexOf(aElement);
|
int32_t theIndex = IndexOfStartingAt(aElement, 0);
|
||||||
if (theIndex >= 0) {
|
if (theIndex >= 0) {
|
||||||
return RemoveElementAt(theIndex) ? NS_OK : NS_ERROR_FAILURE;
|
return RemoveElementAt(theIndex) ? NS_OK : NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -191,25 +443,137 @@ nsSupportsArray::RemoveElement(nsISupports* aElement)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(bool)
|
||||||
|
nsSupportsArray::RemoveLastElement(const nsISupports* aElement)
|
||||||
|
{
|
||||||
|
int32_t theIndex = LastIndexOf(aElement);
|
||||||
|
if (theIndex >= 0) {
|
||||||
|
return RemoveElementAt(theIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(bool)
|
||||||
|
nsSupportsArray::MoveElement(int32_t aFrom, int32_t aTo)
|
||||||
|
{
|
||||||
|
nsISupports* tempElement;
|
||||||
|
|
||||||
|
if (aTo == aFrom) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aTo < 0 || aFrom < 0 ||
|
||||||
|
(uint32_t)aTo >= mCount || (uint32_t)aFrom >= mCount) {
|
||||||
|
// can't extend the array when moving an element. Also catches mImpl = null
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tempElement = mArray[aFrom];
|
||||||
|
|
||||||
|
if (aTo < aFrom) {
|
||||||
|
// Moving one element closer to the head; the elements inbetween move down
|
||||||
|
::memmove(mArray + aTo + 1, mArray + aTo,
|
||||||
|
(aFrom - aTo) * sizeof(mArray[0]));
|
||||||
|
mArray[aTo] = tempElement;
|
||||||
|
} else { // already handled aFrom == aTo
|
||||||
|
// Moving one element closer to the tail; the elements inbetween move up
|
||||||
|
::memmove(mArray + aFrom, mArray + aFrom + 1,
|
||||||
|
(aTo - aFrom) * sizeof(mArray[0]));
|
||||||
|
mArray[aTo] = tempElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSupportsArray::Clear(void)
|
nsSupportsArray::Clear(void)
|
||||||
{
|
{
|
||||||
for (auto& item : mArray) {
|
if (0 < mCount) {
|
||||||
NS_IF_RELEASE(item);
|
do {
|
||||||
|
--mCount;
|
||||||
|
NS_IF_RELEASE(mArray[mCount]);
|
||||||
|
} while (0 != mCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
mArray.Clear();
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSupportsArray::Compact(void)
|
nsSupportsArray::Compact(void)
|
||||||
{
|
{
|
||||||
mArray.Compact();
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
uint32_t oldArraySize = mArraySize;
|
||||||
|
#endif
|
||||||
|
if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
|
||||||
|
nsISupports** oldArray = mArray;
|
||||||
|
if (mCount <= kAutoArraySize) {
|
||||||
|
mArray = mAutoArray;
|
||||||
|
mArraySize = kAutoArraySize;
|
||||||
|
} else {
|
||||||
|
mArray = new nsISupports*[mCount];
|
||||||
|
if (!mArray) {
|
||||||
|
mArray = oldArray;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
mArraySize = mCount;
|
||||||
|
}
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
if (oldArray == mArray &&
|
||||||
|
oldArray != &(mAutoArray[0])) { // can't happen without use of realloc
|
||||||
|
ADD_TO_STATS(GrowInPlace, oldArraySize);
|
||||||
|
}
|
||||||
|
if (oldArray != &(mAutoArray[0])) {
|
||||||
|
ADD_TO_STATS(AllocedOfSize, mArraySize * sizeof(mArray[0]));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||||
|
delete[] oldArray;
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(bool)
|
||||||
|
nsSupportsArray::SizeTo(int32_t aSize)
|
||||||
|
{
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
uint32_t oldArraySize = mArraySize;
|
||||||
|
#endif
|
||||||
|
NS_ASSERTION(aSize >= 0, "negative aSize!");
|
||||||
|
|
||||||
|
// XXX for aSize < mCount we could resize to mCount
|
||||||
|
if (mArraySize == (uint32_t)aSize || (uint32_t)aSize < mCount) {
|
||||||
|
return true; // nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch back to autoarray if possible
|
||||||
|
nsISupports** oldArray = mArray;
|
||||||
|
if ((uint32_t)aSize <= kAutoArraySize) {
|
||||||
|
mArray = mAutoArray;
|
||||||
|
mArraySize = kAutoArraySize;
|
||||||
|
} else {
|
||||||
|
mArray = new nsISupports*[aSize];
|
||||||
|
if (!mArray) {
|
||||||
|
mArray = oldArray;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mArraySize = aSize;
|
||||||
|
}
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
if (oldArray == mArray &&
|
||||||
|
oldArray != &(mAutoArray[0])) { // can't happen without use of realloc
|
||||||
|
ADD_TO_STATS(GrowInPlace, oldArraySize);
|
||||||
|
}
|
||||||
|
if (oldArray != &(mAutoArray[0])) {
|
||||||
|
ADD_TO_STATS(AllocedOfSize, mArraySize * sizeof(mArray[0]));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||||
|
if (oldArray != mAutoArray) {
|
||||||
|
delete[] oldArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSupportsArray::Enumerate(nsIEnumerator** aResult)
|
nsSupportsArray::Enumerate(nsIEnumerator** aResult)
|
||||||
{
|
{
|
||||||
|
@ -228,10 +592,10 @@ nsSupportsArray::Clone(nsISupportsArray** aResult)
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& item : mArray) {
|
uint32_t count = 0;
|
||||||
// AppendElement does an odd cast of bool to nsresult, we just cast back
|
Count(&count);
|
||||||
// here.
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
if (!(bool)newArray->AppendElement(item)) {
|
if (!newArray->InsertElementAt(mArray[i], i)) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,13 @@
|
||||||
#ifndef nsSupportsArray_h__
|
#ifndef nsSupportsArray_h__
|
||||||
#define nsSupportsArray_h__
|
#define nsSupportsArray_h__
|
||||||
|
|
||||||
|
//#define DEBUG_SUPPORTSARRAY 1
|
||||||
|
|
||||||
#include "nsISupportsArray.h"
|
#include "nsISupportsArray.h"
|
||||||
#include "nsTArray.h"
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
|
||||||
|
static const uint32_t kAutoArraySize = 8;
|
||||||
|
|
||||||
class nsSupportsArray final : public nsISupportsArray
|
class nsSupportsArray final : public nsISupportsArray
|
||||||
{
|
{
|
||||||
~nsSupportsArray(void); // nonvirtual since we're not subclassed
|
~nsSupportsArray(void); // nonvirtual since we're not subclassed
|
||||||
|
@ -28,16 +31,18 @@ public:
|
||||||
// nsICollection methods:
|
// nsICollection methods:
|
||||||
NS_IMETHOD Count(uint32_t* aResult) override
|
NS_IMETHOD Count(uint32_t* aResult) override
|
||||||
{
|
{
|
||||||
*aResult = mArray.Length();
|
*aResult = mCount;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
NS_IMETHOD GetElementAt(uint32_t aIndex, nsISupports** aResult) override;
|
NS_IMETHOD GetElementAt(uint32_t aIndex, nsISupports** aResult) override;
|
||||||
MOZ_MUST_USE NS_IMETHOD
|
MOZ_MUST_USE NS_IMETHOD
|
||||||
QueryElementAt(uint32_t aIndex, const nsIID& aIID, void** aResult) override
|
QueryElementAt(uint32_t aIndex, const nsIID& aIID, void** aResult) override
|
||||||
{
|
{
|
||||||
nsISupports* element = mArray.SafeElementAt(aIndex, nullptr);
|
if (aIndex < mCount) {
|
||||||
if (element) {
|
nsISupports* element = mArray[aIndex];
|
||||||
return element->QueryInterface(aIID, aResult);
|
if (element) {
|
||||||
|
return element->QueryInterface(aIID, aResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -49,15 +54,20 @@ public:
|
||||||
MOZ_MUST_USE NS_IMETHOD AppendElement(nsISupports* aElement) override
|
MOZ_MUST_USE NS_IMETHOD AppendElement(nsISupports* aElement) override
|
||||||
{
|
{
|
||||||
// XXX Invalid cast of bool to nsresult (bug 778110)
|
// XXX Invalid cast of bool to nsresult (bug 778110)
|
||||||
return (nsresult)InsertElementAt(aElement, mArray.Length())/* ? NS_OK : NS_ERROR_FAILURE*/;
|
return (nsresult)InsertElementAt(aElement, mCount)/* ? NS_OK : NS_ERROR_FAILURE*/;
|
||||||
}
|
}
|
||||||
// XXX this is badly named - should be RemoveFirstElement
|
// XXX this is badly named - should be RemoveFirstElement
|
||||||
MOZ_MUST_USE NS_IMETHOD RemoveElement(nsISupports* aElement) override;
|
MOZ_MUST_USE NS_IMETHOD RemoveElement(nsISupports* aElement) override;
|
||||||
|
MOZ_MUST_USE NS_IMETHOD_(bool) MoveElement(int32_t aFrom, int32_t aTo) override;
|
||||||
NS_IMETHOD Enumerate(nsIEnumerator** aResult) override;
|
NS_IMETHOD Enumerate(nsIEnumerator** aResult) override;
|
||||||
NS_IMETHOD Clear(void) override;
|
NS_IMETHOD Clear(void) override;
|
||||||
|
|
||||||
// nsISupportsArray methods:
|
// nsISupportsArray methods:
|
||||||
|
NS_IMETHOD_(bool) Equals(const nsISupportsArray* aOther) override;
|
||||||
|
|
||||||
NS_IMETHOD_(int32_t) IndexOf(const nsISupports* aPossibleElement) override;
|
NS_IMETHOD_(int32_t) IndexOf(const nsISupports* aPossibleElement) override;
|
||||||
|
NS_IMETHOD_(int32_t) IndexOfStartingAt(const nsISupports* aPossibleElement,
|
||||||
|
uint32_t aStartIndex = 0) override;
|
||||||
NS_IMETHOD_(int32_t) LastIndexOf(const nsISupports* aPossibleElement) override;
|
NS_IMETHOD_(int32_t) LastIndexOf(const nsISupports* aPossibleElement) override;
|
||||||
|
|
||||||
NS_IMETHOD GetIndexOf(nsISupports* aPossibleElement, int32_t* aResult) override
|
NS_IMETHOD GetIndexOf(nsISupports* aPossibleElement, int32_t* aResult) override
|
||||||
|
@ -66,6 +76,13 @@ public:
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD GetIndexOfStartingAt(nsISupports* aPossibleElement,
|
||||||
|
uint32_t aStartIndex, int32_t* aResult) override
|
||||||
|
{
|
||||||
|
*aResult = IndexOfStartingAt(aPossibleElement, aStartIndex);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHOD GetLastIndexOf(nsISupports* aPossibleElement, int32_t* aResult) override
|
NS_IMETHOD GetLastIndexOf(nsISupports* aPossibleElement, int32_t* aResult) override
|
||||||
{
|
{
|
||||||
*aResult = LastIndexOf(aPossibleElement);
|
*aResult = LastIndexOf(aPossibleElement);
|
||||||
|
@ -79,7 +96,17 @@ public:
|
||||||
ReplaceElementAt(nsISupports* aElement, uint32_t aIndex) override;
|
ReplaceElementAt(nsISupports* aElement, uint32_t aIndex) override;
|
||||||
|
|
||||||
MOZ_MUST_USE NS_IMETHOD_(bool)
|
MOZ_MUST_USE NS_IMETHOD_(bool)
|
||||||
RemoveElementAt(uint32_t aIndex) override;
|
RemoveElementAt(uint32_t aIndex) override
|
||||||
|
{
|
||||||
|
return RemoveElementsAt(aIndex, 1);
|
||||||
|
}
|
||||||
|
MOZ_MUST_USE NS_IMETHOD_(bool)
|
||||||
|
RemoveLastElement(const nsISupports* aElement) override;
|
||||||
|
|
||||||
|
MOZ_MUST_USE NS_IMETHOD DeleteLastElement(nsISupports* aElement) override
|
||||||
|
{
|
||||||
|
return (RemoveLastElement(aElement) ? NS_OK : NS_ERROR_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_MUST_USE NS_IMETHOD DeleteElementAt(uint32_t aIndex) override
|
MOZ_MUST_USE NS_IMETHOD DeleteElementAt(uint32_t aIndex) override
|
||||||
{
|
{
|
||||||
|
@ -90,12 +117,28 @@ public:
|
||||||
|
|
||||||
MOZ_MUST_USE NS_IMETHOD Clone(nsISupportsArray** aResult) override;
|
MOZ_MUST_USE NS_IMETHOD Clone(nsISupportsArray** aResult) override;
|
||||||
|
|
||||||
|
MOZ_MUST_USE NS_IMETHOD_(bool)
|
||||||
|
RemoveElementsAt(uint32_t aIndex, uint32_t aCount) override;
|
||||||
|
|
||||||
|
MOZ_MUST_USE NS_IMETHOD_(bool)
|
||||||
|
SizeTo(int32_t aSize) override;
|
||||||
|
protected:
|
||||||
|
void DeleteArray(void);
|
||||||
|
|
||||||
|
bool GrowArrayBy(uint32_t aGrowBy);
|
||||||
|
|
||||||
|
nsISupports** mArray;
|
||||||
|
uint32_t mArraySize;
|
||||||
|
uint32_t mCount;
|
||||||
|
nsISupports* mAutoArray[kAutoArraySize];
|
||||||
|
#if DEBUG_SUPPORTSARRAY
|
||||||
|
uint32_t mMaxCount;
|
||||||
|
uint32_t mMaxSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Copy constructors are not allowed
|
// Copy constructors are not allowed
|
||||||
explicit nsSupportsArray(const nsISupportsArray& aOther);
|
explicit nsSupportsArray(const nsISupportsArray& aOther);
|
||||||
|
|
||||||
typedef AutoTArray<nsISupports*, 8> ISupportsArray;
|
|
||||||
ISupportsArray mArray;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsSupportsArray_h__
|
#endif // nsSupportsArray_h__
|
||||||
|
|
|
@ -119,19 +119,26 @@ TEST(Array, main)
|
||||||
|
|
||||||
|
|
||||||
// test IndexOf && LastIndexOf
|
// test IndexOf && LastIndexOf
|
||||||
int32_t expectedIndex = 0;
|
int32_t expectedIndex[5] = {0, 4, 6, 12, -1};
|
||||||
|
int32_t count = 0;
|
||||||
int32_t index = array->IndexOf(foo);
|
int32_t index = array->IndexOf(foo);
|
||||||
EXPECT_EQ(index, expectedIndex);
|
EXPECT_EQ(index, expectedIndex[count]);
|
||||||
expectedIndex = 12;
|
while (-1 != index) {
|
||||||
|
count++;
|
||||||
|
index = array->IndexOfStartingAt(foo, index + 1);
|
||||||
|
if (-1 != index)
|
||||||
|
EXPECT_EQ(index, expectedIndex[count]);
|
||||||
|
}
|
||||||
index = array->LastIndexOf(foo);
|
index = array->LastIndexOf(foo);
|
||||||
EXPECT_EQ(index, expectedIndex);
|
count--;
|
||||||
|
EXPECT_EQ(index, expectedIndex[count]);
|
||||||
|
|
||||||
// test ReplaceElementAt
|
// test ReplaceElementAt
|
||||||
array->ReplaceElementAt(foo, 8);
|
array->ReplaceElementAt(foo, 8);
|
||||||
int32_t replaceResult[13] = {3, 0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3};
|
int32_t replaceResult[13] = {3, 0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3};
|
||||||
CheckArray(array, 13, replaceResult, 9);
|
CheckArray(array, 13, replaceResult, 9);
|
||||||
|
|
||||||
// test RemoveElementAt, RemoveElement
|
// test RemoveElementAt, RemoveElement RemoveLastElement
|
||||||
array->RemoveElementAt(0);
|
array->RemoveElementAt(0);
|
||||||
int32_t removeResult[12] = {0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3};
|
int32_t removeResult[12] = {0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3};
|
||||||
CheckArray(array, 12, removeResult, 9);
|
CheckArray(array, 12, removeResult, 9);
|
||||||
|
@ -141,6 +148,9 @@ TEST(Array, main)
|
||||||
array->RemoveElement(foo);
|
array->RemoveElement(foo);
|
||||||
int32_t removeResult3[10] = {0, 1, 2, 4, 3, 5, 7, 8, 9, 3};
|
int32_t removeResult3[10] = {0, 1, 2, 4, 3, 5, 7, 8, 9, 3};
|
||||||
CheckArray(array, 10, removeResult3, 9);
|
CheckArray(array, 10, removeResult3, 9);
|
||||||
|
array->RemoveLastElement(foo);
|
||||||
|
int32_t removeResult4[9] = {0, 1, 2, 4, 3, 5, 7, 8, 9};
|
||||||
|
CheckArray(array, 9, removeResult4, 9);
|
||||||
|
|
||||||
foo = nullptr;
|
foo = nullptr;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче