Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-08-31 21:36:07 -04:00
Родитель bf55adcf8c af7a42b5bb
Коммит 171736767a
265 изменённых файлов: 3621 добавлений и 1247 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -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;
};
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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(),

Просмотреть файл

@ -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 = \

Просмотреть файл

@ -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.

Просмотреть файл

@ -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 \

Просмотреть файл

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше