Merge m-c to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-10-07 15:08:19 +02:00
commit 3346857046
85 changed files with 2030 additions and 401 deletions

View File

@ -677,7 +677,9 @@ let MozLoopServiceInternal = {
// Make the call to get the GUEST session regardless of whether the FXA
// request fails.
this._getCalls(LOOP_SESSION_TYPE.FXA, version).catch(() => {});
if (MozLoopService.userProfile) {
this._getCalls(LOOP_SESSION_TYPE.FXA, version).catch(() => {});
}
this._getCalls(LOOP_SESSION_TYPE.GUEST, version).catch(
error => {this._hawkRequestError(error);});
},

View File

@ -52,6 +52,10 @@ function run_test()
{
setupFakeLoopServer();
// Setup fake login (profile) state so we get FxA requests.
const serviceGlobal = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
serviceGlobal.gFxAOAuthProfile = {email: "test@example.com", uid: "abcd1234"};
// For each notification received from the PushServer, MozLoopService will first query
// for any pending calls on the FxA hawk session and then again using the guest session.
// A pair of response objects in the callsResponses array will be consumed for each
@ -97,6 +101,9 @@ function run_test()
// Revert original Chat.open implementation
Chat.open = openChatOrig;
// Revert fake login state
serviceGlobal.gFxAOAuthProfile = null;
// clear test pref
Services.prefs.clearUserPref("loop.seenToS");
});

View File

@ -3,6 +3,7 @@
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-google-api-keyfile=/builds/gapi.data
ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
. $topsrcdir/build/unix/mozconfig.linux32

View File

@ -3,6 +3,7 @@
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-google-api-keyfile=/builds/gapi.data
ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
. $topsrcdir/build/unix/mozconfig.linux

View File

@ -8,6 +8,7 @@ ac_add_options --enable-application=browser
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-google-api-keyfile=/builds/gapi.data
ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -14,6 +14,12 @@ else
fi
ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
if [ -f /c/builds/google-oauth-api.key ]; then
_google_oauth_api_keyfile=/c/builds/google-oauth-api.key
else
_google_oauth_api_keyfile=/e/builds/google-oauth-api.key
fi
ac_add_options --with-google-api-keyfile=${_google_oauth_api_keyfile}
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -12,6 +12,13 @@ else
fi
ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
if [ -f /c/builds/google-oauth-api.key ]; then
_google_oauth_api_keyfile=/c/builds/google-oauth-api.key
else
_google_oauth_api_keyfile=/e/builds/google-oauth-api.key
fi
ac_add_options --with-google-api-keyfile=${_google_oauth_api_keyfile}
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -98,7 +98,10 @@ this.UITour = {
["help", {query: "#PanelUI-help"}],
["home", {query: "#home-button"}],
["loop", {query: "#loop-call-button"}],
["forget", {query: "#panic-button"}],
["forget", {
query: "#panic-button",
widgetName: "panic-button",
allowAdd: true }],
["privateWindow", {query: "#privatebrowsing-button"}],
["quit", {query: "#PanelUI-quit"}],
["search", {
@ -434,6 +437,15 @@ this.UITour = {
ResetProfile.openConfirmationDialog(window);
break;
}
case "addNavBarWidget": {
// Add a widget to the toolbar
let targetPromise = this.getTarget(window, data.name);
targetPromise.then(target => {
this.addNavBarWidget(target, contentDocument, data.callbackID);
}).then(null, Cu.reportError);
break;
}
}
if (!this.originTabs.has(window))
@ -698,6 +710,7 @@ this.UITour = {
removeTargetListener: targetObject.removeTargetListener,
targetName: aTargetName,
widgetName: targetObject.widgetName,
allowAdd: targetObject.allowAdd,
});
}).then(null, Cu.reportError);
return deferred.promise;
@ -1177,6 +1190,24 @@ this.UITour = {
});
},
addNavBarWidget: function (aTarget, aContentDocument, aCallbackID) {
if (aTarget.node) {
Cu.reportError("UITour: can't add a widget already present: " + data.target);
return;
}
if (!aTarget.allowAdd) {
Cu.reportError("UITour: not allowed to add this widget: " + data.target);
return;
}
if (!aTarget.widgetName) {
Cu.reportError("UITour: can't add a widget without a widgetName property: " + data.target);
return;
}
CustomizableUI.addWidgetToArea(aTarget.widgetName, CustomizableUI.AREA_NAVBAR);
this.sendPageCallback(aContentDocument, aCallbackID);
},
_addAnnotationPanelMutationObserver: function(aPanelEl) {
#ifdef XP_LINUX
let observer = this._annotationPanelMutationObservers.get(aPanelEl);

View File

@ -277,6 +277,31 @@ let tests = [
gContentAPI.getConfiguration("appinfo", callback);
},
function test_addToolbarButton(done) {
let placement = CustomizableUI.getPlacementOfWidget("panic-button");
is(placement, null, "default UI has panic button in the palette");
gContentAPI.getConfiguration("availableTargets", (data) => {
let available = (data.targets.indexOf("forget") != -1);
ok(!available, "Forget button should not be available by default");
gContentAPI.addNavBarWidget("forget", () => {
info("addNavBarWidget callback successfully called");
let placement = CustomizableUI.getPlacementOfWidget("panic-button");
is(placement.area, CustomizableUI.AREA_NAVBAR);
gContentAPI.getConfiguration("availableTargets", (data) => {
let available = (data.targets.indexOf("forget") != -1);
ok(available, "Forget button should now be available");
// Cleanup
CustomizableUI.removeWidgetFromArea("panic-button");
done();
});
});
});
},
// Make sure this test is last in the file so the appMenu gets left open and done will confirm it got tore down.
function cleanupMenus(done) {

View File

@ -183,4 +183,11 @@ if (typeof Mozilla == 'undefined') {
_sendEvent('resetFirefox');
};
Mozilla.UITour.addNavBarWidget= function(name, callback) {
_sendEvent('addNavBarWidget', {
name: name,
callbackID: _waitForCallback(callback),
});
};
})();

View File

@ -309,7 +309,7 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMis
log.info("%s | leakcheck | %s %d bytes leaked (%s)"
% (prefix, processString, totalBytesLeaked, leakedObjectSummary))
def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks):
def processLeakLog(leakLogFile, options):
"""Process the leak log, including separate leak logs created
by child processes.
@ -325,15 +325,25 @@ def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks):
All other file names are treated as being for default processes.
The options argument is checked for two optional attributes,
leakThresholds and ignoreMissingLeaks.
leakThresholds should be a dict mapping process types to leak thresholds,
in bytes. If a process type is not present in the dict the threshold
will be 0.
ignoreMissingLeaks should be a list of process types. If a process
creates a leak log without a TOTAL, then we report an error if it isn't
in the list ignoreMissingLeaks.
"""
if not os.path.exists(leakLogFile):
log.info("WARNING | leakcheck | refcount logging is off, so leaks can't be detected!")
return
leakThresholds = getattr(options, 'leakThresholds', {})
ignoreMissingLeaks = getattr(options, 'ignoreMissingLeaks', [])
# This list is based on kGeckoProcessTypeString. ipdlunittest processes likely
# are not going to produce leak logs we will ever see.
knownProcessTypes = ["default", "plugin", "tab", "geckomediaplugin"]

View File

@ -1728,7 +1728,7 @@ public:
return false;
}
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
if (aIsSync) {
@ -1755,7 +1755,7 @@ public:
return false;
}
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,

View File

@ -60,3 +60,5 @@ MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, "{0} is an invalid header value.")
MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, "Headers require name/value tuples when being initialized by a sequence.")
MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-origin object as {0}.")
MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, "Missing required {0}.")
MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, "Invalid request method {0}.")
MSG_DEF(MSG_REQUEST_BODY_CONSUMED_ERROR, 0, "Request body has already been consumed.")

100
dom/fetch/Fetch.cpp Normal file
View File

@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Fetch.h"
#include "nsIStringStream.h"
#include "nsIUnicodeEncoder.h"
#include "nsStringStream.h"
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/dom/URLSearchParams.h"
namespace mozilla {
namespace dom {
nsresult
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
nsIInputStream** aStream,
nsCString& aContentType)
{
MOZ_ASSERT(aStream);
nsresult rv;
nsCOMPtr<nsIInputStream> byteStream;
if (aBodyInit.IsArrayBuffer()) {
const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
buf.ComputeLengthAndData();
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
rv = NS_NewByteInputStream(getter_AddRefs(byteStream),
reinterpret_cast<char*>(buf.Data()),
buf.Length(), NS_ASSIGNMENT_COPY);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else if (aBodyInit.IsArrayBufferView()) {
const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
buf.ComputeLengthAndData();
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
rv = NS_NewByteInputStream(getter_AddRefs(byteStream),
reinterpret_cast<char*>(buf.Data()),
buf.Length(), NS_ASSIGNMENT_COPY);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else if (aBodyInit.IsScalarValueString()) {
nsString str = aBodyInit.GetAsScalarValueString();
nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
if (!encoder) {
return NS_ERROR_OUT_OF_MEMORY;
}
int32_t destBufferLen;
rv = encoder->GetMaxLength(str.get(), str.Length(), &destBufferLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCString encoded;
if (!encoded.SetCapacity(destBufferLen, fallible_t())) {
return NS_ERROR_OUT_OF_MEMORY;
}
char* destBuffer = encoded.BeginWriting();
int32_t srcLen = (int32_t) str.Length();
int32_t outLen = destBufferLen;
rv = encoder->Convert(str.get(), &srcLen, destBuffer, &outLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(outLen <= destBufferLen);
encoded.SetLength(outLen);
rv = NS_NewCStringInputStream(getter_AddRefs(byteStream), encoded);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8");
} else if (aBodyInit.IsURLSearchParams()) {
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
nsString serialized;
params.Stringify(serialized);
rv = NS_NewStringInputStream(getter_AddRefs(byteStream), serialized);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
}
MOZ_ASSERT(byteStream);
byteStream.forget(aStream);
return NS_OK;
}
} // namespace dom
} // namespace mozilla

29
dom/fetch/Fetch.h Normal file
View File

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_Fetch_h
#define mozilla_dom_Fetch_h
#include "mozilla/dom/UnionTypes.h"
class nsIInputStream;
namespace mozilla {
namespace dom {
/*
* Creates an nsIInputStream based on the fetch specifications 'extract a byte
* stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
* Stores content type in out param aContentType.
*/
nsresult
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
nsIInputStream** aStream,
nsCString& aContentType);
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Fetch_h

View File

@ -7,7 +7,6 @@
#include "mozilla/dom/Headers.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/Preferences.h"
@ -83,6 +82,39 @@ Headers::Constructor(const GlobalObject& aGlobal,
return headers.forget();
}
// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
ErrorResult& aRv)
{
nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports());
if (aInit.IsHeaders()) {
headers->Fill(aInit.GetAsHeaders(), aRv);
} else if (aInit.IsByteStringSequenceSequence()) {
headers->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
} else if (aInit.IsByteStringMozMap()) {
headers->Fill(aInit.GetAsByteStringMozMap(), aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return headers.forget();
}
Headers::Headers(const Headers& aOther)
: mOwner(aOther.mOwner)
, mGuard(aOther.mGuard)
{
SetIsDOMBinding();
ErrorResult result;
Fill(aOther, result);
MOZ_ASSERT(!result.Failed());
}
void
Headers::Append(const nsACString& aName, const nsACString& aValue,
ErrorResult& aRv)
@ -202,6 +234,12 @@ Headers::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv
}
}
void
Headers::Clear()
{
mList.Clear();
}
void
Headers::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
{
@ -328,6 +366,5 @@ Headers::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
}
}
} // namespace dom
} // namespace mozilla

View File

@ -8,6 +8,8 @@
#define mozilla_dom_Headers_h
#include "mozilla/dom/HeadersBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsClassHashtable.h"
#include "nsWrapperCache.h"
@ -42,7 +44,7 @@ private:
nsCString mValue;
};
nsRefPtr<nsISupports> mOwner;
nsCOMPtr<nsISupports> mOwner;
HeadersGuardEnum mGuard;
nsTArray<Entry> mList;
@ -54,6 +56,8 @@ public:
SetIsDOMBinding();
}
explicit Headers(const Headers& aOther);
static bool PrefEnabled(JSContext* cx, JSObject* obj);
static already_AddRefed<Headers>
@ -61,6 +65,11 @@ public:
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
ErrorResult& aRv);
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
ErrorResult& aRv);
void Append(const nsACString& aName, const nsACString& aValue,
ErrorResult& aRv);
void Delete(const nsACString& aName, ErrorResult& aRv);
@ -70,6 +79,8 @@ public:
bool Has(const nsACString& aName, ErrorResult& aRv) const;
void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
void Clear();
// ChromeOnly
HeadersGuardEnum Guard() const { return mGuard; }
void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
@ -77,8 +88,13 @@ public:
virtual JSObject* WrapObject(JSContext* aCx);
nsISupports* GetParentObject() const { return mOwner; }
void Fill(const Headers& aInit, ErrorResult& aRv);
private:
Headers(const Headers& aOther) MOZ_DELETE;
// Since Headers is also an nsISupports, the above constructor can
// accidentally be invoked as new Headers(Headers*[, implied None guard]) when
// the intention is to use the copy constructor. Explicitly disallow it.
Headers(Headers* aOther) MOZ_DELETE;
virtual ~Headers();
static bool IsSimpleHeader(const nsACString& aName,
@ -103,7 +119,6 @@ private:
IsForbiddenResponseHeader(aName);
}
void Fill(const Headers& aInit, ErrorResult& aRv);
void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
};

View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "InternalRequest.h"
#include "nsIContentPolicy.h"
#include "nsIDocument.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/workers/Workers.h"
#include "WorkerPrivate.h"
namespace mozilla {
namespace dom {
// The global is used to extract the principal.
already_AddRefed<InternalRequest>
InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const
{
nsRefPtr<InternalRequest> copy = new InternalRequest();
copy->mURL.Assign(mURL);
copy->SetMethod(mMethod);
copy->mHeaders = new Headers(*mHeaders);
copy->mBodyStream = mBodyStream;
copy->mPreserveContentCodings = true;
if (NS_IsMainThread()) {
nsIPrincipal* principal = aGlobal->PrincipalOrNull();
MOZ_ASSERT(principal);
aRv = nsContentUtils::GetASCIIOrigin(principal, copy->mOrigin);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} else {
workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
workers::WorkerPrivate::LocationInfo& location = worker->GetLocationInfo();
copy->mOrigin = NS_ConvertUTF16toUTF8(location.mOrigin);
}
copy->mMode = mMode;
copy->mCredentialsMode = mCredentialsMode;
// FIXME(nsm): Add ContentType fetch to nsIContentPolicy and friends.
// Then set copy's mContext to that.
return copy.forget();
}
InternalRequest::~InternalRequest()
{
}
} // namespace dom
} // namespace mozilla

264
dom/fetch/InternalRequest.h Normal file
View File

@ -0,0 +1,264 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_InternalRequest_h
#define mozilla_dom_InternalRequest_h
#include "mozilla/dom/Headers.h"
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsIContentPolicy.h"
#include "nsIInputStream.h"
#include "nsISupportsImpl.h"
class nsIDocument;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class FetchBodyStream;
class Request;
class InternalRequest MOZ_FINAL
{
friend class Request;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalRequest)
enum ContextFrameType
{
FRAMETYPE_AUXILIARY = 0,
FRAMETYPE_TOP_LEVEL,
FRAMETYPE_NESTED,
FRAMETYPE_NONE,
};
// Since referrer type can be none, client or a URL.
enum ReferrerType
{
REFERRER_NONE = 0,
REFERRER_CLIENT,
REFERRER_URL,
};
enum ResponseTainting
{
RESPONSETAINT_BASIC,
RESPONSETAINT_CORS,
RESPONSETAINT_OPAQUE,
};
explicit InternalRequest()
: mMethod("GET")
, mHeaders(new Headers(nullptr, HeadersGuardEnum::None))
, mContextFrameType(FRAMETYPE_NONE)
, mReferrerType(REFERRER_CLIENT)
, mMode(RequestMode::No_cors)
, mCredentialsMode(RequestCredentials::Omit)
, mResponseTainting(RESPONSETAINT_BASIC)
, mRedirectCount(0)
, mAuthenticationFlag(false)
, mForceOriginHeader(false)
, mManualRedirect(false)
, mPreserveContentCodings(false)
, mSameOriginDataURL(false)
, mSkipServiceWorker(false)
, mSynchronous(false)
, mUnsafeRequest(false)
, mUseURLCredentials(false)
{
}
explicit InternalRequest(const InternalRequest& aOther)
: mMethod(aOther.mMethod)
, mURL(aOther.mURL)
, mHeaders(aOther.mHeaders)
, mBodyStream(aOther.mBodyStream)
, mContext(aOther.mContext)
, mOrigin(aOther.mOrigin)
, mContextFrameType(aOther.mContextFrameType)
, mReferrerType(aOther.mReferrerType)
, mReferrerURL(aOther.mReferrerURL)
, mMode(aOther.mMode)
, mCredentialsMode(aOther.mCredentialsMode)
, mResponseTainting(aOther.mResponseTainting)
, mRedirectCount(aOther.mRedirectCount)
, mAuthenticationFlag(aOther.mAuthenticationFlag)
, mForceOriginHeader(aOther.mForceOriginHeader)
, mManualRedirect(aOther.mManualRedirect)
, mPreserveContentCodings(aOther.mPreserveContentCodings)
, mSameOriginDataURL(aOther.mSameOriginDataURL)
, mSandboxedStorageAreaURLs(aOther.mSandboxedStorageAreaURLs)
, mSkipServiceWorker(aOther.mSkipServiceWorker)
, mSynchronous(aOther.mSynchronous)
, mUnsafeRequest(aOther.mUnsafeRequest)
, mUseURLCredentials(aOther.mUseURLCredentials)
{
}
void
GetMethod(nsCString& aMethod) const
{
aMethod.Assign(mMethod);
}
void
SetMethod(const nsACString& aMethod)
{
mMethod.Assign(aMethod);
}
void
GetURL(nsCString& aURL) const
{
aURL.Assign(mURL);
}
bool
ReferrerIsNone() const
{
return mReferrerType == REFERRER_NONE;
}
bool
ReferrerIsURL() const
{
return mReferrerType == REFERRER_URL;
}
bool
ReferrerIsClient() const
{
return mReferrerType == REFERRER_CLIENT;
}
nsCString
ReferrerAsURL() const
{
MOZ_ASSERT(ReferrerIsURL());
return mReferrerURL;
}
void
SetReferrer(const nsACString& aReferrer)
{
// May be removed later.
MOZ_ASSERT(!ReferrerIsNone());
mReferrerType = REFERRER_URL;
mReferrerURL.Assign(aReferrer);
}
bool
IsSynchronous() const
{
return mSynchronous;
}
void
SetMode(RequestMode aMode)
{
mMode = aMode;
}
void
SetCredentialsMode(RequestCredentials aCredentialsMode)
{
mCredentialsMode = aCredentialsMode;
}
nsContentPolicyType
GetContext() const
{
return mContext;
}
Headers*
Headers_()
{
return mHeaders;
}
bool
ForceOriginHeader()
{
return mForceOriginHeader;
}
void
GetOrigin(nsCString& aOrigin) const
{
aOrigin.Assign(mOrigin);
}
void
SetBody(nsIInputStream* aStream)
{
mBodyStream = aStream;
}
// Will return the original stream!
// Use a tee or copy if you don't want to erase the original.
void
GetBody(nsIInputStream** aStream)
{
nsCOMPtr<nsIInputStream> s = mBodyStream;
s.forget(aStream);
}
// The global is used as the client for the new object.
already_AddRefed<InternalRequest>
GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
private:
~InternalRequest();
void
SetURL(const nsACString& aURL)
{
mURL.Assign(aURL);
}
nsCString mMethod;
nsCString mURL;
nsRefPtr<Headers> mHeaders;
nsCOMPtr<nsIInputStream> mBodyStream;
// nsContentPolicyType does not cover the complete set defined in the spec,
// but it is a good start.
nsContentPolicyType mContext;
nsCString mOrigin;
ContextFrameType mContextFrameType;
ReferrerType mReferrerType;
// When mReferrerType is REFERRER_URL.
nsCString mReferrerURL;
RequestMode mMode;
RequestCredentials mCredentialsMode;
ResponseTainting mResponseTainting;
uint32_t mRedirectCount;
bool mAuthenticationFlag;
bool mForceOriginHeader;
bool mManualRedirect;
bool mPreserveContentCodings;
bool mSameOriginDataURL;
bool mSandboxedStorageAreaURLs;
bool mSkipServiceWorker;
bool mSynchronous;
bool mUnsafeRequest;
bool mUseURLCredentials;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_InternalRequest_h

View File

@ -5,30 +5,44 @@
#include "Request.h"
#include "nsDOMString.h"
#include "nsISupportsImpl.h"
#include "nsIUnicodeDecoder.h"
#include "nsIURI.h"
#include "nsDOMFile.h"
#include "nsDOMString.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsStreamUtils.h"
#include "nsStringStream.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/dom/Headers.h"
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/URL.h"
#include "mozilla/dom/workers/bindings/URL.h"
// dom/workers
#include "File.h"
#include "WorkerPrivate.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner, mHeaders)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Request::Request(nsISupports* aOwner)
Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest)
: mOwner(aOwner)
, mHeaders(new Headers(aOwner))
, mRequest(aRequest)
, mBodyUsed(false)
{
SetIsDOMBinding();
}
@ -37,82 +51,393 @@ Request::~Request()
{
}
/*static*/ already_AddRefed<Request>
Request::Constructor(const GlobalObject& global,
const RequestOrScalarValueString& aInput,
const RequestInit& aInit, ErrorResult& rv)
already_AddRefed<InternalRequest>
Request::GetInternalRequest()
{
nsRefPtr<Request> request = new Request(global.GetAsSupports());
return request.forget();
nsRefPtr<InternalRequest> r = mRequest;
return r.forget();
}
/*static*/ already_AddRefed<Request>
Request::Constructor(const GlobalObject& aGlobal,
const RequestOrScalarValueString& aInput,
const RequestInit& aInit, ErrorResult& aRv)
{
nsRefPtr<InternalRequest> request;
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (aInput.IsRequest()) {
nsRefPtr<Request> inputReq = &aInput.GetAsRequest();
if (inputReq->BodyUsed()) {
aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
return nullptr;
}
inputReq->SetBodyUsed();
request = inputReq->GetInternalRequest();
} else {
request = new InternalRequest();
}
request = request->GetRequestConstructorCopy(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RequestMode fallbackMode = RequestMode::EndGuard_;
RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
if (aInput.IsScalarValueString()) {
nsString input;
input.Assign(aInput.GetAsScalarValueString());
nsString requestURL;
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
MOZ_ASSERT(window);
nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
nsCString spec;
aRv = docURI->GetSpec(spec);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsRefPtr<mozilla::dom::URL> url =
dom::URL::Constructor(aGlobal, input, NS_ConvertUTF8toUTF16(spec), aRv);
if (aRv.Failed()) {
return nullptr;
}
url->Stringify(requestURL, aRv);
if (aRv.Failed()) {
return nullptr;
}
} else {
workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
nsString baseURL = NS_ConvertUTF8toUTF16(worker->GetLocationInfo().mHref);
nsRefPtr<workers::URL> url =
workers::URL::Constructor(aGlobal, input, baseURL, aRv);
if (aRv.Failed()) {
return nullptr;
}
url->Stringify(requestURL, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
request->SetURL(NS_ConvertUTF16toUTF8(requestURL));
fallbackMode = RequestMode::Cors;
fallbackCredentials = RequestCredentials::Omit;
}
RequestMode mode = aInit.mMode.WasPassed() ? aInit.mMode.Value() : fallbackMode;
RequestCredentials credentials =
aInit.mCredentials.WasPassed() ? aInit.mCredentials.Value()
: fallbackCredentials;
if (mode != RequestMode::EndGuard_) {
request->SetMode(mode);
}
if (credentials != RequestCredentials::EndGuard_) {
request->SetCredentialsMode(credentials);
}
if (aInit.mMethod.WasPassed()) {
nsCString method = aInit.mMethod.Value();
ToLowerCase(method);
if (!method.EqualsASCII("options") &&
!method.EqualsASCII("get") &&
!method.EqualsASCII("head") &&
!method.EqualsASCII("post") &&
!method.EqualsASCII("put") &&
!method.EqualsASCII("delete")) {
NS_ConvertUTF8toUTF16 label(method);
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
return nullptr;
}
ToUpperCase(method);
request->SetMethod(method);
}
nsRefPtr<Request> domRequest = new Request(global, request);
nsRefPtr<Headers> domRequestHeaders = domRequest->Headers_();
nsRefPtr<Headers> headers;
if (aInit.mHeaders.WasPassed()) {
headers = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
if (aRv.Failed()) {
return nullptr;
}
} else {
headers = new Headers(*domRequestHeaders);
}
domRequestHeaders->Clear();
if (domRequest->Mode() == RequestMode::No_cors) {
nsCString method;
domRequest->GetMethod(method);
ToLowerCase(method);
if (!method.EqualsASCII("get") &&
!method.EqualsASCII("head") &&
!method.EqualsASCII("post")) {
NS_ConvertUTF8toUTF16 label(method);
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
return nullptr;
}
domRequestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
domRequestHeaders->Fill(*headers, aRv);
if (aRv.Failed()) {
return nullptr;
}
if (aInit.mBody.WasPassed()) {
const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
nsCOMPtr<nsIInputStream> stream;
nsCString contentType;
aRv = ExtractByteStreamFromBody(bodyInit,
getter_AddRefs(stream), contentType);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
request->SetBody(stream);
if (!contentType.IsVoid() &&
!domRequestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
domRequestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
contentType, aRv);
}
if (aRv.Failed()) {
return nullptr;
}
}
// Extract mime type.
nsTArray<nsCString> contentTypeValues;
domRequestHeaders->GetAll(NS_LITERAL_CSTRING("Content-Type"),
contentTypeValues, aRv);
if (aRv.Failed()) {
return nullptr;
}
// HTTP ABNF states Content-Type may have only one value.
// This is from the "parse a header value" of the fetch spec.
if (contentTypeValues.Length() == 1) {
domRequest->mMimeType = contentTypeValues[0];
ToLowerCase(domRequest->mMimeType);
}
return domRequest.forget();
}
already_AddRefed<Request>
Request::Clone() const
{
nsRefPtr<Request> request = new Request(mOwner);
// FIXME(nsm): Bug 1073231. This is incorrect, but the clone method isn't
// well defined yet.
nsRefPtr<Request> request = new Request(mOwner,
new InternalRequest(*mRequest));
return request.forget();
}
namespace {
nsresult
DecodeUTF8(const nsCString& aBuffer, nsString& aDecoded)
{
nsCOMPtr<nsIUnicodeDecoder> decoder =
EncodingUtils::DecoderForEncoding("UTF-8");
if (!decoder) {
return NS_ERROR_FAILURE;
}
int32_t destBufferLen;
nsresult rv =
decoder->GetMaxLength(aBuffer.get(), aBuffer.Length(), &destBufferLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!aDecoded.SetCapacity(destBufferLen, fallible_t())) {
return NS_ERROR_OUT_OF_MEMORY;
}
char16_t* destBuffer = aDecoded.BeginWriting();
int32_t srcLen = (int32_t) aBuffer.Length();
int32_t outLen = destBufferLen;
rv = decoder->Convert(aBuffer.get(), &srcLen, destBuffer, &outLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(outLen <= destBufferLen);
aDecoded.SetLength(outLen);
return NS_OK;
}
}
already_AddRefed<Promise>
Request::ConsumeBody(ConsumeType aType, ErrorResult& aRv)
{
nsRefPtr<Promise> promise = Promise::Create(mOwner, aRv);
if (aRv.Failed()) {
return nullptr;
}
if (BodyUsed()) {
aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
return nullptr;
}
SetBodyUsed();
// While the spec says to do this asynchronously, all the body constructors
// right now only accept bodies whose streams are backed by an in-memory
// buffer that can be read without blocking. So I think this is fine.
nsCOMPtr<nsIInputStream> stream;
mRequest->GetBody(getter_AddRefs(stream));
if (!stream) {
aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0,
NS_ASSIGNMENT_COPY);
if (aRv.Failed()) {
return nullptr;
}
}
AutoJSAPI api;
api.Init(mOwner);
JSContext* cx = api.cx();
// We can make this assertion because for now we only support memory backed
// structures for the body argument for a Request.
MOZ_ASSERT(NS_InputStreamIsBuffered(stream));
nsCString buffer;
uint64_t len;
aRv = stream->Available(&len);
if (aRv.Failed()) {
return nullptr;
}
aRv = NS_ReadInputStreamToString(stream, buffer, len);
if (aRv.Failed()) {
return nullptr;
}
buffer.SetLength(len);
switch (aType) {
case CONSUME_ARRAYBUFFER: {
JS::Rooted<JSObject*> arrayBuffer(cx);
arrayBuffer =
ArrayBuffer::Create(cx, buffer.Length(),
reinterpret_cast<const uint8_t*>(buffer.get()));
JS::Rooted<JS::Value> val(cx);
val.setObjectOrNull(arrayBuffer);
promise->MaybeResolve(cx, val);
return promise.forget();
}
case CONSUME_BLOB: {
// XXXnsm it is actually possible to avoid these duplicate allocations
// for the Blob case by having the Blob adopt the stream's memory
// directly, but I've not added a special case for now.
//
// This is similar to nsContentUtils::CreateBlobBuffer, but also deals
// with worker wrapping.
uint32_t blobLen = buffer.Length();
void* blobData = moz_malloc(blobLen);
nsCOMPtr<nsIDOMBlob> blob;
if (blobData) {
memcpy(blobData, buffer.BeginReading(), blobLen);
blob = DOMFile::CreateMemoryFile(blobData, blobLen,
NS_ConvertUTF8toUTF16(mMimeType));
} else {
aRv = NS_ERROR_OUT_OF_MEMORY;
return nullptr;
}
JS::Rooted<JS::Value> jsBlob(cx);
if (NS_IsMainThread()) {
aRv = nsContentUtils::WrapNative(cx, blob, &jsBlob);
if (aRv.Failed()) {
return nullptr;
}
} else {
jsBlob.setObject(*workers::file::CreateBlob(cx, blob));
}
promise->MaybeResolve(cx, jsBlob);
return promise.forget();
}
case CONSUME_JSON: {
nsString decoded;
aRv = DecodeUTF8(buffer, decoded);
if (aRv.Failed()) {
return nullptr;
}
JS::Rooted<JS::Value> json(cx);
if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) {
JS::Rooted<JS::Value> exn(cx);
if (JS_GetPendingException(cx, &exn)) {
JS_ClearPendingException(cx);
promise->MaybeReject(cx, exn);
}
}
promise->MaybeResolve(cx, json);
return promise.forget();
}
case CONSUME_TEXT: {
nsString decoded;
aRv = DecodeUTF8(buffer, decoded);
if (aRv.Failed()) {
return nullptr;
}
promise->MaybeResolve(decoded);
return promise.forget();
}
}
NS_NOTREACHED("Unexpected consume body type");
// Silence warnings.
return nullptr;
}
already_AddRefed<Promise>
Request::ArrayBuffer(ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
MOZ_ASSERT(global);
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return promise.forget();
return ConsumeBody(CONSUME_ARRAYBUFFER, aRv);
}
already_AddRefed<Promise>
Request::Blob(ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
MOZ_ASSERT(global);
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return promise.forget();
return ConsumeBody(CONSUME_BLOB, aRv);
}
already_AddRefed<Promise>
Request::Json(ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
MOZ_ASSERT(global);
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return promise.forget();
return ConsumeBody(CONSUME_JSON, aRv);
}
already_AddRefed<Promise>
Request::Text(ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
MOZ_ASSERT(global);
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return promise.forget();
}
bool
Request::BodyUsed()
{
return false;
return ConsumeBody(CONSUME_TEXT, aRv);
}
} // namespace dom
} // namespace mozilla

View File

@ -9,10 +9,12 @@
#include "nsISupportsImpl.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/InternalRequest.h"
// Required here due to certain WebIDL enums/classes being declared in both
// files.
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/UnionTypes.h"
class nsPIDOMWindow;
namespace mozilla {
@ -28,7 +30,7 @@ class Request MOZ_FINAL : public nsISupports
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
public:
Request(nsISupports* aOwner);
Request(nsIGlobalObject* aOwner, InternalRequest* aRequest);
JSObject*
WrapObject(JSContext* aCx)
@ -39,34 +41,40 @@ public:
void
GetUrl(DOMString& aUrl) const
{
aUrl.AsAString() = EmptyString();
aUrl.AsAString() = NS_ConvertUTF8toUTF16(mRequest->mURL);
}
void
GetMethod(nsCString& aMethod) const
{
aMethod = EmptyCString();
aMethod = mRequest->mMethod;
}
RequestMode
Mode() const
{
return RequestMode::Same_origin;
return mRequest->mMode;
}
RequestCredentials
Credentials() const
{
return RequestCredentials::Omit;
return mRequest->mCredentialsMode;
}
void
GetReferrer(DOMString& aReferrer) const
{
aReferrer.AsAString() = EmptyString();
if (mRequest->ReferrerIsNone()) {
aReferrer.AsAString() = EmptyString();
return;
}
// FIXME(nsm): Spec doesn't say what to do if referrer is client.
aReferrer.AsAString() = NS_ConvertUTF8toUTF16(mRequest->mReferrerURL);
}
Headers* Headers_() const { return mHeaders; }
Headers* Headers_() const { return mRequest->Headers_(); }
static already_AddRefed<Request>
Constructor(const GlobalObject& aGlobal, const RequestOrScalarValueString& aInput,
@ -93,12 +101,38 @@ public:
Text(ErrorResult& aRv);
bool
BodyUsed();
BodyUsed() const
{
return mBodyUsed;
}
already_AddRefed<InternalRequest>
GetInternalRequest();
private:
enum ConsumeType
{
CONSUME_ARRAYBUFFER,
CONSUME_BLOB,
// FormData not supported right now,
CONSUME_JSON,
CONSUME_TEXT,
};
~Request();
nsCOMPtr<nsISupports> mOwner;
nsRefPtr<Headers> mHeaders;
already_AddRefed<Promise>
ConsumeBody(ConsumeType aType, ErrorResult& aRv);
void
SetBodyUsed()
{
mBodyUsed = true;
}
nsCOMPtr<nsIGlobalObject> mOwner;
nsRefPtr<InternalRequest> mRequest;
bool mBodyUsed;
nsCString mMimeType;
};
} // namespace dom

View File

@ -5,13 +5,17 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'Fetch.h',
'Headers.h',
'InternalRequest.h',
'Request.h',
'Response.h',
]
UNIFIED_SOURCES += [
'Fetch.cpp',
'Headers.cpp',
'InternalRequest.cpp',
'Request.cpp',
'Response.cpp',
]

View File

@ -0,0 +1,26 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_CPOWManagerGetter_h
#define mozilla_dom_CPOWManagerGetter_h
namespace mozilla {
namespace jsipc {
class JavaScriptShared;
} /* namespace jsipc */
namespace dom {
class CPOWManagerGetter
{
public:
virtual mozilla::jsipc::JavaScriptShared* GetCPOWManager() = 0;
};
} /* namespace dom */
} /* namespace mozilla */
#endif /* mozilla_dom_CPOWManagerGetter_h */

View File

