mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 11:27:49 +00:00
Merge the last PGO-green inbound changeset to m-c.
This commit is contained in:
commit
171736767a
@ -5,7 +5,7 @@
|
||||
#ifndef mozilla_a11y_AccCollector_h__
|
||||
#define mozilla_a11y_AccCollector_h__
|
||||
|
||||
#include "AccFilters.h"
|
||||
#include "Filters.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#define mozilla_a11y_AccIterator_h__
|
||||
|
||||
#include "DocAccessible.h"
|
||||
#include "AccFilters.h"
|
||||
#include "Filters.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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 "AccFilters.h"
|
||||
#include "Filters.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "nsAccUtils.h"
|
@ -19,7 +19,7 @@ CPPSRCS = \
|
||||
AccEvent.cpp \
|
||||
AccGroupInfo.cpp \
|
||||
AccIterator.cpp \
|
||||
AccFilters.cpp \
|
||||
Filters.cpp \
|
||||
ARIAStateMap.cpp \
|
||||
FocusManager.cpp \
|
||||
NotificationController.cpp \
|
||||
|
@ -23,12 +23,17 @@ DirectoryProvider.prototype = {
|
||||
getFile: function dp_getFile(prop, persistent) {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir",
|
||||
"permissionDBPDir", "UpdRootD"];
|
||||
"permissionDBPDir", "UpdRootD"];
|
||||
if (localProps.indexOf(prop) != -1) {
|
||||
prop.persistent = true;
|
||||
let file = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile)
|
||||
file.initWithPath(LOCAL_DIR);
|
||||
persistent.value = true;
|
||||
return file;
|
||||
} else if (prop == "coreAppsDir") {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
|
||||
file.initWithPath("/system/b2g");
|
||||
persistent.value = true;
|
||||
return file;
|
||||
}
|
||||
#endif
|
||||
|
@ -176,7 +176,7 @@
|
||||
<method name="resize">
|
||||
<body><![CDATA[
|
||||
let child = this.firstCollapsedChild;
|
||||
if (child && this.emptyWidth > 200) {
|
||||
if (child && this.emptyWidth > child.viewWidth) {
|
||||
this.showChat(child);
|
||||
}
|
||||
if (!this.firstCollapsedChild) {
|
||||
@ -211,6 +211,7 @@
|
||||
<method name="collapseChat">
|
||||
<parameter name="aChatbox"/>
|
||||
<body><![CDATA[
|
||||
aChatbox.viewWidth = aChatbox.getBoundingClientRect().width;
|
||||
aChatbox.collapsed = true;
|
||||
aChatbox.isActive = false;
|
||||
let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
|
||||
|
@ -3035,7 +3035,7 @@ let SessionStoreInternal = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Restory history for a window
|
||||
* Restore history for a window
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
* @param aTabs
|
||||
|
@ -482,13 +482,6 @@ public:
|
||||
return sIOService;
|
||||
}
|
||||
|
||||
static imgILoader* GetImgLoader()
|
||||
{
|
||||
if (!sImgLoaderInitialized)
|
||||
InitImgLoader();
|
||||
return sImgLoader;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XTF
|
||||
static nsIXTFService* GetXTFService();
|
||||
#endif
|
||||
@ -663,10 +656,17 @@ public:
|
||||
int32_t aLoadFlags,
|
||||
imgIRequest** aRequest);
|
||||
|
||||
/**
|
||||
* Obtain an image loader that respects the given document/channel's privacy status.
|
||||
* Null document/channel arguments return the public image loader.
|
||||
*/
|
||||
static imgILoader* GetImgLoaderForDocument(nsIDocument* aDoc);
|
||||
static imgILoader* GetImgLoaderForChannel(nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Returns whether the given URI is in the image cache.
|
||||
*/
|
||||
static bool IsImageInCache(nsIURI* aURI);
|
||||
static bool IsImageInCache(nsIURI* aURI, nsIDocument* aDocument);
|
||||
|
||||
/**
|
||||
* Method to get an imgIContainer from an image loading content
|
||||
@ -2160,9 +2160,11 @@ private:
|
||||
static bool sImgLoaderInitialized;
|
||||
static void InitImgLoader();
|
||||
|
||||
// The following two members are initialized lazily
|
||||
// The following four members are initialized lazily
|
||||
static imgILoader* sImgLoader;
|
||||
static imgILoader* sPrivateImgLoader;
|
||||
static imgICache* sImgCache;
|
||||
static imgICache* sPrivateImgCache;
|
||||
|
||||
static nsIConsoleService* sConsoleService;
|
||||
|
||||
|
@ -50,6 +50,7 @@ EXPORTS_mozilla/dom = \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(topsrcdir)/image/src \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
@ -119,6 +119,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsParserConstants.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "mozilla/Selection.h"
|
||||
|
||||
@ -134,6 +135,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "imgICache.h"
|
||||
#include "imgLoader.h"
|
||||
#include "xpcprivate.h" // nsXPConnect
|
||||
#include "nsScriptSecurityManager.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
@ -187,7 +189,9 @@ nsIIOService *nsContentUtils::sIOService;
|
||||
nsIXTFService *nsContentUtils::sXTFService = nullptr;
|
||||
#endif
|
||||
imgILoader *nsContentUtils::sImgLoader;
|
||||
imgILoader *nsContentUtils::sPrivateImgLoader;
|
||||
imgICache *nsContentUtils::sImgCache;
|
||||
imgICache *nsContentUtils::sPrivateImgCache;
|
||||
nsIConsoleService *nsContentUtils::sConsoleService;
|
||||
nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr;
|
||||
nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr;
|
||||
@ -508,15 +512,17 @@ nsContentUtils::InitImgLoader()
|
||||
sImgLoaderInitialized = true;
|
||||
|
||||
// Ignore failure and just don't load images
|
||||
nsresult rv = CallGetService("@mozilla.org/image/loader;1", &sImgLoader);
|
||||
if (NS_FAILED(rv)) {
|
||||
// no image loading for us. Oh, well.
|
||||
sImgLoader = nullptr;
|
||||
sImgCache = nullptr;
|
||||
} else {
|
||||
if (NS_FAILED(CallGetService("@mozilla.org/image/cache;1", &sImgCache )))
|
||||
sImgCache = nullptr;
|
||||
}
|
||||
nsresult rv = CallCreateInstance("@mozilla.org/image/loader;1", &sImgLoader);
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Creation should have succeeded");
|
||||
rv = CallCreateInstance("@mozilla.org/image/loader;1", &sPrivateImgLoader);
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Creation should have succeeded");
|
||||
|
||||
rv = CallQueryInterface(sImgLoader, &sImgCache);
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "imgICache and imgILoader should be paired");
|
||||
rv = CallQueryInterface(sPrivateImgLoader, &sPrivateImgCache);
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "imgICache and imgILoader should be paired");
|
||||
|
||||
sPrivateImgCache->RespectPrivacyNotifications();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1493,7 +1499,9 @@ nsContentUtils::Shutdown()
|
||||
NS_IF_RELEASE(sXTFService);
|
||||
#endif
|
||||
NS_IF_RELEASE(sImgLoader);
|
||||
NS_IF_RELEASE(sPrivateImgLoader);
|
||||
NS_IF_RELEASE(sImgCache);
|
||||
NS_IF_RELEASE(sPrivateImgCache);
|
||||
#ifdef IBMBIDI
|
||||
NS_IF_RELEASE(sBidiKeyboard);
|
||||
#endif
|
||||
@ -2692,19 +2700,60 @@ nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext,
|
||||
return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision);
|
||||
}
|
||||
|
||||
imgILoader*
|
||||
nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc)
|
||||
{
|
||||
if (!sImgLoaderInitialized)
|
||||
InitImgLoader();
|
||||
if (!aDoc)
|
||||
return sImgLoader;
|
||||
bool isPrivate = false;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
if (loadGroup) {
|
||||
loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
if (callbacks) {
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
|
||||
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
|
||||
if (channel) {
|
||||
nsCOMPtr<nsILoadContext> context;
|
||||
NS_QueryNotificationCallbacks(channel, context);
|
||||
isPrivate = context && context->UsePrivateBrowsing();
|
||||
}
|
||||
}
|
||||
return isPrivate ? sPrivateImgLoader : sImgLoader;
|
||||
}
|
||||
|
||||
// static
|
||||
imgILoader*
|
||||
nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel)
|
||||
{
|
||||
if (!sImgLoaderInitialized)
|
||||
InitImgLoader();
|
||||
if (!aChannel)
|
||||
return sImgLoader;
|
||||
nsCOMPtr<nsILoadContext> context;
|
||||
NS_QueryNotificationCallbacks(aChannel, context);
|
||||
return context && context->UsePrivateBrowsing() ? sPrivateImgLoader : sImgLoader;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsContentUtils::IsImageInCache(nsIURI* aURI)
|
||||
nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument)
|
||||
{
|
||||
if (!sImgLoaderInitialized)
|
||||
InitImgLoader();
|
||||
|
||||
if (!sImgCache) return false;
|
||||
imgILoader* loader = GetImgLoaderForDocument(aDocument);
|
||||
nsCOMPtr<imgICache> cache = do_QueryInterface(loader);
|
||||
|
||||
// If something unexpected happened we return false, otherwise if props
|
||||
// is set, the image is cached and we return true
|
||||
nsCOMPtr<nsIProperties> props;
|
||||
nsresult rv = sImgCache->FindEntryProperties(aURI, getter_AddRefs(props));
|
||||
nsresult rv = cache->FindEntryProperties(aURI, getter_AddRefs(props));
|
||||
return (NS_SUCCEEDED(rv) && props);
|
||||
}
|
||||
|
||||
@ -2720,7 +2769,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
NS_PRECONDITION(aLoadingPrincipal, "Must have a principal");
|
||||
NS_PRECONDITION(aRequest, "Null out param");
|
||||
|
||||
imgILoader* imgLoader = GetImgLoader();
|
||||
imgILoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument);
|
||||
if (!imgLoader) {
|
||||
// nothing we can do here
|
||||
return NS_OK;
|
||||
|
@ -7681,7 +7681,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr)
|
||||
// which indicates that the "real" load has already started and
|
||||
// that we shouldn't preload it.
|
||||
int16_t blockingStatus;
|
||||
if (nsContentUtils::IsImageInCache(uri) ||
|
||||
if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) ||
|
||||
!nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this),
|
||||
this, NodePrincipal(), &blockingStatus)) {
|
||||
return;
|
||||
|
@ -88,7 +88,7 @@ nsImageLoadingContent::nsImageLoadingContent()
|
||||
mCurrentRequestRegistered(false),
|
||||
mPendingRequestRegistered(false)
|
||||
{
|
||||
if (!nsContentUtils::GetImgLoader()) {
|
||||
if (!nsContentUtils::GetImgLoaderForChannel(nullptr)) {
|
||||
mLoadingEnabled = false;
|
||||
}
|
||||
}
|
||||
@ -334,7 +334,7 @@ nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
|
||||
{
|
||||
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
if (nsContentUtils::GetImgLoader()) {
|
||||
if (nsContentUtils::GetImgLoaderForChannel(nullptr)) {
|
||||
mLoadingEnabled = aLoadingEnabled;
|
||||
}
|
||||
return NS_OK;
|
||||
@ -518,7 +518,7 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
|
||||
{
|
||||
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
if (!nsContentUtils::GetImgLoader()) {
|
||||
if (!nsContentUtils::GetImgLoaderForChannel(aChannel)) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
@ -537,7 +537,7 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
|
||||
|
||||
// Do the load.
|
||||
nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
|
||||
nsresult rv = nsContentUtils::GetImgLoader()->
|
||||
nsresult rv = nsContentUtils::GetImgLoaderForChannel(aChannel)->
|
||||
LoadImageWithChannel(aChannel, this, doc, aListener,
|
||||
getter_AddRefs(req));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -477,7 +477,7 @@ URIEquals(nsIURI *a, nsIURI *b)
|
||||
static bool
|
||||
IsSupportedImage(const nsCString& aMimeType)
|
||||
{
|
||||
imgILoader* loader = nsContentUtils::GetImgLoader();
|
||||
nsCOMPtr<imgILoader> loader = nsContentUtils::GetImgLoaderForChannel(nullptr);
|
||||
if (!loader) {
|
||||
return false;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ function handleRequest(request, response)
|
||||
{
|
||||
var pairs = request.queryString.split('&');
|
||||
var command = pairs.shift();
|
||||
dump("received '" + command + "' command\n");
|
||||
|
||||
var bodyStream = new BinaryInputStream(request.bodyInputStream);
|
||||
var body = "";
|
||||
|
@ -14,7 +14,11 @@ SimpleTest.waitForExplicitFinish();
|
||||
var gen = runTests();
|
||||
|
||||
function log(s) {
|
||||
//document.getElementById("l").textContent += s + "\n";
|
||||
// Uncomment these to get debugging information
|
||||
/*
|
||||
document.getElementById("l").textContent += s + "\n";
|
||||
dump(s + "\n");
|
||||
*/
|
||||
}
|
||||
|
||||
function getEvent(e) {
|
||||
@ -101,6 +105,7 @@ function closeConn() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "progressserver.sjs?close");
|
||||
xhr.send();
|
||||
return xhr;
|
||||
}
|
||||
|
||||
var longString = "long";
|
||||
@ -214,8 +219,9 @@ function runTests() {
|
||||
}
|
||||
if ("close" in test) {
|
||||
log("closing");
|
||||
let xhrClose;
|
||||
if (!testState.file)
|
||||
closeConn();
|
||||
xhrClose = closeConn();
|
||||
|
||||
e = yield;
|
||||
is(e.type, "readystatechange", "should readystate to done closing " + testState.name);
|
||||
@ -241,6 +247,16 @@ function runTests() {
|
||||
is(e.lengthComputable, true, "length should be computable during loadend closing " + testState.name);
|
||||
log("got loadend");
|
||||
|
||||
// if we closed the connection using an explicit request, make sure that goes through before
|
||||
// running the next test in order to avoid reordered requests from closing the wrong
|
||||
// connection.
|
||||
if (xhrClose && xhrClose.readyState != xhrClose.DONE) {
|
||||
log("wait for closeConn to finish");
|
||||
xhrClose.onloadend = getEvent;
|
||||
yield;
|
||||
is(xhrClose.readyState, xhrClose.DONE, "closeConn finished");
|
||||
}
|
||||
|
||||
if (responseType.chunked) {
|
||||
is(xhr.response, null, "chunked data has null response for " + testState.name);
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ CPPSRCS += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
PARALLEL_DIRS += webaudio
|
||||
|
||||
ifdef MOZ_RAW
|
||||
PARALLEL_DIRS += raw
|
||||
endif
|
||||
|
@ -953,10 +953,11 @@ nsBufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate)
|
||||
params.channels = aNumChannels;
|
||||
#ifdef MOZ_SAMPLE_TYPE_S16LE
|
||||
params.format = CUBEB_SAMPLE_S16NE;
|
||||
mBytesPerFrame = sizeof(int16_t) * aNumChannels;
|
||||
#else /* MOZ_SAMPLE_TYPE_FLOAT32 */
|
||||
params.format = CUBEB_SAMPLE_FLOAT32NE;
|
||||
#endif
|
||||
mBytesPerFrame = sizeof(float) * aNumChannels;
|
||||
#endif
|
||||
|
||||
{
|
||||
cubeb_stream* stream;
|
||||
|
56
content/media/webaudio/AudioContext.cpp
Normal file
56
content/media/webaudio/AudioContext.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "AudioContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/AudioContextBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioContext, mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioContext)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioContext)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioContext)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
AudioContext::AudioContext(nsIDOMWindow* aWindow)
|
||||
: mWindow(aWindow)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
AudioContext::~AudioContext()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
AudioContext::WrapObject(JSContext* aCx, JSObject* aScope,
|
||||
bool* aTriedToWrap)
|
||||
{
|
||||
return dom::mozAudioContextBinding::Wrap(aCx, aScope, this,
|
||||
aTriedToWrap);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<AudioContext>
|
||||
AudioContext::Constructor(nsISupports* aGlobal, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(aGlobal);
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AudioContext* object = new AudioContext(window);
|
||||
NS_ADDREF(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
|
46
content/media/webaudio/AudioContext.h
Normal file
46
content/media/webaudio/AudioContext.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "nsWrapperCache.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class JSContext;
|
||||
class nsIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
class AudioContext MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
explicit AudioContext(nsIDOMWindow* aParentWindow);
|
||||
|
||||
public:
|
||||
virtual ~AudioContext();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AudioContext)
|
||||
|
||||
nsIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
|
||||
bool* aTriedToWrap);
|
||||
|
||||
static already_AddRefed<AudioContext>
|
||||
Constructor(nsISupports* aGlobal, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDOMWindow> mWindow;
|
||||
};
|
||||
|
||||
}
|
||||
|
25
content/media/webaudio/Makefile.in
Normal file
25
content/media/webaudio/Makefile.in
Normal file
@ -0,0 +1,25 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH := @DEPTH@
|
||||
topsrcdir := @top_srcdir@
|
||||
srcdir := @srcdir@
|
||||
VPATH := @srcdir@
|
||||
FAIL_ON_WARNINGS := 1
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE := content
|
||||
LIBRARY_NAME := gkconwebaudio_s
|
||||
LIBXUL_LIBRARY := 1
|
||||
|
||||
CPPSRCS := \
|
||||
AudioContext.cpp
|
||||
$(NULL)
|
||||
|
||||
PARALLEL_DIRS := test
|
||||
|
||||
FORCE_STATIC_LIB := 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
17
content/media/webaudio/test/Makefile.in
Normal file
17
content/media/webaudio/test/Makefile.in
Normal file
@ -0,0 +1,17 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH := @DEPTH@
|
||||
topsrcdir := @top_srcdir@
|
||||
srcdir := @srcdir@
|
||||
VPATH := @srcdir@
|
||||
relativesrcdir := @relativesrcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_FILES := \
|
||||
test_AudioContext.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
22
content/media/webaudio/test/test_AudioContext.html
Normal file
22
content/media/webaudio/test/test_AudioContext.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test whether we can create an AudioContext interface</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
var ac = new mozAudioContext();
|
||||
ok(ac, "Create a mozAudioContext object");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -934,7 +934,7 @@ nsSVGSVGElement::GetViewBoxTransform() const
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGSVGElement::ChildrenOnlyTransformChanged()
|
||||
nsSVGSVGElement::ChildrenOnlyTransformChanged(PRUint32 aFlags)
|
||||
{
|
||||
// Avoid wasteful calls:
|
||||
NS_ABORT_IF_FALSE(!(GetPrimaryFrame()->GetStateBits() &
|
||||
@ -957,7 +957,15 @@ nsSVGSVGElement::ChildrenOnlyTransformChanged()
|
||||
nsChangeHint_ChildrenOnlyTransform);
|
||||
}
|
||||
|
||||
nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
|
||||
// If we're not reconstructing the frame tree, then we only call
|
||||
// PostRestyleEvent if we're not being called under reflow to avoid recursing
|
||||
// to death. See bug 767056 comments 10 and 12. Since our nsSVGOuterSVGFrame
|
||||
// is being reflowed we're going to invalidate and repaint its entire area
|
||||
// anyway (which will include our children).
|
||||
if ((changeHint & nsChangeHint_ReconstructFrame) ||
|
||||
!(aFlags & eDuringReflow)) {
|
||||
nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
|
||||
}
|
||||
|
||||
mHasChildrenOnlyTransform = hasChildrenOnlyTransform;
|
||||
}
|
||||
|
@ -210,6 +210,10 @@ public:
|
||||
return mHasChildrenOnlyTransform;
|
||||
}
|
||||
|
||||
enum ChildrenOnlyTransformChangedFlags {
|
||||
eDuringReflow = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* This method notifies the style system that the overflow rects of our
|
||||
* immediate childrens' frames need to be updated. It is called by our own
|
||||
@ -220,7 +224,7 @@ public:
|
||||
* GetAttributeChangeHint is because we need to act on non-attribute (e.g.
|
||||
* currentScale) changes in addition to attribute (e.g. viewBox) changes.
|
||||
*/
|
||||
void ChildrenOnlyTransformChanged();
|
||||
void ChildrenOnlyTransformChanged(PRUint32 aFlags = 0);
|
||||
|
||||
// This services any pending notifications for the transform on on this root
|
||||
// <svg> node needing to be recalculated. (Only applicable in
|
||||
|
@ -24,9 +24,9 @@ nsWebNavigationInfo::Init()
|
||||
mCategoryManager = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mImgLoader = do_GetService("@mozilla.org/image/loader;1", &rv);
|
||||
mImgLoader = nsContentUtils::GetImgLoaderForChannel(nullptr);
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -44,7 +44,6 @@ PARALLEL_DIRS += \
|
||||
apps \
|
||||
base \
|
||||
activities \
|
||||
bindings \
|
||||
battery \
|
||||
browser-element \
|
||||
contacts \
|
||||
@ -91,6 +90,12 @@ PARALLEL_DIRS += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
# Not in PARALLEL_DIRS because we need to make sure it builds before
|
||||
# bindings/test, which builds from TEST_DIRS, which gets appended to DIRS.
|
||||
DIRS = \
|
||||
bindings \
|
||||
$(NULL)
|
||||
|
||||
# bindings/test is here, because it needs to build after bindings/, and
|
||||
# we build subdirectories before ourselves.
|
||||
TEST_DIRS += \
|
||||
|
@ -47,6 +47,11 @@ AppsService.prototype = {
|
||||
return DOMApplicationRegistry.getManifestURLByLocalId(aLocalId);
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) {
|
||||
debug("getAppFromObserverMessage( " + aMessage + " )");
|
||||
return DOMApplicationRegistry.getAppFromObserverMessage(aMessage);
|
||||
},
|
||||
|
||||
classID : APPS_SERVICE_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
|
||||
}
|
||||
|
@ -76,6 +76,11 @@ let DOMApplicationRegistry = {
|
||||
getManifestURLByLocalId: function getManifestURLByLocalId(aLocalId) {
|
||||
debug("getManifestURLByLocalId " + aLocalId);
|
||||
return AppsUtils.getManifestURLByLocalId(this.webapps, aLocalId);
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) {
|
||||
debug("getAppFromObserverMessage " + aMessage);
|
||||
return AppsUtils.getAppFromObserverMessage(this.webapps. aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ let AppsUtils = {
|
||||
installTime: aApp.installTime,
|
||||
manifestURL: aApp.manifestURL,
|
||||
appStatus: aApp.appStatus,
|
||||
removable: aApp.removable,
|
||||
localId: aApp.localId,
|
||||
progress: aApp.progress || 0.0,
|
||||
status: aApp.status || "installed"
|
||||
@ -104,5 +105,20 @@ let AppsUtils = {
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function(aApps, aMessage) {
|
||||
let data = JSON.parse(aMessage);
|
||||
|
||||
for (let id in aApps) {
|
||||
let app = aApps[id];
|
||||
if (app.origin != data.origin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return this.cloneAsMozIApplication(app);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ function convertAppsArray(aApps, aWindow) {
|
||||
let apps = Cu.createArrayIn(aWindow);
|
||||
for (let i = 0; i < aApps.length; i++) {
|
||||
let app = aApps[i];
|
||||
apps.push(createApplicationObject(aWindow, app.origin, app.manifest, app.manifestURL,
|
||||
app.receipts, app.installOrigin, app.installTime));
|
||||
apps.push(createApplicationObject(aWindow, app));
|
||||
}
|
||||
|
||||
return apps;
|
||||
@ -73,8 +72,7 @@ WebappsRegistry.prototype = {
|
||||
let app = msg.app;
|
||||
switch (aMessage.name) {
|
||||
case "Webapps:Install:Return:OK":
|
||||
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
|
||||
app.installOrigin, app.installTime));
|
||||
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
|
||||
break;
|
||||
case "Webapps:Install:Return:KO":
|
||||
Services.DOMRequest.fireError(req, msg.error || "DENIED");
|
||||
@ -82,8 +80,7 @@ WebappsRegistry.prototype = {
|
||||
case "Webapps:GetSelf:Return:OK":
|
||||
if (msg.apps.length) {
|
||||
app = msg.apps[0];
|
||||
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
|
||||
app.installOrigin, app.installTime));
|
||||
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
|
||||
} else {
|
||||
Services.DOMRequest.fireSuccess(req, null);
|
||||
}
|
||||
@ -223,9 +220,9 @@ WebappsRegistry.prototype = {
|
||||
* mozIDOMApplication object
|
||||
*/
|
||||
|
||||
function createApplicationObject(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
|
||||
function createApplicationObject(aWindow, aApp) {
|
||||
let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
|
||||
app.wrappedJSObject.init(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime);
|
||||
app.wrappedJSObject.init(aWindow, aApp);
|
||||
return app;
|
||||
}
|
||||
|
||||
@ -246,20 +243,24 @@ WebappsApplication.prototype = {
|
||||
onprogress: 'rw',
|
||||
launch: 'r',
|
||||
receipts: 'r',
|
||||
removable: 'r',
|
||||
uninstall: 'r'
|
||||
},
|
||||
|
||||
init: function(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
|
||||
this.origin = aOrigin;
|
||||
this.manifest = ObjectWrapper.wrap(aManifest, aWindow);
|
||||
this.manifestURL = aManifestURL;
|
||||
this.receipts = aReceipts;
|
||||
this.installOrigin = aInstallOrigin;
|
||||
this.installTime = aInstallTime;
|
||||
init: function(aWindow, aApp) {
|
||||
this.origin = aApp.origin;
|
||||
this.manifest = ObjectWrapper.wrap(aApp.manifest, aWindow);
|
||||
this.manifestURL = aApp.manifestURL;
|
||||
this.receipts = aApp.receipts;
|
||||
this.installOrigin = aApp.installOrigin;
|
||||
this.installTime = aApp.installTime;
|
||||
this.status = "installed";
|
||||
this.removable = aApp.removable;
|
||||
this.progress = NaN;
|
||||
this._onprogress = null;
|
||||
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO", "Webapps:OfflineCache"]);
|
||||
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK",
|
||||
"Webapps:Uninstall:Return:KO",
|
||||
"Webapps:OfflineCache"]);
|
||||
},
|
||||
|
||||
set onprogress(aCallback) {
|
||||
@ -422,15 +423,14 @@ WebappsApplicationMgmt.prototype = {
|
||||
if (this._oninstall) {
|
||||
let app = msg.app;
|
||||
let event = new this._window.MozApplicationEvent("applicationinstall",
|
||||
{ application : createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
|
||||
app.installOrigin, app.installTime) });
|
||||
{ application : createApplicationObject(this._window, app) });
|
||||
this._oninstall.handleEvent(event);
|
||||
}
|
||||
break;
|
||||
case "Webapps:Uninstall:Return:OK":
|
||||
if (this._onuninstall) {
|
||||
let event = new this._window.MozApplicationEvent("applicationuninstall",
|
||||
{ application : createApplicationObject(this._window, msg.origin, null, null, null, null, 0) });
|
||||
{ application : createApplicationObject(this._window, { origin: msg.origin }) });
|
||||
this._onuninstall.handleEvent(event);
|
||||
}
|
||||
break;
|
||||
|
@ -71,33 +71,46 @@ let DOMApplicationRegistry = {
|
||||
this.appsFile = FileUtils.getFile(DIRECTORY_NAME,
|
||||
["webapps", "webapps.json"], true);
|
||||
|
||||
if (this.appsFile.exists()) {
|
||||
this._loadJSONAsync(this.appsFile, (function(aData) {
|
||||
this.webapps = aData;
|
||||
for (let id in this.webapps) {
|
||||
#ifdef MOZ_SYS_MSG
|
||||
this._processManifestForId(id);
|
||||
let dirList = [DIRECTORY_NAME];
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
dirList.push("coreAppsDir");
|
||||
#endif
|
||||
if (!this.webapps[id].localId) {
|
||||
this.webapps[id].localId = this._nextLocalId();
|
||||
let currentId = 1;
|
||||
dirList.forEach((function(dir) {
|
||||
let curFile = FileUtils.getFile(dir, ["webapps", "webapps.json"], true);
|
||||
if (curFile.exists()) {
|
||||
let appDir = FileUtils.getDir(dir, ["webapps"]);
|
||||
this._loadJSONAsync(curFile, (function(aData) {
|
||||
if (!aData) {
|
||||
return;
|
||||
}
|
||||
// Add new apps to the merged list.
|
||||
for (let id in aData) {
|
||||
this.webapps[id] = aData[id];
|
||||
this.webapps[id].basePath = appDir.path;
|
||||
this.webapps[id].removable = (dir == DIRECTORY_NAME);
|
||||
#ifdef MOZ_SYS_MSG
|
||||
this._processManifestForId(id);
|
||||
#endif
|
||||
// local ids must be stable between restarts.
|
||||
// We partition the ids in two buckets:
|
||||
// - 1 to 1000 for the core apps.
|
||||
// - 1001 to Inf for installed apps.
|
||||
// This way, a gecko update with new core apps will not lead to
|
||||
// changes for installed apps ids.
|
||||
if (!this.webapps[id].removable) {
|
||||
this.webapps[id].localId = currentId++;
|
||||
}
|
||||
|
||||
// Default to a non privileged status.
|
||||
if (this.webapps[id].appStatus === undefined) {
|
||||
this.webapps[id].appStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED;
|
||||
}
|
||||
};
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
try {
|
||||
let hosts = Services.prefs.getCharPref("dom.mozApps.whitelist");
|
||||
hosts.split(",").forEach(function(aHost) {
|
||||
Services.perms.add(Services.io.newURI(aHost, null, null),
|
||||
"webapps-manage",
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
});
|
||||
} catch(e) { }
|
||||
// Default to a non privileged status.
|
||||
if (this.webapps[id].appStatus === undefined) {
|
||||
this.webapps[id].appStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED;
|
||||
}
|
||||
};
|
||||
}).bind(this));
|
||||
}
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
#ifdef MOZ_SYS_MSG
|
||||
@ -254,7 +267,7 @@ let DOMApplicationRegistry = {
|
||||
this.installPackage(msg);
|
||||
break;
|
||||
case "Webapps:GetBasePath":
|
||||
return FileUtils.getFile(DIRECTORY_NAME, ["webapps"], true).path;
|
||||
return this.webapps[msg.id].basePath;
|
||||
break;
|
||||
case "Webapps:GetList":
|
||||
this.children.push(aMessage.target);
|
||||
@ -262,6 +275,10 @@ let DOMApplicationRegistry = {
|
||||
}
|
||||
},
|
||||
|
||||
_getAppDir: function(aId) {
|
||||
return FileUtils.getDir(DIRECTORY_NAME, ["webapps", aId], true, true);
|
||||
},
|
||||
|
||||
_writeFile: function ss_writeFile(aFile, aData, aCallbak) {
|
||||
// Initialize the file output stream.
|
||||
let ostream = FileUtils.openSafeFileOutputStream(aFile);
|
||||
@ -294,12 +311,13 @@ let DOMApplicationRegistry = {
|
||||
|
||||
confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
|
||||
let app = aData.app;
|
||||
app.removable = true;
|
||||
let id = app.syncId || this._appId(app.origin);
|
||||
let localId = this.getAppLocalIdByManifestURL(app.manifestURL);
|
||||
|
||||
// Installing an application again is considered as an update.
|
||||
if (id) {
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
let dir = this._getAppDir(id);
|
||||
try {
|
||||
dir.remove(true);
|
||||
} catch(e) {
|
||||
@ -375,7 +393,8 @@ let DOMApplicationRegistry = {
|
||||
},
|
||||
|
||||
_nextLocalId: function() {
|
||||
let maxLocalId = Ci.nsIScriptSecurityManager.NO_APP_ID;
|
||||
// All installed apps have a localId > 1000.
|
||||
let maxLocalId = 1000;
|
||||
|
||||
for (let id in this.webapps) {
|
||||
if (this.webapps[id].localId > maxLocalId) {
|
||||
@ -419,9 +438,10 @@ let DOMApplicationRegistry = {
|
||||
let id = aData[index].id;
|
||||
|
||||
// the manifest file used to be named manifest.json, so fallback on this.
|
||||
let file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", id, "manifest.webapp"], true);
|
||||
let baseDir = (this.webapps[id].removable ? DIRECTORY_NAME : "coreAppsDir");
|
||||
let file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.webapp"], true);
|
||||
if (!file.exists()) {
|
||||
file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", id, "manifest.json"], true);
|
||||
file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.json"], true);
|
||||
}
|
||||
|
||||
this._loadJSONAsync(file, (function(aJSON) {
|
||||
@ -598,6 +618,9 @@ let DOMApplicationRegistry = {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.webapps[id].removable)
|
||||
return;
|
||||
|
||||
found = true;
|
||||
let appNote = JSON.stringify(AppsUtils.cloneAppObject(app));
|
||||
appNote.id = id;
|
||||
@ -608,7 +631,7 @@ let DOMApplicationRegistry = {
|
||||
#endif
|
||||
}).bind(this));
|
||||
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
let dir = this._getAppDir(id);
|
||||
try {
|
||||
dir.remove(true);
|
||||
} catch (e) {}
|
||||
@ -748,6 +771,10 @@ let DOMApplicationRegistry = {
|
||||
return AppsUtils.getAppLocalIdByManifestURL(this.webapps, aManifestURL);
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function(aMessage) {
|
||||
return AppsUtils.getAppFromObserverMessage(this.webapps, aMessage);
|
||||
},
|
||||
|
||||
getAllWithoutManifests: function(aCallback) {
|
||||
let result = {};
|
||||
for (let id in this.webapps) {
|
||||
@ -761,11 +788,11 @@ let DOMApplicationRegistry = {
|
||||
for (let i = 0; i < aRecords.length; i++) {
|
||||
let record = aRecords[i];
|
||||
if (record.hidden) {
|
||||
if (!this.webapps[record.id])
|
||||
if (!this.webapps[record.id] || !this.webapps[record.id].removable)
|
||||
continue;
|
||||
let origin = this.webapps[record.id].origin;
|
||||
delete this.webapps[record.id];
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", record.id], true, true);
|
||||
let dir = this._getAppDir(record.id);
|
||||
try {
|
||||
dir.remove(true);
|
||||
} catch (e) {
|
||||
@ -798,8 +825,12 @@ let DOMApplicationRegistry = {
|
||||
wipe: function(aCallback) {
|
||||
let ids = this.getAllIDs();
|
||||
for (let id in ids) {
|
||||
if (!this.webapps[id].removable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete this.webapps[id];
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
let dir = this._getAppDir(id);
|
||||
try {
|
||||
dir.remove(true);
|
||||
} catch (e) {
|
||||
|
@ -61,6 +61,11 @@
|
||||
|
||||
DOMInterfaces = {
|
||||
|
||||
'mozAudioContext': {
|
||||
'nativeType': 'AudioContext',
|
||||
'prefable': True,
|
||||
},
|
||||
|
||||
'Blob': [
|
||||
{
|
||||
'headerFile': 'nsIDOMFile.h',
|
||||
|
@ -23,10 +23,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "mRIL", function () {
|
||||
return Cc["@mozilla.org/telephony/system-worker-manager;1"].getService(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIRadioInterfaceLayer);
|
||||
});
|
||||
|
||||
const nsIClassInfo = Ci.nsIClassInfo;
|
||||
const CONTACTPROPERTIES_CID = Components.ID("{f5181640-89e8-11e1-b0c4-0800200c9a66}");
|
||||
const nsIDOMContactProperties = Ci.nsIDOMContactProperties;
|
||||
@ -372,9 +368,10 @@ ContactManager.prototype = {
|
||||
let msg = aMessage.json;
|
||||
let contacts = msg.contacts;
|
||||
|
||||
let req;
|
||||
switch (aMessage.name) {
|
||||
case "Contacts:Find:Return:OK":
|
||||
let req = this.getRequest(msg.requestID);
|
||||
req = this.getRequest(msg.requestID);
|
||||
if (req) {
|
||||
let result = this._convertContactsArray(contacts);
|
||||
Services.DOMRequest.fireSuccess(req.request, result);
|
||||
@ -382,6 +379,20 @@ ContactManager.prototype = {
|
||||
if (DEBUG) debug("no request stored!" + msg.requestID);
|
||||
}
|
||||
break;
|
||||
case "Contacts:GetSimContacts:Return:OK":
|
||||
req = this.getRequest(msg.requestID);
|
||||
if (req) {
|
||||
let result = contacts.map(function(c) {
|
||||
let contact = new Contact();
|
||||
contact.init( { name: [c.alphaId], tel: [ { value: c.number } ] } );
|
||||
return contact;
|
||||
});
|
||||
if (DEBUG) debug("result: " + JSON.stringify(result));
|
||||
Services.DOMRequest.fireSuccess(req.request, result);
|
||||
} else {
|
||||
if (DEBUG) debug("no request stored!" + msg.requestID);
|
||||
}
|
||||
break;
|
||||
case "Contact:Save:Return:OK":
|
||||
case "Contacts:Clear:Return:OK":
|
||||
case "Contact:Remove:Return:OK":
|
||||
@ -542,21 +553,13 @@ ContactManager.prototype = {
|
||||
getSimContacts: function(aType) {
|
||||
let request;
|
||||
request = this.createRequest();
|
||||
let options = {type: aType};
|
||||
|
||||
let allowCallback = function() {
|
||||
let callback = function(aType, aContacts) {
|
||||
if (DEBUG) debug("got SIM contacts: " + aType + " " + JSON.stringify(aContacts));
|
||||
let result = aContacts.map(function(c) {
|
||||
var contact = new Contact();
|
||||
contact.init( { name: [c.alphaId], tel: [ { value: c.number } ] } );
|
||||
return contact;
|
||||
});
|
||||
if (DEBUG) debug("result: " + JSON.stringify(result));
|
||||
Services.DOMRequest.fireSuccess(request, result);
|
||||
};
|
||||
if (DEBUG) debug("getSimContacts " + aType);
|
||||
|
||||
mRIL.getICCContacts(aType, callback);
|
||||
cpmm.sendAsyncMessage("Contacts:GetSimContacts",
|
||||
{requestID: this.getRequestId({request: request, reason: "getSimContacts"}),
|
||||
options: options});
|
||||
}.bind(this);
|
||||
|
||||
let cancelCallback = function() {
|
||||
@ -575,6 +578,7 @@ ContactManager.prototype = {
|
||||
"Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO",
|
||||
"Contact:Save:Return:OK", "Contact:Save:Return:KO",
|
||||
"Contact:Remove:Return:OK", "Contact:Remove:Return:KO",
|
||||
"Contacts:GetSimContacts:Return:OK",
|
||||
"PermissionPromptHelper:AskPermission:OK"]);
|
||||
},
|
||||
|
||||
|
@ -109,7 +109,7 @@ ContactDB.prototype = {
|
||||
// Upgrade existing email field in the DB.
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor && cursor.value.properties.email) {
|
||||
if (DEBUG) debug("upgrade email1: " + JSON.stringify(cursor.value));
|
||||
cursor.value.properties.email =
|
||||
cursor.value.properties.email.map(function(address) { return { address: address }; });
|
||||
@ -131,7 +131,7 @@ ContactDB.prototype = {
|
||||
// Upgrade existing impp field in the DB.
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor && cursor.value.properties.impp) {
|
||||
if (DEBUG) debug("upgrade impp1: " + JSON.stringify(cursor.value));
|
||||
cursor.value.properties.impp =
|
||||
cursor.value.properties.impp.map(function(value) { return { value: value }; });
|
||||
@ -143,7 +143,7 @@ ContactDB.prototype = {
|
||||
// Upgrade existing url field in the DB.
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor && cursor.value.properties.url) {
|
||||
if (DEBUG) debug("upgrade url1: " + JSON.stringify(cursor.value));
|
||||
cursor.value.properties.url =
|
||||
cursor.value.properties.url.map(function(value) { return { value: value }; });
|
||||
|
@ -21,12 +21,18 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageListenerManager");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "mRIL", function () {
|
||||
return Cc["@mozilla.org/telephony/system-worker-manager;1"].
|
||||
getService(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIRadioInterfaceLayer);
|
||||
});
|
||||
|
||||
let myGlobal = this;
|
||||
|
||||
let DOMContactManager = {
|
||||
init: function() {
|
||||
if (DEBUG) debug("Init");
|
||||
this._messages = ["Contacts:Find", "Contacts:Clear", "Contact:Save", "Contact:Remove"];
|
||||
this._messages = ["Contacts:Find", "Contacts:Clear", "Contact:Save", "Contact:Remove", "Contacts:GetSimContacts"];
|
||||
this._messages.forEach((function(msgName) {
|
||||
ppmm.addMessageListener(msgName, this);
|
||||
}).bind(this));
|
||||
@ -141,6 +147,14 @@ let DOMContactManager = {
|
||||
function() { mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID }); }.bind(this),
|
||||
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
|
||||
);
|
||||
break;
|
||||
case "Contacts:GetSimContacts":
|
||||
let callback = function(aType, aContacts) {
|
||||
if (DEBUG) debug("got SIM contacts: " + aType + " " + JSON.stringify(aContacts));
|
||||
mm.sendAsyncMessage("Contacts:GetSimContacts:Return:OK", {requestID: msg.requestID, contacts: aContacts});
|
||||
};
|
||||
mRIL.getICCContacts(msg.options.type, callback);
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) debug("WRONG MESSAGE NAME: " + aMessage.name);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ DOM_SRCDIRS = \
|
||||
content/base/src \
|
||||
content/html/content/src \
|
||||
content/html/document/src \
|
||||
content/media/webaudio \
|
||||
content/svg/content/src \
|
||||
layout/generic \
|
||||
layout/style \
|
||||
|
@ -494,7 +494,6 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
|
||||
|
||||
mozilla::dom::IDBObjectStoreParameters params;
|
||||
KeyPath keyPath(0);
|
||||
nsTArray<nsString> keyPathArray;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
|
@ -2331,7 +2331,7 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
|
||||
}
|
||||
|
||||
if (params.multiEntry && keyPath.IsArray()) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
}
|
||||
|
||||
DatabaseInfo* databaseInfo = mTransaction->DBInfo();
|
||||
|
@ -44,6 +44,7 @@ function testSteps()
|
||||
{ keyPath: "foo.2.bar", exception: true },
|
||||
{ keyPath: "foo. .bar", exception: true },
|
||||
{ keyPath: ".bar", exception: true },
|
||||
{ keyPath: [], exception: true },
|
||||
|
||||
{ keyPath: ["foo", "bar"], value: { foo: 1, bar: 2 }, key: [1, 2] },
|
||||
{ keyPath: ["foo"], value: { foo: 1, bar: 2 }, key: [1] },
|
||||
@ -260,18 +261,6 @@ function testSteps()
|
||||
"expected value stored" + test);
|
||||
}
|
||||
|
||||
// Can't handle autoincrement and empty keypath
|
||||
try {
|
||||
store = db.createObjectStore("storefail", { keyPath: "", autoIncrement: true });
|
||||
ok(false, "Should have thrown when creating empty-keypath autoincrement store");
|
||||
}
|
||||
catch(e) {
|
||||
ok(true, "Did throw when creating empty-keypath autoincrement store");
|
||||
is(e.name, "InvalidAccessError", "expect an InvalidAccessError when creating empty-keypath autoincrement store");
|
||||
ok(e instanceof DOMException, "Got a DOMException when creating empty-keypath autoincrement store");
|
||||
is(e.code, DOMException.INVALID_ACCESS_ERR, "expect an INVALID_ACCESS_ERR when creating empty-keypath autoincrement store");
|
||||
}
|
||||
|
||||
openRequest.onsuccess = grabEventAndContinueHandler;
|
||||
yield;
|
||||
|
||||
|
@ -42,24 +42,20 @@ function testSteps()
|
||||
ok(true, "createIndex with no keyPath should throw");
|
||||
}
|
||||
|
||||
let ex;
|
||||
try {
|
||||
request = objectStore.createIndex("Hola", ["foo"], { multiEntry: true });
|
||||
ok(false, "createIndex with array keyPath and multiEntry should throw");
|
||||
objectStore.createIndex("Hola", ["foo"], { multiEntry: true });
|
||||
}
|
||||
catch(e) {
|
||||
ok(true, "createIndex with array keyPath and multiEntry should throw");
|
||||
ex = e;
|
||||
}
|
||||
ok(ex, "createIndex with array keyPath and multiEntry should throw");
|
||||
is(ex.name, "InvalidAccessError", "should throw right exception");
|
||||
ok(ex instanceof DOMException, "should throw right exception");
|
||||
is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception");
|
||||
|
||||
try {
|
||||
request = objectStore.createIndex("Hola", []);
|
||||
ok(false, "createIndex with empty array keyPath should throw");
|
||||
}
|
||||
catch(e) {
|
||||
ok(true, "createIndex with empty array keyPath should throw");
|
||||
}
|
||||
|
||||
try {
|
||||
request = objectStore.createIndex("foo", "bar", 10);
|
||||
objectStore.createIndex("foo", "bar", 10);
|
||||
ok(false, "createIndex with bad options should throw");
|
||||
}
|
||||
catch(e) {
|
||||
|
@ -99,6 +99,32 @@ function testSteps()
|
||||
is(found, true, "transaction has correct objectStoreNames list");
|
||||
}
|
||||
|
||||
// Can't handle autoincrement and empty keypath
|
||||
let ex;
|
||||
try {
|
||||
db.createObjectStore("storefail", { keyPath: "", autoIncrement: true });
|
||||
}
|
||||
catch(e) {
|
||||
ex = e;
|
||||
}
|
||||
ok(ex, "createObjectStore with empty keyPath and autoIncrement should throw");
|
||||
is(ex.name, "InvalidAccessError", "should throw right exception");
|
||||
ok(ex instanceof DOMException, "should throw right exception");
|
||||
is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception");
|
||||
|
||||
// Can't handle autoincrement and array keypath
|
||||
let ex;
|
||||
try {
|
||||
db.createObjectStore("storefail", { keyPath: ["a"], autoIncrement: true });
|
||||
}
|
||||
catch(e) {
|
||||
ex = e;
|
||||
}
|
||||
ok(ex, "createObjectStore with array keyPath and autoIncrement should throw");
|
||||
is(ex.name, "InvalidAccessError", "should throw right exception");
|
||||
ok(ex instanceof DOMException, "should throw right exception");
|
||||
is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception");
|
||||
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
|
||||
@ -106,4 +132,4 @@ function testSteps()
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
* We expose Gecko-internal helpers related to "web apps" through this
|
||||
* sub-interface.
|
||||
*/
|
||||
[scriptable, uuid(acf46a46-729a-4ab4-9da3-8d59ecfd103d)]
|
||||
[scriptable, uuid(764e8930-ff06-4f23-9a6a-8523b93ac09f)]
|
||||
interface mozIApplication: mozIDOMApplication
|
||||
{
|
||||
/* Return true if this app has |permission|. */
|
||||
@ -19,4 +19,7 @@ interface mozIApplication: mozIDOMApplication
|
||||
|
||||
/* Application status as defined in nsIPrincipal. */
|
||||
readonly attribute unsigned short appStatus;
|
||||
|
||||
/* Returns the local id of the app (not the uuid used for sync). */
|
||||
readonly attribute unsigned long localId;
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface mozIDOMApplication;
|
||||
interface mozIApplication;
|
||||
|
||||
%{C++
|
||||
#define APPS_SERVICE_CID { 0x05072afa, 0x92fe, 0x45bf, { 0xae, 0x22, 0x39, 0xb6, 0x9c, 0x11, 0x70, 0x58 } }
|
||||
@ -15,7 +16,7 @@ interface mozIDOMApplication;
|
||||
* This service allows accessing some DOMApplicationRegistry methods from
|
||||
* non-javascript code.
|
||||
*/
|
||||
[scriptable, uuid(04e4ef3c-1a30-45bc-ab08-291820f13872)]
|
||||
[scriptable, uuid(1f0ec00c-57c7-4ad2-a648-1359aa390360)]
|
||||
interface nsIAppsService : nsISupports
|
||||
{
|
||||
mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
|
||||
@ -37,4 +38,11 @@ interface nsIAppsService : nsISupports
|
||||
* Returns the manifest URL associated to this localId.
|
||||
*/
|
||||
DOMString getManifestURLByLocalId(in unsigned long localId);
|
||||
|
||||
/**
|
||||
* Returns the app that is related to the message.
|
||||
* This is a helper to not have to worry about what is the actual structure
|
||||
* of the message when listening to one.
|
||||
*/
|
||||
mozIApplication getAppFromObserverMessage(in DOMString message);
|
||||
};
|
||||
|
@ -8,7 +8,7 @@
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, uuid(9583b825-46b1-4e8f-bb48-9fed660a95e6)]
|
||||
[scriptable, uuid(e3649c1d-c950-495e-b0ed-6ce40be9743b)]
|
||||
interface mozIDOMApplication : nsISupports
|
||||
{
|
||||
readonly attribute jsval manifest;
|
||||
@ -17,6 +17,7 @@ interface mozIDOMApplication : nsISupports
|
||||
readonly attribute DOMString origin;
|
||||
readonly attribute DOMString installOrigin;
|
||||
readonly attribute unsigned long long installTime;
|
||||
readonly attribute boolean removable;
|
||||
|
||||
/*
|
||||
* The current progress when downloading an offline cache.
|
||||
|
@ -41,31 +41,14 @@ function SystemMessageInternal() {
|
||||
|
||||
SystemMessageInternal.prototype = {
|
||||
sendMessage: function sendMessage(aType, aMessage, aPageURI, aManifestURI) {
|
||||
debug("Broadcasting " + aType + " " + JSON.stringify(aMessage));
|
||||
ppmm.broadcastAsyncMessage("SystemMessageManager:Message" , { type: aType,
|
||||
msg: aMessage,
|
||||
manifest: aManifestURI.spec });
|
||||
this._sendMessage(aType, aMessage, aPageURI.spec, aManifestURI.spec);
|
||||
},
|
||||
|
||||
// Queue the message for pages that registered an handler for this type.
|
||||
this._pages.forEach(function sendMess_openPage(aPage) {
|
||||
if (aPage.type != aType ||
|
||||
aPage.manifest != aManifestURI.spec ||
|
||||
aPage.uri != aPageURI.spec) {
|
||||
return;
|
||||
broadcastMessage: function broadcastMessage(aType, aMessage) {
|
||||
this._pages.forEach(function(aPage) {
|
||||
if (aPage.type == aType) {
|
||||
this._sendMessage(aType, aMessage, aPage.uri, aPage.manifest);
|
||||
}
|
||||
|
||||
aPage.pending.push(aMessage);
|
||||
if (aPage.pending.length > kMaxPendingMessages) {
|
||||
aPage.pending.splice(0, 1);
|
||||
}
|
||||
|
||||
// We don't need to send the full object to observers.
|
||||
let page = { uri: aPage.uri,
|
||||
manifest: aPage.manifest,
|
||||
type: aPage.type,
|
||||
target: aMessage.target };
|
||||
debug("Asking to open " + JSON.stringify(page));
|
||||
Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
|
||||
}.bind(this))
|
||||
},
|
||||
|
||||
@ -118,6 +101,35 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_sendMessage: function _sendMessage(aType, aMessage, aPageURI, aManifestURI) {
|
||||
debug("Broadcasting " + aType + " " + JSON.stringify(aMessage));
|
||||
ppmm.broadcastAsyncMessage("SystemMessageManager:Message" , { type: aType,
|
||||
msg: aMessage,
|
||||
manifest: aManifestURI });
|
||||
|
||||
// Queue the message for pages that registered an handler for this type.
|
||||
this._pages.forEach(function sendMess_openPage(aPage) {
|
||||
if (aPage.type != aType ||
|
||||
aPage.manifest != aManifestURI ||
|
||||
aPage.uri != aPageURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
aPage.pending.push(aMessage);
|
||||
if (aPage.pending.length > kMaxPendingMessages) {
|
||||
aPage.pending.splice(0, 1);
|
||||
}
|
||||
|
||||
// We don't need to send the full object to observers.
|
||||
let page = { uri: aPage.uri,
|
||||
manifest: aPage.manifest,
|
||||
type: aPage.type,
|
||||
target: aMessage.target };
|
||||
debug("Asking to open " + JSON.stringify(page));
|
||||
Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
|
||||
}.bind(this))
|
||||
},
|
||||
|
||||
classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver])
|
||||
|
@ -9,7 +9,7 @@ interface nsIDOMWindow;
|
||||
|
||||
// Implemented by the contract id @mozilla.org/system-message-internal;1
|
||||
|
||||
[scriptable, uuid(3a50fd6b-0263-45c1-b738-a002052ad31b)]
|
||||
[scriptable, uuid(d8de761a-94fe-44d5-80eb-3c8bd8cd7d0b)]
|
||||
interface nsISystemMessagesInternal : nsISupports
|
||||
{
|
||||
/*
|
||||
@ -21,6 +21,14 @@ interface nsISystemMessagesInternal : nsISupports
|
||||
*/
|
||||
void sendMessage(in DOMString type, in jsval message, in nsIURI pageURI, in nsIURI manifestURI);
|
||||
|
||||
/*
|
||||
* Allow any internal user to broadcast a message of a given type.
|
||||
* The application that registers the message will be launched.
|
||||
* @param type The type of the message to be sent.
|
||||
* @param message The message payload.
|
||||
*/
|
||||
void broadcastMessage(in DOMString type, in jsval message);
|
||||
|
||||
/*
|
||||
* Registration of a page that wants to be notified of a message type.
|
||||
* @param type The message type.
|
||||
|
@ -4,8 +4,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
interface nsIDOMMimeType;
|
||||
|
||||
[scriptable, uuid(a361a7e7-7f8d-4b68-91e9-30ae096460d4)]
|
||||
[scriptable, uuid(b8bf0a06-e395-4f44-af39-a51d3e7ef4b9)]
|
||||
interface nsIPluginTag : nsISupports
|
||||
{
|
||||
readonly attribute AUTF8String description;
|
||||
@ -16,4 +17,6 @@ interface nsIPluginTag : nsISupports
|
||||
attribute boolean disabled;
|
||||
attribute boolean blocklisted;
|
||||
attribute boolean clicktoplay;
|
||||
void getMimeTypes([optional] out unsigned long aCount,
|
||||
[retval, array, size_is(aCount)] out nsIDOMMimeType aResults);
|
||||
};
|
||||
|
@ -1373,55 +1373,6 @@ nsPluginHost::IsPluginEnabledForExtension(const char* aExtension,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
class DOMMimeTypeImpl : public nsIDOMMimeType {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
DOMMimeTypeImpl(nsPluginTag* aTag, uint32_t aMimeTypeIndex)
|
||||
{
|
||||
if (!aTag)
|
||||
return;
|
||||
CopyUTF8toUTF16(aTag->mMimeDescriptions[aMimeTypeIndex], mDescription);
|
||||
CopyUTF8toUTF16(aTag->mExtensions[aMimeTypeIndex], mSuffixes);
|
||||
CopyUTF8toUTF16(aTag->mMimeTypes[aMimeTypeIndex], mType);
|
||||
}
|
||||
|
||||
virtual ~DOMMimeTypeImpl() {
|
||||
}
|
||||
|
||||
NS_METHOD GetDescription(nsAString& aDescription)
|
||||
{
|
||||
aDescription.Assign(mDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin)
|
||||
{
|
||||
// this has to be implemented by the DOM version.
|
||||
*aEnabledPlugin = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD GetSuffixes(nsAString& aSuffixes)
|
||||
{
|
||||
aSuffixes.Assign(mSuffixes);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD GetType(nsAString& aType)
|
||||
{
|
||||
aType.Assign(mType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mDescription;
|
||||
nsString mSuffixes;
|
||||
nsString mType;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType)
|
||||
|
||||
class DOMPluginImpl : public nsIDOMPlugin {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsIPlatformCharset.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
#include "nsIDOMMimeType.h"
|
||||
#include "nsPluginLogging.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
@ -33,6 +34,8 @@ inline char* new_str(const char* str)
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType)
|
||||
|
||||
/* nsPluginTag */
|
||||
|
||||
nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
|
||||
@ -344,6 +347,25 @@ nsPluginTag::SetClicktoplay(bool aClicktoplay)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPluginTag::GetMimeTypes(uint32_t* aCount, nsIDOMMimeType*** aResults)
|
||||
{
|
||||
uint32_t count = mMimeTypes.Length();
|
||||
*aResults = static_cast<nsIDOMMimeType**>
|
||||
(nsMemory::Alloc(count * sizeof(**aResults)));
|
||||
if (!*aResults)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
*aCount = count;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
nsIDOMMimeType* mimeType = new DOMMimeTypeImpl(this, i);
|
||||
(*aResults)[i] = mimeType;
|
||||
NS_ADDREF((*aResults)[i]);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsPluginTag::Mark(uint32_t mask)
|
||||
{
|
||||
bool wasEnabled = IsEnabled();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIDOMMimeType.h"
|
||||
|
||||
class nsPluginHost;
|
||||
struct PRLibrary;
|
||||
@ -87,4 +88,50 @@ private:
|
||||
nsresult EnsureMembersAreUTF8();
|
||||
};
|
||||
|
||||
class DOMMimeTypeImpl : public nsIDOMMimeType {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
DOMMimeTypeImpl(nsPluginTag* aTag, PRUint32 aMimeTypeIndex)
|
||||
{
|
||||
if (!aTag)
|
||||
return;
|
||||
CopyUTF8toUTF16(aTag->mMimeDescriptions[aMimeTypeIndex], mDescription);
|
||||
CopyUTF8toUTF16(aTag->mExtensions[aMimeTypeIndex], mSuffixes);
|
||||
CopyUTF8toUTF16(aTag->mMimeTypes[aMimeTypeIndex], mType);
|
||||
}
|
||||
|
||||
virtual ~DOMMimeTypeImpl() {
|
||||
}
|
||||
|
||||
NS_METHOD GetDescription(nsAString& aDescription)
|
||||
{
|
||||
aDescription.Assign(mDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin)
|
||||
{
|
||||
// this has to be implemented by the DOM version.
|
||||
*aEnabledPlugin = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD GetSuffixes(nsAString& aSuffixes)
|
||||
{
|
||||
aSuffixes.Assign(mSuffixes);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD GetType(nsAString& aType)
|
||||
{
|
||||
aType.Assign(mType);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsString mDescription;
|
||||
nsString mSuffixes;
|
||||
nsString mType;
|
||||
};
|
||||
|
||||
#endif // nsPluginTags_h_
|
||||
|
@ -87,6 +87,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
"@mozilla.org/settingsService;1",
|
||||
"nsISettingsService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
|
||||
"@mozilla.org/system-message-internal;1",
|
||||
"nsISystemMessagesInternal");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "WAP", function () {
|
||||
let WAP = {};
|
||||
Cu.import("resource://gre/modules/WapPushManager.js", WAP);
|
||||
@ -758,6 +762,11 @@ RadioInterfaceLayer.prototype = {
|
||||
handleCallStateChange: function handleCallStateChange(call) {
|
||||
debug("handleCallStateChange: " + JSON.stringify(call));
|
||||
call.state = convertRILCallState(call.state);
|
||||
|
||||
if (call.state == nsIRadioInterfaceLayer.CALL_STATE_INCOMING) {
|
||||
gSystemMessenger.broadcastMessage("telephony-incoming", {number: call.number});
|
||||
}
|
||||
|
||||
if (call.isActive) {
|
||||
this._activeCall = call;
|
||||
} else if (this._activeCall &&
|
||||
@ -1033,6 +1042,7 @@ RadioInterfaceLayer.prototype = {
|
||||
|
||||
handleStkProactiveCommand: function handleStkProactiveCommand(message) {
|
||||
debug("handleStkProactiveCommand " + JSON.stringify(message));
|
||||
gSystemMessenger.broadcastMessage("icc-stkcommand", message);
|
||||
ppmm.broadcastAsyncMessage("RIL:StkCommand", message);
|
||||
},
|
||||
|
||||
@ -1730,20 +1740,9 @@ RadioInterfaceLayer.prototype = {
|
||||
}
|
||||
let requestId = Math.floor(Math.random() * 1000);
|
||||
this._contactsCallbacks[requestId] = callback;
|
||||
|
||||
let msgType;
|
||||
switch (type) {
|
||||
case "ADN":
|
||||
msgType = "getPBR";
|
||||
break;
|
||||
case "FDN":
|
||||
msgType = "getFDN";
|
||||
break;
|
||||
default:
|
||||
debug("Unknown contact type. " + type);
|
||||
return;
|
||||
}
|
||||
this.worker.postMessage({rilMessageType: msgType, requestId: requestId});
|
||||
this.worker.postMessage({rilMessageType: "getICCContacts",
|
||||
type: type,
|
||||
requestId: requestId});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,18 @@
|
||||
# limitations under the License.
|
||||
|
||||
# RadioInterfaceLayer.js
|
||||
#
|
||||
# IMPORTANT:
|
||||
# Users of nsIRadioInterfaceLayer should invoke
|
||||
# nsIInterfaceRequestor::GetInterface() as implemented by
|
||||
# "@mozilla.org/telephony/system-worker-manager;1" to
|
||||
# obtain the instance.
|
||||
#
|
||||
# DO NOT use do_CreateInstance()/do_GetService() to directly
|
||||
# instantiate "@mozilla.org/ril;1".
|
||||
#
|
||||
component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js
|
||||
contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea}
|
||||
|
||||
# RILContentHelper.js
|
||||
component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIRadioInterfaceLayer.h"
|
||||
#include "nsINetworkManager.h"
|
||||
#include "nsIWifi.h"
|
||||
#include "nsIWorkerHolder.h"
|
||||
@ -52,7 +51,6 @@ using namespace mozilla::system;
|
||||
|
||||
namespace {
|
||||
|
||||
NS_DEFINE_CID(kRadioInterfaceLayerCID, NS_RADIOINTERFACELAYER_CID);
|
||||
NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
|
||||
NS_DEFINE_CID(kNetworkManagerCID, NS_NETWORKMANAGER_CID);
|
||||
|
||||
@ -414,7 +412,7 @@ SystemWorkerManager::Shutdown()
|
||||
|
||||
StopRil();
|
||||
|
||||
mRILWorker = nullptr;
|
||||
mRIL = nullptr;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
StopNetd();
|
||||
@ -469,8 +467,8 @@ SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult)
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIRadioInterfaceLayer))) {
|
||||
return CallQueryInterface(mRILWorker,
|
||||
reinterpret_cast<nsIRadioInterfaceLayer**>(aResult));
|
||||
NS_IF_ADDREF(*reinterpret_cast<nsIRadioInterfaceLayer**>(aResult) = mRIL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIWifi))) {
|
||||
@ -495,34 +493,37 @@ SystemWorkerManager::InitRIL(JSContext *cx)
|
||||
// We're keeping as much of this implementation as possible in JS, so the real
|
||||
// worker lives in RadioInterfaceLayer.js. All we do here is hold it alive and
|
||||
// hook it up to the RIL thread.
|
||||
nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kRadioInterfaceLayerCID);
|
||||
NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIRadioInterfaceLayer> ril = do_CreateInstance("@mozilla.org/ril;1");
|
||||
NS_ENSURE_TRUE(ril, NS_ERROR_FAILURE);
|
||||
|
||||
jsval workerval;
|
||||
nsresult rv = worker->GetWorker(&workerval);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIWorkerHolder> worker = do_QueryInterface(ril);
|
||||
if (worker) {
|
||||
jsval workerval;
|
||||
nsresult rv = worker->GetWorker(&workerval);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(workerval), NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(workerval), NS_ERROR_UNEXPECTED);
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(workerval));
|
||||
JSAutoRequest ar(cx);
|
||||
JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(workerval));
|
||||
|
||||
WorkerCrossThreadDispatcher *wctd =
|
||||
GetWorkerCrossThreadDispatcher(cx, workerval);
|
||||
if (!wctd) {
|
||||
return NS_ERROR_FAILURE;
|
||||
WorkerCrossThreadDispatcher *wctd =
|
||||
GetWorkerCrossThreadDispatcher(cx, workerval);
|
||||
if (!wctd) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
|
||||
if (!wctd->PostTask(connection)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Now that we're set up, connect ourselves to the RIL thread.
|
||||
mozilla::RefPtr<RILReceiver> receiver = new RILReceiver(wctd);
|
||||
StartRil(receiver);
|
||||
}
|
||||
|
||||
nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
|
||||
if (!wctd->PostTask(connection)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Now that we're set up, connect ourselves to the RIL thread.
|
||||
mozilla::RefPtr<RILReceiver> receiver = new RILReceiver(wctd);
|
||||
StartRil(receiver);
|
||||
|
||||
mRILWorker = worker;
|
||||
mRIL = ril;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define mozilla_dom_system_b2g_systemworkermanager_h__
|
||||
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIRadioInterfaceLayer.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@ -60,7 +61,7 @@ private:
|
||||
#endif
|
||||
nsresult InitWifi(JSContext *cx);
|
||||
|
||||
nsCOMPtr<nsIWorkerHolder> mRILWorker;
|
||||
nsCOMPtr<nsIRadioInterfaceLayer> mRIL;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsCOMPtr<nsIWorkerHolder> mNetdWorker;
|
||||
#endif
|
||||
|
@ -582,56 +582,6 @@ let Buf = {
|
||||
* and acts upon state changes accordingly.
|
||||
*/
|
||||
let RIL = {
|
||||
|
||||
/**
|
||||
* One of the RADIO_STATE_* constants.
|
||||
*/
|
||||
radioState: GECKO_RADIOSTATE_UNAVAILABLE,
|
||||
_isInitialRadioState: true,
|
||||
|
||||
/**
|
||||
* ICC status. Keeps a reference of the data response to the
|
||||
* getICCStatus request.
|
||||
*/
|
||||
iccStatus: null,
|
||||
|
||||
/**
|
||||
* Card state
|
||||
*/
|
||||
cardState: null,
|
||||
|
||||
/**
|
||||
* Strings
|
||||
*/
|
||||
IMEI: null,
|
||||
IMEISV: null,
|
||||
SMSC: null,
|
||||
|
||||
/**
|
||||
* ICC information, such as MSISDN, IMSI, ...etc.
|
||||
*/
|
||||
iccInfo: {},
|
||||
|
||||
/**
|
||||
* Application identification for apps in ICC.
|
||||
*/
|
||||
aid: null,
|
||||
|
||||
networkSelectionMode: null,
|
||||
|
||||
voiceRegistrationState: {},
|
||||
dataRegistrationState: {},
|
||||
|
||||
/**
|
||||
* List of strings identifying the network operator.
|
||||
*/
|
||||
operator: null,
|
||||
|
||||
/**
|
||||
* String containing the baseband version.
|
||||
*/
|
||||
basebandVersion: null,
|
||||
|
||||
/**
|
||||
* Valid calls.
|
||||
*/
|
||||
@ -654,21 +604,92 @@ let RIL = {
|
||||
*/
|
||||
_pendingSentSmsMap: {},
|
||||
|
||||
/**
|
||||
* Whether or not the multiple requests in requestNetworkInfo() are currently
|
||||
* being processed
|
||||
*/
|
||||
_processingNetworkInfo: false,
|
||||
initRILState: function initRILState() {
|
||||
/**
|
||||
* One of the RADIO_STATE_* constants.
|
||||
*/
|
||||
this.radioState = GECKO_RADIOSTATE_UNAVAILABLE;
|
||||
this._isInitialRadioState = true;
|
||||
|
||||
/**
|
||||
* Pending messages to be send in batch from requestNetworkInfo()
|
||||
*/
|
||||
_pendingNetworkInfo: {rilMessageType: "networkinfochanged"},
|
||||
/**
|
||||
* ICC status. Keeps a reference of the data response to the
|
||||
* getICCStatus request.
|
||||
*/
|
||||
this.iccStatus = null;
|
||||
|
||||
/**
|
||||
* Mute or unmute the radio.
|
||||
*/
|
||||
_muted: true,
|
||||
/**
|
||||
* Card state
|
||||
*/
|
||||
this.cardState = null;
|
||||
|
||||
/**
|
||||
* Strings
|
||||
*/
|
||||
this.IMEI = null;
|
||||
this.IMEISV = null;
|
||||
this.SMSC = null;
|
||||
|
||||
/**
|
||||
* ICC information, such as MSISDN, IMSI, ...etc.
|
||||
*/
|
||||
this.iccInfo = {};
|
||||
|
||||
/**
|
||||
* Application identification for apps in ICC.
|
||||
*/
|
||||
this.aid = null;
|
||||
|
||||
/**
|
||||
* Application type for apps in ICC.
|
||||
*/
|
||||
this.appType = null,
|
||||
|
||||
this.networkSelectionMode = null;
|
||||
|
||||
this.voiceRegistrationState = {};
|
||||
this.dataRegistrationState = {};
|
||||
|
||||
/**
|
||||
* List of strings identifying the network operator.
|
||||
*/
|
||||
this.operator = null;
|
||||
|
||||
/**
|
||||
* String containing the baseband version.
|
||||
*/
|
||||
this.basebandVersion = null;
|
||||
|
||||
// Clean up this.currentCalls: rild might have restarted.
|
||||
for each (let currentCall in this.currentCalls) {
|
||||
delete this.currentCalls[currentCall.callIndex];
|
||||
this._handleDisconnectedCall(currentCall);
|
||||
}
|
||||
|
||||
// Deactivate this.currentDataCalls: rild might have restarted.
|
||||
for each (let datacall in this.currentDataCalls) {
|
||||
this.deactivateDataCall(datacall);
|
||||
}
|
||||
|
||||
// Don't clean up this._receivedSmsSegmentsMap or this._pendingSentSmsMap
|
||||
// because on rild restart: we may continue with the pending segments.
|
||||
|
||||
/**
|
||||
* Whether or not the multiple requests in requestNetworkInfo() are currently
|
||||
* being processed
|
||||
*/
|
||||
this._processingNetworkInfo = false;
|
||||
|
||||
/**
|
||||
* Pending messages to be send in batch from requestNetworkInfo()
|
||||
*/
|
||||
this._pendingNetworkInfo = {rilMessageType: "networkinfochanged"};
|
||||
|
||||
/**
|
||||
* Mute or unmute the radio.
|
||||
*/
|
||||
this._muted = true;
|
||||
},
|
||||
|
||||
get muted() {
|
||||
return this._muted;
|
||||
},
|
||||
@ -1308,6 +1329,7 @@ let RIL = {
|
||||
function add(contact) {
|
||||
this.iccInfo.adn.push(contact);
|
||||
};
|
||||
|
||||
function finish() {
|
||||
if (DEBUG) {
|
||||
for (let i = 0; i < this.iccInfo.adn.length; i++) {
|
||||
@ -1315,14 +1337,21 @@ let RIL = {
|
||||
" number = " + this.iccInfo.adn[i].number);
|
||||
}
|
||||
}
|
||||
this.sendDOMMessage({rilMessageType: "icccontacts",
|
||||
contactType: "ADN",
|
||||
contacts: this.iccInfo.adn,
|
||||
requestId: options.requestId});
|
||||
options.rilMessageType = "icccontacts";
|
||||
options.contactType = "ADN";
|
||||
options.contacts = this.iccInfo.adn,
|
||||
this.sendDOMMessage(options);
|
||||
};
|
||||
this.parseDiallingNumber(options, add, finish);
|
||||
}
|
||||
|
||||
function error(options) {
|
||||
options.rilMessageType = "icccontacts";
|
||||
options.contactType = "ADN";
|
||||
options.contacts = [];
|
||||
this.sendDOMMessage(options);
|
||||
}
|
||||
|
||||
this.iccInfo.adn = [];
|
||||
this.iccIO({
|
||||
command: ICC_COMMAND_GET_RESPONSE,
|
||||
@ -1335,8 +1364,9 @@ let RIL = {
|
||||
pin2: null,
|
||||
type: EF_TYPE_LINEAR_FIXED,
|
||||
callback: callback,
|
||||
onerror: error
|
||||
loadAll: true,
|
||||
requestId: options.requestId
|
||||
requestId: options.requestId,
|
||||
});
|
||||
},
|
||||
|
||||
@ -1400,7 +1430,33 @@ let RIL = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Get ICC Phonebook.
|
||||
* Get UICC Phonebook.
|
||||
*
|
||||
* @params type
|
||||
* "ADN" or "FDN".
|
||||
*/
|
||||
getICCContacts: function getICCContacts(options) {
|
||||
let type = options.type;
|
||||
switch (type) {
|
||||
case "ADN":
|
||||
switch (this.appType) {
|
||||
case CARD_APPTYPE_SIM:
|
||||
options.fileId = ICC_EF_ADN;
|
||||
this.getADN(options);
|
||||
break;
|
||||
case CARD_APPTYPE_USIM:
|
||||
this.getPBR(options);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "FDN":
|
||||
this.getFDN(options);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get USIM Phonebook.
|
||||
*
|
||||
* @params requestId
|
||||
* Request id from RadioInterfaceLayer.
|
||||
@ -1421,6 +1477,13 @@ let RIL = {
|
||||
Buf.readStringDelimiter(bufLen);
|
||||
}
|
||||
|
||||
function error(options) {
|
||||
options.rilMessageType = "icccontacts";
|
||||
options.contactType = "ADN";
|
||||
options.contacts = [];
|
||||
this.sendDOMMessage(options);
|
||||
}
|
||||
|
||||
this.iccIO({
|
||||
command: ICC_COMMAND_GET_RESPONSE,
|
||||
fileId: ICC_EF_PBR,
|
||||
@ -1432,6 +1495,7 @@ let RIL = {
|
||||
pin2: null,
|
||||
type: EF_TYPE_LINEAR_FIXED,
|
||||
callback: callback,
|
||||
onerror: error,
|
||||
requestId: options.requestId,
|
||||
});
|
||||
},
|
||||
@ -2178,6 +2242,7 @@ let RIL = {
|
||||
}
|
||||
// fetchICCRecords will need to read aid, so read aid here.
|
||||
this.aid = app.aid;
|
||||
this.appType = app.app_type;
|
||||
|
||||
let newCardState;
|
||||
switch (app.app_state) {
|
||||
@ -3115,6 +3180,8 @@ let RIL = {
|
||||
}
|
||||
};
|
||||
|
||||
RIL.initRILState();
|
||||
|
||||
RIL[REQUEST_GET_SIM_STATUS] = function REQUEST_GET_SIM_STATUS(length, options) {
|
||||
if (options.rilRequestError) {
|
||||
return;
|
||||
@ -3503,6 +3570,13 @@ RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options)
|
||||
this[REQUEST_DATA_CALL_LIST](length, options);
|
||||
};
|
||||
RIL[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) {
|
||||
if (!length) {
|
||||
if (options.onerror) {
|
||||
options.onerror.call(this, options);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't need to read rilRequestError since we can know error status from
|
||||
// sw1 and sw2.
|
||||
let sw1 = Buf.readUint32();
|
||||
@ -3515,6 +3589,9 @@ RIL[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) {
|
||||
" command = " + options.command.toString(16) +
|
||||
"(" + sw1.toString(16) + "/" + sw2.toString(16) + ")");
|
||||
}
|
||||
if (options.onerror) {
|
||||
options.onerror.call(this, options);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._processICCIO(options);
|
||||
@ -3992,6 +4069,8 @@ RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) {
|
||||
debug("Detected RIL version " + version);
|
||||
debug("RILQUIRKS_V5_LEGACY is " + RILQUIRKS_V5_LEGACY);
|
||||
}
|
||||
|
||||
this.initRILState();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,8 @@ Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
"webapps-manage",
|
||||
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
SpecialPowers.setCharPref("dom.mozApps.whitelist", "http://mochi.test:8888");
|
||||
SpecialPowers.addPermission("webapps-manage", true, "http://mochi.test:8888");
|
||||
|
||||
SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true);
|
||||
SpecialPowers.setBoolPref('browser.mozApps.installer.dry_run', true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesWhitelist", "http://www.example.com");
|
||||
@ -62,7 +63,7 @@ function mainCommand() {
|
||||
}
|
||||
|
||||
function popup_listener() {
|
||||
debug("here in popup listener");
|
||||
debug("here in popup listener");
|
||||
popupNotifications.panel.addEventListener("popupshown", mainCommand, false);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<script>
|
||||
|
||||
steps = [get_installed_returns_nothing, install_super_crazy, get_self_returns_nothing,
|
||||
steps = [get_installed_returns_nothing, get_self_returns_nothing,
|
||||
install_wild_crazy, uninstall_wild_crazy, tearDown];
|
||||
|
||||
runAll(steps);
|
||||
@ -38,14 +38,6 @@ function get_installed_returns_nothing(next) {
|
||||
next);
|
||||
}
|
||||
|
||||
function install_super_crazy(next) {
|
||||
debug("in " + arguments.callee.name);
|
||||
var appURL = SERVERS['super_crazy'];
|
||||
install(appURL, ok, function() {
|
||||
getInstalled([appURL], ok, next);
|
||||
});
|
||||
}
|
||||
|
||||
function get_self_returns_nothing(next) {
|
||||
debug("in " + arguments.callee.name);
|
||||
mozAppscb(navigator.mozApps.getSelf(),
|
||||
|
16
dom/webidl/AudioContext.webidl
Normal file
16
dom/webidl/AudioContext.webidl
Normal file
@ -0,0 +1,16 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Constructor]
|
||||
interface mozAudioContext {
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ generated_webidl_files = \
|
||||
$(NULL)
|
||||
|
||||
webidl_files = \
|
||||
AudioContext.webidl \
|
||||
CanvasRenderingContext2D.webidl \
|
||||
CSSStyleDeclaration.webidl \
|
||||
Function.webidl \
|
||||
|
@ -301,8 +301,7 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgIR
|
||||
NS_NewURI(getter_AddRefs(bgUri), bgStringValue);
|
||||
NS_ENSURE_TRUE(bgUri, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<imgILoader> il(do_GetService(
|
||||
"@mozilla.org/image/loader;1"));
|
||||
nsCOMPtr<imgILoader> il(do_CreateInstance("@mozilla.org/image/loader;1"));
|
||||
NS_ENSURE_TRUE(il, NS_ERROR_FAILURE);
|
||||
|
||||
return il->LoadImage(bgUri, nullptr, nullptr, principal, nullptr,
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "mozIApplication.h"
|
||||
|
||||
static nsPermissionManager *gPermissionManager = nullptr;
|
||||
|
||||
@ -121,6 +123,33 @@ GetHostForPrincipal(nsIPrincipal* aPrincipal, nsACString& aHost)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class AppUninstallObserver : public nsIObserver {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIObserver implementation.
|
||||
NS_IMETHODIMP
|
||||
Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *data)
|
||||
{
|
||||
MOZ_ASSERT(!nsCRT::strcmp(aTopic, "webapps-uninstall"));
|
||||
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
|
||||
nsCOMPtr<mozIApplication> app;
|
||||
|
||||
appsService->GetAppFromObserverMessage(nsAutoString(data), getter_AddRefs(app));
|
||||
NS_ENSURE_TRUE(app, NS_ERROR_UNEXPECTED);
|
||||
|
||||
uint32_t appId;
|
||||
app->GetLocalId(&appId);
|
||||
MOZ_ASSERT(appId != nsIScriptSecurityManager::NO_APP_ID);
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permManager = do_GetService("@mozilla.org/permissionmanager;1");
|
||||
return permManager->RemovePermissionsForApp(appId);
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(AppUninstallObserver, nsIObserver)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -238,6 +267,13 @@ NS_IMETHODIMP DeleteFromMozHostListener::HandleCompletion(uint16_t aReason)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsPermissionManager::AppUninstallObserverInit()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
|
||||
observerService->AddObserver(new AppUninstallObserver(), "webapps-uninstall", /* holdsWeak= */ false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsPermissionManager Implementation
|
||||
|
||||
@ -1071,6 +1107,85 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
GetPermissionsForAppStruct* data = static_cast<GetPermissionsForAppStruct*>(arg);
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
if (entry->GetKey()->mAppId != data->appId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data->permissions.AppendObject(new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId)
|
||||
{
|
||||
ENSURE_NOT_CHILD_PROCESS;
|
||||
NS_ENSURE_ARG(aAppId != nsIScriptSecurityManager::NO_APP_ID);
|
||||
|
||||
// We begin by removing all the permissions from the DB.
|
||||
// This is not using a mozIStorageStatement because removing an app should be
|
||||
// rare enough to not have to worry too much about performance.
|
||||
// After clearing the DB, we call AddInternal() to make sure that all
|
||||
// processes are aware of this change and the representation of the DB in
|
||||
// memory is updated.
|
||||
// We have to get all permissions associated with an application and then
|
||||
// remove those because doing so in EnumerateEntries() would fail because
|
||||
// we might happen to actually delete entries from the list.
|
||||
|
||||
nsCAutoString sql;
|
||||
sql.AppendLiteral("DELETE FROM moz_hosts WHERE appId=");
|
||||
sql.AppendInt(aAppId);
|
||||
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(sql);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
GetPermissionsForAppStruct data(aAppId);
|
||||
mPermissionTable.EnumerateEntries(GetPermissionsForApp, &data);
|
||||
|
||||
for (int32_t i=0; i<data.permissions.Count(); ++i) {
|
||||
nsCAutoString host;
|
||||
bool isInBrowserElement;
|
||||
nsCAutoString type;
|
||||
|
||||
data.permissions[i]->GetHost(host);
|
||||
data.permissions[i]->GetIsInBrowserElement(&isInBrowserElement);
|
||||
data.permissions[i]->GetType(type);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (NS_FAILED(GetPrincipal(host, aAppId, isInBrowserElement,
|
||||
getter_AddRefs(principal)))) {
|
||||
NS_ERROR("GetPrincipal() failed!");
|
||||
continue;
|
||||
}
|
||||
|
||||
AddInternal(principal,
|
||||
type,
|
||||
nsIPermissionManager::UNKNOWN_ACTION,
|
||||
0,
|
||||
nsIPermissionManager::EXPIRE_NEVER,
|
||||
0,
|
||||
nsPermissionManager::eNotify,
|
||||
nsPermissionManager::eNoDBOperation);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//*** nsPermissionManager private methods
|
||||
//*****************************************************************************
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsPermission.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class nsIPermission;
|
||||
class nsIIDNService;
|
||||
@ -190,6 +191,14 @@ public:
|
||||
NotifyOperationType aNotifyOperation,
|
||||
DBOperationType aDBOperation);
|
||||
|
||||
/**
|
||||
* Initialize the "webapp-uninstall" observing.
|
||||
* Will create a nsPermissionManager instance if needed.
|
||||
* That way, we can prevent have nsPermissionManager created at startup just
|
||||
* to be able to clear data when an application is uninstalled.
|
||||
*/
|
||||
static void AppUninstallObserverInit();
|
||||
|
||||
private:
|
||||
int32_t GetTypeIndex(const char *aTypeString,
|
||||
bool aAdd);
|
||||
@ -237,6 +246,28 @@ private:
|
||||
uint32_t aAppId,
|
||||
bool aIsInBrowserElement);
|
||||
|
||||
/**
|
||||
* This struct has to be passed as an argument to GetPermissionsForApp.
|
||||
* |appId| has to be defined.
|
||||
* |permissions| will be filed with permissions that are related to the app.
|
||||
*/
|
||||
struct GetPermissionsForAppStruct {
|
||||
uint32_t appId;
|
||||
nsCOMArray<nsIPermission> permissions;
|
||||
|
||||
GetPermissionsForAppStruct() MOZ_DELETE;
|
||||
GetPermissionsForAppStruct(uint32_t aAppId)
|
||||
: appId(aAppId)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will return the list of all permissions that are related to a
|
||||
* specific app.
|
||||
* @param arg has to be an instance of GetPermissionsForAppStruct.
|
||||
*/
|
||||
static PLDHashOperator GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg);
|
||||
|
||||
nsCOMPtr<nsIObserverService> mObserverService;
|
||||
nsCOMPtr<nsIIDNService> mIDNService;
|
||||
|
||||
|
@ -54,6 +54,7 @@ MOCHITEST_FILES = \
|
||||
|
||||
MOCHITEST_CHROME_FILES = \
|
||||
test_permissionmanager_app_isolation.html \
|
||||
test_app_uninstall.html \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_BROWSER_FILES = \
|
||||
|
129
extensions/cookie/test/test_app_uninstall.html
Normal file
129
extensions/cookie/test/test_app_uninstall.html
Normal file
@ -0,0 +1,129 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=786296
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests that uninstalling app removes the permissions</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786296">Mozilla Bug 786296</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
/** Test for Bug 786296 **/
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var permManager = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var appsService = Cc['@mozilla.org/AppsService;1']
|
||||
.getService(Ci.nsIAppsService);
|
||||
var secMan = Cc['@mozilla.org/scriptsecuritymanager;1']
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
||||
function confirmNextInstall() {
|
||||
var panel = window.top.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler.ownerDocument.defaultView
|
||||
.PopupNotifications.panel
|
||||
|
||||
panel.addEventListener("popupshown", function() {
|
||||
panel.removeEventListener("popupshown", arguments.callee, false);
|
||||
this.childNodes[0].button.doCommand();
|
||||
}, false);
|
||||
}
|
||||
|
||||
// If aAppId = -1, returns permissions count, regardless of app.
|
||||
function getPermissionCountForApp(aAppId) {
|
||||
var nbPermissions = 0;
|
||||
var enumerator = permManager.enumerator;
|
||||
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var permission = enumerator.getNext().QueryInterface(Ci.nsIPermission);
|
||||
|
||||
if (permission.appId == aAppId || aAppId == -1) {
|
||||
nbPermissions++;
|
||||
}
|
||||
}
|
||||
|
||||
return nbPermissions;
|
||||
}
|
||||
|
||||
var previousDryRunValue = null;
|
||||
try {
|
||||
previousDryRunValue = SpecialPowers.getBoolPref('browser.mozApps.installer.dry_run');
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
SpecialPowers.setBoolPref('browser.mozApps.installer.dry_run', true);
|
||||
permManager.addFromPrincipal(window.document.nodePrincipal, "webapps-manage",
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var gManifestURL = "http://www.example.com:80/chrome/dom/tests/mochitest/webapps/apps/super_crazy.webapp";
|
||||
|
||||
confirmNextInstall();
|
||||
|
||||
navigator.mozApps.install(gManifestURL, null).onsuccess = function() {
|
||||
var testAppId = appsService.getAppLocalIdByManifestURL(gManifestURL);
|
||||
|
||||
is(getPermissionCountForApp(testAppId), 0, "App should have no permission");
|
||||
|
||||
var currentPermissionCount = getPermissionCountForApp(-1);
|
||||
|
||||
var principal = secMan.getAppCodebasePrincipal(ioService.newURI("http://www.example.com", null, null),
|
||||
testAppId, false);
|
||||
|
||||
permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
permManager.addFromPrincipal(principal, "foo", Ci.nsIPermissionManager.DENY_ACTION);
|
||||
permManager.addFromPrincipal(principal, "bar", Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
|
||||
|
||||
principal = secMan.getAppCodebasePrincipal(ioService.newURI("http://www.example.com", null, null),
|
||||
testAppId, true);
|
||||
permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
principal = secMan.getAppCodebasePrincipal(ioService.newURI("http://www.example.org", null, null),
|
||||
testAppId, false);
|
||||
permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
is(getPermissionCountForApp(testAppId), 5, "App should have 5 permissions");
|
||||
|
||||
// Not installed means not installed as native app.
|
||||
navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() {
|
||||
for (i in this.result) {
|
||||
var app = this.result[i];
|
||||
if (app.manifestURL == gManifestURL) {
|
||||
app.uninstall().onsuccess = function() {
|
||||
is(getPermissionCountForApp(testAppId), 0, "App should have no permissions");
|
||||
|
||||
is(getPermissionCountForApp(-1), currentPermissionCount,
|
||||
"Number of permissions should not have changed");
|
||||
|
||||
SpecialPowers.setBoolPref('browser.mozApps.installer.dry_run', previousDryRunValue);
|
||||
permManager.removeFromPrincipal(window.document.nodePrincipal, "webapps-manage",
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -208,7 +208,8 @@ public:
|
||||
kWindowsXP = 0x50001,
|
||||
kWindowsServer2003 = 0x50002,
|
||||
kWindowsVista = 0x60000,
|
||||
kWindows7 = 0x60001
|
||||
kWindows7 = 0x60001,
|
||||
kWindows8 = 0x60002
|
||||
};
|
||||
|
||||
static int32_t WindowsOSVersion(int32_t *aBuildNum = nullptr);
|
||||
|
@ -96,7 +96,7 @@ static nsresult
|
||||
imglib_Initialize()
|
||||
{
|
||||
mozilla::image::DiscardTracker::Initialize();
|
||||
imgLoader::InitCache();
|
||||
imgLoader::GlobalInit();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ interface nsIProperties;
|
||||
* @version 0.1
|
||||
* @see imagelib2
|
||||
*/
|
||||
[scriptable, uuid(f1b74aae-5661-4753-a21c-66dd644afebc)]
|
||||
[scriptable, uuid(b06e0fa5-d6e2-4fa3-8fc0-7775aed96522)]
|
||||
interface imgICache : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -49,4 +49,11 @@ interface imgICache : nsISupports
|
||||
* @returns NULL if the URL was not found in the cache
|
||||
*/
|
||||
nsIProperties findEntryProperties(in nsIURI uri);
|
||||
|
||||
/**
|
||||
* Make this cache instance respect private browsing notifications. This entails clearing
|
||||
* the chrome and content caches whenever the last-pb-context-exited notification is
|
||||
* observed.
|
||||
*/
|
||||
void respectPrivacyNotifications();
|
||||
};
|
||||
|
@ -8,8 +8,11 @@
|
||||
|
||||
interface nsIInputStream;
|
||||
interface imgIContainer;
|
||||
interface imgILoader;
|
||||
interface imgICache;
|
||||
interface nsIDOMDocument;
|
||||
|
||||
[scriptable, uuid(8e16f39e-7012-46bd-aa22-2a7a3265608f)]
|
||||
[scriptable, uuid(53dd1cbe-cb9f-4d9e-8104-1ab72851c88e)]
|
||||
interface imgITools : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -71,6 +74,26 @@ interface imgITools : nsISupports
|
||||
in long aHeight,
|
||||
[optional] in AString outputOptions);
|
||||
|
||||
/**
|
||||
* getImgLoaderForDocument
|
||||
* Retrieve an image loader that reflects the privacy status of the given
|
||||
* document.
|
||||
*
|
||||
* @param doc
|
||||
* A document. Must not be null.
|
||||
*/
|
||||
imgILoader getImgLoaderForDocument(in nsIDOMDocument doc);
|
||||
|
||||
/**
|
||||
* getImgLoaderForDocument
|
||||
* Retrieve an image cache that reflects the privacy status of the given
|
||||
* document.
|
||||
*
|
||||
* @param doc
|
||||
* A document. Must not be null.
|
||||
*/
|
||||
imgICache getImgCacheForDocument(in nsIDOMDocument doc);
|
||||
|
||||
/**
|
||||
* encodeCroppedImage
|
||||
* Caller provides an image container, and the mime type it should be
|
||||
|
@ -50,7 +50,6 @@
|
||||
#include "nsIApplicationCacheContainer.h"
|
||||
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIPrivateBrowsingService.h"
|
||||
|
||||
// we want to explore making the document own the load group
|
||||
// so we can associate the document URI with the load group.
|
||||
@ -58,6 +57,7 @@
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsILoadContext.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
@ -87,8 +87,11 @@ public:
|
||||
{
|
||||
AllSizes chrome;
|
||||
AllSizes content;
|
||||
imgLoader::sChromeCache.EnumerateRead(EntryAllSizes, &chrome);
|
||||
imgLoader::sCache.EnumerateRead(EntryAllSizes, &content);
|
||||
|
||||
for (PRUint32 i = 0; i < mKnownLoaders.Length(); i++) {
|
||||
mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryAllSizes, &chrome);
|
||||
mKnownLoaders[i]->mCache.EnumerateRead(EntryAllSizes, &content);
|
||||
}
|
||||
|
||||
#define REPORT(_path, _kind, _amount, _desc) \
|
||||
do { \
|
||||
@ -155,8 +158,10 @@ public:
|
||||
NS_IMETHOD GetExplicitNonHeap(int64_t *n)
|
||||
{
|
||||
size_t n2 = 0;
|
||||
imgLoader::sChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
|
||||
imgLoader::sCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
|
||||
for (PRUint32 i = 0; i < mKnownLoaders.Length(); i++) {
|
||||
mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
|
||||
mKnownLoaders[i]->mCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
|
||||
}
|
||||
*n = n2;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -164,11 +169,25 @@ public:
|
||||
static int64_t GetImagesContentUsedUncompressed()
|
||||
{
|
||||
size_t n = 0;
|
||||
imgLoader::sCache.EnumerateRead(EntryUsedUncompressedSize, &n);
|
||||
for (PRUint32 i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) {
|
||||
imgLoader::sMemReporter->mKnownLoaders[i]->mCache.EnumerateRead(EntryUsedUncompressedSize, &n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void RegisterLoader(imgLoader* aLoader)
|
||||
{
|
||||
mKnownLoaders.AppendElement(aLoader);
|
||||
}
|
||||
|
||||
void UnregisterLoader(imgLoader* aLoader)
|
||||
{
|
||||
mKnownLoaders.RemoveElement(aLoader);
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<imgLoader*> mKnownLoaders;
|
||||
|
||||
struct AllSizes {
|
||||
size_t mUsedRaw;
|
||||
size_t mUsedUncompressedHeap;
|
||||
@ -339,11 +358,11 @@ nsProgressNotificationProxy::GetInterface(const nsIID& iid,
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
static void NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry,
|
||||
static void NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry, imgLoader* aLoader,
|
||||
imgRequest **aRequest, imgCacheEntry **aEntry)
|
||||
{
|
||||
nsRefPtr<imgRequest> request = new imgRequest();
|
||||
nsRefPtr<imgCacheEntry> entry = new imgCacheEntry(request, aForcePrincipalCheckForCacheEntry);
|
||||
nsRefPtr<imgRequest> request = new imgRequest(aLoader);
|
||||
nsRefPtr<imgCacheEntry> entry = new imgCacheEntry(aLoader, request, aForcePrincipalCheckForCacheEntry);
|
||||
request.forget(aRequest);
|
||||
entry.forget(aEntry);
|
||||
}
|
||||
@ -511,8 +530,9 @@ static uint32_t SecondsFromPRTime(PRTime prTime)
|
||||
return uint32_t(int64_t(prTime) / int64_t(PR_USEC_PER_SEC));
|
||||
}
|
||||
|
||||
imgCacheEntry::imgCacheEntry(imgRequest *request, bool forcePrincipalCheck)
|
||||
: mRequest(request),
|
||||
imgCacheEntry::imgCacheEntry(imgLoader* loader, imgRequest *request, bool forcePrincipalCheck)
|
||||
: mLoader(loader),
|
||||
mRequest(request),
|
||||
mDataSize(0),
|
||||
mTouchedTime(SecondsFromPRTime(PR_Now())),
|
||||
mExpiryTime(0),
|
||||
@ -546,7 +566,7 @@ void imgCacheEntry::UpdateCache(int32_t diff /* = 0 */)
|
||||
if (!Evicted() && HasNoProxies()) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
mRequest->GetURI(getter_AddRefs(uri));
|
||||
imgLoader::CacheEntriesChanged(uri, diff);
|
||||
mLoader->CacheEntriesChanged(uri, diff);
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,8 +726,6 @@ class imgCacheObserver MOZ_FINAL : public nsIObserver
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
private:
|
||||
imgLoader mLoader;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(imgCacheObserver, nsIObserver)
|
||||
@ -717,10 +735,6 @@ imgCacheObserver::Observe(nsISupports* aSubject, const char* aTopic, const PRUni
|
||||
{
|
||||
if (strcmp(aTopic, "memory-pressure") == 0) {
|
||||
DiscardTracker::DiscardAll();
|
||||
mLoader.MinimizeCaches();
|
||||
} else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
|
||||
strcmp(aTopic, "chrome-flush-caches") == 0) {
|
||||
mLoader.ClearChromeImageCache();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -760,45 +774,44 @@ void imgCacheExpirationTracker::NotifyExpired(imgCacheEntry *entry)
|
||||
// We can be called multiple times on the same entry. Don't do work multiple
|
||||
// times.
|
||||
if (!entry->Evicted())
|
||||
imgLoader::RemoveFromCache(entry);
|
||||
entry->Loader()->RemoveFromCache(entry);
|
||||
|
||||
imgLoader::VerifyCacheSizes();
|
||||
entry->Loader()->VerifyCacheSizes();
|
||||
}
|
||||
|
||||
imgCacheObserver *gCacheObserver;
|
||||
imgCacheExpirationTracker *gCacheTracker;
|
||||
|
||||
imgLoader::imgCacheTable imgLoader::sCache;
|
||||
imgCacheQueue imgLoader::sCacheQueue;
|
||||
|
||||
imgLoader::imgCacheTable imgLoader::sChromeCache;
|
||||
imgCacheQueue imgLoader::sChromeCacheQueue;
|
||||
|
||||
double imgLoader::sCacheTimeWeight;
|
||||
uint32_t imgLoader::sCacheMaxSize;
|
||||
imgMemoryReporter* imgLoader::sMemReporter;
|
||||
|
||||
NS_IMPL_ISUPPORTS5(imgLoader, imgILoader, nsIContentSniffer, imgICache, nsISupportsWeakReference, nsIObserver)
|
||||
|
||||
imgLoader::imgLoader()
|
||||
: mRespectPrivacy(false)
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
sMemReporter->AddRef();
|
||||
sMemReporter->RegisterLoader(this);
|
||||
}
|
||||
|
||||
imgLoader::~imgLoader()
|
||||
{
|
||||
/* destructor code */
|
||||
ClearChromeImageCache();
|
||||
ClearImageCache();
|
||||
sMemReporter->UnregisterLoader(this);
|
||||
sMemReporter->Release();
|
||||
}
|
||||
|
||||
void imgLoader::VerifyCacheSizes()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!gCacheTracker)
|
||||
if (!mCacheTracker)
|
||||
return;
|
||||
|
||||
uint32_t cachesize = sCache.Count() + sChromeCache.Count();
|
||||
uint32_t queuesize = sCacheQueue.GetNumElements() + sChromeCacheQueue.GetNumElements();
|
||||
uint32_t cachesize = mCache.Count() + mChromeCache.Count();
|
||||
uint32_t queuesize = mCacheQueue.GetNumElements() + mChromeCacheQueue.GetNumElements();
|
||||
uint32_t trackersize = 0;
|
||||
for (nsExpirationTracker<imgCacheEntry, 3>::Iterator it(gCacheTracker); it.Next(); )
|
||||
for (nsExpirationTracker<imgCacheEntry, 3>::Iterator it(mCacheTracker); it.Next(); )
|
||||
trackersize++;
|
||||
NS_ABORT_IF_FALSE(queuesize == trackersize, "Queue and tracker sizes out of sync!");
|
||||
NS_ABORT_IF_FALSE(queuesize <= cachesize, "Queue has more elements than cache!");
|
||||
@ -810,9 +823,9 @@ imgLoader::imgCacheTable & imgLoader::GetCache(nsIURI *aURI)
|
||||
bool chrome = false;
|
||||
aURI->SchemeIs("chrome", &chrome);
|
||||
if (chrome)
|
||||
return sChromeCache;
|
||||
return mChromeCache;
|
||||
else
|
||||
return sCache;
|
||||
return mCache;
|
||||
}
|
||||
|
||||
imgCacheQueue & imgLoader::GetCacheQueue(nsIURI *aURI)
|
||||
@ -820,34 +833,22 @@ imgCacheQueue & imgLoader::GetCacheQueue(nsIURI *aURI)
|
||||
bool chrome = false;
|
||||
aURI->SchemeIs("chrome", &chrome);
|
||||
if (chrome)
|
||||
return sChromeCacheQueue;
|
||||
return mChromeCacheQueue;
|
||||
else
|
||||
return sCacheQueue;
|
||||
return mCacheQueue;
|
||||
}
|
||||
|
||||
nsresult imgLoader::InitCache()
|
||||
void imgLoader::GlobalInit()
|
||||
{
|
||||
NS_TIME_FUNCTION;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (!os)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
gCacheObserver = new imgCacheObserver();
|
||||
NS_ADDREF(gCacheObserver);
|
||||
|
||||
os->AddObserver(gCacheObserver, "memory-pressure", false);
|
||||
os->AddObserver(gCacheObserver, "chrome-flush-skin-caches", false);
|
||||
os->AddObserver(gCacheObserver, "chrome-flush-caches", false);
|
||||
|
||||
gCacheTracker = new imgCacheExpirationTracker();
|
||||
|
||||
sCache.Init();
|
||||
sChromeCache.Init();
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os)
|
||||
os->AddObserver(gCacheObserver, "memory-pressure", false);
|
||||
|
||||
int32_t timeweight;
|
||||
rv = Preferences::GetInt("image.cache.timeweight", &timeweight);
|
||||
nsresult rv = Preferences::GetInt("image.cache.timeweight", &timeweight);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
sCacheTimeWeight = timeweight / 1000.0;
|
||||
else
|
||||
@ -860,23 +861,49 @@ nsresult imgLoader::InitCache()
|
||||
else
|
||||
sCacheMaxSize = 5 * 1024 * 1024;
|
||||
|
||||
NS_RegisterMemoryMultiReporter(new imgMemoryReporter());
|
||||
sMemReporter = new imgMemoryReporter();
|
||||
NS_RegisterMemoryMultiReporter(sMemReporter);
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(ImagesContentUsedUncompressed));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult imgLoader::InitCache()
|
||||
{
|
||||
NS_TIME_FUNCTION;
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (!os)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
os->AddObserver(this, "memory-pressure", false);
|
||||
os->AddObserver(this, "chrome-flush-skin-caches", false);
|
||||
os->AddObserver(this, "chrome-flush-caches", false);
|
||||
os->AddObserver(this, "last-pb-context-exited", false);
|
||||
os->AddObserver(this, "profile-before-change", false);
|
||||
os->AddObserver(this, "xpcom-shutdown", false);
|
||||
|
||||
mCacheTracker = new imgCacheExpirationTracker();
|
||||
|
||||
mCache.Init();
|
||||
mChromeCache.Init();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult imgLoader::Init()
|
||||
{
|
||||
InitCache();
|
||||
|
||||
ReadAcceptHeaderPref();
|
||||
|
||||
Preferences::AddWeakObserver(this, "image.http.accept");
|
||||
|
||||
// Listen for when we leave private browsing mode
|
||||
nsCOMPtr<nsIObserverService> obService = mozilla::services::GetObserverService();
|
||||
if (obService)
|
||||
obService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
imgLoader::RespectPrivacyNotifications()
|
||||
{
|
||||
mRespectPrivacy = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -888,12 +915,21 @@ imgLoader::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* a
|
||||
if (!strcmp(NS_ConvertUTF16toUTF8(aData).get(), "image.http.accept")) {
|
||||
ReadAcceptHeaderPref();
|
||||
}
|
||||
}
|
||||
|
||||
// ...and exits from private browsing.
|
||||
else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
|
||||
if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData))
|
||||
} else if (strcmp(aTopic, "memory-pressure") == 0) {
|
||||
MinimizeCaches();
|
||||
} else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
|
||||
strcmp(aTopic, "chrome-flush-caches") == 0) {
|
||||
MinimizeCaches();
|
||||
ClearChromeImageCache();
|
||||
} else if (strcmp(aTopic, "last-pb-context-exited") == 0) {
|
||||
if (mRespectPrivacy) {
|
||||
ClearImageCache();
|
||||
ClearChromeImageCache();
|
||||
}
|
||||
} else if (strcmp(aTopic, "profile-before-change") == 0 ||
|
||||
strcmp(aTopic, "xpcom-shutdown") == 0) {
|
||||
mCacheTracker = nullptr;
|
||||
}
|
||||
|
||||
// (Nothing else should bring us here)
|
||||
@ -942,8 +978,8 @@ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retva
|
||||
*_retval = nullptr;
|
||||
|
||||
if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
|
||||
if (gCacheTracker && entry->HasNoProxies())
|
||||
gCacheTracker->MarkUsed(entry);
|
||||
if (mCacheTracker && entry->HasNoProxies())
|
||||
mCacheTracker->MarkUsed(entry);
|
||||
|
||||
nsRefPtr<imgRequest> request = getter_AddRefs(entry->GetRequest());
|
||||
if (request) {
|
||||
@ -957,27 +993,23 @@ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retva
|
||||
|
||||
void imgLoader::Shutdown()
|
||||
{
|
||||
ClearChromeImageCache();
|
||||
ClearImageCache();
|
||||
NS_IF_RELEASE(gCacheObserver);
|
||||
delete gCacheTracker;
|
||||
gCacheTracker = nullptr;
|
||||
NS_RELEASE(gCacheObserver);
|
||||
}
|
||||
|
||||
nsresult imgLoader::ClearChromeImageCache()
|
||||
{
|
||||
return EvictEntries(sChromeCache);
|
||||
return EvictEntries(mChromeCache);
|
||||
}
|
||||
|
||||
nsresult imgLoader::ClearImageCache()
|
||||
{
|
||||
return EvictEntries(sCache);
|
||||
return EvictEntries(mCache);
|
||||
}
|
||||
|
||||
void imgLoader::MinimizeCaches()
|
||||
{
|
||||
EvictEntries(sCacheQueue);
|
||||
EvictEntries(sChromeCacheQueue);
|
||||
EvictEntries(mCacheQueue);
|
||||
EvictEntries(mChromeCacheQueue);
|
||||
}
|
||||
|
||||
bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
|
||||
@ -1020,8 +1052,8 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
|
||||
if (entry->HasNoProxies()) {
|
||||
nsresult addrv = NS_OK;
|
||||
|
||||
if (gCacheTracker)
|
||||
addrv = gCacheTracker->AddObject(entry);
|
||||
if (mCacheTracker)
|
||||
addrv = mCacheTracker->AddObject(entry);
|
||||
|
||||
if (NS_SUCCEEDED(addrv)) {
|
||||
imgCacheQueue &queue = GetCacheQueue(key);
|
||||
@ -1051,8 +1083,8 @@ bool imgLoader::SetHasNoProxies(nsIURI *key, imgCacheEntry *entry)
|
||||
|
||||
nsresult addrv = NS_OK;
|
||||
|
||||
if (gCacheTracker)
|
||||
addrv = gCacheTracker->AddObject(entry);
|
||||
if (mCacheTracker)
|
||||
addrv = mCacheTracker->AddObject(entry);
|
||||
|
||||
if (NS_SUCCEEDED(addrv)) {
|
||||
queue.Push(entry);
|
||||
@ -1081,8 +1113,8 @@ bool imgLoader::SetHasProxies(nsIURI *key)
|
||||
imgCacheQueue &queue = GetCacheQueue(key);
|
||||
queue.Remove(entry);
|
||||
|
||||
if (gCacheTracker)
|
||||
gCacheTracker->RemoveObject(entry);
|
||||
if (mCacheTracker)
|
||||
mCacheTracker->RemoveObject(entry);
|
||||
|
||||
entry->SetHasNoProxies(false);
|
||||
|
||||
@ -1207,7 +1239,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
|
||||
return false;
|
||||
|
||||
nsRefPtr<imgCacheValidator> hvc =
|
||||
new imgCacheValidator(progressproxy, request, aCX, forcePrincipalCheck);
|
||||
new imgCacheValidator(progressproxy, this, request, aCX, forcePrincipalCheck);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = hvc.get();
|
||||
|
||||
@ -1388,8 +1420,8 @@ bool imgLoader::RemoveFromCache(nsIURI *aKey)
|
||||
|
||||
// Entries with no proxies are in the tracker.
|
||||
if (entry->HasNoProxies()) {
|
||||
if (gCacheTracker)
|
||||
gCacheTracker->RemoveObject(entry);
|
||||
if (mCacheTracker)
|
||||
mCacheTracker->RemoveObject(entry);
|
||||
queue.Remove(entry);
|
||||
}
|
||||
|
||||
@ -1423,8 +1455,8 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry)
|
||||
|
||||
if (entry->HasNoProxies()) {
|
||||
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache removing from tracker");
|
||||
if (gCacheTracker)
|
||||
gCacheTracker->RemoveObject(entry);
|
||||
if (mCacheTracker)
|
||||
mCacheTracker->RemoveObject(entry);
|
||||
queue.Remove(entry);
|
||||
}
|
||||
|
||||
@ -1524,6 +1556,25 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
|
||||
nsresult rv;
|
||||
nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isPrivate = false;
|
||||
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
||||
if (channel) {
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(channel, loadContext);
|
||||
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
|
||||
} else if (aLoadGroup) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
if (callbacks) {
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
|
||||
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(isPrivate == mRespectPrivacy);
|
||||
#endif
|
||||
|
||||
// Get the default load flags from the loadgroup (if possible)...
|
||||
if (aLoadGroup) {
|
||||
aLoadGroup->GetLoadFlags(&requestFlags);
|
||||
@ -1577,8 +1628,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
|
||||
NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!");
|
||||
request->SetCacheEntry(entry);
|
||||
|
||||
if (gCacheTracker)
|
||||
gCacheTracker->MarkUsed(entry);
|
||||
if (mCacheTracker)
|
||||
mCacheTracker->MarkUsed(entry);
|
||||
}
|
||||
|
||||
entry->Touch();
|
||||
@ -1615,8 +1666,13 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NewRequestAndEntry(forcePrincipalCheck, getter_AddRefs(request),
|
||||
getter_AddRefs(entry));
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(newChannel, loadContext);
|
||||
MOZ_ASSERT_IF(loadContext, loadContext->UsePrivateBrowsing() == mRespectPrivacy);
|
||||
#endif
|
||||
|
||||
NewRequestAndEntry(forcePrincipalCheck, this, getter_AddRefs(request), getter_AddRefs(entry));
|
||||
|
||||
PR_LOG(gImgLog, PR_LOG_DEBUG,
|
||||
("[this=%p] imgLoader::LoadImage -- Created new imgRequest [request=%p]\n", this, request.get()));
|
||||
@ -1741,6 +1797,12 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
|
||||
{
|
||||
NS_ASSERTION(channel, "imgLoader::LoadImageWithChannel -- NULL channel pointer");
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(channel, loadContext);
|
||||
MOZ_ASSERT_IF(loadContext, loadContext->UsePrivateBrowsing() == mRespectPrivacy);
|
||||
#endif
|
||||
|
||||
nsRefPtr<imgRequest> request;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
@ -1798,8 +1860,8 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
|
||||
NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!");
|
||||
request->SetCacheEntry(entry);
|
||||
|
||||
if (gCacheTracker)
|
||||
gCacheTracker->MarkUsed(entry);
|
||||
if (mCacheTracker)
|
||||
mCacheTracker->MarkUsed(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1826,7 +1888,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
|
||||
// Default to doing a principal check because we don't know who
|
||||
// started that load and whether their principal ended up being
|
||||
// inherited on the channel.
|
||||
NewRequestAndEntry(true, getter_AddRefs(request), getter_AddRefs(entry));
|
||||
NewRequestAndEntry(true, this, getter_AddRefs(request), getter_AddRefs(entry));
|
||||
|
||||
// We use originalURI here to fulfil the imgIRequest contract on GetURI.
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
@ -2038,17 +2100,16 @@ NS_IMPL_ISUPPORTS5(imgCacheValidator, nsIStreamListener, nsIRequestObserver,
|
||||
nsIChannelEventSink, nsIInterfaceRequestor,
|
||||
nsIAsyncVerifyRedirectCallback)
|
||||
|
||||
imgLoader imgCacheValidator::sImgLoader;
|
||||
|
||||
imgCacheValidator::imgCacheValidator(nsProgressNotificationProxy* progress,
|
||||
imgRequest *request, void *aContext,
|
||||
bool forcePrincipalCheckForCacheEntry)
|
||||
imgLoader* loader, imgRequest *request,
|
||||
void *aContext, bool forcePrincipalCheckForCacheEntry)
|
||||
: mProgressProxy(progress),
|
||||
mRequest(request),
|
||||
mContext(aContext)
|
||||
mContext(aContext),
|
||||
mImgLoader(loader)
|
||||
{
|
||||
NewRequestAndEntry(forcePrincipalCheckForCacheEntry,
|
||||
getter_AddRefs(mNewRequest), getter_AddRefs(mNewEntry));
|
||||
NewRequestAndEntry(forcePrincipalCheckForCacheEntry, loader, getter_AddRefs(mNewRequest),
|
||||
getter_AddRefs(mNewEntry));
|
||||
}
|
||||
|
||||
imgCacheValidator::~imgCacheValidator()
|
||||
@ -2151,7 +2212,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
|
||||
// Try to add the new request into the cache. Note that the entry must be in
|
||||
// the cache before the proxies' ownership changes, because adding a proxy
|
||||
// changes the caching behaviour for imgRequests.
|
||||
sImgLoader.PutIntoCache(originalURI, mNewEntry);
|
||||
mImgLoader->PutIntoCache(originalURI, mNewEntry);
|
||||
|
||||
uint32_t count = mProxies.Count();
|
||||
for (int32_t i = count-1; i>=0; i--) {
|
||||
|
@ -27,16 +27,19 @@
|
||||
#include "prlock.h"
|
||||
#endif
|
||||
|
||||
class imgLoader;
|
||||
class imgRequest;
|
||||
class imgRequestProxy;
|
||||
class imgIRequest;
|
||||
class imgIDecoderObserver;
|
||||
class nsILoadGroup;
|
||||
class imgCacheExpirationTracker;
|
||||
class imgMemoryReporter;
|
||||
|
||||
class imgCacheEntry
|
||||
{
|
||||
public:
|
||||
imgCacheEntry(imgRequest *request, bool aForcePrincipalCheck);
|
||||
imgCacheEntry(imgLoader* loader, imgRequest *request, bool aForcePrincipalCheck);
|
||||
~imgCacheEntry();
|
||||
|
||||
nsrefcnt AddRef()
|
||||
@ -130,6 +133,11 @@ public:
|
||||
return mForcePrincipalCheck;
|
||||
}
|
||||
|
||||
imgLoader* Loader() const
|
||||
{
|
||||
return mLoader;
|
||||
}
|
||||
|
||||
private: // methods
|
||||
friend class imgLoader;
|
||||
friend class imgCacheQueue;
|
||||
@ -148,6 +156,7 @@ private: // data
|
||||
nsAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
imgLoader* mLoader;
|
||||
nsRefPtr<imgRequest> mRequest;
|
||||
uint32_t mDataSize;
|
||||
int32_t mTouchedTime;
|
||||
@ -219,18 +228,19 @@ public:
|
||||
|
||||
static nsresult GetMimeTypeFromContent(const char* aContents, uint32_t aLength, nsACString& aContentType);
|
||||
|
||||
static void GlobalInit(); // for use by the factory
|
||||
static void Shutdown(); // for use by the factory
|
||||
|
||||
static nsresult ClearChromeImageCache();
|
||||
static nsresult ClearImageCache();
|
||||
static void MinimizeCaches();
|
||||
nsresult ClearChromeImageCache();
|
||||
nsresult ClearImageCache();
|
||||
void MinimizeCaches();
|
||||
|
||||
static nsresult InitCache();
|
||||
nsresult InitCache();
|
||||
|
||||
static bool RemoveFromCache(nsIURI *aKey);
|
||||
static bool RemoveFromCache(imgCacheEntry *entry);
|
||||
bool RemoveFromCache(nsIURI *aKey);
|
||||
bool RemoveFromCache(imgCacheEntry *entry);
|
||||
|
||||
static bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
|
||||
bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
|
||||
|
||||
// Returns true if we should prefer evicting cache entry |two| over cache
|
||||
// entry |one|.
|
||||
@ -256,7 +266,7 @@ public:
|
||||
return oneweight < twoweight;
|
||||
}
|
||||
|
||||
static void VerifyCacheSizes();
|
||||
void VerifyCacheSizes();
|
||||
|
||||
// The image loader maintains a hash table of all imgCacheEntries. However,
|
||||
// only some of them will be evicted from the cache: those who have no
|
||||
@ -269,8 +279,8 @@ public:
|
||||
// HasObservers(). The request's cache entry will be re-set before this
|
||||
// happens, by calling imgRequest::SetCacheEntry() when an entry with no
|
||||
// observers is re-requested.
|
||||
static bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
|
||||
static bool SetHasProxies(nsIURI *key);
|
||||
bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
|
||||
bool SetHasProxies(nsIURI *key);
|
||||
|
||||
private: // methods
|
||||
|
||||
@ -307,27 +317,32 @@ private: // methods
|
||||
|
||||
typedef nsRefPtrHashtable<nsCStringHashKey, imgCacheEntry> imgCacheTable;
|
||||
|
||||
static nsresult EvictEntries(imgCacheTable &aCacheToClear);
|
||||
static nsresult EvictEntries(imgCacheQueue &aQueueToClear);
|
||||
nsresult EvictEntries(imgCacheTable &aCacheToClear);
|
||||
nsresult EvictEntries(imgCacheQueue &aQueueToClear);
|
||||
|
||||
static imgCacheTable &GetCache(nsIURI *aURI);
|
||||
static imgCacheQueue &GetCacheQueue(nsIURI *aURI);
|
||||
static void CacheEntriesChanged(nsIURI *aURI, int32_t sizediff = 0);
|
||||
static void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
|
||||
imgCacheTable &GetCache(nsIURI *aURI);
|
||||
imgCacheQueue &GetCacheQueue(nsIURI *aURI);
|
||||
void CacheEntriesChanged(nsIURI *aURI, PRInt32 sizediff = 0);
|
||||
void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
|
||||
|
||||
private: // data
|
||||
friend class imgCacheEntry;
|
||||
friend class imgMemoryReporter;
|
||||
|
||||
static imgCacheTable sCache;
|
||||
static imgCacheQueue sCacheQueue;
|
||||
imgCacheTable mCache;
|
||||
imgCacheQueue mCacheQueue;
|
||||
|
||||
imgCacheTable mChromeCache;
|
||||
imgCacheQueue mChromeCacheQueue;
|
||||
|
||||
static imgCacheTable sChromeCache;
|
||||
static imgCacheQueue sChromeCacheQueue;
|
||||
static double sCacheTimeWeight;
|
||||
static uint32_t sCacheMaxSize;
|
||||
static imgMemoryReporter* sMemReporter;
|
||||
|
||||
nsCString mAcceptHeader;
|
||||
|
||||
nsAutoPtr<imgCacheExpirationTracker> mCacheTracker;
|
||||
bool mRespectPrivacy;
|
||||
};
|
||||
|
||||
|
||||
@ -395,8 +410,8 @@ class imgCacheValidator : public nsIStreamListener,
|
||||
public nsIAsyncVerifyRedirectCallback
|
||||
{
|
||||
public:
|
||||
imgCacheValidator(nsProgressNotificationProxy* progress, imgRequest *request,
|
||||
void *aContext, bool forcePrincipalCheckForCacheEntry);
|
||||
imgCacheValidator(nsProgressNotificationProxy* progress, imgLoader* loader,
|
||||
imgRequest *request, void *aContext, bool forcePrincipalCheckForCacheEntry);
|
||||
virtual ~imgCacheValidator();
|
||||
|
||||
void AddProxy(imgRequestProxy *aProxy);
|
||||
@ -422,7 +437,7 @@ private:
|
||||
|
||||
void *mContext;
|
||||
|
||||
static imgLoader sImgLoader;
|
||||
imgLoader* mImgLoader;
|
||||
};
|
||||
|
||||
#endif // imgLoader_h__
|
||||
|
@ -79,8 +79,8 @@ NS_IMPL_ISUPPORTS8(imgRequest,
|
||||
nsIInterfaceRequestor,
|
||||
nsIAsyncVerifyRedirectCallback)
|
||||
|
||||
imgRequest::imgRequest() :
|
||||
mValidator(nullptr), mImageSniffers("image-sniffing-services"),
|
||||
imgRequest::imgRequest(imgLoader* aLoader) :
|
||||
mLoader(aLoader), mValidator(nullptr), mImageSniffers("image-sniffing-services"),
|
||||
mInnerWindowId(0), mCORSMode(imgIRequest::CORS_NONE),
|
||||
mDecodeRequested(false), mIsMultiPartChannel(false), mGotData(false),
|
||||
mIsInCache(false), mBlockingOnload(false)
|
||||
@ -178,7 +178,7 @@ nsresult imgRequest::AddProxy(imgRequestProxy *proxy)
|
||||
// proxies.
|
||||
if (mObservers.IsEmpty()) {
|
||||
NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri.");
|
||||
imgLoader::SetHasProxies(mURI);
|
||||
mLoader->SetHasProxies(mURI);
|
||||
}
|
||||
|
||||
// If we don't have any current observers, we should restart any animation.
|
||||
@ -223,7 +223,7 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, bool
|
||||
if (mCacheEntry) {
|
||||
NS_ABORT_IF_FALSE(mURI, "Removing last observer without key uri.");
|
||||
|
||||
imgLoader::SetHasNoProxies(mURI, mCacheEntry);
|
||||
mLoader->SetHasNoProxies(mURI, mCacheEntry);
|
||||
}
|
||||
#if defined(PR_LOGGING)
|
||||
else {
|
||||
@ -328,9 +328,9 @@ void imgRequest::RemoveFromCache()
|
||||
if (mIsInCache) {
|
||||
// mCacheEntry is nulled out when we have no more observers.
|
||||
if (mCacheEntry)
|
||||
imgLoader::RemoveFromCache(mCacheEntry);
|
||||
mLoader->RemoveFromCache(mCacheEntry);
|
||||
else
|
||||
imgLoader::RemoveFromCache(mURI);
|
||||
mLoader->RemoveFromCache(mURI);
|
||||
}
|
||||
|
||||
mCacheEntry = nullptr;
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
class imgCacheValidator;
|
||||
|
||||
class imgLoader;
|
||||
class imgRequestProxy;
|
||||
class imgCacheEntry;
|
||||
class imgMemoryReporter;
|
||||
@ -50,7 +51,7 @@ class imgRequest : public imgIDecoderObserver,
|
||||
public nsIAsyncVerifyRedirectCallback
|
||||
{
|
||||
public:
|
||||
imgRequest();
|
||||
imgRequest(imgLoader* aLoader);
|
||||
virtual ~imgRequest();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -183,6 +184,8 @@ public:
|
||||
private:
|
||||
friend class imgMemoryReporter;
|
||||
|
||||
// Weak reference to parent loader; this request cannot outlive its owner.
|
||||
imgLoader* mLoader;
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
// The original URI we were loaded with. This is the same as the URI we are
|
||||
// keyed on in the cache.
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsError.h"
|
||||
#include "imgILoader.h"
|
||||
#include "imgICache.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgIEncoder.h"
|
||||
#include "imgIDecoderObserver.h"
|
||||
@ -19,10 +21,14 @@
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "RasterImage.h"
|
||||
|
||||
using namespace mozilla::image;
|
||||
|
||||
class nsIDOMDocument;
|
||||
class nsIDocument;
|
||||
|
||||
/* ========== imgITools implementation ========== */
|
||||
|
||||
|
||||
@ -269,3 +275,20 @@ NS_IMETHODIMP imgTools::GetFirstImageFrame(imgIContainer *aContainer,
|
||||
frame.forget(aSurface);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
|
||||
NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(doc));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
imgTools::GetImgCacheForDocument(nsIDOMDocument* aDoc, imgICache** aCache)
|
||||
{
|
||||
nsCOMPtr<imgILoader> loader;
|
||||
nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return CallQueryInterface(loader, aCache);
|
||||
}
|
||||
|
@ -7,9 +7,10 @@
|
||||
// Helper function to clear the image cache of content images
|
||||
function clearImageCache()
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var imageCache = Components.classes["@mozilla.org/image/cache;1"]
|
||||
.getService(Components.interfaces.imgICache);
|
||||
var tools = SpecialPowers.wrap(Components)
|
||||
.classes["@mozilla.org/image/tools;1"]
|
||||
.getService(Components.interfaces.imgITools);
|
||||
var imageCache = tools.getImgCacheForDocument(window.document);
|
||||
imageCache.clearCache(false); // true=chrome, false=content
|
||||
}
|
||||
|
||||
|
@ -85,9 +85,8 @@ function checkSecondLoad()
|
||||
{
|
||||
do_test_pending();
|
||||
|
||||
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
|
||||
var listener = new ImageListener(checkClone, secondLoadDone);
|
||||
requests.push(loader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null));
|
||||
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null));
|
||||
listener.synchronous = false;
|
||||
}
|
||||
|
||||
@ -139,12 +138,11 @@ function checkSecondChannelLoad()
|
||||
var channellistener = new ChannelListener();
|
||||
channel.asyncOpen(channellistener, null);
|
||||
|
||||
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
|
||||
var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener),
|
||||
getChannelLoadImageStopCallback(channellistener,
|
||||
all_done_callback));
|
||||
var outlistener = {};
|
||||
requests.push(loader.loadImageWithChannel(channel, listener, null, outlistener));
|
||||
requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener));
|
||||
channellistener.outputListener = outlistener.value;
|
||||
|
||||
listener.synchronous = false;
|
||||
@ -152,11 +150,8 @@ function checkSecondChannelLoad()
|
||||
|
||||
function run_loadImageWithChannel_tests()
|
||||
{
|
||||
// To ensure we're testing what we expect to, clear the content image cache
|
||||
// between test runs.
|
||||
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
|
||||
loader.QueryInterface(Ci.imgICache);
|
||||
loader.clearCache(false);
|
||||
// To ensure we're testing what we expect to, create a new loader and cache.
|
||||
gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
|
||||
|
||||
do_test_pending();
|
||||
|
||||
@ -165,12 +160,11 @@ function run_loadImageWithChannel_tests()
|
||||
var channellistener = new ChannelListener();
|
||||
channel.asyncOpen(channellistener, null);
|
||||
|
||||
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
|
||||
var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener),
|
||||
getChannelLoadImageStopCallback(channellistener,
|
||||
checkSecondChannelLoad));
|
||||
var outlistener = {};
|
||||
requests.push(loader.loadImageWithChannel(channel, listener, null, outlistener));
|
||||
requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener));
|
||||
channellistener.outputListener = outlistener.value;
|
||||
|
||||
listener.synchronous = false;
|
||||
@ -185,12 +179,10 @@ function startImageCallback(otherCb)
|
||||
{
|
||||
return function(listener, request)
|
||||
{
|
||||
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
|
||||
|
||||
// Make sure we can load the same image immediately out of the cache.
|
||||
do_test_pending();
|
||||
var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); });
|
||||
requests.push(loader.loadImage(uri, null, null, null, null, listener2, null, 0, null, null, null));
|
||||
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener2, null, 0, null, null, null));
|
||||
listener2.synchronous = false;
|
||||
|
||||
// Now that we've started another load, chain to the callback.
|
||||
@ -198,13 +190,15 @@ function startImageCallback(otherCb)
|
||||
}
|
||||
}
|
||||
|
||||
var gCurrentLoader;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
|
||||
gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
|
||||
|
||||
do_test_pending();
|
||||
var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone);
|
||||
var req = loader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null);
|
||||
var req = gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null);
|
||||
requests.push(req);
|
||||
|
||||
// Ensure that we don't cause any mayhem when we lock an image.
|
||||
|
111
image/test/unit/test_private_channel.js
Normal file
111
image/test/unit/test_private_channel.js
Normal file
@ -0,0 +1,111 @@
|
||||
Components.utils.import("resource://testing-common/httpd.js");
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
var server = new HttpServer();
|
||||
server.registerPathHandler('/image.png', imageHandler);
|
||||
server.start(8088);
|
||||
|
||||
load('image_load_helpers.js');
|
||||
|
||||
var gHits = 0;
|
||||
|
||||
var gIoService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
var gPublicLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
|
||||
var gPrivateLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
|
||||
gPrivateLoader.QueryInterface(Ci.imgICache).respectPrivacyNotifications();
|
||||
|
||||
function imageHandler(metadata, response) {
|
||||
gHits++;
|
||||
response.setHeader("Cache-Control", "max-age=10000", false);
|
||||
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "image/png", false);
|
||||
var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
var requests = [];
|
||||
var listeners = [];
|
||||
|
||||
function NotificationCallbacks(isPrivate) {
|
||||
this.usePrivateBrowsing = isPrivate;
|
||||
}
|
||||
|
||||
NotificationCallbacks.prototype = {
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsILoadContext))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
getInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsILoadContext))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
var gImgPath = 'http://localhost:8088/image.png';
|
||||
|
||||
function setup_chan(path, isPrivate, callback) {
|
||||
var uri = gIoService.newURI(gImgPath, null, null);
|
||||
var chan = gIoService.newChannelFromURI(uri);
|
||||
chan.notificationCallbacks = new NotificationCallbacks(isPrivate);
|
||||
var channelListener = new ChannelListener();
|
||||
chan.asyncOpen(channelListener, null);
|
||||
|
||||
var listener = new ImageListener(null, callback);
|
||||
listeners.push(listener);
|
||||
var outlistener = {};
|
||||
var loader = isPrivate ? gPrivateLoader : gPublicLoader;
|
||||
requests.push(loader.loadImageWithChannel(chan, listener, null, outlistener));
|
||||
channelListener.outputListener = outlistener.value;
|
||||
listener.synchronous = false;
|
||||
}
|
||||
|
||||
function loadImage(isPrivate, callback) {
|
||||
var listener = new ImageListener(null, callback);
|
||||
var uri = gIoService.newURI(gImgPath, null, null);
|
||||
var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup);
|
||||
loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate);
|
||||
var loader = isPrivate ? gPrivateLoader : gPublicLoader;
|
||||
requests.push(loader.loadImage(uri, null, null, null, loadGroup, listener, null, 0, null, null, null));
|
||||
listener.synchronous = false;
|
||||
}
|
||||
|
||||
function run_loadImage_tests() {
|
||||
let cs = Cc["@mozilla.org/network/cache-service;1"].getService(Ci.nsICacheService);
|
||||
cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
|
||||
gHits = 0;
|
||||
loadImage(false, function() {
|
||||
loadImage(false, function() {
|
||||
loadImage(true, function() {
|
||||
loadImage(true, function() {
|
||||
do_check_eq(gHits, 2);
|
||||
server.stop(do_test_finished);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
// We create a public channel that loads an image, then an identical
|
||||
// one that should cause a cache read. We then create a private channel
|
||||
// and load the same image, and do that a second time to ensure a cache
|
||||
// read. In total, we should cause two separate http responses to occur,
|
||||
// since the private channels shouldn't be able to use the public cache.
|
||||
setup_chan('/image.png', false, function() {
|
||||
setup_chan('/image.png', false, function() {
|
||||
setup_chan('/image.png', true, function() {
|
||||
setup_chan('/image.png', true, function() {
|
||||
do_check_eq(gHits, 2);
|
||||
run_loadImage_tests();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -11,3 +11,4 @@ tail =
|
||||
# Bug 676968: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_moz_icon_uri.js]
|
||||
[test_private_channel.js]
|
@ -133,7 +133,7 @@ class WorkQueue : public PlatformThread::Delegate {
|
||||
bool allow_help_requests_; // Workers can signal more workers.
|
||||
bool shutdown_; // Set when threads need to terminate.
|
||||
|
||||
DFAKE_MUTEX(locked_methods_);
|
||||
DFAKE_MUTEX(locked_methods_)
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "base/process_util.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/wait.h>
|
||||
@ -95,7 +94,7 @@ bool LaunchApp(const std::vector<std::string>& argv,
|
||||
bool wait, ProcessHandle* process_handle,
|
||||
ProcessArchitecture arch) {
|
||||
return LaunchApp(argv, fds_to_remap, env_vars_to_set,
|
||||
SAME_PRIVILEGES_AS_PARENT,
|
||||
PRIVILEGES_INHERIT,
|
||||
wait, process_handle);
|
||||
}
|
||||
|
||||
@ -220,7 +219,7 @@ bool LaunchApp(const std::vector<std::string>& argv,
|
||||
bool wait, ProcessHandle* process_handle,
|
||||
ProcessArchitecture arch) {
|
||||
return LaunchApp(argv, fds_to_remap, env_vars_to_set,
|
||||
SAME_PRIVILEGES_AS_PARENT,
|
||||
PRIVILEGES_INHERIT,
|
||||
wait, process_handle);
|
||||
}
|
||||
|
||||
@ -256,7 +255,7 @@ bool LaunchApp(const std::vector<std::string>& argv,
|
||||
argv_cstr[i] = const_cast<char*>(argv[i].c_str());
|
||||
argv_cstr[argv.size()] = NULL;
|
||||
|
||||
if (privs == UNPRIVILEGED) {
|
||||
if (privs == PRIVILEGES_UNPRIVILEGED) {
|
||||
if (setgid(CHILD_UNPRIVILEGED_GID) != 0) {
|
||||
DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS, path: " << argv_cstr[0];
|
||||
_exit(127);
|
||||
|
@ -28,7 +28,7 @@ class RefCountedBase {
|
||||
bool in_dtor_;
|
||||
#endif
|
||||
|
||||
DFAKE_MUTEX(add_release_);
|
||||
DFAKE_MUTEX(add_release_)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
|
||||
};
|
||||
|
@ -101,7 +101,7 @@
|
||||
// Defines a class member that acts like a mutex. It is used only as a
|
||||
// verification tool.
|
||||
#define DFAKE_MUTEX(obj) \
|
||||
mutable base::ThreadCollisionWarner obj
|
||||
mutable base::ThreadCollisionWarner obj;
|
||||
// Asserts the call is never called simultaneously in two threads. Used at
|
||||
// member function scope.
|
||||
#define DFAKE_SCOPED_LOCK(obj) \
|
||||
|
@ -17,7 +17,7 @@ MSVC_PUSH_DISABLE_WARNING(4822)
|
||||
|
||||
// Would cause a memory leak otherwise.
|
||||
#undef DFAKE_MUTEX
|
||||
#define DFAKE_MUTEX(obj) scoped_ptr<base::AsserterBase> obj
|
||||
#define DFAKE_MUTEX(obj) scoped_ptr<base::AsserterBase> obj;
|
||||
|
||||
// In Release, we expect the AsserterBase::warn() to not happen.
|
||||
#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE
|
||||
@ -140,7 +140,7 @@ TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
|
||||
}
|
||||
|
||||
private:
|
||||
DFAKE_MUTEX(push_pop_);
|
||||
DFAKE_MUTEX(push_pop_)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
|
||||
};
|
||||
@ -198,7 +198,7 @@ TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) {
|
||||
}
|
||||
|
||||
private:
|
||||
DFAKE_MUTEX(push_pop_);
|
||||
DFAKE_MUTEX(push_pop_)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
|
||||
};
|
||||
@ -256,7 +256,7 @@ TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
|
||||
}
|
||||
|
||||
private:
|
||||
DFAKE_MUTEX(push_pop_);
|
||||
DFAKE_MUTEX(push_pop_)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
|
||||
};
|
||||
@ -330,7 +330,7 @@ TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
|
||||
}
|
||||
|
||||
private:
|
||||
DFAKE_MUTEX(push_pop_);
|
||||
DFAKE_MUTEX(push_pop_)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
|
||||
};
|
||||
|
@ -30,7 +30,7 @@ class FileDescriptorSet : public base::RefCountedThreadSafe<FileDescriptorSet> {
|
||||
// In debugging mode, it's a fatal error to try and add more than this number
|
||||
// of descriptors to a FileDescriptorSet.
|
||||
enum {
|
||||
MAX_DESCRIPTORS_PER_MESSAGE = 4,
|
||||
MAX_DESCRIPTORS_PER_MESSAGE = 4
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -91,7 +91,7 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
|
||||
// We assume a worst case: kReadBufferSize bytes of messages, where each
|
||||
// message has no payload and a full complement of descriptors.
|
||||
MAX_READ_FDS = (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) *
|
||||
FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE,
|
||||
FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE
|
||||
};
|
||||
|
||||
// This is a control message buffer large enough to hold kMaxReadFDs
|
||||
|
@ -389,6 +389,9 @@ Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
|
||||
if (ss.isJSON()) {
|
||||
ss.appendDecimal("Page Faults", "",
|
||||
double(slices[i].endFaults - slices[i].startFaults));
|
||||
|
||||
ss.appendNumber("Start Timestamp", "%llu", "", (unsigned long long)slices[i].start);
|
||||
ss.appendNumber("End Timestamp", "%llu", "", (unsigned long long)slices[i].end);
|
||||
}
|
||||
if (slices[i].resetReason)
|
||||
ss.appendString("Reset", slices[i].resetReason);
|
||||
|
@ -17,6 +17,7 @@ CPPSRCS = \
|
||||
tests.cpp \
|
||||
selfTest.cpp \
|
||||
testAddPropertyPropcache.cpp \
|
||||
testArrayBuffer.cpp \
|
||||
testArgumentsObject.cpp \
|
||||
testBindCallable.cpp \
|
||||
testBug604087.cpp \
|
||||
|
164
js/src/jsapi-tests/testArrayBuffer.cpp
Normal file
164
js/src/jsapi-tests/testArrayBuffer.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#define NUM_TEST_BUFFERS 2
|
||||
#define MAGIC_VALUE_1 3
|
||||
#define MAGIC_VALUE_2 17
|
||||
|
||||
BEGIN_TEST(testArrayBuffer_bug720949_steal)
|
||||
{
|
||||
JS::RootedObject buf_len1(cx), buf_len200(cx);
|
||||
JS::RootedObject tarray_len1(cx), tarray_len200(cx);
|
||||
|
||||
uint32_t sizes[NUM_TEST_BUFFERS] = { sizeof(uint32_t), 200 * sizeof(uint32_t) };
|
||||
JS::HandleObject testBuf[NUM_TEST_BUFFERS] = { buf_len1, buf_len200 };
|
||||
JS::HandleObject testArray[NUM_TEST_BUFFERS] = { tarray_len1, tarray_len200 };
|
||||
|
||||
// Single-element ArrayBuffer (uses fixed slots for storage)
|
||||
CHECK(buf_len1 = JS_NewArrayBuffer(cx, sizes[0]));
|
||||
CHECK(tarray_len1 = JS_NewInt32ArrayWithBuffer(cx, testBuf[0], 0, -1));
|
||||
|
||||
jsval dummy = INT_TO_JSVAL(MAGIC_VALUE_1);
|
||||
JS_SetElement(cx, testArray[0], 0, &dummy);
|
||||
|
||||
// Many-element ArrayBuffer (uses dynamic storage)
|
||||
CHECK(buf_len200 = JS_NewArrayBuffer(cx, 200 * sizeof(uint32_t)));
|
||||
CHECK(tarray_len200 = JS_NewInt32ArrayWithBuffer(cx, testBuf[1], 0, -1));
|
||||
|
||||
for (unsigned i = 0; i < NUM_TEST_BUFFERS; i++) {
|
||||
JS::HandleObject obj = testBuf[i];
|
||||
JS::HandleObject view = testArray[i];
|
||||
uint32_t size = sizes[i];
|
||||
jsval v;
|
||||
|
||||
// Byte lengths should all agree
|
||||
CHECK(JS_IsArrayBufferObject(obj, cx));
|
||||
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), size);
|
||||
JS_GetProperty(cx, obj, "byteLength", &v);
|
||||
CHECK_SAME(v, INT_TO_JSVAL(size));
|
||||
JS_GetProperty(cx, view, "byteLength", &v);
|
||||
CHECK_SAME(v, INT_TO_JSVAL(size));
|
||||
|
||||
// Modifying the underlying data should update the value returned through the view
|
||||
uint8_t *data = JS_GetArrayBufferData(obj, cx);
|
||||
CHECK(data != NULL);
|
||||
*reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
|
||||
CHECK(JS_GetElement(cx, view, 0, &v));
|
||||
CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
|
||||
|
||||
// Steal the contents
|
||||
void *contents;
|
||||
CHECK(JS_StealArrayBufferContents(cx, obj, &contents));
|
||||
CHECK(contents != NULL);
|
||||
|
||||
// Check that the original ArrayBuffer is neutered
|
||||
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0);
|
||||
CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
|
||||
CHECK_SAME(v, INT_TO_JSVAL(0));
|
||||
CHECK(JS_GetProperty(cx, view, "byteLength", &v));
|
||||
CHECK_SAME(v, INT_TO_JSVAL(0));
|
||||
CHECK(JS_GetProperty(cx, view, "byteOffset", &v));
|
||||
CHECK_SAME(v, INT_TO_JSVAL(0));
|
||||
CHECK(JS_GetProperty(cx, view, "length", &v));
|
||||
CHECK_SAME(v, INT_TO_JSVAL(0));
|
||||
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0);
|
||||
v = JSVAL_VOID;
|
||||
JS_GetElement(cx, obj, 0, &v);
|
||||
CHECK_SAME(v, JSVAL_VOID);
|
||||
|
||||
// Transfer to a new ArrayBuffer
|
||||
JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, contents));
|
||||
CHECK(JS_IsArrayBufferObject(dst, cx));
|
||||
data = JS_GetArrayBufferData(obj, cx);
|
||||
|
||||
JS::RootedObject dstview(cx, JS_NewInt32ArrayWithBuffer(cx, dst, 0, -1));
|
||||
CHECK(dstview != NULL);
|
||||
|
||||
CHECK_EQUAL(JS_GetArrayBufferByteLength(dst, cx), size);
|
||||
data = JS_GetArrayBufferData(dst, cx);
|
||||
CHECK(data != NULL);
|
||||
CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
|
||||
CHECK(JS_GetElement(cx, dstview, 0, &v));
|
||||
CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testArrayBuffer_bug720949_steal)
|
||||
|
||||
static void GC(JSContext *cx)
|
||||
{
|
||||
JS_GC(JS_GetRuntime(cx));
|
||||
JS_GC(JS_GetRuntime(cx)); // Trigger another to wait for background finalization to end
|
||||
}
|
||||
|
||||
// Varying number of views of a buffer, to test the neutering weak pointers
|
||||
BEGIN_TEST(testArrayBuffer_bug720949_viewList)
|
||||
{
|
||||
JS::RootedObject buffer(cx);
|
||||
|
||||
// No views
|
||||
buffer = JS_NewArrayBuffer(cx, 2000);
|
||||
buffer = NULL;
|
||||
GC(cx);
|
||||
|
||||
// One view.
|
||||
{
|
||||
buffer = JS_NewArrayBuffer(cx, 2000);
|
||||
JS::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
|
||||
void *contents;
|
||||
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents));
|
||||
CHECK(contents != NULL);
|
||||
JS_free(cx, contents);
|
||||
GC(cx);
|
||||
CHECK(isNeutered(view));
|
||||
CHECK(isNeutered(buffer));
|
||||
view = NULL;
|
||||
GC(cx);
|
||||
buffer = NULL;
|
||||
GC(cx);
|
||||
}
|
||||
|
||||
// Two views
|
||||
{
|
||||
buffer = JS_NewArrayBuffer(cx, 2000);
|
||||
|
||||
JS::RootedObject view1(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
|
||||
JS::RootedObject view2(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200));
|
||||
|
||||
// Remove, re-add a view
|
||||
view2 = NULL;
|
||||
GC(cx);
|
||||
view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200);
|
||||
|
||||
// Neuter
|
||||
void *contents;
|
||||
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents));
|
||||
CHECK(contents != NULL);
|
||||
JS_free(cx, contents);
|
||||
|
||||
CHECK(isNeutered(view1));
|
||||
CHECK(isNeutered(view2));
|
||||
CHECK(isNeutered(buffer));
|
||||
|
||||
view1 = NULL;
|
||||
GC(cx);
|
||||
view2 = NULL;
|
||||
GC(cx);
|
||||
buffer = NULL;
|
||||
GC(cx);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isNeutered(JS::HandleObject obj) {
|
||||
JS::Value v;
|
||||
return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0;
|
||||
}
|
||||
|
||||
END_TEST(testArrayBuffer_bug720949_viewList)
|
@ -1082,7 +1082,7 @@ JS_NewRuntime(uint32_t maxbytes)
|
||||
InitMemorySubsystem();
|
||||
|
||||
if (!JS::TlsRuntime.init())
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
js_NewRuntimeWasCalled = JS_TRUE;
|
||||
}
|
||||
|
@ -4834,6 +4834,37 @@ JS_ClearNonGlobalObject(JSContext *cx, JSObject *objArg);
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg);
|
||||
|
||||
/*
|
||||
* Create a new array buffer with the given contents, which must have been
|
||||
* returned by JS_AllocateArrayBufferContents or JS_StealArrayBufferContents.
|
||||
* The new array buffer takes ownership. After calling this function, do not
|
||||
* free |contents| or use |contents| from another thread.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_NewArrayBufferWithContents(JSContext *cx, void *contents);
|
||||
|
||||
/*
|
||||
* Steal the contents of the given array buffer. The array buffer has its
|
||||
* length set to 0 and its contents array cleared. The caller takes ownership
|
||||
* of |contents| and must free it or transfer ownership via
|
||||
* JS_NewArrayBufferWithContents when done using it.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents);
|
||||
|
||||
/*
|
||||
* Allocate memory that may be eventually passed to
|
||||
* JS_NewArrayBufferWithContents. |nbytes| is the number of payload bytes
|
||||
* required. The pointer to pass to JS_NewArrayBufferWithContents is returned
|
||||
* in |contents|. The pointer to the |nbytes| of usable memory is returned in
|
||||
* |data|. (*|contents| will contain a header before |data|.) The only legal
|
||||
* operations on *|contents| is to free it or pass it to
|
||||
* JS_NewArrayBufferWithContents.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data);
|
||||
|
||||
|
||||
extern JS_PUBLIC_API(JSIdArray *)
|
||||
JS_Enumerate(JSContext *cx, JSObject *obj);
|
||||
|
||||
|
@ -238,7 +238,11 @@ JSRuntime::createJaegerRuntime(JSContext *cx)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
||||
{
|
||||
PrintError(cx, stderr, message, report, true);
|
||||
}
|
||||
static JSClass self_hosting_global_class = {
|
||||
"self-hosting-global", JSCLASS_GLOBAL_FLAGS,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
@ -264,11 +268,16 @@ JSRuntime::initSelfHosting(JSContext *cx)
|
||||
|
||||
RootedObject shg(cx, selfHostedGlobal_);
|
||||
Value rv;
|
||||
if (!Evaluate(cx, shg, options, src, srcLen, &rv))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Set a temporary error reporter printing to stderr because it is too
|
||||
* early in the startup process for any other reporter to be registered
|
||||
* and we don't want errors in self-hosted code to be silently swallowed.
|
||||
*/
|
||||
JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
|
||||
bool ok = Evaluate(cx, shg, options, src, srcLen, &rv);
|
||||
JS_SetErrorReporter(cx, oldReporter);
|
||||
JS_SetGlobalObject(cx, savedGlobal);
|
||||
return true;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
@ -678,6 +687,78 @@ ReportUsageError(JSContext *cx, HandleObject callee, const char *msg)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *report,
|
||||
bool reportWarnings)
|
||||
{
|
||||
if (!report) {
|
||||
fprintf(file, "%s\n", message);
|
||||
fflush(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Conditionally ignore reported warnings. */
|
||||
if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
|
||||
return false;
|
||||
|
||||
char *prefix = NULL;
|
||||
if (report->filename)
|
||||
prefix = JS_smprintf("%s:", report->filename);
|
||||
if (report->lineno) {
|
||||
char *tmp = prefix;
|
||||
prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column);
|
||||
JS_free(cx, tmp);
|
||||
}
|
||||
if (JSREPORT_IS_WARNING(report->flags)) {
|
||||
char *tmp = prefix;
|
||||
prefix = JS_smprintf("%s%swarning: ",
|
||||
tmp ? tmp : "",
|
||||
JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
|
||||
JS_free(cx, tmp);
|
||||
}
|
||||
|
||||
/* embedded newlines -- argh! */
|
||||
const char *ctmp;
|
||||
while ((ctmp = strchr(message, '\n')) != 0) {
|
||||
ctmp++;
|
||||
if (prefix)
|
||||
fputs(prefix, file);
|
||||
fwrite(message, 1, ctmp - message, file);
|
||||
message = ctmp;
|
||||
}
|
||||
|
||||
/* If there were no filename or lineno, the prefix might be empty */
|
||||
if (prefix)
|
||||
fputs(prefix, file);
|
||||
fputs(message, file);
|
||||
|
||||
if (report->linebuf) {
|
||||
/* report->linebuf usually ends with a newline. */
|
||||
int n = strlen(report->linebuf);
|
||||
fprintf(file, ":\n%s%s%s%s",
|
||||
prefix,
|
||||
report->linebuf,
|
||||
(n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n",
|
||||
prefix);
|
||||
n = report->tokenptr - report->linebuf;
|
||||
for (int i = 0, j = 0; i < n; i++) {
|
||||
if (report->linebuf[i] == '\t') {
|
||||
for (int k = (j + 8) & ~7; j < k; j++) {
|
||||
fputc('.', file);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
fputc('.', file);
|
||||
j++;
|
||||
}
|
||||
fputc('^', file);
|
||||
}
|
||||
fputc('\n', file);
|
||||
fflush(file);
|
||||
JS_free(cx, prefix);
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
|
@ -1759,6 +1759,15 @@ namespace js {
|
||||
extern void
|
||||
ReportUsageError(JSContext *cx, HandleObject callee, const char *msg);
|
||||
|
||||
/*
|
||||
* Prints a full report and returns true if the given report is non-NULL and
|
||||
* the report doesn't have the JSREPORT_WARNING flag set or reportWarnings is
|
||||
* true.
|
||||
* Returns false otherwise, printing just the message if the report is NULL.
|
||||
*/
|
||||
extern bool
|
||||
PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *report,
|
||||
bool reportWarnings);
|
||||
} /* namespace js */
|
||||
|
||||
extern void
|
||||
|
@ -1193,7 +1193,7 @@ JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSArrayBufferViewType)
|
||||
JS_GetTypedArrayType(JSObject *obj, JSContext *cx);
|
||||
JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may
|
||||
@ -1202,7 +1202,7 @@ JS_GetTypedArrayType(JSObject *obj, JSContext *cx);
|
||||
* accessor JSAPI calls defined below.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferObject(JSObject *obj, JSContext *cx);
|
||||
JS_IsArrayBufferObject(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Return the available byte length of an array buffer.
|
||||
@ -1213,11 +1213,12 @@ JS_IsArrayBufferObject(JSObject *obj, JSContext *cx);
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Return a pointer to an array buffer's data. The buffer is still owned by the
|
||||
* array buffer object, and should not be modified on another thread.
|
||||
* array buffer object, and should not be modified on another thread. The
|
||||
* returned pointer is stable across GCs.
|
||||
*
|
||||
* |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
|
||||
* that it would pass such a test: it is an ArrayBuffer or a wrapper of an
|
||||
@ -1225,7 +1226,7 @@ JS_GetArrayBufferByteLength(JSObject *obj, JSContext *cx);
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetArrayBufferData(JSObject *obj, JSContext *cx);
|
||||
JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Return the number of elements in a typed array.
|
||||
@ -1287,30 +1288,30 @@ JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx);
|
||||
*/
|
||||
|
||||
extern JS_FRIEND_API(int8_t *)
|
||||
JS_GetInt8ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(int16_t *)
|
||||
JS_GetInt16ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(uint16_t *)
|
||||
JS_GetUint16ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(int32_t *)
|
||||
JS_GetInt32ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(uint32_t *)
|
||||
JS_GetUint32ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(float *)
|
||||
JS_GetFloat32ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(double *)
|
||||
JS_GetFloat64ArrayData(JSObject *obj, JSContext *cx);
|
||||
JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
|
||||
* versions when possible.
|
||||
*/
|
||||
extern JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *cx);
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetDataView* APIs. Note that this may fail and
|
||||
@ -1330,7 +1331,7 @@ JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx);
|
||||
JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Return the byte length of a data view.
|
||||
@ -1341,7 +1342,7 @@ JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx);
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Return a pointer to the beginning of the data referenced by a DataView.
|
||||
@ -1352,7 +1353,7 @@ JS_GetDataViewByteLength(JSObject *obj, JSContext *cx);
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetDataViewData(JSObject *obj, JSContext *cx);
|
||||
JS_GetDataViewData(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
|
@ -558,7 +558,7 @@ struct JSObject : public js::ObjectImpl
|
||||
inline bool ensureElements(JSContext *cx, unsigned cap);
|
||||
bool growElements(JSContext *cx, unsigned cap);
|
||||
void shrinkElements(JSContext *cx, unsigned cap);
|
||||
|
||||
inline void setDynamicElements(js::ObjectElements *header);
|
||||
|
||||
/*
|
||||
* Array-specific getters and setters (for both dense and slow arrays).
|
||||
|
@ -415,6 +415,14 @@ JSObject::ensureElements(JSContext *cx, uint32_t capacity)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDynamicElements(js::ObjectElements *header)
|
||||
{
|
||||
JS_ASSERT(!hasDynamicElements());
|
||||
elements = header->elements();
|
||||
JS_ASSERT(hasDynamicElements());
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDenseArrayElement(unsigned idx, const js::Value &val)
|
||||
{
|
||||
|
@ -5968,7 +5968,7 @@ ExpressionDecompiler::decompilePC(jsbytecode *pc)
|
||||
else
|
||||
return write("[") &&
|
||||
quote(prop, '\'') &&
|
||||
write("]") >= 0;
|
||||
write("]");
|
||||
return true;
|
||||
}
|
||||
case JSOP_GETELEM:
|
||||
@ -6024,7 +6024,7 @@ ExpressionDecompiler::decompilePC(jsbytecode *pc)
|
||||
return write(js_this_str);
|
||||
case JSOP_CALL:
|
||||
case JSOP_FUNCALL:
|
||||
return decompilePC(pcstack[-(GET_ARGC(pc) + 2)]) &&
|
||||
return decompilePC(pcstack[-int32_t(GET_ARGC(pc) + 2)]) &&
|
||||
write("(...)");
|
||||
default:
|
||||
break;
|
||||
@ -6192,13 +6192,13 @@ DecompileExpressionFromStack(JSContext *cx, int spindex, int skipStackHits, Valu
|
||||
if (!valuepc)
|
||||
return true;
|
||||
|
||||
ExpressionDecompiler ea(cx, script, fun);
|
||||
if (!ea.init())
|
||||
ExpressionDecompiler ed(cx, script, fun);
|
||||
if (!ed.init())
|
||||
return false;
|
||||
if (!ea.decompilePC(valuepc))
|
||||
if (!ed.decompilePC(valuepc))
|
||||
return false;
|
||||
|
||||
return ea.getOutput(res);
|
||||
return ed.getOutput(res);
|
||||
}
|
||||
|
||||
char *
|
||||
|
@ -178,7 +178,7 @@ XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, un
|
||||
}
|
||||
|
||||
for (BindingIter bi(script->bindings); bi; bi++) {
|
||||
uint8_t u8 = (uint8_t(bi->kind()) << 1) | bi->aliased();
|
||||
uint8_t u8 = (uint8_t(bi->kind()) << 1) | uint8_t(bi->aliased());
|
||||
if (!xdr->codeUint8(&u8))
|
||||
return false;
|
||||
}
|
||||
|
@ -202,8 +202,28 @@ ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that some callers are allowed to pass in a NULL cx, so we allocate with
|
||||
* the cx if available and fall back to the runtime.
|
||||
*/
|
||||
static ObjectElements *
|
||||
AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, uint8_t *contents)
|
||||
{
|
||||
uint32_t size = nbytes + sizeof(ObjectElements);
|
||||
ObjectElements *newheader =
|
||||
static_cast<ObjectElements *>(maybecx ? maybecx->calloc_(size) : OffTheBooks::calloc_(size));
|
||||
if (!newheader) {
|
||||
if (maybecx)
|
||||
js_ReportOutOfMemory(maybecx);
|
||||
return NULL;
|
||||
}
|
||||
if (contents)
|
||||
memcpy(newheader->elements(), contents, nbytes);
|
||||
return newheader;
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayBufferObject::allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents)
|
||||
ArrayBufferObject::allocateSlots(JSContext *maybecx, uint32_t bytes, uint8_t *contents)
|
||||
{
|
||||
/*
|
||||
* ArrayBufferObjects delegate added properties to another JSObject, so
|
||||
@ -214,36 +234,133 @@ ArrayBufferObject::allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents
|
||||
|
||||
size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER;
|
||||
|
||||
if (size > sizeof(Value) * usableSlots) {
|
||||
ObjectElements *newheader = (ObjectElements *)cx->calloc_(size + sizeof(ObjectElements));
|
||||
if (!newheader)
|
||||
if (bytes > sizeof(Value) * usableSlots) {
|
||||
ObjectElements *header = AllocateArrayBufferContents(maybecx, bytes, contents);
|
||||
if (!header)
|
||||
return false;
|
||||
elements = newheader->elements();
|
||||
if (contents)
|
||||
memcpy(elements, contents, size);
|
||||
elements = header->elements();
|
||||
} else {
|
||||
elements = fixedElements();
|
||||
if (contents)
|
||||
memcpy(elements, contents, size);
|
||||
memcpy(elements, contents, bytes);
|
||||
else
|
||||
memset(elements, 0, size);
|
||||
memset(elements, 0, bytes);
|
||||
}
|
||||
|
||||
ObjectElements *header = getElementsHeader();
|
||||
|
||||
/*
|
||||
* Note that |bytes| may not be a multiple of |sizeof(Value)|, so
|
||||
* |capacity * sizeof(Value)| may underestimate the size by up to
|
||||
* |sizeof(Value) - 1| bytes.
|
||||
*/
|
||||
header->capacity = size / sizeof(Value);
|
||||
header->initializedLength = 0;
|
||||
header->length = size;
|
||||
header->unused = 0;
|
||||
setElementsHeader(getElementsHeader(), bytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
NextViewSlot(JSObject *obj)
|
||||
{
|
||||
return obj->isTypedArray() ? TypedArray::FIELD_NEXT_VIEW : DataViewObject::NEXT_VIEW_SLOT;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
NextView(JSObject *obj)
|
||||
{
|
||||
return obj->getFixedSlot(NextViewSlot(obj)).toObjectOrNull();
|
||||
}
|
||||
|
||||
static void
|
||||
SetNextView(JSObject *obj, JSObject *view)
|
||||
{
|
||||
return obj->setFixedSlot(NextViewSlot(obj), ObjectOrNullValue(view));
|
||||
}
|
||||
|
||||
static JSObject **
|
||||
GetViewList(ArrayBufferObject *obj)
|
||||
{
|
||||
#if USE_NEW_OBJECT_REPRESENTATION
|
||||
// untested
|
||||
return obj->getElementsHeader()->asArrayBufferElements().viewList();
|
||||
#else
|
||||
// The list of views must be stored somewhere in the ArrayBufferObject, but
|
||||
// the slots are already being used for the element storage and the private
|
||||
// field is used for a delegate object. The ObjectElements header has space
|
||||
// for it, but I don't want to mess around with adding unions to it with
|
||||
// USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much
|
||||
// more cleanly.
|
||||
struct OldObjectRepresentationHack {
|
||||
uint32_t capacity;
|
||||
uint32_t initializedLength;
|
||||
JSObject *views;
|
||||
};
|
||||
return &reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayBufferObject::uninlineData(JSContext *maybecx)
|
||||
{
|
||||
if (hasDynamicElements())
|
||||
return true;
|
||||
|
||||
// Grab out data before invalidating it
|
||||
uint32_t bytes = byteLength();
|
||||
uintptr_t oldPointer = uintptr_t(dataPointer());
|
||||
JSObject *view = *GetViewList(this);
|
||||
JSObject *viewListHead = view;
|
||||
|
||||
ObjectElements *header = AllocateArrayBufferContents(maybecx, bytes,
|
||||
reinterpret_cast<uint8_t*>(oldPointer));
|
||||
if (!header)
|
||||
return false;
|
||||
elements = header->elements();
|
||||
setElementsHeader(getElementsHeader(), bytes);
|
||||
|
||||
// Update all views
|
||||
uintptr_t newPointer = uintptr_t(dataPointer());
|
||||
while (view) {
|
||||
uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldPointer + newPointer;
|
||||
view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr));
|
||||
view = NextView(view);
|
||||
}
|
||||
|
||||
// Restore the list of views
|
||||
*GetViewList(this) = viewListHead;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ArrayBufferObject::addView(JSContext *cx, RawObject view)
|
||||
{
|
||||
JSObject **views = GetViewList(this);
|
||||
SetNextView(view, *views);
|
||||
*views = view;
|
||||
}
|
||||
|
||||
void
|
||||
ArrayBufferObject::removeFinalizedView(FreeOp *fop, RawObject view)
|
||||
{
|
||||
JSObject **views = GetViewList(this);
|
||||
|
||||
if (*views == view) {
|
||||
*views = NextView(view);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We traverse this during finalization, but all views in the list are
|
||||
* guaranteed to be valid. Any view that has already been finalized will
|
||||
* have already been removed from the list. Anything left either has not
|
||||
* been finalized yet, or is still alive.
|
||||
*/
|
||||
JSObject *next;
|
||||
for (JSObject *linkObj = *views; true; linkObj = next) {
|
||||
JS_ASSERT(linkObj); // Should always find view in the list
|
||||
uint32_t linkObjSlot = NextViewSlot(linkObj);
|
||||
next = linkObj->getFixedSlot(linkObjSlot).toObjectOrNull();
|
||||
if (next == view) {
|
||||
linkObj->setFixedSlot(linkObjSlot, ObjectOrNullValue(NextView(next)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *
|
||||
ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents)
|
||||
{
|
||||
@ -263,8 +380,8 @@ ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents)
|
||||
obj->setLastPropertyInfallible(empty);
|
||||
|
||||
/*
|
||||
* The first 8 bytes hold the length.
|
||||
* The rest of it is a flat data store for the array buffer.
|
||||
* The beginning stores an ObjectElements header structure holding the
|
||||
* length. The rest of it is a flat data store for the array buffer.
|
||||
*/
|
||||
if (!obj->asArrayBuffer().allocateSlots(cx, nbytes, contents))
|
||||
return NULL;
|
||||
@ -318,6 +435,39 @@ ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp
|
||||
return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents)
|
||||
{
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
JSObject *views = *GetViewList(&buffer);
|
||||
js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
|
||||
if (buffer.hasDynamicElements()) {
|
||||
*contents = header;
|
||||
|
||||
buffer.setFixedElements();
|
||||
header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
|
||||
} else {
|
||||
uint32_t length = buffer.byteLength();
|
||||
js::ObjectElements *newheader =
|
||||
AllocateArrayBufferContents(cx, length, buffer.dataPointer());
|
||||
if (!newheader) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
ArrayBufferObject::setElementsHeader(newheader, length);
|
||||
*contents = newheader;
|
||||
}
|
||||
|
||||
// Neuter the donor ArrayBuffer and all views of it
|
||||
ArrayBufferObject::setElementsHeader(header, 0);
|
||||
*GetViewList(&buffer) = views;
|
||||
for (JSObject *view = views; view; view = NextView(view))
|
||||
TypedArray::neuter(cx, view);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
@ -704,6 +854,16 @@ js::IsDataView(JSObject* obj)
|
||||
return obj->isDataView();
|
||||
}
|
||||
|
||||
void
|
||||
TypedArray::neuter(JSContext *cx, RawObject tarray)
|
||||
{
|
||||
JS_ASSERT(tarray->isTypedArray());
|
||||
tarray->setSlot(FIELD_LENGTH, Int32Value(0));
|
||||
tarray->setSlot(FIELD_BYTELENGTH, Int32Value(0));
|
||||
tarray->setSlot(FIELD_BYTEOFFSET, Int32Value(0));
|
||||
tarray->setPrivate(NULL);
|
||||
}
|
||||
|
||||
JSBool
|
||||
TypedArray::obj_lookupGeneric(JSContext *cx, HandleObject tarray, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
@ -916,6 +1076,15 @@ class TypedArrayTemplate
|
||||
return v.isObject() && v.toObject().hasClass(fastClass());
|
||||
}
|
||||
|
||||
static void
|
||||
obj_finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->hasClass(fastClass()));
|
||||
JSObject *bufobj = buffer(obj);
|
||||
if (!JS_IsAboutToBeFinalized(bufobj))
|
||||
bufobj->asArrayBuffer().removeFinalizedView(fop, obj);
|
||||
}
|
||||
|
||||
static void
|
||||
obj_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
@ -1244,10 +1413,10 @@ class TypedArrayTemplate
|
||||
makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len,
|
||||
HandleObject proto)
|
||||
{
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, protoClass()));
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, fastClass()));
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8_BACKGROUND);
|
||||
JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8);
|
||||
|
||||
if (proto) {
|
||||
types::TypeObject *type = proto->getNewType(cx);
|
||||
@ -1278,9 +1447,14 @@ class TypedArrayTemplate
|
||||
obj->setSlot(FIELD_LENGTH, Int32Value(len));
|
||||
obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset));
|
||||
obj->setSlot(FIELD_BYTELENGTH, Int32Value(len * sizeof(NativeType)));
|
||||
obj->setSlot(FIELD_NEXT_VIEW, NullValue());
|
||||
|
||||
JS_ASSERT(obj->getClass() == protoClass());
|
||||
|
||||
// Mark the object as non-extensible. We cannot simply call
|
||||
// obj->preventExtensions() because that has to iterate through all
|
||||
// properties, and on long arrays that is much too slow. We could
|
||||
// initialize the length fields to zero to avoid that, but then it
|
||||
// would just boil down to a slightly slower wrapper around the
|
||||
// following code anyway:
|
||||
js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(),
|
||||
obj->getProto(), obj->getParent(),
|
||||
gc::FINALIZE_OBJECT8,
|
||||
@ -1300,6 +1474,8 @@ class TypedArrayTemplate
|
||||
JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS);
|
||||
#endif
|
||||
|
||||
buffer->addView(cx, obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -1726,8 +1902,11 @@ class TypedArrayTemplate
|
||||
fromArray(JSContext *cx, HandleObject other)
|
||||
{
|
||||
uint32_t len;
|
||||
if (!GetLengthProperty(cx, other, &len))
|
||||
if (other->isTypedArray()) {
|
||||
len = length(other);
|
||||
} else if (!GetLengthProperty(cx, other, &len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RootedObject bufobj(cx, createBufferWithSizeAndCount(cx, len));
|
||||
if (!bufobj)
|
||||
@ -1821,6 +2000,9 @@ class TypedArrayTemplate
|
||||
JS_ASSERT(thisTypedArrayObj->isTypedArray());
|
||||
JS_ASSERT(offset <= length(thisTypedArrayObj));
|
||||
JS_ASSERT(len <= length(thisTypedArrayObj) - offset);
|
||||
if (ar->isTypedArray())
|
||||
return copyFromTypedArray(cx, thisTypedArrayObj, ar, offset);
|
||||
|
||||
NativeType *dest = static_cast<NativeType*>(viewData(thisTypedArrayObj)) + offset;
|
||||
SkipRoot skip(cx, &dest);
|
||||
|
||||
@ -2258,6 +2440,14 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
return construct(cx, bufobj, args, NULL);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
DataViewObject::obj_finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
DataViewObject &view = obj->asDataView();
|
||||
if (view.hasBuffer() && !JS_IsAboutToBeFinalized(&view.arrayBuffer()))
|
||||
view.arrayBuffer().removeFinalizedView(fop, &view);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
DataViewObject::getDataPointer(JSContext *cx, Handle<DataViewObject*> obj,
|
||||
CallArgs args, size_t typeSize, uint8_t **data)
|
||||
@ -2956,7 +3146,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
|
||||
JS_EnumerateStub, \
|
||||
JS_ResolveStub, \
|
||||
JS_ConvertStub, \
|
||||
NULL, /* finalize */ \
|
||||
_typedArray::obj_finalize, \
|
||||
NULL, /* checkAccess */ \
|
||||
NULL, /* call */ \
|
||||
NULL, /* construct */ \
|
||||
@ -3156,7 +3346,7 @@ Class js::DataViewClass = {
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
NULL, /* finalize */
|
||||
DataViewObject::obj_finalize,
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
@ -3354,23 +3544,24 @@ JS_IsArrayBufferViewObject(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferByteLength(JSObject *objArg, JSContext *cx)
|
||||
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
return obj->asArrayBuffer().byteLength();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
JS_GetArrayBufferData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
return obj->asArrayBuffer().dataPointer();
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
if (!buffer.uninlineData(maybecx))
|
||||
return NULL;
|
||||
return buffer.dataPointer();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
@ -3380,11 +3571,51 @@ JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
|
||||
return ArrayBufferObject::create(cx, nbytes);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayLength(JSObject *objArg, JSContext *cx)
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewArrayBufferWithContents(JSContext *cx, void *contents)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
if (!contents)
|
||||
return NULL;
|
||||
JSObject *obj = ArrayBufferObject::create(cx, 0);
|
||||
obj->setDynamicElements(reinterpret_cast<js::ObjectElements *>(contents));
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data)
|
||||
{
|
||||
js::ObjectElements *header = AllocateArrayBufferContents(cx, nbytes, NULL);
|
||||
if (!header)
|
||||
return false;
|
||||
|
||||
ArrayBufferObject::setElementsHeader(header, nbytes);
|
||||
|
||||
*contents = header;
|
||||
*data = reinterpret_cast<uint8_t*>(header->elements());
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents)
|
||||
{
|
||||
if (!(obj = UnwrapObjectChecked(cx, obj)))
|
||||
return false;
|
||||
|
||||
if (!obj->isArrayBuffer()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ArrayBufferObject::stealContents(cx, obj, contents))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayLength(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3392,10 +3623,9 @@ JS_GetTypedArrayLength(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayByteOffset(JSObject *objArg, JSContext *cx)
|
||||
JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3403,10 +3633,9 @@ JS_GetTypedArrayByteOffset(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayByteLength(JSObject *objArg, JSContext *cx)
|
||||
JS_GetTypedArrayByteLength(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3414,10 +3643,9 @@ JS_GetTypedArrayByteLength(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSArrayBufferViewType)
|
||||
JS_GetTypedArrayType(JSObject *objArg, JSContext *cx)
|
||||
JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return ArrayBufferView::TYPE_MAX;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3425,10 +3653,9 @@ JS_GetTypedArrayType(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int8_t *)
|
||||
JS_GetInt8ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3437,10 +3664,9 @@ JS_GetInt8ArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3449,10 +3675,9 @@ JS_GetUint8ArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ClampedArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3461,10 +3686,9 @@ JS_GetUint8ClampedArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int16_t *)
|
||||
JS_GetInt16ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3473,10 +3697,9 @@ JS_GetInt16ArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint16_t *)
|
||||
JS_GetUint16ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3485,10 +3708,9 @@ JS_GetUint16ArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int32_t *)
|
||||
JS_GetInt32ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3497,10 +3719,9 @@ JS_GetInt32ArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t *)
|
||||
JS_GetUint32ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3509,10 +3730,9 @@ JS_GetUint32ArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(float *)
|
||||
JS_GetFloat32ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3521,10 +3741,9 @@ JS_GetFloat32ArrayData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(double *)
|
||||
JS_GetFloat64ArrayData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
@ -3544,20 +3763,18 @@ JS_IsDataViewObject(JSContext *cx, JSObject *objArg, JSBool *isDataView)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteOffset(JSObject *objArg, JSContext *cx)
|
||||
JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
return obj->asDataView().byteOffset();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetDataViewData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetDataViewData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isDataView());
|
||||
@ -3565,10 +3782,9 @@ JS_GetDataViewData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteLength(JSObject *objArg, JSContext *cx)
|
||||
JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isDataView());
|
||||
@ -3576,10 +3792,9 @@ JS_GetDataViewByteLength(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *objArg, JSContext *cx)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
@ -3587,10 +3802,9 @@ JS_GetArrayBufferViewData(JSObject *objArg, JSContext *cx)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferViewByteLength(JSObject *objArg, JSContext *cx)
|
||||
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
RootedObject obj_(cx, objArg);
|
||||
JSObject *obj = CheckedUnwrap(cx, obj_);
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
|
@ -142,9 +142,28 @@ class ArrayBufferObject : public JSObject
|
||||
static JSType
|
||||
obj_typeOf(JSContext *cx, HandleObject obj);
|
||||
|
||||
static bool
|
||||
stealContents(JSContext *cx, JSObject *obj, void **contents);
|
||||
|
||||
static inline void
|
||||
setElementsHeader(js::ObjectElements *header, uint32_t bytes);
|
||||
|
||||
void
|
||||
addView(JSContext *cx, RawObject view);
|
||||
|
||||
void
|
||||
removeFinalizedView(FreeOp *fop, RawObject view);
|
||||
|
||||
bool
|
||||
allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL);
|
||||
|
||||
/*
|
||||
* Ensure that the data is not stored inline. Used when handing back a
|
||||
* GC-safe pointer.
|
||||
*/
|
||||
bool
|
||||
uninlineData(JSContext *cx);
|
||||
|
||||
inline uint32_t byteLength() const;
|
||||
|
||||
inline uint8_t * dataPointer() const;
|
||||
@ -192,6 +211,7 @@ struct TypedArray {
|
||||
FIELD_BYTELENGTH,
|
||||
FIELD_TYPE,
|
||||
FIELD_BUFFER,
|
||||
FIELD_NEXT_VIEW,
|
||||
FIELD_MAX,
|
||||
NUM_FIXED_SLOTS = 7
|
||||
};
|
||||
@ -239,6 +259,9 @@ struct TypedArray {
|
||||
static bool
|
||||
isArrayIndex(JSContext *cx, JSObject *obj, jsid id, uint32_t *ip = NULL);
|
||||
|
||||
static void
|
||||
neuter(JSContext *cx, RawObject tarray);
|
||||
|
||||
static inline uint32_t slotWidth(int atype);
|
||||
static inline int slotWidth(JSObject *obj);
|
||||
|
||||
@ -280,11 +303,14 @@ IsTypedArrayProto(JSObject *obj)
|
||||
|
||||
class DataViewObject : public JSObject
|
||||
{
|
||||
static Class protoClass;
|
||||
|
||||
public:
|
||||
static const size_t BYTEOFFSET_SLOT = 0;
|
||||
static const size_t BYTELENGTH_SLOT = 1;
|
||||
static const size_t BUFFER_SLOT = 2;
|
||||
static const size_t NEXT_VIEW_SLOT = 3;
|
||||
|
||||
private:
|
||||
static Class protoClass;
|
||||
|
||||
static inline bool is(const Value &v);
|
||||
|
||||
@ -301,7 +327,9 @@ class DataViewObject : public JSObject
|
||||
defineGetter(JSContext *cx, PropertyName *name, HandleObject proto);
|
||||
|
||||
public:
|
||||
static const size_t RESERVED_SLOTS = 3;
|
||||
// 4 slots + 1 private = 5, which gets rounded up to FINALIZE_OBJECT8,
|
||||
// which is 7 non-private
|
||||
static const size_t RESERVED_SLOTS = 7;
|
||||
|
||||
static inline Value bufferValue(DataViewObject &view);
|
||||
static inline Value byteOffsetValue(DataViewObject &view);
|
||||
@ -363,9 +391,12 @@ class DataViewObject : public JSObject
|
||||
static bool setFloat64Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static void
|
||||
obj_finalize(FreeOp *fop, JSObject *obj);
|
||||
|
||||
inline uint32_t byteLength();
|
||||
inline uint32_t byteOffset();
|
||||
inline JSObject & arrayBuffer();
|
||||
inline ArrayBufferObject & arrayBuffer();
|
||||
inline void *dataPointer();
|
||||
inline bool hasBuffer() const;
|
||||
static JSObject *initClass(JSContext *cx);
|
||||
|
@ -13,11 +13,25 @@
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
inline void
|
||||
js::ArrayBufferObject::setElementsHeader(js::ObjectElements *header, uint32_t bytes)
|
||||
{
|
||||
/*
|
||||
* Note that |bytes| may not be a multiple of |sizeof(Value)|, so
|
||||
* |capacity * sizeof(Value)| may underestimate the size by up to
|
||||
* |sizeof(Value) - 1| bytes.
|
||||
*/
|
||||
header->capacity = bytes / sizeof(js::Value);
|
||||
header->initializedLength = bytes;
|
||||
header->length = 0;
|
||||
header->unused = 0;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
js::ArrayBufferObject::byteLength() const
|
||||
{
|
||||
JS_ASSERT(isArrayBuffer());
|
||||
return getElementsHeader()->length;
|
||||
return getElementsHeader()->initializedLength;
|
||||
}
|
||||
|
||||
inline uint8_t *
|
||||
@ -231,6 +245,7 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
||||
dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength));
|
||||
dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
|
||||
dvobj.setFixedSlot(NEXT_VIEW_SLOT, NullValue());
|
||||
InitTypedArrayDataPointer(obj, arrayBuffer, byteOffset);
|
||||
JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
|
||||
|
||||
@ -264,11 +279,11 @@ DataViewObject::dataPointer()
|
||||
return getPrivate();
|
||||
}
|
||||
|
||||
inline JSObject &
|
||||
inline ArrayBufferObject &
|
||||
DataViewObject::arrayBuffer()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
return getReservedSlot(BUFFER_SLOT).toObject();
|
||||
return getReservedSlot(BUFFER_SLOT).toObject().asArrayBuffer();
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user