mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
Merge m-c to b2g-inbound
This commit is contained in:
commit
3346857046
@ -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);});
|
||||
},
|
||||
|
@ -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");
|
||||
});
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -183,4 +183,11 @@ if (typeof Mozilla == 'undefined') {
|
||||
_sendEvent('resetFirefox');
|
||||
};
|
||||
|
||||
Mozilla.UITour.addNavBarWidget= function(name, callback) {
|
||||
_sendEvent('addNavBarWidget', {
|
||||
name: name,
|
||||
callbackID: _waitForCallback(callback),
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -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"]
|
||||
|
@ -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,
|
||||
|
@ -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
100
dom/fetch/Fetch.cpp
Normal 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
29
dom/fetch/Fetch.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
60
dom/fetch/InternalRequest.cpp
Normal file
60
dom/fetch/InternalRequest.cpp
Normal 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
264
dom/fetch/InternalRequest.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
]
|
||||
|
26
dom/ipc/CPOWManagerGetter.h
Normal file
26
dom/ipc/CPOWManagerGetter.h
Normal 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 */
|
@ -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()) {
|
||||
|
@ -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,
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -1777,7 +1777,7 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
|
||||
}
|
||||
}
|
||||
|
||||
jsipc::JavaScriptParent*
|
||||
jsipc::JavaScriptShared*
|
||||
ContentParent::GetCPOWManager()
|
||||
{
|
||||
if (ManagedPJavaScriptParent().Length()) {
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ EXPORTS.mozilla.dom += [
|
||||
'ContentChild.h',
|
||||
'ContentParent.h',
|
||||
'ContentProcess.h',
|
||||
'CPOWManagerGetter.h',
|
||||
'CrashReporterChild.h',
|
||||
'CrashReporterParent.h',
|
||||
'FilePickerParent.h',
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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*);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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"
|
||||
|
@ -1,5 +1,7 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
worker_interfaces.js
|
||||
worker_test_request.js
|
||||
|
||||
[test_interfaces.html]
|
||||
[test_request.html]
|
||||
|
48
dom/workers/test/fetch/test_request.html
Normal file
48
dom/workers/test/fetch/test_request.html
Normal 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>
|
||||
|
215
dom/workers/test/fetch/worker_test_request.js
Normal file
215
dom/workers/test/fetch/worker_test_request.js
Normal 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();
|
||||
})
|
||||
}
|
@ -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.
|
||||
|
@ -358,7 +358,7 @@ public:
|
||||
|
||||
virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
|
||||
{
|
||||
mReleaseFenceHandle = aReleaseFenceHandle;
|
||||
mReleaseFenceHandle.Merge(aReleaseFenceHandle);
|
||||
}
|
||||
|
||||
const FenceHandle& GetReleaseFenceHandle() const
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -421,8 +421,6 @@ public:
|
||||
*/
|
||||
PTextureParent* GetIPDLActor();
|
||||
|
||||
static void SendFenceHandleIfPresent(PTextureParent* actor);
|
||||
|
||||
FenceHandle GetAndResetReleaseFenceHandle();
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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"
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
||||
|
55
mozglue/linker/BaseElf.cpp
Normal file
55
mozglue/linker/BaseElf.cpp
Normal 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
93
mozglue/linker/BaseElf.h
Normal 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 */
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -290,6 +290,10 @@ public:
|
||||
static_cast<T *>(this)->munmap(get(), GetLength());
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
MemoryRange::Assign(MAP_FAILED, 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct MappedPtr: public GenericMappedPtr<MappedPtr>
|
||||
|
@ -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',
|
||||
|
@ -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 []
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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 '
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user