@ -98,7 +98,7 @@ ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
// This implementation is identical to ContentChild::GetCPOWManager but we can't
// move it to nsIContentChild because it calls ManagedPJavaScriptChild() which
// only exists in PContentChild and PContentBridgeChild.
jsipc::JavaScriptChild *
jsipc::JavaScriptShared*
ContentBridgeChild::GetCPOWManager()
{
if (ManagedPJavaScriptChild().Length()) {

View File

@ -36,7 +36,7 @@ public:
SendPBlobConstructor(PBlobChild* actor,
const BlobConstructorParams& params);
jsipc::JavaScriptChild* GetCPOWManager();
jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
const IPCTabContext& aContext,

View File

@ -148,7 +148,7 @@ ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
// This implementation is identical to ContentParent::GetCPOWManager but we can't
// move it to nsIContentParent because it calls ManagedPJavaScriptParent() which
// only exists in PContentParent and PContentBridgeParent.
jsipc::JavaScriptParent*
jsipc::JavaScriptShared*
ContentBridgeParent::GetCPOWManager()
{
if (ManagedPJavaScriptParent().Length()) {

View File

@ -39,7 +39,7 @@ public:
const bool& aIsForApp,
const bool& aIsForBrowser) MOZ_OVERRIDE;
jsipc::JavaScriptParent* GetCPOWManager();
jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
virtual uint64_t ChildID() MOZ_OVERRIDE
{

View File

@ -1246,7 +1246,7 @@ ContentChild::DeallocPTestShellChild(PTestShellChild* shell)
return true;
}
jsipc::JavaScriptChild *
jsipc::JavaScriptShared*
ContentChild::GetCPOWManager()
{
if (ManagedPJavaScriptChild().Length()) {
@ -1731,7 +1731,7 @@ ContentChild::RecvAsyncMessage(const nsString& aMsg,
nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
if (cpm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
CpowIdHolder cpows(this, aCpows);
cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
}

View File

@ -34,7 +34,7 @@ class URIParams;
}// namespace ipc
namespace jsipc {
class JavaScriptChild;
class JavaScriptShared;
}
namespace layers {
@ -194,7 +194,7 @@ public:
virtual PTestShellChild* AllocPTestShellChild() MOZ_OVERRIDE;
virtual bool DeallocPTestShellChild(PTestShellChild*) MOZ_OVERRIDE;
virtual bool RecvPTestShellConstructor(PTestShellChild*) MOZ_OVERRIDE;
jsipc::JavaScriptChild *GetCPOWManager();
jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
PMobileConnectionChild*
SendPMobileConnectionConstructor(PMobileConnectionChild* aActor,

View File

@ -1777,7 +1777,7 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
}
}
jsipc::JavaScriptParent*
jsipc::JavaScriptShared*
ContentParent::GetCPOWManager()
{
if (ManagedPJavaScriptParent().Length()) {

View File

@ -45,7 +45,7 @@ class TestShellParent;
} // namespace ipc
namespace jsipc {
class JavaScriptParent;
class JavaScriptShared;
class PJavaScriptParent;
}
@ -177,7 +177,7 @@ public:
TestShellParent* CreateTestShell();
bool DestroyTestShell(TestShellParent* aTestShell);
TestShellParent* GetTestShellSingleton();
jsipc::JavaScriptParent *GetCPOWManager();
jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
void ReportChildAlreadyBlocked();
bool RequestRunToCompletion();

View File

@ -2574,7 +2574,7 @@ TabChild::RecvAsyncMessage(const nsString& aMessage,
StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
CpowIdHolder cpows(Manager(), aCpows);
mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
}
@ -2910,7 +2910,7 @@ TabChild::DoSendBlockingMessage(JSContext* aCx,
return false;
}
InfallibleTArray<CpowEntry> cpows;
if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
if (aIsSync) {
@ -2934,7 +2934,7 @@ TabChild::DoSendAsyncMessage(JSContext* aCx,
return false;
}
InfallibleTArray<CpowEntry> cpows;
if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,

View File

@ -1114,7 +1114,7 @@ TabParent::RecvSyncMessage(const nsString& aMessage,
}
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
CpowIdHolder cpows(Manager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
}
@ -1136,7 +1136,7 @@ TabParent::AnswerRpcMessage(const nsString& aMessage,
}
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
CpowIdHolder cpows(Manager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
}
@ -1157,7 +1157,7 @@ TabParent::RecvAsyncMessage(const nsString& aMessage,
}
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
CpowIdHolder cpows(Manager(), aCpows);
return ReceiveMessage(aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
}

View File

@ -20,6 +20,7 @@ EXPORTS.mozilla.dom += [
'ContentChild.h',
'ContentParent.h',
'ContentProcess.h',
'CPOWManagerGetter.h',
'CrashReporterChild.h',
'CrashReporterParent.h',
'FilePickerParent.h',

View File

@ -120,7 +120,7 @@ nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
if (cpm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
CpowIdHolder cpows(this, aCpows);
cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
}

View File

@ -9,6 +9,7 @@
#include "nsISupports.h"
#include "nsTArrayForwardDeclare.h"
#include "mozilla/dom/CPOWManagerGetter.h"
#define NS_ICONTENTCHILD_IID \
{ 0x4eed2e73, 0x94ba, 0x48a8, \
@ -25,7 +26,6 @@ namespace mozilla {
namespace jsipc {
class PJavaScriptChild;
class JavaScriptChild;
class CpowEntry;
} // jsipc
@ -39,6 +39,7 @@ class PBlobChild;
class PBrowserChild;
class nsIContentChild : public nsISupports
, public CPOWManagerGetter
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTCHILD_IID)
@ -56,7 +57,6 @@ public:
const uint64_t& aID,
const bool& aIsForApp,
const bool& aIsForBrowser) = 0;
virtual jsipc::JavaScriptChild* GetCPOWManager() = 0;
protected:
virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);

View File

@ -185,8 +185,7 @@ nsIContentParent::RecvSyncMessage(const nsString& aMsg,
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
CpowIdHolder cpows(this, aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
}
@ -213,7 +212,7 @@ nsIContentParent::AnswerRpcMessage(const nsString& aMsg,
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
CpowIdHolder cpows(this, aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
}
@ -239,7 +238,7 @@ nsIContentParent::RecvAsyncMessage(const nsString& aMsg,
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
CpowIdHolder cpows(this, aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
}

View File

@ -9,6 +9,7 @@
#include "nsFrameMessageManager.h"
#include "nsISupports.h"
#include "mozilla/dom/CPOWManagerGetter.h"
#define NS_ICONTENTPARENT_IID \
{ 0xeeec9ebf, 0x8ecf, 0x4e38, \
@ -25,7 +26,6 @@ namespace mozilla {
namespace jsipc {
class PJavaScriptParent;
class JavaScriptParent;
class CpowEntry;
} // namespace jsipc
@ -40,6 +40,7 @@ class PBrowserParent;
class nsIContentParent : public nsISupports
, public mozilla::dom::ipc::MessageManagerCallback
, public CPOWManagerGetter
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)
@ -64,8 +65,6 @@ public:
const bool& aIsForApp,
const bool& aIsForBrowser) NS_WARN_UNUSED_RESULT = 0;
virtual jsipc::JavaScriptParent *GetCPOWManager() = 0;
virtual bool IsContentParent() { return false; }
ContentParent* AsContentParent();

View File

@ -22,7 +22,7 @@
#include "nsString.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "StructuredCloneTags.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "Queue.h"
#include "WorkerFeature.h"

View File

@ -1,5 +1,7 @@
[DEFAULT]
support-files =
worker_interfaces.js
worker_test_request.js
[test_interfaces.html]
[test_request.html]

View File

@ -0,0 +1,48 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug XXXXXX - Test Request object in worker</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
function checkEnabled() {
var worker = new Worker("worker_test_request.js");
worker.onmessage = function(event) {
if (event.data.type == 'finish') {
SimpleTest.finish();
} else if (event.data.type == 'status') {
ok(event.data.status, event.data.msg);
}
}
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.message + " at " + event.lineno);
SimpleTest.finish();
};
worker.postMessage(true);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.fetch.enabled", true]
]}, function() {
checkEnabled();
});
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,215 @@
function ok(a, msg) {
dump("OK: " + !!a + " => " + a + " " + msg + "\n");
postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
}
function is(a, b, msg) {
dump("IS: " + (a===b) + " => " + a + " | " + b + " " + msg + "\n");
postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
}
function testDefaultCtor() {
var req = new Request("");
is(req.method, "GET", "Default Request method is GET");
ok(req.headers instanceof Headers, "Request should have non-null Headers object");
is(req.url, self.location.href, "URL should be resolved with entry settings object's API base URL");
is(req.referrer, "", "Default referrer is `client` which serializes to empty string.");
is(req.mode, "cors", "Request mode for string input is cors");
is(req.credentials, "omit", "Default Request credentials is omit");
var req = new Request(req);
is(req.method, "GET", "Default Request method is GET");
ok(req.headers instanceof Headers, "Request should have non-null Headers object");
is(req.url, self.location.href, "URL should be resolved with entry settings object's API base URL");
is(req.referrer, "", "Default referrer is `client` which serializes to empty string.");
is(req.mode, "cors", "Request mode string input is cors");
is(req.credentials, "omit", "Default Request credentials is omit");
}
function testClone() {
var req = (new Request("./cloned_request.txt", {
method: 'POST',
headers: { "Content-Length": 5 },
body: "Sample body",
mode: "same-origin",
credentials: "same-origin",
})).clone();
ok(req.method === "POST", "Request method is POST");
ok(req.headers instanceof Headers, "Request should have non-null Headers object");
is(req.headers.get('content-length'), "5", "Request content-length should be 5.");
ok(req.url === (new URL("./cloned_request.txt", self.location.href)).href,
"URL should be resolved with entry settings object's API base URL");
ok(req.referrer === "", "Default referrer is `client` which serializes to empty string.");
ok(req.mode === "same-origin", "Request mode is same-origin");
ok(req.credentials === "same-origin", "Default credentials is same-origin");
}
function testUsedRequest() {
// Passing a used request should fail.
var req = new Request("", { body: "This is foo" });
var p1 = req.text().then(function(v) {
try {
var req2 = new Request(req);
ok(false, "Used Request cannot be passed to new Request");
} catch(e) {
ok(true, "Used Request cannot be passed to new Request");
}
});
// Passing a request should set the request as used.
var reqA = new Request("", { body: "This is foo" });
var reqB = new Request(reqA);
is(reqA.bodyUsed, true, "Passing a Request to another Request should set the former as used");
return p1;
}
function testSimpleUrlParse() {
// Just checks that the URL parser is actually being used.
var req = new Request("/file.html");
is(req.url, (new URL("/file.html", self.location.href)).href, "URL parser should be used to resolve Request URL");
}
function testMethod() {
var allowed = ["delete", "get", "head", "options", "post", "put"];
for (var i = 0; i < allowed.length; ++i) {
try {
var r = new Request("", { method: allowed[i] });
ok(true, "Method " + allowed[i] + " should be allowed");
} catch(e) {
ok(false, "Method " + allowed[i] + " should be allowed");
}
}
var forbidden = ["aardvark", "connect", "trace", "track"];
for (var i = 0; i < forbidden.length; ++i) {
try {
var r = new Request("", { method: forbidden[i] });
ok(false, "Method " + forbidden[i] + " should be forbidden");
} catch(e) {
ok(true, "Method " + forbidden[i] + " should be forbidden");
}
}
var allowedNoCors = ["get", "head", "post"];
for (var i = 0; i < allowedNoCors.length; ++i) {
try {
var r = new Request("", { method: allowedNoCors[i], mode: "no-cors" });
ok(true, "Method " + allowedNoCors[i] + " should be allowed in no-cors mode");
} catch(e) {
ok(false, "Method " + allowedNoCors[i] + " should be allowed in no-cors mode");
}
}
var forbiddenNoCors = ["aardvark", "delete", "options", "put"];
for (var i = 0; i < forbiddenNoCors.length; ++i) {
try {
var r = new Request("", { method: forbiddenNoCors[i], mode: "no-cors" });
ok(false, "Method " + forbiddenNoCors[i] + " should be forbidden in no-cors mode");
} catch(e) {
ok(true, "Method " + forbiddenNoCors[i] + " should be forbidden in no-cors mode");
}
}
}
function testUrlFragment() {
var req = new Request("./request#withfragment");
ok(req.url, (new URL("./request", self.location.href)).href, "request.url should be serialized with exclude fragment flag set");
}
function testBodyUsed() {
var req = new Request("./bodyused", { body: "Sample body" });
is(req.bodyUsed, false, "bodyUsed is initially false.");
return req.text().then((v) => {
is(v, "Sample body", "Body should match");
is(req.bodyUsed, true, "After reading body, bodyUsed should be true.");
}).then((v) => {
return req.blob().then((v) => {
ok(false, "Attempting to read body again should fail.");
}, (e) => {
ok(true, "Attempting to read body again should fail.");
})
});
}
// FIXME(nsm): Bug 1071290: We can't use Blobs as the body yet.
function testBodyCreation() {
var text = "κόσμε";
var req1 = new Request("", { body: text });
var p1 = req1.text().then(function(v) {
ok(typeof v === "string", "Should resolve to string");
is(text, v, "Extracted string should match");
});
var req2 = new Request("", { body: new Uint8Array([72, 101, 108, 108, 111]) });
var p2 = req2.text().then(function(v) {
is("Hello", v, "Extracted string should match");
});
var req2b = new Request("", { body: (new Uint8Array([72, 101, 108, 108, 111])).buffer });
var p2b = req2b.text().then(function(v) {
is("Hello", v, "Extracted string should match");
});
var params = new URLSearchParams();
params.append("item", "Geckos");
params.append("feature", "stickyfeet");
params.append("quantity", "700");
var req3 = new Request("", { body: params });
var p3 = req3.text().then(function(v) {
var extracted = new URLSearchParams(v);
is(extracted.get("item"), "Geckos", "Param should match");
is(extracted.get("feature"), "stickyfeet", "Param should match");
is(extracted.get("quantity"), "700", "Param should match");
});
return Promise.all([p1, p2, p2b, p3]);
}
function testBodyExtraction() {
var text = "κόσμε";
var newReq = function() { return new Request("", { body: text }); }
return newReq().text().then(function(v) {
ok(typeof v === "string", "Should resolve to string");
is(text, v, "Extracted string should match");
}).then(function() {
return newReq().blob().then(function(v) {
ok(v instanceof Blob, "Should resolve to Blob");
var fs = new FileReaderSync();
is(fs.readAsText(v), text, "Decoded Blob should match original");
});
}).then(function() {
return newReq().json().then(function(v) {
ok(false, "Invalid json should reject");
}, function(e) {
ok(true, "Invalid json should reject");
})
}).then(function() {
return newReq().arrayBuffer().then(function(v) {
ok(v instanceof ArrayBuffer, "Should resolve to ArrayBuffer");
var dec = new TextDecoder();
is(dec.decode(new Uint8Array(v)), text, "UTF-8 decoded ArrayBuffer should match original");
});
})
}
onmessage = function() {
var done = function() { postMessage({ type: 'finish' }) }
testDefaultCtor();
testClone();
testSimpleUrlParse();
testUrlFragment();
testMethod();
Promise.resolve()
.then(testBodyCreation)
.then(testBodyUsed)
.then(testBodyExtraction)
.then(testUsedRequest)
// Put more promise based tests here.
.then(done)
.catch(function(e) {
ok(false, "Some Request tests failed " + e);
done();
})
}

View File

@ -13,6 +13,7 @@
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
#include "mozilla/gfx/Types.h" // for Float
#include "mozilla/layers/CompositorTypes.h" // for DiagnosticTypes, etc
#include "mozilla/layers/FenceUtils.h" // for FenceHandle
#include "mozilla/layers/LayersTypes.h" // for LayersBackend
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsRegion.h"
@ -353,6 +354,11 @@ public:
virtual void SetFBAcquireFence(Layer* aLayer) {}
virtual FenceHandle GetReleaseFence()
{
return FenceHandle();
}
/**
* Post-rendering stuff if the rendering is done outside of this Compositor
* e.g., by Composer2D.

View File

@ -358,7 +358,7 @@ public:
virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
{
mReleaseFenceHandle = aReleaseFenceHandle;
mReleaseFenceHandle.Merge(aReleaseFenceHandle);
}
const FenceHandle& GetReleaseFenceHandle() const

View File

@ -80,8 +80,6 @@ public:
void CompositorRecycle();
void SendFenceHandleIfPresent();
virtual bool RecvClientRecycle() MOZ_OVERRIDE;
virtual bool RecvClearTextureHostSync() MOZ_OVERRIDE;
@ -147,14 +145,6 @@ TextureHost::GetIPDLActor()
return mActor;
}
// static
void
TextureHost::SendFenceHandleIfPresent(PTextureParent* actor)
{
TextureParent* parent = static_cast<TextureParent*>(actor);
parent->SendFenceHandleIfPresent();
}
FenceHandle
TextureHost::GetAndResetReleaseFenceHandle()
{
@ -714,7 +704,6 @@ void
TextureParent::CompositorRecycle()
{
mTextureHost->ClearRecycleCallback();
SendFenceHandleIfPresent();
if (mTextureHost->GetFlags() & TextureFlags::RECYCLE) {
mozilla::unused << SendCompositorRecycle();
@ -724,28 +713,6 @@ TextureParent::CompositorRecycle()
}
}
void
TextureParent::SendFenceHandleIfPresent()
{
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
if (mTextureHost) {
TextureHostOGL* hostOGL = mTextureHost->AsHostOGL();
if (!hostOGL) {
return;
}
android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence();
if (fence.get() && fence->isValid()) {
// HWC might not provide Fence.
// In this case, HWC implicitly handles buffer's fence.
FenceHandle handle = FenceHandle(fence);
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(handle);
mCompositableManager->SendFenceHandle(tracker, this, handle);
}
}
#endif
}
bool
TextureParent::RecvClientRecycle()
{

View File

@ -421,8 +421,6 @@ public:
*/
PTextureParent* GetIPDLActor();
static void SendFenceHandleIfPresent(PTextureParent* actor);
FenceHandle GetAndResetReleaseFenceHandle();
/**

View File

@ -162,7 +162,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
MOZ_ASSERT(tex.get());
compositable->RemoveTextureHost(tex);
// send FenceHandle if present.
TextureHost::SendFenceHandleIfPresent(op.textureParent());
SendFenceHandleIfPresent(op.textureParent(), compositable);
break;
}
case CompositableOperation::TOpRemoveTextureAsync: {
@ -179,7 +179,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
GetChildProcessId(),
op.holderId(),
op.transactionId(),
op.textureParent());
op.textureParent(),
compositable);
// If the message is recievied via PLayerTransaction,
// Send message back via PImageBridge.
@ -190,7 +191,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
op.transactionId()));
} else {
// send FenceHandle if present.
TextureHost::SendFenceHandleIfPresent(op.textureParent());
SendFenceHandleIfPresent(op.textureParent(), compositable);
ReplyRemoveTexture(OpReplyRemoveTexture(false, // isMain
op.holderId(),
@ -258,6 +259,42 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
return true;
}
void
CompositableParentManager::SendPendingAsyncMessges()
{
if (mPendingAsyncMessage.empty()) {
return;
}
// Some type of AsyncParentMessageData message could have
// one file descriptor (e.g. OpDeliverFence).
// A number of file descriptors per gecko ipc message have a limitation
// on OS_POSIX (MACOSX or LINUX).
#if defined(OS_POSIX)
static const uint32_t kMaxMessageNumber = FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE;
#else
// default number that works everywhere else
static const uint32_t kMaxMessageNumber = 250;
#endif
InfallibleTArray<AsyncParentMessageData> messages;
messages.SetCapacity(mPendingAsyncMessage.size());
for (size_t i = 0; i < mPendingAsyncMessage.size(); i++) {
messages.AppendElement(mPendingAsyncMessage[i]);
// Limit maximum number of messages.
if (messages.Length() >= kMaxMessageNumber) {
SendAsyncMessage(messages);
// Initialize Messages.
messages.Clear();
}
}
if (messages.Length() > 0) {
SendAsyncMessage(messages);
}
mPendingAsyncMessage.clear();
}
} // namespace
} // namespace

View File

@ -30,12 +30,17 @@ class CompositableParentManager : public ISurfaceAllocator
, public AsyncTransactionTrackersHolder
{
public:
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost) = 0;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence) = 0;
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) = 0;
void SendPendingAsyncMessges();
/**
* Get child side's process Id.
*/
@ -57,6 +62,7 @@ protected:
virtual void ReplyRemoveTexture(const OpReplyRemoveTexture& aReply) {}
std::vector<AsyncParentMessageData> mPendingAsyncMessage;
};
} // namespace

View File

@ -26,6 +26,7 @@ struct FenceHandle {
explicit FenceHandle(const FenceHandleFromChild& aFenceHandle) {}
bool operator==(const FenceHandle&) const { return false; }
bool IsValid() const { return false; }
void Merge(const FenceHandle& aFenceHandle) {}
};
struct FenceHandleFromChild {

View File

@ -49,6 +49,7 @@ ParamTraits<FenceHandle>::Write(Message* aMsg,
flattenable->flatten(data, nbytes, fds, nfds);
#endif
aMsg->WriteSize(nbytes);
aMsg->WriteSize(nfds);
aMsg->WriteBytes(data, nbytes);
for (size_t n = 0; n < nfds; ++n) {
// These buffers can't die in transit because they're created
@ -63,14 +64,20 @@ ParamTraits<FenceHandle>::Read(const Message* aMsg,
void** aIter, paramType* aResult)
{
size_t nbytes;
size_t nfds;
const char* data;
if (!aMsg->ReadSize(aIter, &nbytes) ||
!aMsg->ReadSize(aIter, &nfds) ||
!aMsg->ReadBytes(aIter, &data, nbytes)) {
return false;
}
size_t nfds = aMsg->num_fds();
// Check if nfds is correct.
// aMsg->num_fds() could include fds of another ParamTraits<>s.
if (nfds > aMsg->num_fds()) {
return false;
}
int fds[nfds];
for (size_t n = 0; n < nfds; ++n) {
@ -138,6 +145,7 @@ ParamTraits<FenceHandleFromChild>::Write(Message* aMsg,
flattenable->flatten(data, nbytes, fds, nfds);
#endif
aMsg->WriteSize(nbytes);
aMsg->WriteSize(nfds);
aMsg->WriteBytes(data, nbytes);
for (size_t n = 0; n < nfds; ++n) {
// If the Fence was shared cross-process, SCM_RIGHTS does
@ -161,14 +169,20 @@ ParamTraits<FenceHandleFromChild>::Read(const Message* aMsg,
void** aIter, paramType* aResult)
{
size_t nbytes;
size_t nfds;
const char* data;
if (!aMsg->ReadSize(aIter, &nbytes) ||
!aMsg->ReadSize(aIter, &nfds) ||
!aMsg->ReadBytes(aIter, &data, nbytes)) {
return false;
}
size_t nfds = aMsg->num_fds();
// Check if nfds is correct.
// aMsg->num_fds() could include fds of another ParamTraits<>s.
if (nfds > aMsg->num_fds()) {
return false;
}
int fds[nfds];
for (size_t n = 0; n < nfds; ++n) {
@ -211,6 +225,30 @@ FenceHandle::FenceHandle(const FenceHandleFromChild& aFenceHandle) {
mFence = aFenceHandle.mFence;
}
void
FenceHandle::Merge(const FenceHandle& aFenceHandle)
{
if (!aFenceHandle.IsValid()) {
return;
}
if (!IsValid()) {
mFence = aFenceHandle.mFence;
} else {
android::sp<android::Fence> mergedFence = android::Fence::merge(
android::String8::format("FenceHandle"),
mFence, aFenceHandle.mFence);
if (!mergedFence.get()) {
// synchronization is broken, the best we can do is hope fences
// signal in order so the new fence will act like a union.
// This error handling is same as android::ConsumerBase does.
mFence = aFenceHandle.mFence;
return;
}
mFence = mergedFence;
}
}
FenceHandleFromChild::FenceHandleFromChild(const sp<Fence>& aFence)
: mFence(aFence)
{

View File

@ -23,9 +23,9 @@ struct FenceHandle {
FenceHandle()
{ }
FenceHandle(const android::sp<Fence>& aFence);
explicit FenceHandle(const android::sp<Fence>& aFence);
FenceHandle(const FenceHandleFromChild& aFenceHandle);
explicit FenceHandle(const FenceHandleFromChild& aFenceHandle);
bool operator==(const FenceHandle& aOther) const {
return mFence.get() == aOther.mFence.get();
@ -36,6 +36,8 @@ struct FenceHandle {
return mFence.get() && mFence->isValid();
}
void Merge(const FenceHandle& aFenceHandle);
android::sp<Fence> mFence;
};
@ -44,9 +46,9 @@ struct FenceHandleFromChild {
FenceHandleFromChild()
{ }
FenceHandleFromChild(const android::sp<Fence>& aFence);
explicit FenceHandleFromChild(const android::sp<Fence>& aFence);
FenceHandleFromChild(const FenceHandle& aFence) {
explicit FenceHandleFromChild(const FenceHandle& aFence) {
mFence = aFence.mFence;
}

View File

@ -96,9 +96,25 @@ ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
}
class MOZ_STACK_CLASS AutoImageBridgeParentAsyncMessageSender
{
public:
explicit AutoImageBridgeParentAsyncMessageSender(ImageBridgeParent* aImageBridge)
: mImageBridge(aImageBridge) {}
~AutoImageBridgeParentAsyncMessageSender()
{
mImageBridge->SendPendingAsyncMessges();
}
private:
ImageBridgeParent* mImageBridge;
};
bool
ImageBridgeParent::RecvUpdate(const EditArray& aEdits, EditReplyArray* aReply)
{
AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this);
// If we don't actually have a compositor, then don't bother
// creating any textures.
if (Compositor::GetBackend() == LayersBackend::LAYERS_NONE) {
@ -336,9 +352,7 @@ bool ImageBridgeParent::IsSameProcess() const
void
ImageBridgeParent::ReplyRemoveTexture(const OpReplyRemoveTexture& aReply)
{
InfallibleTArray<AsyncParentMessageData> messages;
messages.AppendElement(aReply);
mozilla::unused << SendParentAsyncMessages(messages);
mPendingAsyncMessage.push_back(aReply);
}
/*static*/ void
@ -352,35 +366,80 @@ ImageBridgeParent::ReplyRemoveTexture(base::ProcessId aChildProcessId,
imageBridge->ReplyRemoveTexture(aReply);
}
/*static*/ void
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture)
void
ImageBridgeParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost)
{
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
if (!texture) {
return;
}
// Send a ReleaseFence of CompositorOGL.
if (aCompositableHost && aCompositableHost->GetCompositor()) {
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
fence));
}
}
// Send a ReleaseFence that is set by HwcComposer2D.
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
if (!fence.IsValid()) {
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
fence));
}
}
void
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost)
{
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
if (!texture) {
return;
}
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
InfallibleTArray<AsyncParentMessageData> messages;
messages.AppendElement(OpDeliverFenceToTracker(tracker->GetId(),
aDestHolderId,
aTransactionId,
fence));
mozilla::unused << SendParentAsyncMessages(messages);
// Send a ReleaseFence of CompositorOGL.
if (aCompositableHost && aCompositableHost->GetCompositor()) {
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(tracker->GetId(),
aDestHolderId,
aTransactionId,
fence));
}
}
// Send a ReleaseFence that is set by HwcComposer2D.
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(tracker->GetId(),
aDestHolderId,
aTransactionId,
fence));
}
}
/*static*/ void
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProcessId,
uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture)
PTextureParent* aTexture,
CompositableHost* aCompositableHost)
{
ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
if (!imageBridge) {
@ -388,9 +447,21 @@ ImageBridgeParent::SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProce
}
imageBridge->SendFenceHandleToTrackerIfPresent(aDestHolderId,
aTransactionId,
aTexture);
aTexture,
aCompositableHost);
}
/*static*/ void
ImageBridgeParent::SendPendingAsyncMessges(base::ProcessId aChildProcessId)
{
#ifdef MOZ_WIDGET_GONK
ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
if (!imageBridge) {
return;
}
imageBridge->SendPendingAsyncMessges();
#endif
}
} // layers
} // mozilla

View File

@ -56,6 +56,9 @@ public:
Create(Transport* aTransport, ProcessId aChildProcessId);
// CompositableParentManager
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost) MOZ_OVERRIDE;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence) MOZ_OVERRIDE;
@ -122,12 +125,17 @@ public:
void SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture);
PTextureParent* aTexture,
CompositableHost* aCompositableHost);
static void SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProcessId,
uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture);
PTextureParent* aTexture,
CompositableHost* aCompositableHost);
using CompositableParentManager::SendPendingAsyncMessges;
static void SendPendingAsyncMessges(base::ProcessId aChildProcessId);
static ImageBridgeParent* GetInstance(ProcessId aId);

View File

@ -18,6 +18,7 @@
#include "mozilla/layers/ColorLayerComposite.h"
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/ContainerLayerComposite.h"
#include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
#include "mozilla/layers/ImageLayerComposite.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
@ -192,6 +193,21 @@ LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,
aTransactionStart, nullptr);
}
class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender
{
public:
explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction)
: mLayerTransaction(aLayerTransaction) {}
~AutoLayerTransactionParentAsyncMessageSender()
{
mLayerTransaction->SendPendingAsyncMessges();
ImageBridgeParent::SendPendingAsyncMessges(mLayerTransaction->GetChildProcessId());
}
private:
LayerTransactionParent* mLayerTransaction;
};
bool
LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
const uint64_t& aTransactionId,
@ -223,6 +239,7 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
}
EditReplyVector replyv;
AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this);
{
AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
@ -890,6 +907,38 @@ bool LayerTransactionParent::IsSameProcess() const
return OtherProcess() == ipc::kInvalidProcessHandle;
}
void
LayerTransactionParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost)
{
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
if (!texture) {
return;
}
// Send a ReleaseFence of CompositorOGL.
if (aCompositableHost && aCompositableHost->GetCompositor()) {
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
fence));
}
}
// Send a ReleaseFence that is set by HwcComposer2D.
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
fence));
}
}
void
LayerTransactionParent::SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,

View File

@ -86,6 +86,9 @@ public:
void SetPendingTransactionId(uint64_t aId) { mPendingTransaction = aId; }
// CompositableParentManager
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost) MOZ_OVERRIDE;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence) MOZ_OVERRIDE;

View File

@ -1398,49 +1398,33 @@ CompositorOGL::SetFBAcquireFence(Layer* aLayer)
return;
}
const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
if (visibleRegion.IsEmpty()) {
return;
android::sp<android::Fence> fence = new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd());
if (fence.get() && fence->isValid()) {
FenceHandle handle = FenceHandle(fence);
mReleaseFenceHandle.Merge(handle);
}
// Set FBAcquireFence on ContainerLayer's childs
ContainerLayer* container = aLayer->AsContainerLayer();
if (container) {
for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
SetFBAcquireFence(child);
}
return;
}
// Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer.
TiledLayerComposer* composer = nullptr;
LayerComposite* shadow = aLayer->AsLayerComposite();
// Only ask for the composer if we have a compositable host. Timing
// may make it so that we don't - see bug 1000634.
if (shadow && shadow->GetCompositableHost()) {
composer = shadow->GetTiledLayerComposer();
if (composer) {
composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
return;
}
}
// Set FBAcquireFence as layer buffer's ReleaseFence
LayerRenderState state = aLayer->GetRenderState();
if (!state.mTexture) {
return;
}
TextureHostOGL* texture = state.mTexture->AsHostOGL();
if (!texture) {
return;
}
texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
}
FenceHandle
CompositorOGL::GetReleaseFence()
{
if (!mReleaseFenceHandle.IsValid()) {
return FenceHandle();
}
return FenceHandle(new android::Fence(mReleaseFenceHandle.mFence->dup()));
}
#else
void
CompositorOGL::SetFBAcquireFence(Layer* aLayer)
{
}
FenceHandle
CompositorOGL::GetReleaseFence()
{
return FenceHandle();
}
#endif
void

View File

@ -209,6 +209,7 @@ public:
virtual void EndFrame() MOZ_OVERRIDE;
virtual void SetFBAcquireFence(Layer* aLayer) MOZ_OVERRIDE;
virtual FenceHandle GetReleaseFence() MOZ_OVERRIDE;
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE;
virtual void AbortFrame() MOZ_OVERRIDE;
@ -393,6 +394,8 @@ private:
* FlipY for the y-flipping calculation.
*/
GLint mHeight;
FenceHandle mReleaseFenceHandle;
};
}

View File

@ -7,6 +7,7 @@
#include "JavaScriptShared.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/CPOWManagerGetter.h"
#include "mozilla/dom/TabChild.h"
#include "jsfriendapi.h"
#include "xpcprivate.h"
@ -515,9 +516,21 @@ JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in,
return true;
}
CpowIdHolder::CpowIdHolder(dom::CPOWManagerGetter *managerGetter, const InfallibleTArray<CpowEntry> &cpows)
: js_(nullptr),
cpows_(cpows)
{
// Only instantiate the CPOW manager if we might need it later.
if (cpows.Length())
js_ = managerGetter->GetCPOWManager();
}
bool
CpowIdHolder::ToObject(JSContext *cx, JS::MutableHandleObject objp)
{
if (!cpows_.Length())
return true;
return js_->Unwrap(cx, cpows_, objp);
}

View File

@ -14,6 +14,11 @@
#include "nsFrameMessageManager.h"
namespace mozilla {
namespace dom {
class CPOWManagerGetter;
}
namespace jsipc {
class ObjectId {
@ -63,11 +68,7 @@ class JavaScriptShared;
class CpowIdHolder : public CpowHolder
{
public:
CpowIdHolder(JavaScriptShared *js, const InfallibleTArray<CpowEntry> &cpows)
: js_(js),
cpows_(cpows)
{
}
CpowIdHolder(dom::CPOWManagerGetter *managerGetter, const InfallibleTArray<CpowEntry> &cpows);
bool ToObject(JSContext *cx, JS::MutableHandleObject objp);

View File

@ -162,10 +162,6 @@ class RemoteOptions(ReftestOptions):
if not options.httpdPath:
options.httpdPath = os.path.join(options.utilityPath, "components")
# Android does not run leak tests, but set some reasonable defaults to avoid errors.
options.leakThresholds = {}
options.ignoreMissingLeaks = []
# TODO: Copied from main, but I think these are no longer used in a post xulrunner world
#options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner'
#options.utilityPath = options.testRoot + self.automation._product + '/bin'

View File

@ -344,7 +344,7 @@ class RefTest(object):
# give the JS harness 30 seconds to deal
# with its own timeouts
timeout=options.timeout + 30.0)
processLeakLog(self.leakLogFile, options.leakThresholds, options.ignoreMissingLeaks)
processLeakLog(self.leakLogFile, options)
self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
finally:
self.cleanup(profileDir)
@ -512,7 +512,6 @@ class ReftestOptions(OptionParser):
self.error("cannot specify a debugger with parallel tests")
options.leakThresholds = {"default": options.defaultLeakThreshold}
options.ignoreMissingLeaks = []
return options

View File

@ -203,10 +203,6 @@ class B2GOptions(ReftestOptions):
if not options.httpdPath:
options.httpdPath = os.path.join(options.xrePath, "components")
# B2G reftests do not do leak checking, but set some reasonable defaults to avoid errors.
options.leakThresholds = {}
options.ignoreMissingLeaks = []
return options

View File

@ -13,7 +13,7 @@
android:insetLeft="@dimen/new_tablet_browser_toolbar_menu_item_inset_horizontal"
android:insetRight="@dimen/new_tablet_browser_toolbar_menu_item_inset_horizontal">
<shape android:shape="rectangle">
<solid android:color="#D7D7DC"/>
<solid android:color="@color/new_tablet_highlight"/>
<corners android:radius="@dimen/new_tablet_browser_toolbar_menu_item_corner_radius"/>
</shape>
</inset>
@ -28,7 +28,7 @@
android:insetLeft="@dimen/new_tablet_browser_toolbar_menu_item_inset_horizontal"
android:insetRight="@dimen/new_tablet_browser_toolbar_menu_item_inset_horizontal">
<shape android:shape="rectangle">
<solid android:color="#C0C9D0"/>
<solid android:color="@color/new_tablet_highlight_focused"/>
<corners android:radius="@dimen/new_tablet_browser_toolbar_menu_item_corner_radius"/>
</shape>
</inset>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto">
<!-- private pressed state -->
<item gecko:state_private="true"
android:state_pressed="true"
android:drawable="@color/new_tablet_highlight_pb"/>
<!-- focused state -->
<item gecko:state_private="true"
android:state_focused="true"
android:state_pressed="false"
android:drawable="@color/new_tablet_highlight_focused_pb"/>
<!-- pressed state -->
<item android:state_pressed="true"
android:drawable="@color/new_tablet_highlight"/>
<!-- focused state -->
<item android:state_focused="true"
android:state_pressed="false"
android:drawable="@color/new_tablet_highlight_focused"/>
<!-- private browsing mode -->
<item gecko:state_private="true"
android:drawable="@color/background_private"/>
<!-- normal mode -->
<item android:drawable="@color/background_normal"/>
</selector>

View File

@ -32,7 +32,7 @@
android:layout_alignParentLeft="true"
android:src="@drawable/new_tablet_ic_menu_back"
android:contentDescription="@string/back"
android:background="@drawable/url_bar_nav_button"/>
android:background="@drawable/new_tablet_url_bar_nav_button"/>
<org.mozilla.gecko.toolbar.ToolbarEditLayout android:id="@+id/edit_layout"
style="@style/UrlBar.Button"

View File

@ -33,6 +33,7 @@
<item name="android:layout_marginTop">11.5dp</item>
<item name="android:layout_marginBottom">11.5dp</item>
<item name="android:src">@drawable/new_tablet_ic_menu_forward</item>
<item name="android:background">@drawable/new_tablet_url_bar_nav_button</item>
</style>
<style name="UrlBar.ImageButton.TabCount.NewTablet">

View File

@ -13,6 +13,12 @@
<color name="highlight_dark">#33FFFFFF</color>
<color name="highlight_dark_focused">#1AFFFFFF</color>
<!-- (bug 1077195) Focused state values are temporary. -->
<color name="new_tablet_highlight">#D7D7DC</color>
<color name="new_tablet_highlight_focused">#C0C9D0</color>
<color name="new_tablet_highlight_pb">#222222</color>
<color name="new_tablet_highlight_focused_pb">#363B40</color>
<!-- highlight on shaped button: 20% white over background_tabs -->
<color name="highlight_shaped">#FF696D71</color>

View File

@ -0,0 +1,55 @@
/* 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 "BaseElf.h"
#include "Elfxx.h"
#include "Logging.h"
using namespace Elf;
unsigned long
BaseElf::Hash(const char *symbol)
{
const unsigned char *sym = reinterpret_cast<const unsigned char *>(symbol);
unsigned long h = 0, g;
while (*sym) {
h = (h << 4) + *sym++;
g = h & 0xf0000000;
h ^= g;
h ^= g >> 24;
}
return h;
}
void *
BaseElf::GetSymbolPtr(const char *symbol, unsigned long hash) const
{
const Sym *sym = GetSymbol(symbol, hash);
void *ptr = nullptr;
if (sym && sym->st_shndx != SHN_UNDEF)
ptr = GetPtr(sym->st_value);
DEBUG_LOG("BaseElf::GetSymbolPtr(%p [\"%s\"], \"%s\") = %p",
reinterpret_cast<const void *>(this), GetPath(), symbol, ptr);
return ptr;
}
const Sym *
BaseElf::GetSymbol(const char *symbol, unsigned long hash) const
{
/* Search symbol with the buckets and chains tables.
* The hash computed from the symbol name gives an index in the buckets
* table. The corresponding value in the bucket table is an index in the
* symbols table and in the chains table.
* If the corresponding symbol in the symbols table matches, we're done.
* Otherwise, the corresponding value in the chains table is a new index
* in both tables, which corresponding symbol is tested and so on and so
* forth */
size_t bucket = hash % buckets.numElements();
for (size_t y = buckets[bucket]; y != STN_UNDEF; y = chains[y]) {
if (strcmp(symbol, strtab.GetStringAt(symtab[y].st_name)))
continue;
return &symtab[y];
}
return nullptr;
}

93
mozglue/linker/BaseElf.h Normal file
View File

@ -0,0 +1,93 @@
/* 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/. */
#ifndef BaseElf_h
#define BaseElf_h
#include "ElfLoader.h"
#include "Elfxx.h"
/**
* Base class for ELF libraries. This class includes things that will be
* common between SystemElfs and CustomElfs.
*/
class BaseElf: public LibHandle
{
public:
/**
* Hash function for symbol lookup, as defined in ELF standard for System V.
*/
static unsigned long Hash(const char *symbol);
/**
* Returns the address corresponding to the given symbol name (with a
* pre-computed hash).
*/
void *GetSymbolPtr(const char *symbol, unsigned long hash) const;
/**
* Returns a pointer to the Elf Symbol in the Dynamic Symbol table
* corresponding to the given symbol name (with a pre-computed hash).
*/
const Elf::Sym *GetSymbol(const char *symbol, unsigned long hash) const;
BaseElf(const char *path)
: LibHandle(path) { }
protected:
/**
* Inherited from LibHandle. Those are temporary and are not supposed to
* be used.
*/
virtual void *GetSymbolPtr(const char *symbol) const { return NULL; };
virtual bool Contains(void *addr) const { return false; };
virtual void *GetBase() const { return GetPtr(0); }
#ifdef __ARM_EABI__
virtual const void *FindExidx(int *pcount) const { return NULL; };
#endif
virtual Mappable *GetMappable() const { return NULL; };
public:
/* private: */
/**
* Returns a pointer relative to the base address where the library is
* loaded.
*/
void *GetPtr(const Elf::Addr offset) const
{
if (reinterpret_cast<void *>(offset) > base)
return reinterpret_cast<void *>(offset);
return base + offset;
}
/**
* Like the above, but returns a typed (const) pointer
*/
template <typename T>
const T *GetPtr(const Elf::Addr offset) const
{
if (reinterpret_cast<void *>(offset) > base)
return reinterpret_cast<const T *>(offset);
return reinterpret_cast<const T *>(base + offset);
}
/* Base address where the library is loaded */
MappedPtr base;
/* Buckets and chains for the System V symbol hash table */
Array<Elf::Word> buckets;
UnsizedArray<Elf::Word> chains;
/* protected: */
/* String table */
Elf::Strtab strtab;
/* Symbol table */
UnsizedArray<Elf::Sym> symtab;
};
#endif /* BaseElf_h */

View File

@ -7,7 +7,9 @@
#include <vector>
#include <dlfcn.h>
#include <signal.h>
#include <string.h>
#include "CustomElf.h"
#include "BaseElf.h"
#include "Mappable.h"
#include "Logging.h"
@ -279,43 +281,10 @@ CustomElf::~CustomElf()
ElfLoader::Singleton.Forget(this);
}
namespace {
/**
* Hash function for symbol lookup, as defined in ELF standard for System V
*/
unsigned long
ElfHash(const char *symbol)
{
const unsigned char *sym = reinterpret_cast<const unsigned char *>(symbol);
unsigned long h = 0, g;
while (*sym) {
h = (h << 4) + *sym++;
if ((g = h & 0xf0000000))
h ^= g >> 24;
h &= ~g;
}
return h;
}
} /* anonymous namespace */
void *
CustomElf::GetSymbolPtr(const char *symbol) const
{
return GetSymbolPtr(symbol, ElfHash(symbol));
}
void *
CustomElf::GetSymbolPtr(const char *symbol, unsigned long hash) const
{
const Sym *sym = GetSymbol(symbol, hash);
void *ptr = nullptr;
if (sym && sym->st_shndx != SHN_UNDEF)
ptr = GetPtr(sym->st_value);
DEBUG_LOG("CustomElf::GetSymbolPtr(%p [\"%s\"], \"%s\") = %p",
reinterpret_cast<const void *>(this), GetPath(), symbol, ptr);
return ptr;
return BaseElf::GetSymbolPtr(symbol, Hash(symbol));
}
void *
@ -372,16 +341,17 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
}
void *sym;
/* Search the symbol in the main program. Note this also tries all libraries
* the system linker will have loaded RTLD_GLOBAL. Unfortunately, that doesn't
* work with bionic, but its linker doesn't normally search the main binary
* anyways. Moreover, on android, the main binary is dalvik. */
#ifdef __GLIBC__
sym = dlsym(RTLD_DEFAULT, symbol);
DEBUG_LOG("dlsym(RTLD_DEFAULT, \"%s\") = %p", symbol, sym);
if (sym)
return sym;
#endif
unsigned long hash = Hash(symbol);
/* self_elf should never be NULL, but better safe than sorry. */
if (ElfLoader::Singleton.self_elf) {
/* We consider the library containing this code a permanent LD_PRELOAD,
* so, check if the symbol exists here first. */
sym = ElfLoader::Singleton.self_elf->GetSymbolPtr(symbol, hash);
if (sym)
return sym;
}
/* Then search the symbol in our dependencies. Since we already searched in
* libraries the system linker loaded, skip those (on glibc systems). We
@ -389,15 +359,13 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
* directly, not in their own dependent libraries. Building libraries with
* --no-allow-shlib-undefined ensures such indirect symbol dependency don't
* happen. */
unsigned long hash = ElfHash(symbol);
for (std::vector<RefPtr<LibHandle> >::const_iterator it = dependencies.begin();
it < dependencies.end(); ++it) {
if (!(*it)->IsSystemElf()) {
sym = reinterpret_cast<CustomElf *>((*it).get())->GetSymbolPtr(symbol, hash);
#ifndef __GLIBC__
sym = static_cast<BaseElf *>(
static_cast<CustomElf *>((*it).get()))->GetSymbolPtr(symbol, hash);
} else {
sym = (*it)->GetSymbolPtr(symbol);
#endif
}
if (sym)
return sym;
@ -405,26 +373,6 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
return nullptr;
}
const Sym *
CustomElf::GetSymbol(const char *symbol, unsigned long hash) const
{
/* Search symbol with the buckets and chains tables.
* The hash computed from the symbol name gives an index in the buckets
* table. The corresponding value in the bucket table is an index in the
* symbols table and in the chains table.
* If the corresponding symbol in the symbols table matches, we're done.
* Otherwise, the corresponding value in the chains table is a new index
* in both tables, which corresponding symbol is tested and so on and so
* forth */
size_t bucket = hash % buckets.numElements();
for (size_t y = buckets[bucket]; y != STN_UNDEF; y = chains[y]) {
if (strcmp(symbol, strtab.GetStringAt(symtab[y].st_name)))
continue;
return &symtab[y];
}
return nullptr;
}
bool
CustomElf::Contains(void *addr) const
{

View File

@ -6,6 +6,7 @@
#define CustomElf_h
#include "ElfLoader.h"
#include "BaseElf.h"
#include "Logging.h"
#include "Elfxx.h"
@ -13,7 +14,7 @@
* Library Handle class for ELF libraries we don't let the system linker
* handle.
*/
class CustomElf: public LibHandle, private ElfLoader::link_map
class CustomElf: public BaseElf, private ElfLoader::link_map
{
friend class ElfLoader;
friend class SEGVHandler;
@ -31,7 +32,7 @@ public:
const char *path, int flags);
/**
* Inherited from LibHandle
* Inherited from LibHandle/BaseElf
*/
virtual ~CustomElf();
virtual void *GetSymbolPtr(const char *symbol) const;
@ -54,18 +55,6 @@ public:
void stats(const char *when) const;
private:
/**
* Returns a pointer to the Elf Symbol in the Dynamic Symbol table
* corresponding to the given symbol name (with a pre-computed hash).
*/
const Elf::Sym *GetSymbol(const char *symbol, unsigned long hash) const;
/**
* Returns the address corresponding to the given symbol name (with a
* pre-computed hash).
*/
void *GetSymbolPtr(const char *symbol, unsigned long hash) const;
/**
* Scan dependent libraries to find the address corresponding to the
* given symbol name. This is used to find symbols that are undefined
@ -77,7 +66,7 @@ private:
* Private constructor
*/
CustomElf(Mappable *mappable, const char *path)
: LibHandle(path)
: BaseElf(path)
, mappable(mappable)
, init(0)
, fini(0)
@ -85,24 +74,6 @@ private:
, has_text_relocs(false)
{ }
/**
* Returns a pointer relative to the base address where the library is
* loaded.
*/
void *GetPtr(const Elf::Addr offset) const
{
return base + offset;
}
/**
* Like the above, but returns a typed (const) pointer
*/
template <typename T>
const T *GetPtr(const Elf::Addr offset) const
{
return reinterpret_cast<const T *>(base + offset);
}
/**
* Loads an Elf segment defined by the given PT_LOAD header.
* Returns whether this succeeded or failed.
@ -167,19 +138,6 @@ private:
/* Appropriated Mappable */
mozilla::RefPtr<Mappable> mappable;
/* Base address where the library is loaded */
MappedPtr base;
/* String table */
Elf::Strtab strtab;
/* Symbol table */
UnsizedArray<Elf::Sym> symtab;
/* Buckets and chains for the System V symbol hash table */
Array<Elf::Word> buckets;
UnsizedArray<Elf::Word> chains;
/* List of dependent libraries */
std::vector<mozilla::RefPtr<LibHandle> > dependencies;

View File

@ -11,6 +11,7 @@
#include <algorithm>
#include <fcntl.h>
#include "ElfLoader.h"
#include "BaseElf.h"
#include "CustomElf.h"
#include "Mappable.h"
#include "Logging.h"
@ -38,6 +39,10 @@ extern "C" MOZ_EXPORT const void *
__gnu_Unwind_Find_exidx(void *pc, int *pcount) __attribute__((weak));
#endif
/* Pointer to the PT_DYNAMIC section of the executable or library
* containing this code. */
extern "C" Elf::Dyn _DYNAMIC[];
using namespace mozilla;
/**
@ -331,6 +336,10 @@ ElfLoader::Load(const char *path, int flags, LibHandle *parent)
/* Ensure logging is initialized or refresh if environment changed. */
Logging::Init();
/* Ensure self_elf initialization. */
if (!self_elf)
Init();
RefPtr<LibHandle> handle;
/* Handle dlopen(nullptr) directly. */
@ -466,6 +475,54 @@ ElfLoader::Forget(LibHandle *handle)
}
}
void
ElfLoader::Init()
{
Dl_info info;
/* On Android < 4.1 can't reenter dl* functions. So when the library
* containing this code is dlopen()ed, it can't call dladdr from a
* static initializer. */
if (dladdr(_DYNAMIC, &info) != 0) {
/* Ideally, we wouldn't be initializing self_elf this way, but until
* SystemElf actually inherits from BaseElf, we'll just do it this
* (gross) way. */
UniquePtr<BaseElf> elf = mozilla::MakeUnique<BaseElf>(info.dli_fname);
elf->base.Assign(info.dli_fbase, -1);
size_t symnum = 0;
for (const Elf::Dyn *dyn = _DYNAMIC; dyn->d_tag; dyn++) {
switch (dyn->d_tag) {
case DT_HASH:
{
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_HASH", dyn->d_un.d_val);
const Elf::Word *hash_table_header = \
elf->GetPtr<Elf::Word>(dyn->d_un.d_ptr);
symnum = hash_table_header[1];
elf->buckets.Init(&hash_table_header[2], hash_table_header[0]);
elf->chains.Init(&*elf->buckets.end());
}
break;
case DT_STRTAB:
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_STRTAB", dyn->d_un.d_val);
elf->strtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
break;
case DT_SYMTAB:
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_SYMTAB", dyn->d_un.d_val);
elf->symtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
break;
}
}
if (!elf->buckets || !symnum) {
ERROR("%s: Missing or broken DT_HASH", info.dli_fname);
} else if (!elf->strtab) {
ERROR("%s: Missing DT_STRTAB", info.dli_fname);
} else if (!elf->symtab) {
ERROR("%s: Missing DT_SYMTAB", info.dli_fname);
} else {
self_elf = Move(elf);
}
}
}
ElfLoader::~ElfLoader()
{
LibHandleList list;
@ -507,6 +564,10 @@ ElfLoader::~ElfLoader()
}
}
}
/* Avoid self_elf->base destructor unmapping something that doesn't actually
* belong to it. */
if (self_elf)
self_elf->base.release();
}
void

View File

@ -9,6 +9,7 @@
#include <dlfcn.h>
#include <signal.h>
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "Zip.h"
#include "Elfxx.h"
#include "Mappable.h"
@ -63,6 +64,9 @@ IsSignalHandlingBroken();
}
/* Forward declaration because BaseElf.h includes ElfLoader.h */
class BaseElf;
/**
* Specialize RefCounted template for LibHandle. We may get references to
* LibHandles during the execution of their destructor, so we need
@ -439,6 +443,13 @@ protected:
private:
~ElfLoader();
/* Initialization code that can't run during static initialization. */
void Init();
/* System loader handle for the library/program containing our code. This
* is used to resolve wrapped functions. */
mozilla::UniquePtr<BaseElf> self_elf;
/* Bookkeeping */
typedef std::vector<LibHandle *> LibHandleList;
LibHandleList handles;
@ -557,6 +568,12 @@ private:
} r_state;
};
/* Memory representation of ELF Auxiliary Vectors */
struct AuxVector {
Elf::Addr type;
Elf::Addr value;
};
/* Helper class used to integrate libraries loaded by this linker in
* r_debug */
class DebuggerHelper
@ -564,6 +581,8 @@ private:
public:
DebuggerHelper();
void Init(AuxVector *auvx);
operator bool()
{
return dbg;

View File

@ -290,6 +290,10 @@ public:
static_cast<T *>(this)->munmap(get(), GetLength());
}
void release()
{
MemoryRange::Assign(MAP_FAILED, 0);
}
};
struct MappedPtr: public GenericMappedPtr<MappedPtr>

View File

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'BaseElf.cpp',
'CustomElf.cpp',
'ElfLoader.cpp',
'Mappable.cpp',

View File

@ -77,9 +77,6 @@ class MethodHandler(object):
# Description of the purpose of this command.
'description',
# Whether to allow all arguments from the parser.
'allow_all_arguments',
# Functions used to 'skip' commands if they don't meet the conditions
# in a given context.
'conditions',
@ -94,15 +91,13 @@ class MethodHandler(object):
)
def __init__(self, cls, method, name, category=None, description=None,
allow_all_arguments=False, conditions=None, parser=None, arguments=None,
pass_context=False):
conditions=None, parser=None, arguments=None, pass_context=False):
self.cls = cls
self.method = method
self.name = name
self.category = category
self.description = description
self.allow_all_arguments = allow_all_arguments
self.conditions = conditions or []
self.parser = parser
self.arguments = arguments or []

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import argparse
import collections
import inspect
import types
@ -56,8 +57,8 @@ def CommandProvider(cls):
if not isinstance(value, types.FunctionType):
continue
command_name, category, description, allow_all, conditions, parser = getattr(
value, '_mach_command', (None, None, None, None, None, None))
command_name, category, description, conditions, parser = getattr(
value, '_mach_command', (None, None, None, None, None))
if command_name is None:
continue
@ -82,9 +83,8 @@ def CommandProvider(cls):
arguments = getattr(value, '_mach_command_args', None)
handler = MethodHandler(cls, attr, command_name, category=category,
description=description, allow_all_arguments=allow_all,
conditions=conditions, parser=parser, arguments=arguments,
pass_context=pass_context)
description=description, conditions=conditions, parser=parser,
arguments=arguments, pass_context=pass_context)
Registrar.register_command_handler(handler)
@ -102,9 +102,6 @@ class Command(object):
description -- A brief description of what the command does.
allow_all_args -- Bool indicating whether to allow unknown arguments
through to the command.
parser -- an optional argparse.ArgumentParser instance to use as
the basis for the command arguments.
@ -114,18 +111,17 @@ class Command(object):
def foo(self):
pass
"""
def __init__(self, name, category=None, description=None,
allow_all_args=False, conditions=None, parser=None):
def __init__(self, name, category=None, description=None, conditions=None,
parser=None):
self._name = name
self._category = category
self._description = description
self._allow_all_args = allow_all_args
self._conditions = conditions
self._parser = parser
def __call__(self, func):
func._mach_command = (self._name, self._category, self._description,
self._allow_all_args, self._conditions, self._parser)
self._conditions, self._parser)
return func
@ -145,6 +141,11 @@ class CommandArgument(object):
pass
"""
def __init__(self, *args, **kwargs):
if kwargs.get('nargs') == argparse.REMAINDER:
# These are the assertions we make in dispatcher.py about
# those types of CommandArguments.
assert len(args) == 1
assert all(k in ('default', 'nargs', 'help') for k in kwargs)
self._command_args = (args, kwargs)
def __call__(self, func):

View File

@ -135,19 +135,27 @@ class CommandAction(argparse.Action):
parser_args = {
'add_help': False,
'usage': '%(prog)s [global arguments] ' + command +
' command arguments]',
' [command arguments]',
}
if handler.allow_all_arguments:
parser_args['prefix_chars'] = '+'
if handler.parser:
subparser = handler.parser
else:
subparser = argparse.ArgumentParser(**parser_args)
remainder = None
for arg in handler.arguments:
subparser.add_argument(*arg[0], **arg[1])
if arg[1].get('nargs') == argparse.REMAINDER:
# parse_known_args expects all argparse.REMAINDER ('...')
# arguments to be all stuck together. Instead, we want them to
# pick any extra argument, wherever they are.
# Assume a limited CommandArgument for those arguments.
assert len(arg[0]) == 1
assert all(k in ('default', 'nargs', 'help') for k in arg[1])
remainder = arg
else:
subparser.add_argument(*arg[0], **arg[1])
# We define the command information on the main parser result so as to
# not interfere with arguments passed to the command.
@ -156,7 +164,32 @@ class CommandAction(argparse.Action):
command_namespace, extra = subparser.parse_known_args(args)
setattr(namespace, 'command_args', command_namespace)
if extra:
if remainder:
(name,), options = remainder
# parse_known_args usefully puts all arguments after '--' in
# extra, but also puts '--' there. We don't want to pass it down
# to the command handler. Note that if multiple '--' are on the
# command line, only the first one is removed, so that subsequent
# ones are passed down.
if '--' in extra:
extra.remove('--')
# Commands with argparse.REMAINDER arguments used to force the
# other arguments to be '+' prefixed. If a user now passes such
# an argument, if will silently end up in extra. So, check if any
# of the allowed arguments appear in a '+' prefixed form, and error
# out if that's the case.
for args, _ in handler.arguments:
for arg in args:
arg = arg.replace('-', '+', 1)
if arg in extra:
raise UnrecognizedArgumentError(command, [arg])
if extra:
setattr(command_namespace, name, extra)
else:
setattr(command_namespace, name, options.get('default', []))
elif extra:
raise UnrecognizedArgumentError(command, extra)
def _handle_main_help(self, parser, verbose):
@ -234,9 +267,6 @@ class CommandAction(argparse.Action):
'add_help': False,
}
if handler.allow_all_arguments:
parser_args['prefix_chars'] = '+'
if handler.parser:
c_parser = handler.parser
c_parser.formatter_class = NoUsageFormatter

View File

@ -25,7 +25,6 @@ from mach.decorators import (
@CommandProvider
class MachCommands(MachCommandBase):
@Command('python', category='devenv',
allow_all_args=True,
description='Run Python.')
@CommandArgument('args', nargs=argparse.REMAINDER)
def python(self, args):

View File

@ -810,24 +810,21 @@ def get_run_args(mach_command, params, remote, background, noprofile):
if params:
args.extend(params)
if '--' in args:
args.remove('--')
return args
@CommandProvider
class RunProgram(MachCommandBase):
"""Launch the compiled binary"""
@Command('run', category='post-build', allow_all_args=True,
@Command('run', category='post-build',
description='Run the compiled program.')
@CommandArgument('params', default=None, nargs='...',
@CommandArgument('params', nargs='...',
help='Command-line arguments to be passed through to the program. Not specifying a -profile or -P option will result in a temporary profile being used.')
@CommandArgument('+remote', '+r', action='store_true',
@CommandArgument('-remote', '-r', action='store_true',
help='Do not pass the -no-remote argument by default.')
@CommandArgument('+background', '+b', action='store_true',
@CommandArgument('-background', '-b', action='store_true',
help='Do not pass the -foreground argument by default on Mac')
@CommandArgument('+noprofile', '+n', action='store_true',
@CommandArgument('-noprofile', '-n', action='store_true',
help='Do not pass the -profile argument by default.')
def run(self, params, remote, background, noprofile):
args = get_run_args(self, params, remote, background, noprofile)
@ -841,26 +838,26 @@ class RunProgram(MachCommandBase):
class DebugProgram(MachCommandBase):
"""Debug the compiled binary"""
@Command('debug', category='post-build', allow_all_args=True,
@Command('debug', category='post-build',
description='Debug the compiled program.')
@CommandArgument('params', default=None, nargs='...',
@CommandArgument('params', nargs='...',
help='Command-line arguments to be passed through to the program. Not specifying a -profile or -P option will result in a temporary profile being used.')
@CommandArgument('+remote', '+r', action='store_true',
@CommandArgument('-remote', '-r', action='store_true',
help='Do not pass the -no-remote argument by default')
@CommandArgument('+background', '+b', action='store_true',
@CommandArgument('-background', '-b', action='store_true',
help='Do not pass the -foreground argument by default on Mac')
@CommandArgument('+debugger', default=None, type=str,
@CommandArgument('-debugger', default=None, type=str,
help='Name of debugger to launch')
@CommandArgument('+debugparams', default=None, metavar='params', type=str,
@CommandArgument('-debugparams', default=None, metavar='params', type=str,
help='Command-line arguments to pass to the debugger itself; split as the Bourne shell would.')
# Bug 933807 introduced JS_DISABLE_SLOW_SCRIPT_SIGNALS to avoid clever
# segfaults induced by the slow-script-detecting logic for Ion/Odin JITted
# code. If we don't pass this, the user will need to periodically type
# "continue" to (safely) resume execution. There are ways to implement
# automatic resuming; see the bug.
@CommandArgument('+slowscript', action='store_true',
@CommandArgument('-slowscript', action='store_true',
help='Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; when not set, recoverable but misleading SIGSEGV instances may occur in Ion/Odin JIT code')
@CommandArgument('+noprofile', '+n', action='store_true',
@CommandArgument('-noprofile', '-n', action='store_true',
help='Do not pass the -profile argument by default.')
def debug(self, params, remote, background, debugger, debugparams, slowscript, noprofile):
# Parameters come from the CLI. We need to convert them before their use.
@ -868,7 +865,7 @@ class DebugProgram(MachCommandBase):
import pymake.process
argv, badchar = pymake.process.clinetoargv(debugparams, os.getcwd())
if badchar:
print("The +debugparams you passed require a real shell to parse them.")
print("The -debugparams you passed require a real shell to parse them.")
print("(We can't handle the %r character.)" % (badchar,))
return 1
debugparams = argv;
@ -925,7 +922,7 @@ class RunDmd(MachCommandBase):
@Command('dmd', category='post-build',
description='Run the compiled program with DMD enabled.')
@CommandArgument('params', default=None, nargs='...',
@CommandArgument('params', nargs='...',
help=('Command-line arguments to be passed through to the program. '
'Not specifying a -profile or -P option will result in a '
'temporary profile being used. If passing -params use a "--" to '

View File

@ -15,22 +15,6 @@ skip = false
[include:unit/unit-tests.ini]
test_container = true
; webapi tests
[include:../../../../../dom/bluetooth/tests/marionette/manifest.ini]
[include:../../../../../dom/telephony/test/marionette/manifest.ini]
[include:../../../../../dom/voicemail/test/marionette/manifest.ini]
[include:../../../../../dom/battery/test/marionette/manifest.ini]
[include:../../../../../dom/mobilemessage/tests/marionette/manifest.ini]
[include:../../../../../dom/mobileconnection/tests/marionette/manifest.ini]
[include:../../../../../dom/system/gonk/tests/marionette/manifest.ini]
[include:../../../../../dom/icc/tests/marionette/manifest.ini]
[include:../../../../../dom/system/tests/marionette/manifest.ini]
[include:../../../../../dom/nfc/tests/marionette/manifest.ini]
[include:../../../../../dom/events/test/marionette/manifest.ini]
[include:../../../../../dom/wifi/test/marionette/manifest.ini]
[include:../../../../../dom/cellbroadcast/tests/marionette/manifest.ini]
[include:../../../../../dom/tethering/tests/marionette/manifest.ini]
; layout tests
[include:../../../../../layout/base/tests/marionette/manifest.ini]

View File

@ -1845,7 +1845,7 @@ class Mochitest(MochitestUtilsMixin):
self.stopVMwareRecording();
self.stopServers()
processLeakLog(self.leak_report_file, options.leakThresholds, options.ignoreMissingLeaks)
processLeakLog(self.leak_report_file, options)
if self.nsprLogs:
with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:

View File

@ -202,7 +202,7 @@ class B2GMochitest(MochitestUtilsMixin):
self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name)
self.app_ctx.dm.removeFile(self.leak_report_file)
processLeakLog(local_leak_file.name, options.leakThresholds, options.ignoreMissingLeaks)
processLeakLog(local_leak_file.name, options)
except KeyboardInterrupt:
self.log.info("runtests.py | Received keyboard interrupt.\n");
status = -1

View File

@ -550,6 +550,11 @@ stage-marionette: make-stage-dir
$(topsrcdir)/testing/marionette/client/marionette/tests/unit-tests.ini \
| (cd $(topsrcdir) && xargs tar $(TAR_CREATE_FLAGS) -) \
| (cd $(MARIONETTE_DIR)/tests && tar -xf -)
$(PYTHON) $(topsrcdir)/testing/marionette/client/marionette/tests/print-manifest-dirs.py \
$(topsrcdir) \
$(topsrcdir)/testing/marionette/client/marionette/tests/webapi-tests.ini \
| (cd $(topsrcdir) && xargs tar $(TAR_CREATE_FLAGS) -) \
| (cd $(MARIONETTE_DIR)/tests && tar -xf -)
stage-mozbase: make-stage-dir
$(MAKE) -C $(DEPTH)/testing/mozbase stage-package

View File

@ -294,7 +294,7 @@ class PastebinProvider(object):
@CommandProvider
class ReviewboardToolsProvider(MachCommandBase):
@Command('rbt', category='devenv', allow_all_args=True,
@Command('rbt', category='devenv',
description='Run Reviewboard Tools')
@CommandArgument('args', nargs='...', help='Arguments to rbt tool')
def rbt(self, args):