merge mozilla-inbound to mozilla-central a=merge

--HG--
rename : mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java => mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
rename : mobile/android/base/java/org/mozilla/gecko/gfx/GeckoLayerClient.java => mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
rename : mobile/android/base/java/org/mozilla/gecko/gfx/LayerRenderer.java => mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerRenderer.java
rename : mobile/android/base/java/org/mozilla/gecko/gfx/PanningPerfAPI.java => mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/PanningPerfAPI.java
This commit is contained in:
Carsten "Tomcat" Book 2016-08-04 15:55:50 +02:00
Родитель d036bdb09c 03f2893f26
Коммит 389a3e0817
306 изменённых файлов: 16058 добавлений и 5158 удалений

26
build/macosx/build-cctools.sh Executable file
Просмотреть файл

@ -0,0 +1,26 @@
#!/bin/bash
set -e
if ! git remote -v | grep origin | grep -q cctools-port; then
echo "must be in a cctools-port checkout"
exit 1
fi
mkdir build-cctools
cd build-cctools
CFLAGS='-mcpu=generic -mtune=generic' MACOSX_DEPLOYMENT_TARGET=10.7 ../cctools/configure --target=x86_64-apple-darwin11
env MACOSX_DEPLOYMENT_TARGET=10.7 make -s -j4
if test ! -e ld64/src/ld/ld; then
echo "ld did not get built"
exit 1
fi
gtar jcf cctools.tar.bz2 ld64/src/ld/ld --transform 's#ld64/src/ld#cctools/bin#'
cd ../
echo "build from $(git show --pretty=format:%H -s HEAD) complete!"
echo "upload the build-cctools/cctools.tar.bz2 file to tooltool"

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

@ -16,16 +16,18 @@ if [ -d "$topsrcdir/clang" ]; then
export CXX=$topsrcdir/clang/bin/clang++
export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config
export DSYMUTIL=$topsrcdir/clang/bin/llvm-dsymutil
# Use an updated linker.
ldflags="-B$topsrcdir/cctools/bin"
elif [ -d "$topsrcdir/../clang" ]; then
# comm-central based build
export CC=$topsrcdir/../clang/bin/clang
export CXX=$topsrcdir/../clang/bin/clang++
export LLVMCONFIG=$topsrcdir/../clang/bin/llvm-config
export DSYMUTIL=$topsrcdir/../clang/bin/llvm-dsymutil
# Use an updated linker.
ldflags="-B$topsrcdir/../cctools/bin"
fi
# Use an updated linker.
ldflags="-B$topsrcdir/cctools/bin"
# Ensure the updated linker doesn't generate things our older build tools
# don't understand.
ldflags="$ldflags -Wl,-no_data_in_code_info"

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

@ -72,8 +72,8 @@ def rust_target(rust_compiler, rustc, target, cross_compiling):
os_or_kernel = target.kernel if target.kernel == 'Linux' and target.os != 'Android' else target.os
rustc_target = {
# DragonFly
('x86_64', 'Dragonfly'): 'x86_64-unknown-dragonfly',
# FreeBSD, GNU/kFreeBSD
('x86_64', 'DragonFly'): 'x86_64-unknown-dragonfly',
# FreeBSD
('x86', 'FreeBSD'): 'i686-unknown-freebsd',
('x86_64', 'FreeBSD'): 'x86_64-unknown-freebsd',
# NetBSD

3
config/external/icu/defs.mozbuild поставляемый
Просмотреть файл

@ -24,6 +24,9 @@ DEFINES.update(
if not CONFIG['HAVE_LANGINFO_CODESET']:
DEFINES['U_HAVE_NL_LANGINFO_CODESET'] = 0
if CONFIG['MOZ_DEBUG']:
DEFINES['U_DEBUG'] = 1
# ICU requires RTTI
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-frtti']

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

@ -17,9 +17,9 @@ function test() {
"-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'",
"-H 'Accept-Language: " + navigator.language + "'",
"--compressed",
"-H 'X-Custom-Header-1: Custom value'",
"-H 'X-Custom-Header-2: 8.8.8.8'",
"-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'",
"-H 'x-custom-header-1: Custom value'",
"-H 'x-custom-header-2: 8.8.8.8'",
"-H 'x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT'",
"-H 'Referer: " + CURL_URL + "'",
"-H 'Connection: keep-alive'",
"-H 'Pragma: no-cache'",
@ -34,9 +34,9 @@ function test() {
'-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"',
'-H "Accept-Language: ' + navigator.language + '"',
"--compressed",
'-H "X-Custom-Header-1: Custom value"',
'-H "X-Custom-Header-2: 8.8.8.8"',
'-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"',
'-H "x-custom-header-1: Custom value"',
'-H "x-custom-header-2: 8.8.8.8"',
'-H "x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT"',
'-H "Referer: ' + CURL_URL + '"',
'-H "Connection: keep-alive"',
'-H "Pragma: no-cache"',
@ -56,7 +56,36 @@ function test() {
let requestItem = RequestsMenu.getItemAtIndex(0);
RequestsMenu.selectedItem = requestItem;
waitForClipboard(EXPECTED_RESULT, function setup() {
waitForClipboard(function validate(aResult) {
if (typeof aResult !== "string") {
return false;
}
// Different setups may produce the same command, but with the
// parameters in a different order in the commandline (which is fine).
// Here we confirm that the commands are the same even in that case.
var expected = EXPECTED_RESULT.toString().match(/[-A-Za-z1-9]+ ([\"'])(?:\\\1|.)*?\1/g),
actual = aResult.match(/[-A-Za-z1-9]+ ([\"'])(?:\\\1|.)*?\1/g);
// Must begin with the same "curl 'URL'" segment
if (!actual || expected[0] != actual[0]) {
return false;
}
// Must match each of the params in the middle (headers)
var expectedSet = new Set(expected);
var actualSet = new Set(actual);
if (expected.size != actual.size) {
return false;
}
for (let param of expectedSet) {
if (!actualSet.has(param)) {
return false;
}
}
return true;
}, function setup() {
RequestsMenu.copyAsCurl();
}, function onSuccess() {
ok(true, "Clipboard contains a cURL command for the currently selected item's url.");

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

@ -154,7 +154,7 @@ function testSentRequest(aData, aOrigData) {
is(aData.url, aOrigData.url + "&" + ADD_QUERY, "correct url in sent request");
let hasHeader = aData.requestHeaders.headers.some((header) => {
return (header.name + ": " + header.value) == ADD_HEADER;
return (header.name.toLowerCase() + ": " + header.value) == ADD_HEADER.toLowerCase();
});
ok(hasHeader, "new header added to sent request");

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

@ -142,6 +142,9 @@ var CanvasActor = exports.CanvasActor = protocol.ActorClassWithSpec(canvasSpec,
*/
setup: function ({ reload }) {
if (this._initialized) {
if (reload) {
this.tabActor.window.location.reload();
}
return;
}
this._initialized = true;

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

@ -451,6 +451,9 @@ var WebAudioActor = exports.WebAudioActor = protocol.ActorClassWithSpec(webAudio
this._nativeToActorID.clear();
if (this._initialized) {
if (reload) {
this.tabActor.window.location.reload();
}
return;
}

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

@ -715,11 +715,7 @@ nsSHEntry::AddChild(nsISHEntry* aChild, int32_t aOffset)
}
}
if (!mChildren.ReplaceObjectAt(aChild, aOffset)) {
NS_WARNING("Adding a child failed!");
aChild->SetParent(nullptr);
return NS_ERROR_FAILURE;
}
mChildren.ReplaceObjectAt(aChild, aOffset);
}
return NS_OK;
@ -737,7 +733,8 @@ nsSHEntry::RemoveChild(nsISHEntry* aChild)
} else {
int32_t index = mChildren.IndexOfObject(aChild);
if (index >= 0) {
childRemoved = mChildren.ReplaceObjectAt(nullptr, index);
mChildren.ReplaceObjectAt(nullptr, index);
childRemoved = true;
}
}
if (childRemoved) {
@ -780,9 +777,8 @@ nsSHEntry::ReplaceChild(nsISHEntry* aNewEntry)
if (mChildren[i] && NS_SUCCEEDED(mChildren[i]->GetDocshellID(&otherID)) &&
docshellID == otherID) {
mChildren[i]->SetParent(nullptr);
if (mChildren.ReplaceObjectAt(aNewEntry, i)) {
return aNewEntry->SetParent(this);
}
mChildren.ReplaceObjectAt(aNewEntry, i);
return aNewEntry->SetParent(this);
}
}
return NS_ERROR_FAILURE;

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

@ -1258,7 +1258,8 @@ Element::GetAttributeNS(const nsAString& aNamespaceURI,
nsAString& aReturn)
{
int32_t nsid =
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
nsContentUtils::IsChromeDoc(OwnerDoc()));
if (nsid == kNameSpaceID_Unknown) {
// Unknown namespace means no attribute.
@ -1300,7 +1301,8 @@ Element::RemoveAttributeNS(const nsAString& aNamespaceURI,
{
nsCOMPtr<nsIAtom> name = NS_Atomize(aLocalName);
int32_t nsid =
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
nsContentUtils::IsChromeDoc(OwnerDoc()));
if (nsid == kNameSpaceID_Unknown) {
// If the namespace ID is unknown, it means there can't possibly be an
@ -1377,7 +1379,8 @@ Element::HasAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName) const
{
int32_t nsid =
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
nsContentUtils::IsChromeDoc(OwnerDoc()));
if (nsid == kNameSpaceID_Unknown) {
// Unknown namespace means no attr...

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

@ -23,6 +23,7 @@ static const int32_t kNameSpaceID_None = 0;
#define kNameSpaceID_RDF 8
#define kNameSpaceID_XUL 9
#define kNameSpaceID_SVG 10
#define kNameSpaceID_LastBuiltin 10 // last 'built-in' namespace
#define kNameSpaceID_disabled_MathML 11
#define kNameSpaceID_LastBuiltin 11 // last 'built-in' namespace
#endif // mozilla_dom_NameSpaceConstants_h__

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

@ -197,7 +197,8 @@ bool
NodeInfo::NamespaceEquals(const nsAString& aNamespaceURI) const
{
int32_t nsid =
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
nsContentUtils::IsChromeDoc(mOwnerManager->GetDocument()));
return mozilla::dom::NodeInfo::NamespaceEquals(nsid);
}

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

@ -281,6 +281,7 @@ static const DOMIfaceAndProtoJSClass WindowNamedPropertiesClass = {
PROXY_CLASS_DEF("WindowProperties",
JSCLASS_IS_DOMIFACEANDPROTOJSCLASS),
eNamedPropertiesObject,
false,
prototypes::id::_ID_Count,
0,
sWindowNamedPropertiesNativePropertyHooks,

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

@ -2892,7 +2892,8 @@ nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver,
nameSpace);
NS_ENSURE_SUCCESS(rv, rv);
*aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace);
*aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace,
nsContentUtils::IsChromeDoc(aNamespaceResolver->OwnerDoc()));
if (*aNamespace == kNameSpaceID_Unknown)
return NS_ERROR_FAILURE;
@ -7071,9 +7072,8 @@ nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString& aHeader)
static const char *kInvalidHeaders[] = {
"accept-charset", "accept-encoding", "access-control-request-headers",
"access-control-request-method", "connection", "content-length",
"cookie", "cookie2", "content-transfer-encoding", "date", "dnt",
"expect", "host", "keep-alive", "origin", "referer", "te", "trailer",
"transfer-encoding", "upgrade", "via"
"cookie", "cookie2", "date", "dnt", "expect", "host", "keep-alive",
"origin", "referer", "te", "trailer", "transfer-encoding", "upgrade", "via"
};
for (uint32_t i = 0; i < ArrayLength(kInvalidHeaders); ++i) {
if (aHeader.LowerCaseEqualsASCII(kInvalidHeaders[i])) {

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

@ -446,7 +446,8 @@ nsDOMAttributeMap::GetAttrNodeInfo(const nsAString& aNamespaceURI,
if (!aNamespaceURI.IsEmpty()) {
nameSpaceID =
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
nsContentUtils::IsChromeDoc(mContent->OwnerDoc()));
if (nameSpaceID == kNameSpaceID_Unknown) {
return nullptr;

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

@ -243,6 +243,12 @@ public:
*/
inline bool IsInHTMLDocument() const;
/**
* Returns true if in a chrome document
*/
virtual bool IsInChromeDocument();
/**
* Get the namespace that this element's tag is defined in
* @return the namespace

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

@ -9,6 +9,7 @@
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsContentUtils.h"
inline bool
nsIContent::IsInHTMLDocument() const
@ -16,4 +17,10 @@ nsIContent::IsInHTMLDocument() const
return OwnerDoc()->IsHTMLDocument();
}
inline bool
nsIContent::IsInChromeDocument()
{
return nsContentUtils::IsChromeDoc(OwnerDoc());
}
#endif // nsIContentInlines_h

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

@ -15,17 +15,25 @@
#include "mozilla/dom/NodeInfo.h"
#include "nsCOMArray.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "nsGkAtoms.h"
#include "nsIDocument.h"
#include "nsString.h"
#include "mozilla/dom/NodeInfo.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/XBLChildrenElement.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::dom;
StaticAutoPtr<nsNameSpaceManager> nsNameSpaceManager::sInstance;
static const char* kPrefMathMLDisabled = "mathml.disabled";
static const char* kObservedPrefs[] = {
kPrefMathMLDisabled,
nullptr
};
StaticRefPtr<nsNameSpaceManager> nsNameSpaceManager::sInstance;
/* static */ nsNameSpaceManager*
nsNameSpaceManager::GetInstance() {
@ -49,6 +57,14 @@ bool nsNameSpaceManager::Init()
rv = AddNameSpace(dont_AddRef(uri), id); \
NS_ENSURE_SUCCESS(rv, false)
#define REGISTER_DISABLED_NAMESPACE(uri, id) \
rv = AddDisabledNameSpace(dont_AddRef(uri), id); \
NS_ENSURE_SUCCESS(rv, false)
mozilla::Preferences::AddStrongObservers(this, kObservedPrefs);
mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled);
// Need to be ordered according to ID.
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xmlns, kNameSpaceID_XMLNS);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xml, kNameSpaceID_XML);
@ -60,8 +76,10 @@ bool nsNameSpaceManager::Init()
REGISTER_NAMESPACE(nsGkAtoms::nsuri_rdf, kNameSpaceID_RDF);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xul, kNameSpaceID_XUL);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_SVG);
REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_mathml, kNameSpaceID_disabled_MathML);
#undef REGISTER_NAMESPACE
#undef REGISTER_DISABLED_NAMESPACE
return true;
}
@ -110,24 +128,32 @@ nsNameSpaceManager::GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI)
}
int32_t
nsNameSpaceManager::GetNameSpaceID(const nsAString& aURI)
nsNameSpaceManager::GetNameSpaceID(const nsAString& aURI,
bool aInChromeDoc)
{
if (aURI.IsEmpty()) {
return kNameSpaceID_None; // xmlns="", see bug 75700 for details
}
nsCOMPtr<nsIAtom> atom = NS_Atomize(aURI);
return GetNameSpaceID(atom);
return GetNameSpaceID(atom, aInChromeDoc);
}
int32_t
nsNameSpaceManager::GetNameSpaceID(nsIAtom* aURI)
nsNameSpaceManager::GetNameSpaceID(nsIAtom* aURI,
bool aInChromeDoc)
{
if (aURI == nsGkAtoms::_empty) {
return kNameSpaceID_None; // xmlns="", see bug 75700 for details
}
int32_t nameSpaceID;
if (mMathMLDisabled &&
mDisabledURIToIDTable.Get(aURI, &nameSpaceID) &&
!aInChromeDoc) {
NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID");
return nameSpaceID;
}
if (mURIToIDTable.Get(aURI, &nameSpaceID)) {
NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID");
return nameSpaceID;
@ -153,7 +179,19 @@ NS_NewElement(Element** aResult,
}
#endif
if (ns == kNameSpaceID_MathML) {
return NS_NewMathMLElement(aResult, ni.forget());
// If the mathml.disabled pref. is true, convert all MathML nodes into
// disabled MathML nodes by swapping the namespace.
nsNameSpaceManager* nsmgr = nsNameSpaceManager::GetInstance();
if ((nsmgr && !nsmgr->mMathMLDisabled) ||
nsContentUtils::IsChromeDoc(ni->GetDocument())) {
return NS_NewMathMLElement(aResult, ni.forget());
}
RefPtr<mozilla::dom::NodeInfo> genericXMLNI =
ni->NodeInfoManager()->
GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(),
kNameSpaceID_disabled_MathML, ni->NodeType(), ni->GetExtraName());
return NS_NewXMLElement(aResult, genericXMLNI.forget());
}
if (ns == kNameSpaceID_SVG) {
return NS_NewSVGElement(aResult, ni.forget(), aFromParser);
@ -195,3 +233,35 @@ nsresult nsNameSpaceManager::AddNameSpace(already_AddRefed<nsIAtom> aURI,
return NS_OK;
}
nsresult
nsNameSpaceManager::AddDisabledNameSpace(already_AddRefed<nsIAtom> aURI,
const int32_t aNameSpaceID)
{
nsCOMPtr<nsIAtom> uri = aURI;
if (aNameSpaceID < 0) {
// We've wrapped... Can't do anything else here; just bail.
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ASSERTION(aNameSpaceID - 1 == (int32_t) mURIArray.Length(),
"BAD! AddDisabledNameSpace not called in right order!");
mURIArray.AppendElement(uri.forget());
mDisabledURIToIDTable.Put(mURIArray.LastElement(), aNameSpaceID);
return NS_OK;
}
// nsISupports
NS_IMPL_ISUPPORTS(nsNameSpaceManager,
nsIObserver)
// nsIObserver
NS_IMETHODIMP
nsNameSpaceManager::Observe(nsISupports* aObject, const char* aTopic,
const char16_t* aMessage)
{
mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled);
return NS_OK;
}

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

@ -10,6 +10,8 @@
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsIAtom.h"
#include "nsIDocument.h"
#include "nsIObserver.h"
#include "nsTArray.h"
#include "mozilla/StaticPtr.h"
@ -30,34 +32,42 @@ class nsAString;
*
*/
class nsNameSpaceManager final
class nsNameSpaceManager final : public nsIObserver
{
public:
~nsNameSpaceManager() {}
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
virtual nsresult RegisterNameSpace(const nsAString& aURI,
int32_t& aNameSpaceID);
nsresult RegisterNameSpace(const nsAString& aURI, int32_t& aNameSpaceID);
nsresult GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI);
virtual nsresult GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI);
nsIAtom* NameSpaceURIAtom(int32_t aNameSpaceID) {
MOZ_ASSERT(aNameSpaceID > 0 && (int64_t) aNameSpaceID <= (int64_t) mURIArray.Length());
return mURIArray.ElementAt(aNameSpaceID - 1); // id is index + 1
}
int32_t GetNameSpaceID(const nsAString& aURI);
int32_t GetNameSpaceID(nsIAtom* aURI);
int32_t GetNameSpaceID(const nsAString& aURI,
bool aInChromeDoc);
int32_t GetNameSpaceID(nsIAtom* aURI,
bool aInChromeDoc);
bool HasElementCreator(int32_t aNameSpaceID);
static nsNameSpaceManager* GetInstance();
bool mMathMLDisabled;
private:
bool Init();
nsresult AddNameSpace(already_AddRefed<nsIAtom> aURI, const int32_t aNameSpaceID);
nsresult AddDisabledNameSpace(already_AddRefed<nsIAtom> aURI, const int32_t aNameSpaceID);
~nsNameSpaceManager() {};
nsDataHashtable<nsISupportsHashKey, int32_t> mURIToIDTable;
nsDataHashtable<nsISupportsHashKey, int32_t> mDisabledURIToIDTable;
nsTArray<nsCOMPtr<nsIAtom>> mURIArray;
static mozilla::StaticAutoPtr<nsNameSpaceManager> sInstance;
static mozilla::StaticRefPtr<nsNameSpaceManager> sInstance;
};
#endif // nsNameSpaceManager_h___

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

@ -317,7 +317,7 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
Element* oldScopeElement = nullptr;
if (mStyleSheet) {
if (mStyleSheet->IsServo()) {
NS_ERROR("stylo: ServoStyleSheets don't support <style scoped>");
NS_WARNING("stylo: ServoStyleSheets don't support <style scoped>");
} else {
oldScopeElement = mStyleSheet->AsGecko()->GetScopeElement();
}

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

@ -1083,14 +1083,15 @@ nsTreeSanitizer::SanitizeStyleSheet(const nsAString& aOriginal,
// -moz-binding is blacklisted.
bool didSanitize = false;
// Create a sheet to hold the parsed CSS
RefPtr<CSSStyleSheet> sheet = new CSSStyleSheet(CORS_NONE, aDocument->GetReferrerPolicy());
RefPtr<CSSStyleSheet> sheet =
new CSSStyleSheet(mozilla::css::eAuthorSheetFeatures,
CORS_NONE, aDocument->GetReferrerPolicy());
sheet->SetURIs(aDocument->GetDocumentURI(), nullptr, aBaseURI);
sheet->SetPrincipal(aDocument->NodePrincipal());
// Create the CSS parser, and parse the CSS text.
nsCSSParser parser(nullptr, sheet);
rv = parser.ParseSheet(aOriginal, aDocument->GetDocumentURI(), aBaseURI,
aDocument->NodePrincipal(), 0,
mozilla::css::eAuthorSheetFeatures);
aDocument->NodePrincipal(), 0);
NS_ENSURE_SUCCESS(rv, true);
// Mark the sheet as complete.
MOZ_ASSERT(!sheet->IsModified(),

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

@ -712,7 +712,6 @@ static JSObject*
CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> constructorProto,
const js::Class* constructorClass,
const JSNativeHolder* constructorNative,
unsigned ctorNargs, const NamedConstructor* namedConstructors,
JS::Handle<JSObject*> proto,
const NativeProperties* properties,
@ -720,35 +719,38 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
const char* name, bool defineOnGlobal)
{
JS::Rooted<JSObject*> constructor(cx);
if (constructorClass) {
MOZ_ASSERT(constructorProto);
constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
constructorProto);
} else {
MOZ_ASSERT(constructorNative);
MOZ_ASSERT(constructorProto == JS_GetFunctionPrototype(cx, global));
constructor = CreateConstructor(cx, global, name, constructorNative,
ctorNargs);
}
MOZ_ASSERT(constructorProto);
MOZ_ASSERT(constructorClass);
constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
constructorProto);
if (!constructor) {
return nullptr;
}
if (constructorClass) {
if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
JSPROP_READONLY)) {
return nullptr;
}
if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
JSPROP_READONLY)) {
return nullptr;
}
// Might as well intern, since we're going to need an atomized
// version of name anyway when we stick our constructor on the
// global.
JS::Rooted<JSString*> nameStr(cx, JS_AtomizeAndPinString(cx, name));
if (!nameStr) {
return nullptr;
}
// Might as well intern, since we're going to need an atomized
// version of name anyway when we stick our constructor on the
// global.
JS::Rooted<JSString*> nameStr(cx, JS_AtomizeAndPinString(cx, name));
if (!nameStr) {
return nullptr;
}
if (!JS_DefineProperty(cx, constructor, "name", nameStr, JSPROP_READONLY)) {
if (!JS_DefineProperty(cx, constructor, "name", nameStr, JSPROP_READONLY)) {
return nullptr;
}
if (DOMIfaceAndProtoJSClass::FromJSClass(constructorClass)->wantsInterfaceHasInstance) {
JS::Rooted<jsid> hasInstanceId(cx,
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)));
if (!JS_DefineFunctionById(cx, constructor, hasInstanceId,
InterfaceHasInstance, 1,
// Flags match those of Function[Symbol.hasInstance]
JSPROP_READONLY | JSPROP_PERMANENT)) {
return nullptr;
}
}
@ -829,12 +831,16 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
const js::Class* protoClass,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties,
const char* const* unscopableNames)
const char* const* unscopableNames,
bool isGlobal)
{
JS::Rooted<JSObject*> ourProto(cx,
JS_NewObjectWithUniqueType(cx, Jsvalify(protoClass), parentProto));
if (!ourProto ||
!DefineProperties(cx, ourProto, properties, chromeOnlyProperties)) {
// We don't try to define properties on the global's prototype; those
// properties go on the global itself.
(!isGlobal &&
!DefineProperties(cx, ourProto, properties, chromeOnlyProperties))) {
return nullptr;
}
@ -910,16 +916,17 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> protoProto,
const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
JS::Handle<JSObject*> constructorProto,
const js::Class* constructorClass, const JSNativeHolder* constructor,
const js::Class* constructorClass,
unsigned ctorNargs, const NamedConstructor* namedConstructors,
JS::Heap<JSObject*>* constructorCache,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties,
const char* name, bool defineOnGlobal,
const char* const* unscopableNames)
const char* const* unscopableNames,
bool isGlobal)
{
MOZ_ASSERT(protoClass || constructorClass || constructor,
"Need at least one class or a constructor!");
MOZ_ASSERT(protoClass || constructorClass,
"Need at least one class!");
MOZ_ASSERT(!((properties &&
(properties->HasMethods() || properties->HasAttributes())) ||
(chromeOnlyProperties &&
@ -932,18 +939,17 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
(chromeOnlyProperties &&
(chromeOnlyProperties->HasStaticMethods() ||
chromeOnlyProperties->HasStaticAttributes()))) ||
constructorClass || constructor,
"Static methods but no constructorClass or constructor!");
MOZ_ASSERT(bool(name) == bool(constructorClass || constructor),
constructorClass,
"Static methods but no constructorClass!");
MOZ_ASSERT(bool(name) == bool(constructorClass),
"Must have name precisely when we have an interface object");
MOZ_ASSERT(!constructorClass || !constructor);
MOZ_ASSERT(!protoClass == !protoCache,
"If, and only if, there is an interface prototype object we need "
"to cache it");
MOZ_ASSERT(!(constructorClass || constructor) == !constructorCache,
MOZ_ASSERT(bool(constructorClass) == bool(constructorCache),
"If, and only if, there is an interface object we need to cache "
"it");
MOZ_ASSERT(constructorProto || (!constructorClass && !constructor),
MOZ_ASSERT(constructorProto || !constructorClass,
"Must have a constructor proto if we plan to create a constructor "
"object");
@ -952,7 +958,7 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
proto =
CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
properties, chromeOnlyProperties,
unscopableNames);
unscopableNames, isGlobal);
if (!proto) {
return;
}
@ -964,11 +970,11 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
}
JSObject* interface;
if (constructorClass || constructor) {
if (constructorClass) {
interface = CreateInterfaceObject(cx, global, constructorProto,
constructorClass, constructor,
ctorNargs, namedConstructors, proto,
properties, chromeOnlyProperties, name,
constructorClass, ctorNargs,
namedConstructors, proto, properties,
chromeOnlyProperties, name,
defineOnGlobal);
if (!interface) {
if (protoCache) {
@ -1237,7 +1243,15 @@ static JSObject*
XrayCreateFunction(JSContext* cx, JS::Handle<JSObject*> wrapper,
JSNativeWrapper native, unsigned nargs, JS::Handle<jsid> id)
{
JSFunction* fun = js::NewFunctionByIdWithReserved(cx, native.op, nargs, 0, id);
JSFunction* fun;
if (JSID_IS_STRING(id)) {
fun = js::NewFunctionByIdWithReserved(cx, native.op, nargs, 0, id);
} else {
// Can't pass this id (probably a symbol) to NewFunctionByIdWithReserved;
// just use an empty name for lack of anything better.
fun = js::NewFunctionWithReserved(cx, native.op, nargs, 0, nullptr);
}
if (!fun) {
return nullptr;
}
@ -1656,6 +1670,26 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JSPROP_PERMANENT | JSPROP_READONLY,
desc, cacheOnHolder);
}
if (id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)) &&
DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj))->
wantsInterfaceHasInstance) {
cacheOnHolder = true;
JSNativeWrapper interfaceHasInstanceWrapper = { InterfaceHasInstance,
nullptr };
JSObject* funObj = XrayCreateFunction(cx, wrapper,
interfaceHasInstanceWrapper, 1, id);
if (!funObj) {
return false;
}
desc.value().setObject(*funObj);
desc.setAttributes(JSPROP_READONLY | JSPROP_PERMANENT);
desc.object().set(wrapper);
desc.setSetter(nullptr);
desc.setGetter(nullptr);
return true;
}
} else {
MOZ_ASSERT(IsInterfacePrototype(type));
@ -1880,7 +1914,7 @@ const js::ClassOps sBoringInterfaceObjectClassClassOps = {
nullptr, /* mayResolve */
nullptr, /* finalize */
ThrowingConstructor, /* call */
InterfaceHasInstance, /* hasInstance */
nullptr, /* hasInstance */
ThrowingConstructor, /* construct */
nullptr, /* trace */
};
@ -2220,24 +2254,69 @@ GlobalObject::GetAsSupports() const
return nullptr;
}
bool
InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
JS::Handle<JSObject*> instance,
bool* bp)
static bool
CallOrdinaryHasInstance(JSContext* cx, JS::CallArgs& args)
{
const DOMIfaceAndProtoJSClass* clasp =
DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
JS::Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
bool isInstance;
if (!JS::OrdinaryHasInstance(cx, thisObj, args.get(0), &isInstance)) {
return false;
}
args.rval().setBoolean(isInstance);
return true;
}
bool
InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
// If the thing we were passed is not an object, return false like
// OrdinaryHasInstance does.
if (!args.get(0).isObject()) {
args.rval().setBoolean(false);
return true;
}
// If "this" is not an object, likewise return false (again, like
// OrdinaryHasInstance).
if (!args.thisv().isObject()) {
args.rval().setBoolean(false);
return true;
}
// If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
// constructor, so just fall back to OrdinaryHasInstance. But note that we
// should CheckedUnwrap here, because otherwise we won't get the right
// answers.
JS::Rooted<JSObject*> thisObj(cx, js::CheckedUnwrap(&args.thisv().toObject()));
if (!thisObj) {
// Just fall back on the normal thing, in case it still happens to work.
return CallOrdinaryHasInstance(cx, args);
}
const js::Class* thisClass = js::GetObjectClass(thisObj);
if (!IsDOMIfaceAndProtoClass(thisClass)) {
return CallOrdinaryHasInstance(cx, args);
}
const DOMIfaceAndProtoJSClass* clasp =
DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
// If "this" isn't a DOM constructor or is a constructor for an interface
// without a prototype, just fall back to OrdinaryHasInstance.
if (clasp->mType != eInterface ||
clasp->mPrototypeID == prototypes::id::_ID_Count) {
return CallOrdinaryHasInstance(cx, args);
}
JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
const DOMJSClass* domClass =
GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count,
"Why do we have a hasInstance hook if we don't have a prototype "
"ID?");
if (domClass &&
domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
*bp = true;
args.rval().setBoolean(true);
return true;
}
@ -2247,49 +2326,11 @@ InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
clasp->mDepth, &boolp)) {
return false;
}
*bp = boolp;
args.rval().setBoolean(boolp);
return true;
}
JS::Rooted<JS::Value> protov(cx);
DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", &protov);
MOZ_ASSERT(ok, "Someone messed with our prototype property?");
JS::Rooted<JSObject*> interfacePrototype(cx, &protov.toObject());
MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)),
"Someone messed with our prototype property?");
JS::Rooted<JSObject*> proto(cx);
if (!JS_GetPrototype(cx, instance, &proto)) {
return false;
}
while (proto) {
if (proto == interfacePrototype) {
*bp = true;
return true;
}
if (!JS_GetPrototype(cx, proto, &proto)) {
return false;
}
}
*bp = false;
return true;
}
bool
InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
bool* bp)
{
if (!vp.isObject()) {
*bp = false;
return true;
}
JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject());
return InterfaceHasInstance(cx, obj, instanceObject, bp);
return CallOrdinaryHasInstance(cx, args);
}
bool

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

@ -599,6 +599,9 @@ struct NamedConstructor
* underlying global.
* unscopableNames if not null it points to a null-terminated list of const
* char* names of the unscopable properties for this interface.
* isGlobal if true, we're creating interface objects for a [Global] or
* [PrimaryGlobal] interface, and hence shouldn't define properties on
* the prototype object.
*
* At least one of protoClass, constructorClass or constructor should be
* non-null. If constructorClass or constructor are non-null, the resulting
@ -610,13 +613,14 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> protoProto,
const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
JS::Handle<JSObject*> interfaceProto,
const js::Class* constructorClass, const JSNativeHolder* constructor,
const js::Class* constructorClass,
unsigned ctorNargs, const NamedConstructor* namedConstructors,
JS::Heap<JSObject*>* constructorCache,
const NativeProperties* regularProperties,
const NativeProperties* chromeOnlyProperties,
const char* name, bool defineOnGlobal,
const char* const* unscopableNames);
const char* const* unscopableNames,
bool isGlobal);
/**
* Define the properties (regular and chrome-only) on obj.
@ -2673,17 +2677,11 @@ nsresult
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
/**
* Used to implement the hasInstance hook of an interface object.
*
* instance should not be a security wrapper.
* Used to implement the Symbol.hasInstance property of an interface object.
*/
bool
InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
JS::Handle<JSObject*> instance,
bool* bp);
bool
InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
bool* bp);
InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp);
bool
InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
JS::Handle<JSObject*> instance,

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

@ -602,6 +602,7 @@ class CGPrototypeJSClass(CGThing):
JS_NULL_OBJECT_OPS
},
${type},
false,
${prototypeID},
${depth},
${hooks},
@ -673,12 +674,10 @@ class CGInterfaceObjectJSClass(CGThing):
ctorname = "nullptr"
else:
ctorname = "ThrowingConstructor"
if NeedsGeneratedHasInstance(self.descriptor):
hasinstance = HASINSTANCE_HOOK_NAME
elif self.descriptor.interface.hasInterfacePrototypeObject():
hasinstance = "InterfaceHasInstance"
else:
hasinstance = "nullptr"
needsHasInstance = (
not NeedsGeneratedHasInstance(self.descriptor) and
self.descriptor.interface.hasInterfacePrototypeObject())
prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
slotCount = "DOM_INTERFACE_SLOTS_BASE"
if len(self.descriptor.interface.namedConstructors) > 0:
@ -687,10 +686,10 @@ class CGInterfaceObjectJSClass(CGThing):
(protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor,
forXrays=True)
if ctorname == "ThrowingConstructor" and hasinstance == "InterfaceHasInstance":
if ctorname == "ThrowingConstructor":
ret = ""
classOpsPtr = "&sBoringInterfaceObjectClassClassOps"
elif ctorname == "nullptr" and hasinstance == "nullptr":
elif ctorname == "nullptr":
ret = ""
classOpsPtr = "JS_NULL_CLASS_OPS"
else:
@ -706,14 +705,13 @@ class CGInterfaceObjectJSClass(CGThing):
nullptr, /* mayResolve */
nullptr, /* finalize */
${ctorname}, /* call */
${hasInstance}, /* hasInstance */
nullptr, /* hasInstance */
${ctorname}, /* construct */
nullptr, /* trace */
};
""",
ctorname=ctorname,
hasInstance=hasinstance)
ctorname=ctorname)
classOpsPtr = "&sInterfaceObjectClassOps"
if self.descriptor.interface.isNamespace():
@ -744,6 +742,7 @@ class CGInterfaceObjectJSClass(CGThing):
${objectOps}
},
eInterface,
${needsHasInstance},
${prototypeID},
${depth},
${hooks},
@ -753,11 +752,10 @@ class CGInterfaceObjectJSClass(CGThing):
""",
classString=classString,
slotCount=slotCount,
ctorname=ctorname,
hasInstance=hasinstance,
classOpsPtr=classOpsPtr,
hooks=NativePropertyHooks(self.descriptor),
objectOps=objectOps,
needsHasInstance=toStringBool(needsHasInstance),
prototypeID=prototypeID,
depth=depth,
toStringResult=toStringResult,
@ -1716,24 +1714,6 @@ class CGConstructNavigatorObject(CGAbstractMethod):
""") + genConstructorBody(self.descriptor)
class CGClassConstructHookHolder(CGGeneric):
def __init__(self, descriptor):
if descriptor.interface.ctor():
constructHook = CONSTRUCT_HOOK_NAME
else:
constructHook = "ThrowingConstructor"
CGGeneric.__init__(self, fill(
"""
static const JSNativeHolder ${CONSTRUCT_HOOK_NAME}_holder = {
${constructHook},
${hooks}
};
""",
CONSTRUCT_HOOK_NAME=CONSTRUCT_HOOK_NAME,
constructHook=constructHook,
hooks=NativePropertyHooks(descriptor)))
def NamedConstructorName(m):
return '_' + m.identifier.name
@ -1783,19 +1763,17 @@ class CGNamedConstructors(CGThing):
namedConstructors=namedConstructors)
class CGClassHasInstanceHook(CGAbstractStaticMethod):
class CGHasInstanceHook(CGAbstractStaticMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'obj'),
Argument('JS::MutableHandle<JS::Value>', 'vp'),
Argument('bool*', 'bp')]
Argument('unsigned', 'argc'),
Argument('JS::Value*', 'vp')]
assert descriptor.interface.hasInterfaceObject()
assert NeedsGeneratedHasInstance(descriptor)
CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
'bool', args)
def define(self):
if not NeedsGeneratedHasInstance(self.descriptor):
return ""
return CGAbstractStaticMethod.define(self)
def definition_body(self):
@ -1803,12 +1781,13 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
def generate_code(self):
header = dedent("""
if (!vp.isObject()) {
*bp = false;
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
if (!args.get(0).isObject()) {
args.rval().setBoolean(false);
return true;
}
JS::Rooted<JSObject*> instance(cx, &vp.toObject());
JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
""")
if self.descriptor.interface.hasInterfacePrototypeObject():
return (
@ -1819,8 +1798,8 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
static_assert(IsBaseOf<nsISupports, ${nativeType}>::value,
"HasInstance only works for nsISupports-based classes.");
bool ok = InterfaceHasInstance(cx, obj, instance, bp);
if (!ok || *bp) {
bool ok = InterfaceHasInstance(cx, argc, vp);
if (!ok || args.rval().toBoolean()) {
return ok;
}
@ -1829,7 +1808,7 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
nsCOMPtr<nsIDOM${name}> qiResult = do_QueryInterface(native);
*bp = !!qiResult;
args.rval().setBoolean(!!qiResult);
return true;
""",
nativeType=self.descriptor.nativeType,
@ -1838,16 +1817,16 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
hasInstanceCode = dedent("""
const DOMJSClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
*bp = false;
if (!domClass) {
// Not a DOM object, so certainly not an instance of this interface
args.rval().setBoolean(false);
return true;
}
""")
if self.descriptor.interface.identifier.name == "ChromeWindow":
setBp = "*bp = UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false))->IsChromeWindow()"
setRval = "args.rval().setBoolean(UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false))->IsChromeWindow())"
else:
setBp = "*bp = true"
setRval = "args.rval().setBoolean(true)"
# Sort interaces implementing self by name so we get stable output.
for iface in sorted(self.descriptor.interface.interfacesImplementingSelf,
key=lambda iface: iface.identifier.name):
@ -1855,13 +1834,14 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
"""
if (domClass->mInterfaceChain[PrototypeTraits<prototypes::id::${name}>::Depth] == prototypes::id::${name}) {
${setBp};
${setRval};
return true;
}
""",
name=iface.identifier.name,
setBp=setBp)
hasInstanceCode += "return true;\n"
setRval=setRval)
hasInstanceCode += ("args.rval().setBoolean(false);\n"
"return true;\n")
return header + hasInstanceCode
@ -2244,6 +2224,20 @@ class MethodDefiner(PropertyDefiner):
"condition": MemberCondition()
})
if (static and
not unforgeable and
descriptor.interface.hasInterfaceObject() and
NeedsGeneratedHasInstance(descriptor)):
self.regular.append({
"name": "@@hasInstance",
"methodInfo": False,
"nativeName": HASINSTANCE_HOOK_NAME,
"length": 1,
# Flags match those of Function[Symbol.hasInstance]
"flags": "JSPROP_READONLY | JSPROP_PERMANENT",
"condition": MemberCondition()
})
# Generate the keys/values/entries aliases for value iterables.
maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
if (not static and
@ -2792,11 +2786,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
else:
prefCache = None
if (needInterfaceObject and
self.descriptor.needsConstructHookHolder()):
constructHookHolder = "&" + CONSTRUCT_HOOK_NAME + "_holder"
else:
constructHookHolder = "nullptr"
if self.descriptor.interface.ctor():
constructArgs = methodLength(self.descriptor.interface.ctor())
else:
@ -2831,11 +2820,11 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
constructorProto = "nullptr"
isGlobal = self.descriptor.isGlobal() is not None
if not isGlobal and self.properties.hasNonChromeOnly():
if self.properties.hasNonChromeOnly():
properties = "sNativeProperties.Upcast()"
else:
properties = "nullptr"
if not isGlobal and self.properties.hasChromeOnly():
if self.properties.hasChromeOnly():
chromeProperties = "nsContentUtils::ThreadsafeIsCallerChrome() ? sChromeOnlyNativeProperties.Upcast() : nullptr"
else:
chromeProperties = "nullptr"
@ -2846,26 +2835,27 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
${protoClass}, protoCache,
${constructorProto}, ${interfaceClass}, ${constructHookHolder}, ${constructArgs}, ${namedConstructors},
${constructorProto}, ${interfaceClass}, ${constructArgs}, ${namedConstructors},
interfaceCache,
${properties},
${chromeProperties},
${name}, aDefineOnGlobal,
${unscopableNames});
${unscopableNames},
${isGlobal});
""",
protoClass=protoClass,
parentProto=parentProto,
protoCache=protoCache,
constructorProto=constructorProto,
interfaceClass=interfaceClass,
constructHookHolder=constructHookHolder,
constructArgs=constructArgs,
namedConstructors=namedConstructors,
interfaceCache=interfaceCache,
properties=properties,
chromeProperties=chromeProperties,
name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr",
unscopableNames="unscopableNames" if self.haveUnscopables else "nullptr")
unscopableNames="unscopableNames" if self.haveUnscopables else "nullptr",
isGlobal=toStringBool(isGlobal))
# If we fail after here, we must clear interface and prototype caches
# using this code: intermediate failure must not expose the interface in
@ -11976,6 +11966,12 @@ class CGDescriptor(CGThing):
for m in clearableCachedAttrs(descriptor):
cgThings.append(CGJSImplClearCachedValueMethod(descriptor, m))
# Need to output our generated hasinstance bits before
# PropertyArrays tries to use them.
if (descriptor.interface.hasInterfaceObject() and
NeedsGeneratedHasInstance(descriptor)):
cgThings.append(CGHasInstanceHook(descriptor))
properties = PropertyArrays(descriptor)
cgThings.append(CGGeneric(define=str(properties)))
cgThings.append(CGNativeProperties(descriptor, properties))
@ -11996,10 +11992,7 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasInterfaceObject():
cgThings.append(CGClassConstructor(descriptor,
descriptor.interface.ctor()))
cgThings.append(CGClassHasInstanceHook(descriptor))
cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
if descriptor.needsConstructHookHolder():
cgThings.append(CGClassConstructHookHolder(descriptor))
cgThings.append(CGNamedConstructors(descriptor))
cgThings.append(CGLegacyCallHook(descriptor))

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

@ -602,10 +602,6 @@ class Descriptor(DescriptorProvider):
def hasNonOrdinaryGetPrototypeOf(self):
return self.interface.getExtendedAttribute("NonOrdinaryGetPrototypeOf")
def needsConstructHookHolder(self):
assert self.interface.hasInterfaceObject()
return False
def needsHeaderInclude(self):
"""
An interface doesn't need a header file if it is not concrete, not

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

@ -386,9 +386,14 @@ struct DOMIfaceAndProtoJSClass
// Either eInterface, eInterfacePrototype, eGlobalInterfacePrototype or
// eNamedPropertiesObject.
DOMObjectType mType;
DOMObjectType mType; // uint8_t
const prototypes::ID mPrototypeID;
// Boolean indicating whether this object wants a @@hasInstance property
// pointing to InterfaceHasInstance defined on it. Only ever true for the
// eInterface case.
bool wantsInterfaceHasInstance;
const prototypes::ID mPrototypeID; // uint16_t
const uint32_t mDepth;
const NativePropertyHooks* mNativeHooks;

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

@ -1630,6 +1630,13 @@ WebGLContext::DummyReadFramebufferOperation(const char* funcName)
}
}
bool
WebGLContext::HasTimestampBits() const
{
// 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+.
return gl->IsSupported(GLFeature::sync);
}
static bool
CheckContextLost(GLContext* gl, bool* const out_isGuilty)
{

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

@ -1475,6 +1475,8 @@ protected:
bool mNeedsFakeNoStencil;
bool mNeedsEmulatedLoneDepthStencil;
bool HasTimestampBits() const;
struct ScopedMaskWorkaround {
WebGLContext& mWebGL;
const bool mFakeNoAlpha;

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

@ -267,7 +267,11 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
if (pname == LOCAL_GL_TIMESTAMP_EXT) {
GLuint64 iv = 0;
gl->fGetInteger64v(pname, (GLint64*) &iv);
if (HasTimestampBits()) {
gl->fGetInteger64v(pname, (GLint64*)&iv);
} else {
GenerateWarning("QUERY_COUNTER_BITS_EXT for TIMESTAMP_EXT is 0.");
}
// TODO: JS doesn't support 64-bit integers. Be lossy and
// cast to double (53 bits)
return JS::NumberValue(static_cast<double>(iv));

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

@ -20,6 +20,7 @@ WebGLExtensionDepthTexture::WebGLExtensionDepthTexture(WebGLContext* webgl)
GLenum unpackType)
{
auto usage = fua->EditUsage(effFormat);
usage->isFilterable = true;
usage->SetRenderable();
const webgl::PackingInfo pi = {unpackFormat, unpackType};

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

@ -177,7 +177,9 @@ WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target,
return;
}
GLint bits = 0;
mContext->GL()->fGetQueryiv(target, pname, &bits);
if (mContext->HasTimestampBits()) {
mContext->GL()->fGetQueryiv(target, pname, &bits);
}
retval.set(JS::Int32Value(int32_t(bits)));
break;
}
@ -242,11 +244,7 @@ WebGLExtensionDisjointTimerQuery::IsSupported(const WebGLContext* webgl)
gl::GLContext* gl = webgl->GL();
return gl->IsSupported(gl::GLFeature::query_objects) &&
gl->IsSupported(gl::GLFeature::get_query_object_i64v) &&
gl->IsSupported(gl::GLFeature::query_counter) && // provides GL_TIMESTAMP
gl->IsSupported(gl::GLFeature::sync); // provides glGetInteger64v
// 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+.
// Since there are no differences between support for glGetInteger64v and support for
// 'sync', we just piggy-back off of 'sync'.
gl->IsSupported(gl::GLFeature::query_counter); // provides GL_TIMESTAMP
}
void

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

@ -338,18 +338,7 @@ WebGLTexture::IsComplete(uint32_t texUnit, const char** const out_reason) const
auto formatUsage = baseImageInfo.mFormat;
auto format = formatUsage->format;
// "* The effective internal format specified for the texture arrays is a sized
// internal color format that is not texture-filterable, and either the
// magnification filter is not NEAREST or the minification filter is neither
// NEAREST nor NEAREST_MIPMAP_NEAREST."
// Since all (GLES3) unsized color formats are filterable just like their sized
// equivalents, we don't have to care whether its sized or not.
if (format->IsColorFormat() && !formatUsage->isFilterable) {
*out_reason = "Because minification or magnification filtering is not NEAREST"
" or NEAREST_MIPMAP_NEAREST, and the texture's format is a"
" color format, its format must be \"texture-filterable\".";
return false;
}
bool isFilterable = formatUsage->isFilterable;
// "* The effective internal format specified for the texture arrays is a sized
// internal depth or depth and stencil format, the value of
@ -360,16 +349,21 @@ WebGLTexture::IsComplete(uint32_t texUnit, const char** const out_reason) const
// 3.0.1:
// "* Clarify that a texture is incomplete if it has a depth component, no
// shadow comparison, and linear filtering (also Bug 9481)."
// As of OES_packed_depth_stencil rev #3, the sample code explicitly samples from
// a DEPTH_STENCIL_OES texture with a min-filter of LINEAR. Therefore we relax
// this restriction if WEBGL_depth_texture is enabled.
if (!mContext->IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
if (format->d && mTexCompareMode != LOCAL_GL_NONE) {
*out_reason = "A depth or depth-stencil format with TEXTURE_COMPARE_MODE"
" of NONE must have minification or magnification filtering"
" of NEAREST or NEAREST_MIPMAP_NEAREST.";
return false;
}
if (format->d && mTexCompareMode != LOCAL_GL_NONE) {
isFilterable = true;
}
// "* The effective internal format specified for the texture arrays is a sized
// internal color format that is not texture-filterable, and either the
// magnification filter is not NEAREST or the minification filter is neither
// NEAREST nor NEAREST_MIPMAP_NEAREST."
// Since all (GLES3) unsized color formats are filterable just like their sized
// equivalents, we don't have to care whether its sized or not.
if (!isFilterable) {
*out_reason = "Because minification or magnification filtering is not NEAREST"
" or NEAREST_MIPMAP_NEAREST, and the texture's format must be"
" \"texture-filterable\".";
return false;
}
}

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

@ -15,7 +15,7 @@ fail-if = (os == 'android')
[ensure-exts/test_EXT_color_buffer_half_float.html]
fail-if = (os == 'android')
[ensure-exts/test_EXT_disjoint_timer_query.html]
fail-if = (os == 'android') || (os == 'mac') || (os == 'win')
fail-if = (os == 'android') || (os == 'mac') || (os == 'win' && os_version == '5.1')
[ensure-exts/test_EXT_frag_depth.html]
fail-if = (os == 'android')
[ensure-exts/test_EXT_sRGB.html]
@ -84,6 +84,7 @@ skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[test_webgl_compressed_texture_es3.html]
[test_webgl_disjoint_timer_query.html]
fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2'))
[test_webgl_force_enable.html]
[test_webgl_request_context.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests

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

@ -797,6 +797,17 @@ HTMLMediaElement::MozDumpDebugInfo()
}
}
void
HTMLMediaElement::SetVisible(bool aVisible)
{
if (!mDecoder) {
return;
}
mDecoder->NotifyOwnerActivityChanged(aVisible);
}
already_AddRefed<DOMMediaStream>
HTMLMediaElement::GetSrcObject() const
{

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

@ -606,6 +606,8 @@ public:
void MozDumpDebugInfo();
void SetVisible(bool aVisible);
already_AddRefed<DOMMediaStream> GetSrcObject() const;
void SetSrcObject(DOMMediaStream& aValue);
void SetSrcObject(DOMMediaStream* aValue);

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

@ -2491,6 +2491,10 @@ BackgroundRequestChild::Recv__delete__(const RequestResponse& aResponse)
HandleResponse(aResponse.get_ObjectStoreGetResponse().cloneInfo());
break;
case RequestResponse::TObjectStoreGetKeyResponse:
HandleResponse(aResponse.get_ObjectStoreGetKeyResponse().key());
break;
case RequestResponse::TObjectStoreGetAllResponse:
HandleResponse(aResponse.get_ObjectStoreGetAllResponse().cloneInfos());
break;
@ -2643,8 +2647,7 @@ BackgroundCursorChild::AssertIsOnOwningThread() const
#endif // DEBUG
void
BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams,
const Key& aKey)
BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
@ -2661,66 +2664,7 @@ BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams,
mTransaction->OnNewRequest();
CursorRequestParams params = aParams;
Key key = aKey;
switch (params.type()) {
case CursorRequestParams::TContinueParams: {
if (key.IsUnset()) {
break;
}
while (!mCachedResponses.IsEmpty()) {
if (mCachedResponses[0].mKey == key) {
break;
}
mCachedResponses.RemoveElementAt(0);
}
break;
}
case CursorRequestParams::TAdvanceParams: {
uint32_t& advanceCount = params.get_AdvanceParams().count();
while (advanceCount > 1 && !mCachedResponses.IsEmpty()) {
key = mCachedResponses[0].mKey;
mCachedResponses.RemoveElementAt(0);
--advanceCount;
}
break;
}
default:
MOZ_CRASH("Should never get here!");
}
if (!mCachedResponses.IsEmpty()) {
nsCOMPtr<nsIRunnable> continueRunnable = new DelayedActionRunnable(
this, &BackgroundCursorChild::SendDelayedContinueInternal);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(continueRunnable));
} else {
MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(params, key));
}
}
void
BackgroundCursorChild::SendDelayedContinueInternal()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(mCursor);
MOZ_ASSERT(mStrongCursor);
MOZ_ASSERT(!mCachedResponses.IsEmpty());
RefPtr<IDBCursor> cursor;
mStrongCursor.swap(cursor);
auto& item = mCachedResponses[0];
mCursor->Reset(Move(item.mKey), Move(item.mCloneInfo));
mCachedResponses.RemoveElementAt(0);
ResultHelper helper(mRequest, mTransaction, mCursor);
DispatchSuccessEvent(&helper);
mTransaction->OnRequestFinished(/* aActorDestroyedNormally */ true);
MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(aParams));
}
void
@ -2743,14 +2687,6 @@ BackgroundCursorChild::SendDeleteMeInternal()
}
}
void
BackgroundCursorChild::InvalidateCachedResponses()
{
AssertIsOnOwningThread();
mCachedResponses.Clear();
}
void
BackgroundCursorChild::HandleResponse(nsresult aResponse)
{
@ -2816,14 +2752,7 @@ BackgroundCursorChild::HandleResponse(
RefPtr<IDBCursor> newCursor;
if (mCursor) {
if (mCursor->IsContinueCalled()) {
mCursor->Reset(Move(response.key()), Move(cloneReadInfo));
} else {
CachedResponse cachedResponse;
cachedResponse.mKey = Move(response.key());
cachedResponse.mCloneInfo = Move(cloneReadInfo);
mCachedResponses.AppendElement(Move(cachedResponse));
}
mCursor->Reset(Move(response.key()), Move(cloneReadInfo));
} else {
newCursor = IDBCursor::Create(this,
Move(response.key()),
@ -3046,16 +2975,6 @@ DelayedActionRunnable::Cancel()
return NS_OK;
}
BackgroundCursorChild::CachedResponse::CachedResponse()
{
}
BackgroundCursorChild::CachedResponse::CachedResponse(CachedResponse&& aOther)
: mKey(Move(aOther.mKey))
{
mCloneInfo = Move(aOther.mCloneInfo);
}
/*******************************************************************************
* BackgroundUtilsChild
******************************************************************************/

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

@ -688,17 +688,6 @@ class BackgroundCursorChild final
class DelayedActionRunnable;
struct CachedResponse
{
CachedResponse();
CachedResponse(CachedResponse&& aOther);
Key mKey;
Key mObjectKey;
StructuredCloneReadInfo mCloneInfo;
};
IDBRequest* mRequest;
IDBTransaction* mTransaction;
IDBObjectStore* mObjectStore;
@ -715,8 +704,6 @@ class BackgroundCursorChild final
PRThread* mOwningThread;
#endif
nsTArray<CachedResponse> mCachedResponses;
public:
BackgroundCursorChild(IDBRequest* aRequest,
IDBObjectStore* aObjectStore,
@ -735,14 +722,11 @@ public:
#endif
void
SendContinueInternal(const CursorRequestParams& aParams, const Key& aKey);
SendContinueInternal(const CursorRequestParams& aParams);
void
SendDeleteMeInternal();
void
InvalidateCachedResponses();
IDBRequest*
GetRequest() const
{
@ -780,9 +764,6 @@ private:
// BackgroundVersionChangeTransactionChild.
~BackgroundCursorChild();
void
SendDelayedContinueInternal();
void
HandleResponse(nsresult aResponse);
@ -810,7 +791,7 @@ private:
// Force callers to use SendContinueInternal.
bool
SendContinue(const CursorRequestParams& aParams, const Key& aKey) = delete;
SendContinue(const CursorRequestParams& aParams) = delete;
bool
SendDeleteMe() = delete;

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

@ -8185,23 +8185,24 @@ private:
GetResponse(RequestResponse& aResponse) override;
};
class ObjectStoreGetAllKeysRequestOp final
class ObjectStoreGetKeyRequestOp final
: public NormalTransactionOp
{
friend class TransactionBase;
const ObjectStoreGetAllKeysParams mParams;
const uint32_t mObjectStoreId;
const OptionalKeyRange mOptionalKeyRange;
const uint32_t mLimit;
const bool mGetAll;
FallibleTArray<Key> mResponse;
private:
// Only created by TransactionBase.
ObjectStoreGetAllKeysRequestOp(TransactionBase* aTransaction,
const ObjectStoreGetAllKeysParams& aParams)
: NormalTransactionOp(aTransaction)
, mParams(aParams)
{ }
ObjectStoreGetKeyRequestOp(TransactionBase* aTransaction,
const RequestParams& aParams,
bool aGetAll);
~ObjectStoreGetAllKeysRequestOp()
~ObjectStoreGetKeyRequestOp()
{ }
virtual nsresult
@ -8426,6 +8427,7 @@ private:
nsCString mContinueQuery;
nsCString mContinueToQuery;
nsCString mContinuePrimaryKeyQuery;
nsCString mLocale;
Key mKey;
@ -8483,7 +8485,7 @@ private:
RecvDeleteMe() override;
virtual bool
RecvContinue(const CursorRequestParams& aParams, const Key& key) override;
RecvContinue(const CursorRequestParams& aParams) override;
bool
IsLocaleAware() const {
@ -8578,16 +8580,13 @@ class Cursor::ContinueOp final
friend class Cursor;
const CursorRequestParams mParams;
const Key mKey;
private:
// Only created by Cursor.
ContinueOp(Cursor* aCursor,
const CursorRequestParams& aParams,
const Key& aKey)
const CursorRequestParams& aParams)
: CursorOpBase(aCursor)
, mParams(aParams)
, mKey(aKey)
{
MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
}
@ -14531,6 +14530,22 @@ TransactionBase::VerifyRequestParams(const RequestParams& aParams) const
break;
}
case RequestParams::TObjectStoreGetKeyParams: {
const ObjectStoreGetKeyParams& params =
aParams.get_ObjectStoreGetKeyParams();
const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return false;
}
if (NS_WARN_IF(!VerifyRequestParams(params.keyRange()))) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
}
case RequestParams::TObjectStoreGetAllParams: {
const ObjectStoreGetAllParams& params =
aParams.get_ObjectStoreGetAllParams();
@ -14993,10 +15008,14 @@ TransactionBase::AllocRequest(const RequestParams& aParams, bool aTrustParams)
new ObjectStoreGetRequestOp(this, aParams, /* aGetAll */ true);
break;
case RequestParams::TObjectStoreGetKeyParams:
actor =
new ObjectStoreGetKeyRequestOp(this, aParams, /* aGetAll */ false);
break;
case RequestParams::TObjectStoreGetAllKeysParams:
actor =
new ObjectStoreGetAllKeysRequestOp(this,
aParams.get_ObjectStoreGetAllKeysParams());
new ObjectStoreGetKeyRequestOp(this, aParams, /* aGetAll */ true);
break;
case RequestParams::TObjectStoreDeleteParams:
@ -16164,6 +16183,34 @@ Cursor::VerifyRequestParams(const CursorRequestParams& aParams) const
break;
}
case CursorRequestParams::TContinuePrimaryKeyParams: {
const Key& key = aParams.get_ContinuePrimaryKeyParams().key();
const Key& primaryKey = aParams.get_ContinuePrimaryKeyParams().primaryKey();
MOZ_ASSERT(!key.IsUnset());
MOZ_ASSERT(!primaryKey.IsUnset());
switch (mDirection) {
case IDBCursor::NEXT:
if (NS_WARN_IF(key < sortKey ||
(key == sortKey && primaryKey <= mObjectKey))) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
case IDBCursor::PREV:
if (NS_WARN_IF(key > sortKey ||
(key == sortKey && primaryKey >= mObjectKey))) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
default:
MOZ_CRASH("Should never get here!");
}
break;
}
case CursorRequestParams::TAdvanceParams:
if (NS_WARN_IF(!aParams.get_AdvanceParams().count())) {
ASSERT_UNLESS_FUZZING();
@ -16324,7 +16371,7 @@ Cursor::RecvDeleteMe()
}
bool
Cursor::RecvContinue(const CursorRequestParams& aParams, const Key& aKey)
Cursor::RecvContinue(const CursorRequestParams& aParams)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
@ -16358,7 +16405,7 @@ Cursor::RecvContinue(const CursorRequestParams& aParams, const Key& aKey)
return false;
}
RefPtr<ContinueOp> continueOp = new ContinueOp(this, aParams, aKey);
RefPtr<ContinueOp> continueOp = new ContinueOp(this, aParams);
if (NS_WARN_IF(!continueOp->Init(mTransaction))) {
continueOp->Cleanup();
return false;
@ -25866,31 +25913,54 @@ ObjectStoreGetRequestOp::GetResponse(RequestResponse& aResponse)
}
}
ObjectStoreGetKeyRequestOp::ObjectStoreGetKeyRequestOp(
TransactionBase* aTransaction,
const RequestParams& aParams,
bool aGetAll)
: NormalTransactionOp(aTransaction)
, mObjectStoreId(aGetAll ?
aParams.get_ObjectStoreGetAllKeysParams().objectStoreId() :
aParams.get_ObjectStoreGetKeyParams().objectStoreId())
, mOptionalKeyRange(aGetAll ?
aParams.get_ObjectStoreGetAllKeysParams()
.optionalKeyRange() :
OptionalKeyRange(aParams.get_ObjectStoreGetKeyParams()
.keyRange()))
, mLimit(aGetAll ? aParams.get_ObjectStoreGetAllKeysParams().limit() : 1)
, mGetAll(aGetAll)
{
MOZ_ASSERT(aParams.type() == RequestParams::TObjectStoreGetKeyParams ||
aParams.type() == RequestParams::TObjectStoreGetAllKeysParams);
MOZ_ASSERT(mObjectStoreId);
MOZ_ASSERT_IF(!aGetAll,
mOptionalKeyRange.type() ==
OptionalKeyRange::TSerializedKeyRange);
}
nsresult
ObjectStoreGetAllKeysRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
ObjectStoreGetKeyRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
{
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
PROFILER_LABEL("IndexedDB",
"ObjectStoreGetAllKeysRequestOp::DoDatabaseWork",
"ObjectStoreGetKeyRequestOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
const bool hasKeyRange =
mParams.optionalKeyRange().type() == OptionalKeyRange::TSerializedKeyRange;
mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
nsAutoCString keyRangeClause;
if (hasKeyRange) {
GetBindingClauseForKeyRange(
mParams.optionalKeyRange().get_SerializedKeyRange(),
NS_LITERAL_CSTRING("key"),
keyRangeClause);
GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
NS_LITERAL_CSTRING("key"),
keyRangeClause);
}
nsAutoCString limitClause;
if (uint32_t limit = mParams.limit()) {
if (mLimit) {
limitClause.AssignLiteral(" LIMIT ");
limitClause.AppendInt(limit);
limitClause.AppendInt(mLimit);
}
nsCString query =
@ -25907,16 +25977,14 @@ ObjectStoreGetAllKeysRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
mParams.objectStoreId());
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStoreId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (hasKeyRange) {
rv = BindKeyRangeToStatement(
mParams.optionalKeyRange().get_SerializedKeyRange(),
stmt);
rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
stmt);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -25939,18 +26007,32 @@ ObjectStoreGetAllKeysRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
MOZ_ASSERT_IF(!mGetAll, mResponse.Length() <= 1);
return NS_OK;
}
void
ObjectStoreGetAllKeysRequestOp::GetResponse(RequestResponse& aResponse)
ObjectStoreGetKeyRequestOp::GetResponse(RequestResponse& aResponse)
{
aResponse = ObjectStoreGetAllKeysResponse();
MOZ_ASSERT_IF(mLimit, mResponse.Length() <= mLimit);
if (mGetAll) {
aResponse = ObjectStoreGetAllKeysResponse();
if (!mResponse.IsEmpty()) {
nsTArray<Key>& response =
aResponse.get_ObjectStoreGetAllKeysResponse().keys();
mResponse.SwapElements(response);
}
return;
}
aResponse = ObjectStoreGetKeyResponse();
if (!mResponse.IsEmpty()) {
nsTArray<Key>& response =
aResponse.get_ObjectStoreGetAllKeysResponse().keys();
mResponse.SwapElements(response);
aResponse.get_ObjectStoreGetKeyResponse().key() = Move(mResponse[0]);
}
}
@ -27338,6 +27420,13 @@ OpenOp::DoIndexDatabaseWork(DatabaseConnection* aConnection)
NS_LITERAL_CSTRING(" AND sort_column >= :current_key") +
directionClause +
openLimit;
mCursor->mContinuePrimaryKeyQuery =
queryStart +
NS_LITERAL_CSTRING(" AND sort_column >= :current_key "
"AND index_table.object_data_key >= :object_key "
) +
directionClause +
openLimit;
break;
}
@ -27383,6 +27472,13 @@ OpenOp::DoIndexDatabaseWork(DatabaseConnection* aConnection)
NS_LITERAL_CSTRING(" AND sort_column <= :current_key") +
directionClause +
openLimit;
mCursor->mContinuePrimaryKeyQuery =
queryStart +
NS_LITERAL_CSTRING(" AND sort_column <= :current_key "
"AND index_table.object_data_key <= :object_key "
) +
directionClause +
openLimit;
break;
}
@ -27560,6 +27656,13 @@ OpenOp::DoIndexKeyDatabaseWork(DatabaseConnection* aConnection)
NS_LITERAL_CSTRING(" AND sort_column >= :current_key ") +
directionClause +
openLimit;
mCursor->mContinuePrimaryKeyQuery =
queryStart +
NS_LITERAL_CSTRING(" AND sort_column >= :current_key "
"AND object_data_key >= :object_key "
) +
directionClause +
openLimit;
break;
}
@ -27605,6 +27708,13 @@ OpenOp::DoIndexKeyDatabaseWork(DatabaseConnection* aConnection)
NS_LITERAL_CSTRING(" AND sort_column <= :current_key ") +
directionClause +
openLimit;
mCursor->mContinuePrimaryKeyQuery =
queryStart +
NS_LITERAL_CSTRING(" AND sort_column <= :current_key "
"AND object_data_key <= :object_key "
) +
directionClause +
openLimit;
break;
}
@ -27645,6 +27755,7 @@ OpenOp::DoDatabaseWork(DatabaseConnection* aConnection)
MOZ_ASSERT(mCursor);
MOZ_ASSERT(mCursor->mContinueQuery.IsEmpty());
MOZ_ASSERT(mCursor->mContinueToQuery.IsEmpty());
MOZ_ASSERT(mCursor->mContinuePrimaryKeyQuery.IsEmpty());
MOZ_ASSERT(mCursor->mKey.IsUnset());
MOZ_ASSERT(mCursor->mRangeKey.IsUnset());
@ -27727,6 +27838,10 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection)
mCursor->mType == OpenCursorParams::TIndexOpenCursorParams ||
mCursor->mType == OpenCursorParams::TIndexOpenKeyCursorParams;
MOZ_ASSERT_IF(isIndex &&
(mCursor->mDirection == IDBCursor::NEXT ||
mCursor->mDirection == IDBCursor::PREV),
!mCursor->mContinuePrimaryKeyQuery.IsEmpty());
MOZ_ASSERT_IF(isIndex, mCursor->mIndexId);
MOZ_ASSERT_IF(isIndex, !mCursor->mObjectKey.IsUnset());
@ -27744,21 +27859,35 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection)
// Note: Changing the number or order of SELECT columns in the query will
// require changes to CursorOpBase::PopulateResponseFromStatement.
bool hasContinueKey = false;
bool hasContinuePrimaryKey = false;
uint32_t advanceCount = 1;
Key& currentKey = mCursor->IsLocaleAware() ? mCursor->mSortKey : mCursor->mKey;
if (mParams.type() == CursorRequestParams::TContinueParams) {
// Always go to the next result.
if (mParams.get_ContinueParams().key().IsUnset()) {
hasContinueKey = false;
} else {
switch (mParams.type()) {
case CursorRequestParams::TContinueParams:
if (!mParams.get_ContinueParams().key().IsUnset()) {
hasContinueKey = true;
currentKey = mParams.get_ContinueParams().key();
}
break;
case CursorRequestParams::TContinuePrimaryKeyParams:
MOZ_ASSERT(!mParams.get_ContinuePrimaryKeyParams().key().IsUnset());
MOZ_ASSERT(!mParams.get_ContinuePrimaryKeyParams().primaryKey().IsUnset());
MOZ_ASSERT(mCursor->mDirection == IDBCursor::NEXT ||
mCursor->mDirection == IDBCursor::PREV);
hasContinueKey = true;
}
} else {
advanceCount = mParams.get_AdvanceParams().count();
hasContinueKey = false;
hasContinuePrimaryKey = true;
currentKey = mParams.get_ContinuePrimaryKeyParams().key();
break;
case CursorRequestParams::TAdvanceParams:
advanceCount = mParams.get_AdvanceParams().count();
break;
default:
MOZ_CRASH("Should never get here!");
}
const nsCString& continueQuery =
hasContinuePrimaryKey ? mCursor->mContinuePrimaryKeyQuery :
hasContinueKey ? mCursor->mContinueToQuery : mCursor->mContinueQuery;
MOZ_ASSERT(advanceCount > 0);
@ -27771,15 +27900,6 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection)
NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
const bool localeAware = mCursor->IsLocaleAware();
Key& currentKey = mCursor->mKey;
if (hasContinueKey) {
currentKey = mParams.get_ContinueParams().key();
} else if (localeAware) {
currentKey = mCursor->mSortKey;
}
const bool usingRangeKey = !mCursor->mRangeKey.IsUnset();
DatabaseConnection::CachedStatement stmt;
@ -27821,6 +27941,16 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection)
}
}
// Bind object key if primaryKey is specified.
if (hasContinuePrimaryKey) {
rv = mParams.get_ContinuePrimaryKeyParams().primaryKey()
.BindToStatement(stmt, objectKeyName);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
bool hasResult;
for (uint32_t index = 0; index < advanceCount; index++) {
rv = stmt->ExecuteStep(&hasResult);
@ -27843,23 +27973,6 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
uint32_t extraCount = 1;
for (uint32_t i = 0; i < extraCount; i++) {
rv = stmt->ExecuteStep(&hasResult);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!hasResult) {
break;
}
rv = PopulateResponseFromStatement(stmt, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}

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

@ -510,7 +510,117 @@ IDBCursor::Continue(JSContext* aCx,
IDB_LOG_STRINGIFY(key));
}
mBackgroundActor->SendContinueInternal(ContinueParams(key), mKey);
mBackgroundActor->SendContinueInternal(ContinueParams(key));
mContinueCalled = true;
}
void
IDBCursor::ContinuePrimaryKey(JSContext* aCx,
JS::Handle<JS::Value> aKey,
JS::Handle<JS::Value> aPrimaryKey,
ErrorResult &aRv)
{
AssertIsOnOwningThread();
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return;
}
if (IsSourceDeleted()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return;
}
if ((mType != Type_Index && mType != Type_IndexKey) ||
(mDirection != NEXT && mDirection != PREV)) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
}
if (!mHaveValue || mContinueCalled) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return;
}
Key key;
aRv = key.SetFromJSVal(aCx, aKey);
if (aRv.Failed()) {
return;
}
#ifdef ENABLE_INTL_API
if (IsLocaleAware() && !key.IsUnset()) {
Key tmp;
aRv = key.ToLocaleBasedKey(tmp, mSourceIndex->Locale());
if (aRv.Failed()) {
return;
}
key = tmp;
}
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
#else
const Key& sortKey = mKey;
#endif
if (key.IsUnset()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
}
Key primaryKey;
aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey);
if (aRv.Failed()) {
return;
}
if (primaryKey.IsUnset()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
}
switch (mDirection) {
case NEXT:
if (key < sortKey ||
(key == sortKey && primaryKey <= mPrimaryKey)) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
}
break;
case PREV:
if (key > sortKey ||
(key == sortKey && primaryKey >= mPrimaryKey)) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
}
break;
default:
MOZ_CRASH("Unknown direction type!");
}
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
mRequest->SetLoggingSerialNumber(requestSerialNumber);
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).continuePrimaryKey(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continuePrimaryKey()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
IDB_LOG_STRINGIFY(mSourceIndex),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(key),
IDB_LOG_STRINGIFY(primaryKey));
mBackgroundActor->SendContinueInternal(ContinuePrimaryKeyParams(key, primaryKey));
mContinueCalled = true;
}
@ -568,7 +678,7 @@ IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
aCount);
}
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), mKey);
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount));
mContinueCalled = true;
}
@ -603,8 +713,6 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
MOZ_ASSERT(!mKey.IsUnset());
MOZ_ASSERT_IF(mType == Type_Index, !mPrimaryKey.IsUnset());
mBackgroundActor->InvalidateCachedResponses();
IDBObjectStore* objectStore;
if (mType == Type_ObjectStore) {
objectStore = mSourceObjectStore;
@ -722,8 +830,6 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index);
MOZ_ASSERT(!mKey.IsUnset());
mBackgroundActor->InvalidateCachedResponses();
IDBObjectStore* objectStore;
if (mType == Type_ObjectStore) {
objectStore = mSourceObjectStore;

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

@ -135,8 +135,6 @@ public:
IDBCursorDirection
GetDirection() const;
bool IsContinueCalled() const { return mContinueCalled; }
void
GetKey(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult,
@ -155,6 +153,12 @@ public:
void
Continue(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
void
ContinuePrimaryKey(JSContext* aCx,
JS::Handle<JS::Value> aKey,
JS::Handle<JS::Value> aPrimaryKey,
ErrorResult& aRv);
void
Advance(uint32_t aCount, ErrorResult& aRv);

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

@ -1702,9 +1702,10 @@ IDBObjectStore::IndexNames()
}
already_AddRefed<IDBRequest>
IDBObjectStore::Get(JSContext* aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
IDBObjectStore::GetInternal(bool aKeyOnly,
JSContext* aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
{
AssertIsOnOwningThread();
@ -1730,9 +1731,17 @@ IDBObjectStore::Get(JSContext* aCx,
return nullptr;
}
ObjectStoreGetParams params;
params.objectStoreId() = Id();
keyRange->ToSerialized(params.keyRange());
const int64_t id = Id();
SerializedKeyRange serializedKeyRange;
keyRange->ToSerialized(serializedKeyRange);
RequestParams params;
if (aKeyOnly) {
params = ObjectStoreGetKeyParams(id, serializedKeyRange);
} else {
params = ObjectStoreGetParams(id, serializedKeyRange);
}
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
MOZ_ASSERT(request);

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

@ -203,7 +203,24 @@ public:
}
already_AddRefed<IDBRequest>
Get(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
Get(JSContext* aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
{
AssertIsOnOwningThread();
return GetInternal(/* aKeyOnly */ false, aCx, aKey, aRv);
}
already_AddRefed<IDBRequest>
GetKey(JSContext* aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
{
AssertIsOnOwningThread();
return GetInternal(/* aKeyOnly */ true, aCx, aKey, aRv);
}
already_AddRefed<IDBRequest>
Clear(JSContext* aCx, ErrorResult& aRv);
@ -333,6 +350,12 @@ private:
bool aFromCursor,
ErrorResult& aRv);
already_AddRefed<IDBRequest>
GetInternal(bool aKeyOnly,
JSContext* aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv);
already_AddRefed<IDBRequest>
GetAllInternal(bool aKeysOnly,
JSContext* aCx,

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

@ -26,6 +26,12 @@ struct ContinueParams
Key key;
};
struct ContinuePrimaryKeyParams
{
Key key;
Key primaryKey;
};
struct AdvanceParams
{
uint32_t count;
@ -34,6 +40,7 @@ struct AdvanceParams
union CursorRequestParams
{
ContinueParams;
ContinuePrimaryKeyParams;
AdvanceParams;
};
@ -80,7 +87,7 @@ protocol PBackgroundIDBCursor
parent:
async DeleteMe();
async Continue(CursorRequestParams params, Key key);
async Continue(CursorRequestParams params);
child:
async __delete__();

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

@ -36,6 +36,11 @@ struct ObjectStoreGetResponse
SerializedStructuredCloneReadInfo cloneInfo;
};
struct ObjectStoreGetKeyResponse
{
Key key;
};
struct ObjectStoreGetAllResponse
{
SerializedStructuredCloneReadInfo[] cloneInfos;
@ -86,6 +91,7 @@ union RequestResponse
{
nsresult;
ObjectStoreGetResponse;
ObjectStoreGetKeyResponse;
ObjectStoreAddResponse;
ObjectStorePutResponse;
ObjectStoreDeleteResponse;

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

@ -187,6 +187,12 @@ struct ObjectStoreGetParams
SerializedKeyRange keyRange;
};
struct ObjectStoreGetKeyParams
{
int64_t objectStoreId;
SerializedKeyRange keyRange;
};
struct ObjectStoreGetAllParams
{
int64_t objectStoreId;
@ -260,6 +266,7 @@ union RequestParams
ObjectStoreAddParams;
ObjectStorePutParams;
ObjectStoreGetParams;
ObjectStoreGetKeyParams;
ObjectStoreGetAllParams;
ObjectStoreGetAllKeysParams;
ObjectStoreDeleteParams;

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

@ -317,6 +317,11 @@ public:
return &mIsSuspended;
}
// Switch the video decoder to BlankDecoderModule. It might takes effective
// since a few samples later depends on how much demuxed samples are already
// queued in the original video decoder.
virtual void SetVideoBlankDecode(bool aIsBlankDecode) {}
protected:
virtual ~MediaDecoderReader();

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

@ -410,4 +410,14 @@ MediaDecoderReaderWrapper::OnMetadataRead(MetadataHolder* aMetadata)
}
}
void
MediaDecoderReaderWrapper::SetVideoBlankDecode(bool aIsBlankDecode)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
nsCOMPtr<nsIRunnable> r =
NewRunnableMethod<bool>(mReader, &MediaDecoderReader::SetVideoBlankDecode,
aIsBlankDecode);
mReader->OwnerThread()->Dispatch(r.forget());
}
} // namespace mozilla

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

@ -121,6 +121,8 @@ public:
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
#endif
void SetVideoBlankDecode(bool aIsBlankDecode);
private:
~MediaDecoderReaderWrapper();

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

@ -1353,6 +1353,7 @@ void MediaDecoderStateMachine::VisibilityChanged()
if (mVideoDecodeSuspended) {
mVideoDecodeSuspended = false;
mReader->SetVideoBlankDecode(false);
if (mIsReaderSuspended) {
return;
@ -2631,7 +2632,7 @@ bool MediaDecoderStateMachine::IsStateMachineScheduled() const
bool MediaDecoderStateMachine::IsVideoDecodeSuspended() const
{
MOZ_ASSERT(OnTaskQueue());
return mVideoDecodeSuspended || mIsReaderSuspended;
return mIsReaderSuspended;
}
void
@ -2923,6 +2924,7 @@ MediaDecoderStateMachine::OnSuspendTimerResolved()
DECODER_LOG("OnSuspendTimerResolved");
mVideoDecodeSuspendTimer.CompleteRequest();
mVideoDecodeSuspended = true;
mReader->SetVideoBlankDecode(true);
}
void

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

@ -418,7 +418,8 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
decoder.mInfo ? *decoder.mInfo->GetAsAudioInfo() : mInfo.mAudio,
decoder.mTaskQueue,
decoder.mCallback.get(),
mCrashHelper
mCrashHelper,
decoder.mIsBlankDecode
});
break;
}
@ -432,7 +433,8 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
decoder.mCallback.get(),
mLayersBackendType,
GetImageContainer(),
mCrashHelper
mCrashHelper,
decoder.mIsBlankDecode
});
break;
}
@ -2060,4 +2062,32 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString)
aString += NS_ConvertUTF8toUTF16(result);
}
void
MediaFormatReader::SetVideoBlankDecode(bool aIsBlankDecode)
{
MOZ_ASSERT(OnTaskQueue());
return SetBlankDecode(TrackType::kVideoTrack, aIsBlankDecode);
}
void
MediaFormatReader::SetBlankDecode(TrackType aTrack, bool aIsBlankDecode)
{
MOZ_ASSERT(OnTaskQueue());
auto& decoder = GetDecoderData(aTrack);
LOG("%s, decoder.mIsBlankDecode = %d => aIsBlankDecode = %d",
TrackTypeToStr(aTrack), decoder.mIsBlankDecode, aIsBlankDecode);
if (decoder.mIsBlankDecode == aIsBlankDecode) {
return;
}
decoder.mIsBlankDecode = aIsBlankDecode;
decoder.Flush();
decoder.ShutdownDecoder();
NotifyDecodingRequested(TrackInfo::kVideoTrack); // Calls ScheduleUpdate().
return;
}
} // namespace mozilla

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

@ -101,6 +101,8 @@ public:
// Used for debugging purposes.
void GetMozDebugReaderData(nsAString& aString);
void SetVideoBlankDecode(bool aIsBlankDecode) override;
private:
bool HasVideo() { return mVideo.mTrackDemuxer; }
@ -253,6 +255,7 @@ private:
, mSizeOfQueue(0)
, mIsHardwareAccelerated(false)
, mLastStreamSourceID(UINT32_MAX)
, mIsBlankDecode(false)
{}
MediaFormatReader* mOwner;
@ -427,6 +430,9 @@ private:
Maybe<media::TimeUnit> mLastTimeRangesEnd;
RefPtr<SharedTrackInfo> mInfo;
Maybe<media::TimeUnit> mFirstDemuxedSampleTime;
// Use BlankDecoderModule or not.
bool mIsBlankDecode;
};
class DecoderDataWithPromise : public DecoderData {
@ -571,6 +577,8 @@ private:
RefPtr<CDMProxy> mCDMProxy;
#endif
RefPtr<GMPCrashHelper> mCrashHelper;
void SetBlankDecode(TrackType aTrack, bool aIsBlankDecode);
};
} // namespace mozilla

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

@ -81,6 +81,7 @@ PDMFactory::PDMFactory()
{
EnsureInit();
CreatePDMs();
CreateBlankPDM();
}
PDMFactory::~PDMFactory()
@ -120,6 +121,11 @@ PDMFactory::EnsureInit() const
already_AddRefed<MediaDataDecoder>
PDMFactory::CreateDecoder(const CreateDecoderParams& aParams)
{
if (aParams.mUseBlankDecoder) {
MOZ_ASSERT(mBlankPDM);
return CreateDecoderWithPDM(mBlankPDM, aParams);
}
const TrackInfo& config = aParams.mConfig;
bool isEncrypted = mEMEPDM && config.mCrypto.mValid;
@ -287,6 +293,13 @@ PDMFactory::CreatePDMs()
}
}
void
PDMFactory::CreateBlankPDM()
{
mBlankPDM = CreateBlankDecoderModule();
MOZ_ASSERT(mBlankPDM && NS_SUCCEEDED(mBlankPDM->Startup()));
}
bool
PDMFactory::StartupPDM(PlatformDecoderModule* aPDM)
{

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

@ -47,6 +47,7 @@ public:
private:
virtual ~PDMFactory();
void CreatePDMs();
void CreateBlankPDM();
// Startup the provided PDM and add it to our list if successful.
bool StartupPDM(PlatformDecoderModule* aPDM);
// Returns the first PDM in our list supporting the mimetype.
@ -60,6 +61,7 @@ private:
nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs;
RefPtr<PlatformDecoderModule> mEMEPDM;
RefPtr<PlatformDecoderModule> mBlankPDM;
bool mWMFFailedToLoad = false;
bool mFFmpegFailedToLoad = false;

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

@ -64,6 +64,7 @@ struct CreateDecoderParams {
layers::ImageContainer* mImageContainer = nullptr;
layers::LayersBackend mLayersBackend = layers::LayersBackend::LAYERS_NONE;
RefPtr<GMPCrashHelper> mCrashHelper;
bool mUseBlankDecoder = false;
private:
void Set(TaskQueue* aTaskQueue) { mTaskQueue = aTaskQueue; }
@ -72,6 +73,7 @@ private:
void Set(layers::ImageContainer* aImageContainer) { mImageContainer = aImageContainer; }
void Set(layers::LayersBackend aLayersBackend) { mLayersBackend = aLayersBackend; }
void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
void Set(bool aUseBlankDecoder) { mUseBlankDecoder = aUseBlankDecoder; }
template <typename T1, typename T2, typename... Ts>
void Set(T1&& a1, T2&& a2, Ts&&... args)
{

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

@ -11,9 +11,12 @@
#include "mozilla/mozalloc.h" // for operator new, and new (fallible)
#include "mozilla/RefPtr.h"
#include "mozilla/TaskQueue.h"
#include "mp4_demuxer/H264.h"
#include "MP4Decoder.h"
#include "nsAutoPtr.h"
#include "nsRect.h"
#include "PlatformDecoderModule.h"
#include "ReorderQueue.h"
#include "TimeUnits.h"
#include "VideoUtils.h"
@ -29,6 +32,10 @@ public:
const CreateDecoderParams& aParams)
: mCreator(aCreator)
, mCallback(aParams.mCallback)
, mMaxRefFrames(aParams.mConfig.GetType() == TrackInfo::kVideoTrack &&
MP4Decoder::IsH264(aParams.mConfig.mMimeType)
? mp4_demuxer::H264::ComputeMaxRefFrames(aParams.VideoConfig().mExtraData)
: 0)
, mType(aParams.mConfig.GetType())
{
}
@ -47,19 +54,25 @@ public:
mCreator->Create(media::TimeUnit::FromMicroseconds(aSample->mTime),
media::TimeUnit::FromMicroseconds(aSample->mDuration),
aSample->mOffset);
if (!data) {
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
} else {
mCallback->Output(data);
OutputFrame(data);
return NS_OK;
}
nsresult Flush() override
{
mReorderQueue.Clear();
return NS_OK;
}
nsresult Drain() override
{
while (!mReorderQueue.IsEmpty()) {
mCallback->Output(mReorderQueue.Pop().get());
}
return NS_OK;
}
nsresult Flush() override {
return NS_OK;
}
nsresult Drain() override {
mCallback->DrainComplete();
return NS_OK;
}
@ -69,9 +82,32 @@ public:
return "blank media data decoder";
}
private:
void OutputFrame(MediaData* aData)
{
if (!aData) {
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
return;
}
// Frames come out in DTS order but we need to output them in PTS order.
mReorderQueue.Push(aData);
while (mReorderQueue.Length() > mMaxRefFrames) {
mCallback->Output(mReorderQueue.Pop().get());
}
if (mReorderQueue.Length() <= mMaxRefFrames) {
mCallback->InputExhausted();
}
}
private:
nsAutoPtr<BlankMediaDataCreator> mCreator;
MediaDataDecoderCallback* mCallback;
const uint32_t mMaxRefFrames;
ReorderQueue mReorderQueue;
TrackInfo::TrackType mType;
};
@ -93,10 +129,10 @@ public:
{
// Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
// with a U and V plane that are half the size of the Y plane, i.e 8 bit,
// 2x2 subsampled. Have the data pointers of each frame point to the
// first plane, they'll always be zero'd memory anyway.
auto frame = MakeUnique<uint8_t[]>(mFrameWidth * mFrameHeight);
memset(frame.get(), 0, mFrameWidth * mFrameHeight);
// 2x2 subsampled.
const int sizeY = mFrameWidth * mFrameHeight;
const int sizeCbCr = ((mFrameWidth + 1) / 2) * ((mFrameHeight + 1) / 2);
auto frame = MakeUnique<uint8_t[]>(sizeY + sizeCbCr);
VideoData::YCbCrBuffer buffer;
// Y plane.
@ -108,7 +144,7 @@ public:
buffer.mPlanes[0].mSkip = 0;
// Cb plane.
buffer.mPlanes[1].mData = frame.get();
buffer.mPlanes[1].mData = frame.get() + sizeY;
buffer.mPlanes[1].mStride = mFrameWidth / 2;
buffer.mPlanes[1].mHeight = mFrameHeight / 2;
buffer.mPlanes[1].mWidth = mFrameWidth / 2;
@ -116,13 +152,17 @@ public:
buffer.mPlanes[1].mSkip = 0;
// Cr plane.
buffer.mPlanes[2].mData = frame.get();
buffer.mPlanes[2].mData = frame.get() + sizeY;
buffer.mPlanes[2].mStride = mFrameWidth / 2;
buffer.mPlanes[2].mHeight = mFrameHeight / 2;
buffer.mPlanes[2].mWidth = mFrameWidth / 2;
buffer.mPlanes[2].mOffset = 0;
buffer.mPlanes[2].mSkip = 0;
// Set to color white.
memset(buffer.mPlanes[0].mData, 255, sizeY);
memset(buffer.mPlanes[1].mData, 128, sizeCbCr);
return VideoData::Create(mInfo,
mImageContainer,
nullptr,
@ -134,6 +174,7 @@ public:
aDTS.ToMicroseconds(),
mPicture);
}
private:
VideoInfo mInfo;
gfx::IntRect mPicture;
@ -142,7 +183,6 @@ private:
RefPtr<layers::ImageContainer> mImageContainer;
};
class BlankAudioDataCreator {
public:
BlankAudioDataCreator(uint32_t aChannelCount, uint32_t aSampleRate)
@ -229,7 +269,11 @@ public:
ConversionRequired
DecoderNeedsConversion(const TrackInfo& aConfig) const override
{
return kNeedNone;
if (aConfig.IsVideo() && MP4Decoder::IsH264(aConfig.mMimeType)) {
return kNeedAVCC;
} else {
return kNeedNone;
}
}
};

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

@ -11,9 +11,9 @@
#include "AppleUtils.h"
#include "AppleVTDecoder.h"
#include "AppleVTLinker.h"
#include "mp4_demuxer/H264.h"
#include "MediaData.h"
#include "mozilla/ArrayUtils.h"
#include "mp4_demuxer/H264.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "mozilla/Logging.h"
@ -24,22 +24,6 @@
namespace mozilla {
static uint32_t ComputeMaxRefFrames(const MediaByteBuffer* aExtraData)
{
uint32_t maxRefFrames = 4;
// Retrieve video dimensions from H264 SPS NAL.
mp4_demuxer::SPSData spsdata;
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata)) {
// max_num_ref_frames determines the size of the sliding window
// we need to queue that many frames in order to guarantee proper
// pts frames ordering. Use a minimum of 4 to ensure proper playback of
// non compliant videos.
maxRefFrames =
std::min(std::max(maxRefFrames, spsdata.max_num_ref_frames + 1), 16u);
}
return maxRefFrames;
}
AppleVTDecoder::AppleVTDecoder(const VideoInfo& aConfig,
TaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback,
@ -52,7 +36,7 @@ AppleVTDecoder::AppleVTDecoder(const VideoInfo& aConfig,
, mDisplayHeight(aConfig.mDisplay.height)
, mQueuedSamples(0)
, mTaskQueue(aTaskQueue)
, mMaxRefFrames(ComputeMaxRefFrames(aConfig.mExtraData))
, mMaxRefFrames(mp4_demuxer::H264::ComputeMaxRefFrames(aConfig.mExtraData))
, mImageContainer(aImageContainer)
, mInputIncoming(0)
, mIsShutDown(false)

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

@ -786,9 +786,12 @@ function AudioStreamHelper() {
AudioStreamHelper.prototype = {
checkAudio: function(stream, analyser, fun) {
/*
analyser.enableDebugCanvas();
return analyser.waitForAnalysisSuccess(fun)
.then(() => analyser.disableDebugCanvas());
*/
return analyser.waitForAnalysisSuccess(fun);
},
checkAudioFlowing: function(stream) {

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

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ControllerConnectionCollection.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsIPresentationService.h"
#include "PresentationConnection.h"
namespace mozilla {
namespace dom {
/* static */
StaticAutoPtr<ControllerConnectionCollection>
ControllerConnectionCollection::sSingleton;
/* static */ ControllerConnectionCollection*
ControllerConnectionCollection::GetSingleton()
{
MOZ_ASSERT(NS_IsMainThread());
if (!sSingleton) {
sSingleton = new ControllerConnectionCollection();
ClearOnShutdown(&sSingleton);
}
return sSingleton;
}
ControllerConnectionCollection::ControllerConnectionCollection()
{
MOZ_COUNT_CTOR(ControllerConnectionCollection);
}
ControllerConnectionCollection::~ControllerConnectionCollection()
{
MOZ_COUNT_DTOR(ControllerConnectionCollection);
}
void
ControllerConnectionCollection::AddConnection(
PresentationConnection* aConnection,
const uint8_t aRole)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
return;
}
if (!aConnection) {
return;
}
WeakPtr<PresentationConnection> connection = aConnection;
if (mConnections.Contains(connection)) {
return;
}
mConnections.AppendElement(connection);
}
void
ControllerConnectionCollection::RemoveConnection(
PresentationConnection* aConnection,
const uint8_t aRole)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
return;
}
if (!aConnection) {
return;
}
WeakPtr<PresentationConnection> connection = aConnection;
mConnections.RemoveElement(connection);
}
already_AddRefed<PresentationConnection>
ControllerConnectionCollection::FindConnection(
uint64_t aWindowId,
const nsAString& aId,
const uint8_t aRole)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
return nullptr;
}
// Loop backwards to allow removing elements in the loop.
for (int i = mConnections.Length() - 1; i >= 0; --i) {
WeakPtr<PresentationConnection> connection = mConnections[i];
if (!connection) {
// The connection was destroyed. Remove it from the list.
mConnections.RemoveElementAt(i);
continue;
}
if (connection->Equals(aWindowId, aId)) {
RefPtr<PresentationConnection> matchedConnection = connection.get();
return matchedConnection.forget();
}
}
return nullptr;
}
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_ControllerConnectionCollection_h
#define mozilla_dom_ControllerConnectionCollection_h
#include "mozilla/StaticPtr.h"
#include "mozilla/WeakPtr.h"
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class PresentationConnection;
class ControllerConnectionCollection final
{
public:
static ControllerConnectionCollection* GetSingleton();
void AddConnection(PresentationConnection* aConnection,
const uint8_t aRole);
void RemoveConnection(PresentationConnection* aConnection,
const uint8_t aRole);
already_AddRefed<PresentationConnection>
FindConnection(uint64_t aWindowId,
const nsAString& aId,
const uint8_t aRole);
private:
friend class StaticAutoPtr<ControllerConnectionCollection>;
ControllerConnectionCollection();
virtual ~ControllerConnectionCollection();
static StaticAutoPtr<ControllerConnectionCollection> sSingleton;
nsTArray<WeakPtr<PresentationConnection>> mConnections;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ControllerConnectionCollection_h

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

@ -13,6 +13,7 @@
#include "PresentationCallbacks.h"
#include "PresentationRequest.h"
#include "PresentationConnection.h"
#include "nsThreadUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -28,6 +29,7 @@ PresentationRequesterCallback::PresentationRequesterCallback(PresentationRequest
const nsAString& aSessionId,
Promise* aPromise)
: mRequest(aRequest)
, mUrl(aUrl)
, mSessionId(aSessionId)
, mPromise(aPromise)
{
@ -46,10 +48,8 @@ PresentationRequesterCallback::NotifySuccess()
{
MOZ_ASSERT(NS_IsMainThread());
// At the sender side, this function must get called after the transport
// channel is ready. So we simply set the connection state as connected.
RefPtr<PresentationConnection> connection =
PresentationConnection::Create(mRequest->GetOwner(), mSessionId,
PresentationConnection::Create(mRequest->GetOwner(), mSessionId, mUrl,
nsIPresentationService::ROLE_CONTROLLER);
if (NS_WARN_IF(!connection)) {
mPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
@ -74,6 +74,74 @@ PresentationRequesterCallback::NotifyError(nsresult aError)
* Implementation of PresentationRequesterCallback
*/
NS_IMPL_ISUPPORTS_INHERITED0(PresentationReconnectCallback,
PresentationRequesterCallback)
PresentationReconnectCallback::PresentationReconnectCallback(
PresentationRequest* aRequest,
const nsAString& aUrl,
const nsAString& aSessionId,
Promise* aPromise,
PresentationConnection* aConnection)
: PresentationRequesterCallback(aRequest, aUrl, aSessionId, aPromise)
, mConnection(aConnection)
{
}
PresentationReconnectCallback::~PresentationReconnectCallback()
{
}
NS_IMETHODIMP
PresentationReconnectCallback::NotifySuccess()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv = NS_OK;
// We found a matched connection with the same window ID, URL, and
// the session ID. Resolve the promise with this connection and dispatch
// the event.
if (mConnection) {
mPromise->MaybeResolve(mConnection);
rv = mRequest->DispatchConnectionAvailableEvent(mConnection);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
// Use |PresentationRequesterCallback::NotifySuccess| to create a new
// connection since we don't find one that can be reused.
rv = PresentationRequesterCallback::NotifySuccess();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = service->UpdateWindowIdBySessionId(mSessionId,
mRequest->GetOwner()->WindowID());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
nsString sessionId = nsString(mSessionId);
return NS_DispatchToMainThread(
NS_NewRunnableFunction([sessionId, service]() -> void {
service->BuildTransport(sessionId,
nsIPresentationService::ROLE_CONTROLLER);
}));
}
NS_IMETHODIMP
PresentationReconnectCallback::NotifyError(nsresult aError)
{
return PresentationRequesterCallback::NotifyError(aError);
}
NS_IMPL_ISUPPORTS(PresentationResponderLoadingCallback,
nsIWebProgressListener,
nsISupportsWeakReference)

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

@ -20,10 +20,11 @@ class nsIWebProgress;
namespace mozilla {
namespace dom {
class PresentationConnection;
class PresentationRequest;
class Promise;
class PresentationRequesterCallback final : public nsIPresentationServiceCallback
class PresentationRequesterCallback : public nsIPresentationServiceCallback
{
public:
NS_DECL_ISUPPORTS
@ -34,14 +35,33 @@ public:
const nsAString& aSessionId,
Promise* aPromise);
private:
~PresentationRequesterCallback();
protected:
virtual ~PresentationRequesterCallback();
RefPtr<PresentationRequest> mRequest;
nsString mUrl;
nsString mSessionId;
RefPtr<Promise> mPromise;
};
class PresentationReconnectCallback final : public PresentationRequesterCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIPRESENTATIONSERVICECALLBACK
PresentationReconnectCallback(PresentationRequest* aRequest,
const nsAString& aUrl,
const nsAString& aSessionId,
Promise* aPromise,
PresentationConnection* aConnection);
private:
virtual ~PresentationReconnectCallback();
RefPtr<PresentationConnection> mConnection;
};
class PresentationResponderLoadingCallback final : public nsIWebProgressListener
, public nsSupportsWeakReference
{

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

@ -6,6 +6,7 @@
#include "PresentationConnection.h"
#include "ControllerConnectionCollection.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/MessageEvent.h"
@ -43,10 +44,12 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
const nsAString& aId,
const nsAString& aUrl,
const uint8_t aRole,
PresentationConnectionList* aList)
: DOMEventTargetHelper(aWindow)
, mId(aId)
, mUrl(aUrl)
, mState(PresentationConnectionState::Connecting)
, mOwningConnectionList(aList)
{
@ -62,14 +65,24 @@ PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
/* static */ already_AddRefed<PresentationConnection>
PresentationConnection::Create(nsPIDOMWindowInner* aWindow,
const nsAString& aId,
const nsAString& aUrl,
const uint8_t aRole,
PresentationConnectionList* aList)
{
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
aRole == nsIPresentationService::ROLE_RECEIVER);
RefPtr<PresentationConnection> connection =
new PresentationConnection(aWindow, aId, aRole, aList);
return NS_WARN_IF(!connection->Init()) ? nullptr : connection.forget();
new PresentationConnection(aWindow, aId, aUrl, aRole, aList);
if (NS_WARN_IF(!connection->Init())) {
return nullptr;
}
if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
ControllerConnectionCollection::GetSingleton()->AddConnection(connection,
aRole);
}
return connection.forget();
}
bool
@ -112,6 +125,11 @@ PresentationConnection::Shutdown()
rv = RemoveFromLoadGroup();
NS_WARN_IF(NS_FAILED(rv));
if (mRole == nsIPresentationService::ROLE_CONTROLLER) {
ControllerConnectionCollection::GetSingleton()->RemoveConnection(this,
mRole);
}
}
/* virtual */ void
@ -134,6 +152,12 @@ PresentationConnection::GetId(nsAString& aId) const
aId = mId;
}
void
PresentationConnection::GetUrl(nsAString& aUrl) const
{
aUrl = mUrl;
}
PresentationConnectionState
PresentationConnection::State() const
{
@ -203,6 +227,15 @@ PresentationConnection::Terminate(ErrorResult& aRv)
NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole)));
}
bool
PresentationConnection::Equals(uint64_t aWindowId,
const nsAString& aId)
{
return GetOwner() &&
aWindowId == GetOwner()->WindowID() &&
mId.Equals(aId);
}
NS_IMETHODIMP
PresentationConnection::NotifyStateChange(const nsAString& aSessionId,
uint16_t aState,
@ -252,6 +285,8 @@ nsresult
PresentationConnection::ProcessStateChanged(nsresult aReason)
{
switch (mState) {
case PresentationConnectionState::Connecting:
return NS_OK;
case PresentationConnectionState::Connected: {
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, NS_LITERAL_STRING("connect"), false);
@ -333,6 +368,14 @@ PresentationConnection::NotifyMessage(const nsAString& aSessionId,
return DispatchMessageEvent(jsData);
}
NS_IMETHODIMP
PresentationConnection::NotifyReplaced()
{
return NotifyStateChange(mId,
nsIPresentationSessionListener::STATE_CLOSED,
NS_OK);
}
nsresult
PresentationConnection::DispatchConnectionClosedEvent(
PresentationConnectionClosedReason aReason,

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

@ -8,6 +8,7 @@
#define mozilla_dom_PresentationConnection_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/PresentationConnectionBinding.h"
#include "mozilla/dom/PresentationConnectionClosedEventBinding.h"
#include "nsIPresentationListener.h"
@ -22,6 +23,7 @@ class PresentationConnectionList;
class PresentationConnection final : public DOMEventTargetHelper
, public nsIPresentationSessionListener
, public nsIRequest
, public SupportsWeakPtr<PresentationConnection>
{
public:
NS_DECL_ISUPPORTS_INHERITED
@ -29,10 +31,12 @@ public:
DOMEventTargetHelper)
NS_DECL_NSIPRESENTATIONSESSIONLISTENER
NS_DECL_NSIREQUEST
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PresentationConnection)
static already_AddRefed<PresentationConnection>
Create(nsPIDOMWindowInner* aWindow,
const nsAString& aId,
const nsAString& aUrl,
const uint8_t aRole,
PresentationConnectionList* aList = nullptr);
@ -44,6 +48,8 @@ public:
// WebIDL (public APIs)
void GetId(nsAString& aId) const;
void GetUrl(nsAString& aUrl) const;
PresentationConnectionState State() const;
void Send(const nsAString& aData,
@ -53,6 +59,9 @@ public:
void Terminate(ErrorResult& aRv);
bool
Equals(uint64_t aWindowId, const nsAString& aId);
IMPL_EVENT_HANDLER(connect);
IMPL_EVENT_HANDLER(close);
IMPL_EVENT_HANDLER(terminate);
@ -61,6 +70,7 @@ public:
private:
PresentationConnection(nsPIDOMWindowInner* aWindow,
const nsAString& aId,
const nsAString& aUrl,
const uint8_t aRole,
PresentationConnectionList* aList);
@ -84,6 +94,7 @@ private:
nsresult RemoveFromLoadGroup();
nsString mId;
nsString mUrl;
uint8_t mRole;
PresentationConnectionState mState;
RefPtr<PresentationConnectionList> mOwningConnectionList;

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

@ -262,6 +262,27 @@ PresentationDeviceManager::OnTerminateRequest(nsIPresentationDevice* aDevice,
return NS_OK;
}
NS_IMETHODIMP
PresentationDeviceManager::OnReconnectRequest(nsIPresentationDevice* aDevice,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel)
{
NS_ENSURE_ARG(aDevice);
NS_ENSURE_ARG(aControlChannel);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
RefPtr<PresentationSessionRequest> request =
new PresentationSessionRequest(aDevice, aUrl, aPresentationId, aControlChannel);
obs->NotifyObservers(request,
PRESENTATION_RECONNECT_REQUEST_TOPIC,
nullptr);
return NS_OK;
}
// nsIObserver
NS_IMETHODIMP
PresentationDeviceManager::Observe(nsISupports *aSubject,

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

@ -8,6 +8,7 @@
#include "mozilla/dom/PresentationReceiverBinding.h"
#include "mozilla/dom/Promise.h"
#include "nsContentUtils.h"
#include "nsIPresentationService.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
@ -56,7 +57,11 @@ PresentationReceiver::Init()
}
mWindowId = mOwner->WindowID();
return true;
nsCOMPtr<nsIDocShell> docShell = mOwner->GetDocShell();
MOZ_ASSERT(docShell);
nsContentUtils::GetPresentationURL(docShell, mUrl);
return !mUrl.IsEmpty();
}
void PresentationReceiver::Shutdown()
@ -96,7 +101,7 @@ PresentationReceiver::NotifySessionConnect(uint64_t aWindowId,
}
RefPtr<PresentationConnection> connection =
PresentationConnection::Create(mOwner, aSessionId,
PresentationConnection::Create(mOwner, aSessionId, mUrl,
nsIPresentationService::ROLE_RECEIVER,
mConnectionList);
if (NS_WARN_IF(!connection)) {

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

@ -54,6 +54,7 @@ private:
uint64_t mWindowId;
nsCOMPtr<nsPIDOMWindowInner> mOwner;
nsString mUrl;
RefPtr<Promise> mGetConnectionListPromise;
RefPtr<PresentationConnectionList> mConnectionList;
};

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

@ -6,6 +6,7 @@
#include "PresentationRequest.h"
#include "ControllerConnectionCollection.h"
#include "mozilla/dom/PresentationRequestBinding.h"
#include "mozilla/dom/PresentationConnectionAvailableEvent.h"
#include "mozilla/dom/Promise.h"
@ -152,6 +153,118 @@ PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
return promise.forget();
}
already_AddRefed<Promise>
PresentationRequest::Reconnect(const nsAString& aPresentationId,
ErrorResult& aRv)
{
// TODO: Before starting to reconnect, we have to run the prohibits
// mixed security contexts algorithm first. This will be implemented
// in bug 1254488.
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (NS_WARN_IF(!global)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();
}
nsString presentationId = nsString(aPresentationId);
nsCOMPtr<nsIRunnable> r =
NewRunnableMethod<nsString, RefPtr<Promise>>(
this,
&PresentationRequest::FindOrCreatePresentationConnection,
presentationId,
promise);
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)))) {
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
}
return promise.forget();
}
void
PresentationRequest::FindOrCreatePresentationConnection(
const nsAString& aPresentationId,
Promise* aPromise)
{
MOZ_ASSERT(aPromise);
if (NS_WARN_IF(!GetOwner())) {
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
return;
}
RefPtr<PresentationConnection> connection =
ControllerConnectionCollection::GetSingleton()->FindConnection(
GetOwner()->WindowID(),
aPresentationId,
nsIPresentationService::ROLE_CONTROLLER);
if (connection) {
nsAutoString url;
connection->GetUrl(url);
if (url.Equals(mUrl)) {
switch (connection->State()) {
case PresentationConnectionState::Closed:
// We found the matched connection.
break;
case PresentationConnectionState::Connecting:
case PresentationConnectionState::Connected:
aPromise->MaybeResolve(connection);
return;
case PresentationConnectionState::Terminated:
// A terminated connection cannot be reused.
connection = nullptr;
break;
default:
MOZ_CRASH("Unknown presentation session state.");
return;
}
} else {
connection = nullptr;
}
}
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if(NS_WARN_IF(!service)) {
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
return;
}
nsCOMPtr<nsIPresentationServiceCallback> callback =
new PresentationReconnectCallback(this,
mUrl,
aPresentationId,
aPromise,
connection);
nsresult rv =
service->ReconnectSession(mUrl,
aPresentationId,
nsIPresentationService::ROLE_CONTROLLER,
callback);
if (NS_WARN_IF(NS_FAILED(rv))) {
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
}
}
already_AddRefed<Promise>
PresentationRequest::GetAvailability(ErrorResult& aRv)
{

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

@ -36,6 +36,9 @@ public:
already_AddRefed<Promise> StartWithDevice(const nsAString& aDeviceId,
ErrorResult& aRv);
already_AddRefed<Promise> Reconnect(const nsAString& aPresentationId,
ErrorResult& aRv);
already_AddRefed<Promise> GetAvailability(ErrorResult& aRv);
IMPL_EVENT_HANDLER(connectionavailable);
@ -50,6 +53,9 @@ private:
bool Init();
void FindOrCreatePresentationConnection(const nsAString& aPresentationId,
Promise* aPromise);
nsString mUrl;
RefPtr<PresentationAvailability> mAvailability;
};

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

@ -223,6 +223,10 @@ PresentationService::Init()
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
rv = obs->AddObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
@ -258,6 +262,13 @@ PresentationService::Observe(nsISupports* aSubject,
}
return HandleTerminateRequest(request);
} else if (!strcmp(aTopic, PRESENTATION_RECONNECT_REQUEST_TOPIC)) {
nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject));
if (NS_WARN_IF(!request)) {
return NS_ERROR_FAILURE;
}
return HandleReconnectRequest(request);
} else if (!strcmp(aTopic, "profile-after-change")) {
// It's expected since we add and entry to |kLayoutCategories| in
// |nsLayoutModule.cpp| to launch this service earlier.
@ -285,6 +296,7 @@ PresentationService::HandleShutdown()
obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC);
obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC);
obs->RemoveObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC);
obs->RemoveObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC);
}
}
@ -366,12 +378,18 @@ PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aReques
// Create or reuse session info.
RefPtr<PresentationSessionInfo> info =
GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
if (NS_WARN_IF(info)) {
// TODO Bug 1195605. Update here after session join/resume becomes supported.
ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
return NS_ERROR_DOM_ABORT_ERR;
// This is the case for reconnecting a session.
// Update the control channel and device of the session info.
// Call |NotifyResponderReady| to indicate the receiver page is already there.
if (info) {
info->SetControlChannel(ctrlChannel);
info->SetDevice(device);
return static_cast<PresentationPresentingInfo*>(
info.get())->NotifyResponderReady();
}
// This is the case for a new session.
info = new PresentationPresentingInfo(url, sessionId, device);
rv = info->Init(ctrlChannel);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -452,6 +470,53 @@ PresentationService::HandleTerminateRequest(nsIPresentationTerminateRequest* aRe
return info->OnTerminate(ctrlChannel);
}
nsresult
PresentationService::HandleReconnectRequest(nsIPresentationSessionRequest* aRequest)
{
nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
return rv;
}
nsAutoString sessionId;
rv = aRequest->GetPresentationId(sessionId);
if (NS_WARN_IF(NS_FAILED(rv))) {
ctrlChannel->Disconnect(rv);
return rv;
}
uint64_t windowId;
rv = GetWindowIdBySessionIdInternal(sessionId, &windowId);
if (NS_WARN_IF(NS_FAILED(rv))) {
ctrlChannel->Disconnect(rv);
return rv;
}
RefPtr<PresentationSessionInfo> info =
GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
if (NS_WARN_IF(!info)) {
// Cannot reconnect non-existed session
ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
return NS_ERROR_DOM_ABORT_ERR;
}
nsAutoString url;
rv = aRequest->GetUrl(url);
if (NS_WARN_IF(NS_FAILED(rv))) {
ctrlChannel->Disconnect(rv);
return rv;
}
// Make sure the url is the same as the previous one.
if (NS_WARN_IF(!info->GetUrl().Equals(url))) {
ctrlChannel->Disconnect(rv);
return rv;
}
return HandleSessionRequest(aRequest);
}
void
PresentationService::NotifyAvailableChange(bool aIsAvailable)
{
@ -642,6 +707,57 @@ PresentationService::TerminateSession(const nsAString& aSessionId,
return info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED);
}
NS_IMETHODIMP
PresentationService::ReconnectSession(const nsAString& aUrl,
const nsAString& aSessionId,
uint8_t aRole,
nsIPresentationServiceCallback* aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aSessionId.IsEmpty());
MOZ_ASSERT(aCallback);
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
return NS_ERROR_INVALID_ARG;
}
if (NS_WARN_IF(!aCallback)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
if (NS_WARN_IF(!info)) {
return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
}
if (NS_WARN_IF(!info->GetUrl().Equals(aUrl))) {
return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
}
return static_cast<PresentationControllingInfo*>(info.get())->Reconnect(aCallback);
}
NS_IMETHODIMP
PresentationService::BuildTransport(const nsAString& aSessionId,
uint8_t aRole)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aSessionId.IsEmpty());
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "Only controller can call BuildTransport.");
return NS_ERROR_INVALID_ARG;
}
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
if (NS_WARN_IF(!info)) {
return NS_ERROR_NOT_AVAILABLE;
}
return static_cast<PresentationControllingInfo*>(info.get())->BuildTransport();
}
NS_IMETHODIMP
PresentationService::RegisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
{
@ -848,6 +964,13 @@ PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId,
return GetWindowIdBySessionIdInternal(aSessionId, aWindowId);
}
NS_IMETHODIMP
PresentationService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
const uint64_t aWindowId)
{
return UpdateWindowIdBySessionIdInternal(aSessionId, aWindowId);
}
bool
PresentationService::IsSessionAccessible(const nsAString& aSessionId,
const uint8_t aRole,

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

@ -68,6 +68,7 @@ private:
nsresult HandleDeviceChange();
nsresult HandleSessionRequest(nsIPresentationSessionRequest* aRequest);
nsresult HandleTerminateRequest(nsIPresentationTerminateRequest* aRequest);
nsresult HandleReconnectRequest(nsIPresentationSessionRequest* aRequest);
void NotifyAvailableChange(bool aIsAvailable);
bool IsAppInstalled(nsIURI* aUri);

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

@ -36,6 +36,8 @@ PresentationServiceBase::GetWindowIdBySessionIdInternal(
const nsAString& aSessionId,
uint64_t* aWindowId)
{
MOZ_ASSERT(NS_IsMainThread());
if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
return NS_OK;
}
@ -46,6 +48,8 @@ void
PresentationServiceBase::AddRespondingSessionId(uint64_t aWindowId,
const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(aWindowId == 0)) {
return;
}
@ -63,6 +67,8 @@ PresentationServiceBase::AddRespondingSessionId(uint64_t aWindowId,
void
PresentationServiceBase::RemoveRespondingSessionId(const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
uint64_t windowId = 0;
if (mRespondingWindowIds.Get(aSessionId, &windowId)) {
mRespondingWindowIds.Remove(aSessionId);
@ -76,5 +82,17 @@ PresentationServiceBase::RemoveRespondingSessionId(const nsAString& aSessionId)
}
}
nsresult
PresentationServiceBase::UpdateWindowIdBySessionIdInternal(
const nsAString& aSessionId,
const uint64_t aWindowId)
{
MOZ_ASSERT(NS_IsMainThread());
RemoveRespondingSessionId(aSessionId);
AddRespondingSessionId(aWindowId, aSessionId);
return NS_OK;
}
} // namespace dom
} // namespace mozilla

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

@ -37,6 +37,8 @@ protected:
nsresult GetWindowIdBySessionIdInternal(const nsAString& aSessionId, uint64_t* aWindowId);
void AddRespondingSessionId(uint64_t aWindowId, const nsAString& aSessionId);
void RemoveRespondingSessionId(const nsAString& aSessionId);
nsresult UpdateWindowIdBySessionIdInternal(const nsAString& aSessionId,
const uint64_t aWindowId);
// Store the responding listener based on the window ID of the (in-process or
// OOP) receiver page.

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

@ -244,6 +244,10 @@ PresentationSessionInfo::Shutdown(nsresult aReason)
nsresult
PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener)
{
if (mListener && aListener) {
NS_WARN_IF(NS_FAILED(mListener->NotifyReplaced()));
}
mListener = aListener;
if (mListener) {
@ -425,7 +429,8 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
// potential subsequent |Shutdown| calls.
mTransport = nullptr;
if (NS_WARN_IF(!IsSessionReady())) {
if (NS_WARN_IF(!IsSessionReady() &&
mState == nsIPresentationSessionListener::STATE_CONNECTING)) {
// It happens before the session is ready. Reply the callback.
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
}
@ -744,6 +749,10 @@ PresentationControllingInfo::NotifyConnected()
switch (mState) {
case nsIPresentationSessionListener::STATE_CONNECTING: {
nsresult rv = mControlChannel->Launch(GetSessionId(), GetUrl());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Unused << NS_WARN_IF(NS_FAILED(BuildTransport()));
break;
}
@ -758,14 +767,27 @@ PresentationControllingInfo::NotifyConnected()
return NS_OK;
}
NS_IMETHODIMP
PresentationControllingInfo::NotifyReconnected()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mReconnectCallback);
if (NS_WARN_IF(mState == nsIPresentationSessionListener::STATE_TERMINATED)) {
return NS_ERROR_FAILURE;
}
SetStateWithReason(nsIPresentationSessionListener::STATE_CONNECTING, NS_OK);
return mReconnectCallback->NotifySuccess();
}
nsresult
PresentationControllingInfo::BuildTransport()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult rv = mControlChannel->Launch(GetSessionId(), GetUrl());
if (NS_FAILED(rv)) {
return rv;
if (mState != nsIPresentationSessionListener::STATE_CONNECTING) {
return NS_OK;
}
if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
@ -807,7 +829,7 @@ PresentationControllingInfo::BuildTransport()
if (NS_WARN_IF(!dataChannelBuilder)) {
return NS_ERROR_NOT_AVAILABLE;
}
rv = dataChannelBuilder->
nsresult rv = dataChannelBuilder->
BuildDataChannelTransport(nsIPresentationService::ROLE_CONTROLLER,
window,
this);
@ -893,6 +915,41 @@ PresentationControllingInfo::OnStopListening(nsIServerSocket* aServerSocket,
return NS_OK;
}
nsresult
PresentationControllingInfo::Reconnect(nsIPresentationServiceCallback* aCallback)
{
if (!aCallback) {
return NS_ERROR_INVALID_ARG;
}
mReconnectCallback = aCallback;
if (NS_WARN_IF(mState == nsIPresentationSessionListener::STATE_TERMINATED)) {
return mReconnectCallback->NotifyError(NS_ERROR_DOM_INVALID_STATE_ERR);
}
nsresult rv = NS_OK;
if (!mControlChannel) {
nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
rv = mDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
if (NS_WARN_IF(NS_FAILED(rv))) {
return mReconnectCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
rv = Init(ctrlChannel);
if (NS_WARN_IF(NS_FAILED(rv))) {
return mReconnectCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
}
rv = mControlChannel->Reconnect(mSessionId, GetUrl());
if (NS_WARN_IF(NS_FAILED(rv))) {
return mReconnectCallback->NotifyError(rv);
}
return NS_OK;
}
/**
* Implementation of PresentationPresentingInfo
*
@ -1217,6 +1274,13 @@ PresentationPresentingInfo::NotifyConnected()
return NS_OK;
}
NS_IMETHODIMP
PresentationPresentingInfo::NotifyReconnected()
{
MOZ_ASSERT(false, "NotifyReconnected should not be called at receiver side.");
return NS_OK;
}
NS_IMETHODIMP
PresentationPresentingInfo::NotifyDisconnected(nsresult aReason)
{

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

@ -186,6 +186,10 @@ public:
nsresult Init(nsIPresentationControlChannel* aControlChannel) override;
nsresult Reconnect(nsIPresentationServiceCallback* aCallback);
nsresult BuildTransport();
private:
~PresentationControllingInfo()
{
@ -198,9 +202,8 @@ private:
nsresult OnGetAddress(const nsACString& aAddress);
nsresult BuildTransport();
nsCOMPtr<nsIServerSocket> mServerSocket;
nsCOMPtr<nsIPresentationServiceCallback> mReconnectCallback;
};
// Session info with presenting browsing context (receiver side) behaviors.

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

@ -64,6 +64,11 @@ interface nsIPresentationControlChannelListener: nsISupports
* @param reason The reason of channel close, NS_OK represents normal close.
*/
void notifyDisconnected(in nsresult reason);
/*
* The callback for notifying the reconnect command is acknowledged.
*/
void notifyReconnected();
};
/*
@ -122,4 +127,13 @@ interface nsIPresentationControlChannel: nsISupports
* @param reason The reason of disconnecting channel; NS_OK represents normal.
*/
void disconnect(in nsresult reason);
/*
* Reconnect a presentation on remote endpoint.
* Note that only controller is allowed to reconnect a session.
* @param presentationId The Id for representing this session.
* @param url The URL requested to open by remote device.
* @throws NS_ERROR_FAILURE on failure
*/
void reconnect(in DOMString presentationId, in DOMString url);
};

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

@ -57,6 +57,18 @@ interface nsIPresentationControlServerListener: nsISupports
in DOMString aPresentationId,
in nsIPresentationControlChannel aControlChannel,
in boolean aIsFromReceiver);
/**
* Callback while the remote host is requesting to reconnect a presentation session.
* @param aDeviceInfo The device information related to the remote host.
* @param aUrl The URL requested to open by remote device.
* @param aPresentationId The Id for representing this session.
* @param aControlChannel The control channel for this session.
*/
void onReconnectRequest(in nsITCPDeviceInfo aDeviceInfo,
in DOMString url,
in DOMString aPresentationId,
in nsIPresentationControlChannel aControlChannel);
};
/**

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

@ -44,6 +44,18 @@ interface nsIPresentationDeviceListener: nsISupports
in DOMString presentationId,
in nsIPresentationControlChannel controlChannel,
in boolean aIsFromReceiver);
/*
* Callback while the remote device is requesting to reconnect a presentation session.
* @param device The remote device that sent session request.
* @param aUrl The URL requested to open by remote device.
* @param presentationId The Id for representing this session.
* @param controlChannel The control channel for this session.
*/
void onReconnectRequest(in nsIPresentationDevice device,
in DOMString url,
in DOMString presentationId,
in nsIPresentationControlChannel controlChannel);
};
/*

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

@ -33,6 +33,11 @@ interface nsIPresentationSessionListener : nsISupports
*/
void notifyMessage(in DOMString sessionId,
in ACString data);
/*
* Called when this listener is replaced by another one.
*/
void notifyReplaced();
};
[scriptable, uuid(27f101d7-9ed1-429e-b4f8-43b00e8e111c)]

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

@ -98,6 +98,21 @@ interface nsIPresentationService : nsISupports
void terminateSession(in DOMString sessionId,
in uint8_t role);
/*
* Reconnect the session.
*
* @param url: The url of presenting page.
* @param sessionId: An ID to identify presentation session.
* @param role: Identify the function called by controller or receiver.
* @param callback: NotifySuccess() is called when a control channel
* is opened successfully.
* Otherwise, NotifyError() is called with a error message.
*/
void reconnectSession(in DOMString url,
in DOMString sessionId,
in uint8_t role,
in nsIPresentationServiceCallback callback);
/*
* Register an availability listener. Must be called from the main thread.
*
@ -191,4 +206,23 @@ interface nsIPresentationService : nsISupports
* The windowId for building RTCDataChannel session transport
*/
unsigned long long getWindowIdBySessionId(in DOMString sessionId);
/*
* Update the mapping of the session ID and window ID.
*
* @param sessionId: An ID to identify presentation session.
* @param windowId: The inner window ID associated with the presentation
* session.
*/
void updateWindowIdBySessionId(in DOMString sessionId,
in unsigned long long windowId);
/*
* To build the session transport.
* NOTE: This function should be only called at controller side.
*
* @param sessionId: An ID to identify presentation session.
* @param role: Identify the function called by controller or receiver.
*/
void buildTransport(in DOMString sessionId, in uint8_t role);
};

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

@ -9,11 +9,14 @@ interface nsIPresentationControlChannel;
%{C++
#define PRESENTATION_SESSION_REQUEST_TOPIC "presentation-session-request"
#define PRESENTATION_RECONNECT_REQUEST_TOPIC "presentation-reconnect-request"
%}
/*
* The event of a device requesting for a presentation session. User can
* monitor the session request on every device by observing "presentation-sesion-request".
* The event of a device requesting for starting or reconnecting
* a presentation session. User can monitor the session request
* on every device by observing "presentation-sesion-request" for a
* new session and "presentation-reconnect-request" for reconnecting.
*/
[scriptable, uuid(d808a084-d0f8-455a-a8df-5879e05a755b)]
interface nsIPresentationSessionRequest: nsISupports

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

@ -42,12 +42,27 @@ struct TerminateSessionRequest
uint8_t role;
};
struct ReconnectSessionRequest
{
nsString url;
nsString sessionId;
uint8_t role;
};
struct BuildTransportRequest
{
nsString sessionId;
uint8_t role;
};
union PresentationIPCRequest
{
StartSessionRequest;
SendSessionMessageRequest;
CloseSessionRequest;
TerminateSessionRequest;
ReconnectSessionRequest;
BuildTransportRequest;
};
sync protocol PPresentation

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

@ -5,8 +5,11 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DCPresentationChannelDescription.h"
#include "nsComponentManagerUtils.h"
#include "nsGlobalWindow.h"
#include "PresentationBuilderChild.h"
#include "PresentationIPCService.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
namespace dom {

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

@ -28,12 +28,20 @@ PresentationContentSessionInfo::Init() {
nsresult
PresentationContentSessionInfo::Send(const nsAString& aData)
{
if (!mTransport) {
return NS_ERROR_NOT_AVAILABLE;
}
return mTransport->Send(aData);
}
nsresult
PresentationContentSessionInfo::Close(nsresult aReason)
{
if (!mTransport) {
return NS_ERROR_NOT_AVAILABLE;
}
return mTransport->Close(aReason);
}

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

@ -131,6 +131,39 @@ PresentationIPCService::TerminateSession(const nsAString& aSessionId,
return NS_OK;
}
NS_IMETHODIMP
PresentationIPCService::ReconnectSession(const nsAString& aUrl,
const nsAString& aSessionId,
uint8_t aRole,
nsIPresentationServiceCallback* aCallback)
{
MOZ_ASSERT(!aSessionId.IsEmpty());
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
return NS_ERROR_INVALID_ARG;
}
return SendRequest(aCallback, ReconnectSessionRequest(nsString(aUrl),
nsString(aSessionId),
aRole));
}
NS_IMETHODIMP
PresentationIPCService::BuildTransport(const nsAString& aSessionId,
uint8_t aRole)
{
MOZ_ASSERT(!aSessionId.IsEmpty());
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
return NS_ERROR_INVALID_ARG;
}
return SendRequest(nullptr, BuildTransportRequest(nsString(aSessionId),
aRole));
}
nsresult
PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
const PresentationIPCRequest& aRequest)
@ -176,6 +209,13 @@ PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aListener);
nsCOMPtr<nsIPresentationSessionListener> listener;
if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) {
NS_WARN_IF(NS_FAILED(listener->NotifyReplaced()));
mSessionListeners.Put(aSessionId, aListener);
return NS_OK;
}
mSessionListeners.Put(aSessionId, aListener);
if (sPresentationChild) {
NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsString(aSessionId), aRole));
@ -245,6 +285,13 @@ PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
return GetWindowIdBySessionIdInternal(aSessionId, aWindowId);
}
NS_IMETHODIMP
PresentationIPCService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
const uint64_t aWindowId)
{
return UpdateWindowIdBySessionIdInternal(aSessionId, aWindowId);
}
nsresult
PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
uint16_t aState,

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

@ -62,14 +62,6 @@ private:
nsRefPtrHashtable<nsUint64HashKey,
nsIPresentationRespondingListener> mRespondingListeners;
RefPtr<PresentationResponderLoadingCallback> mCallback;
// Store the mapping between the window ID of the OOP page (in this process)
// and the ID of the responding session. It's used for an OOP receiver page
// to retrieve the correspondent session ID. Besides, also keep the mapping
// between the responding session ID and the window ID to help look up the
// window ID.
nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
nsRefPtrHashtable<nsStringHashKey,
PresentationContentSessionInfo> mSessionInfos;
};

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

@ -89,6 +89,12 @@ PresentationParent::RecvPPresentationRequestConstructor(
case PresentationIPCRequest::TTerminateSessionRequest:
rv = actor->DoRequest(aRequest.get_TerminateSessionRequest());
break;
case PresentationIPCRequest::TReconnectSessionRequest:
rv = actor->DoRequest(aRequest.get_ReconnectSessionRequest());
break;
case PresentationIPCRequest::TBuildTransportRequest:
rv = actor->DoRequest(aRequest.get_BuildTransportRequest());
break;
default:
MOZ_CRASH("Unknown PresentationIPCRequest type");
}
@ -242,6 +248,14 @@ PresentationParent::NotifyStateChange(const nsAString& aSessionId,
return NS_OK;
}
NS_IMETHODIMP
PresentationParent::NotifyReplaced()
{
// Do nothing here, since |PresentationIPCService::RegisterSessionListener|
// already dealt with this in content process.
return NS_OK;
}
NS_IMETHODIMP
PresentationParent::NotifyMessage(const nsAString& aSessionId,
const nsACString& aData)
@ -382,6 +396,48 @@ PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest)
return NotifySuccess();
}
nsresult
PresentationRequestParent::DoRequest(const ReconnectSessionRequest& aRequest)
{
MOZ_ASSERT(mService);
// Validate the accessibility (primarily for receiver side) so that a
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
// NOTE: Return NS_ERROR_DOM_NOT_FOUND_ERR here to match the spec.
// https://w3c.github.io/presentation-api/#reconnecting-to-a-presentation
return NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
}
mNeedRegisterBuilder = true;
mSessionId = aRequest.sessionId();
return mService->ReconnectSession(aRequest.url(),
aRequest.sessionId(),
aRequest.role(),
this);
}
nsresult
PresentationRequestParent::DoRequest(const BuildTransportRequest& aRequest)
{
MOZ_ASSERT(mService);
// Validate the accessibility (primarily for receiver side) so that a
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
}
nsresult rv = mService->BuildTransport(aRequest.sessionId(), aRequest.role());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NotifyError(rv);
}
return NotifySuccess();
}
NS_IMETHODIMP
PresentationRequestParent::NotifySuccess()
{

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

@ -113,6 +113,10 @@ private:
nsresult DoRequest(const TerminateSessionRequest& aRequest);
nsresult DoRequest(const ReconnectSessionRequest& aRequest);
nsresult DoRequest(const BuildTransportRequest& aRequest);
bool mActorDestroyed = false;
bool mNeedRegisterBuilder = false;
nsString mSessionId;

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

@ -32,6 +32,7 @@ EXPORTS.mozilla.dom += [
]
UNIFIED_SOURCES += [
'ControllerConnectionCollection.cpp',
'DCPresentationChannelDescription.cpp',
'ipc/PresentationBuilderChild.cpp',
'ipc/PresentationBuilderParent.cpp',

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

@ -60,6 +60,9 @@ var handlers = [
case CommandType.ICE_CANDIDATE:
stateMachine._notifyChannelDescriptor(command);
break;
case CommandType.RECONNECT_ACK:
stateMachine._notifyReconnect(command.presentationId);
break;
default:
debug("unexpected command: " + JSON.stringify(command));
// ignore unexpected command.
@ -111,6 +114,16 @@ ControllerStateMachine.prototype = {
}
},
reconnect: function _reconnect(presentationId, url) {
if (this.state === State.CONNECTED) {
this._sendCommand({
type: CommandType.RECONNECT,
presentationId: presentationId,
url: url,
});
}
},
sendOffer: function _sendOffer(offer) {
if (this.state === State.CONNECTED) {
this._sendCommand({
@ -200,6 +213,10 @@ ControllerStateMachine.prototype = {
this._channel.notifyTerminate(presentationId);
},
_notifyReconnect: function _notifyReconnect(presentationId) {
this._channel.notifyReconnect(presentationId);
},
_notifyChannelDescriptor: function _notifyChannelDescriptor(command) {
switch (command.type) {
case CommandType.ANSWER:

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

@ -436,6 +436,37 @@ DisplayDeviceProvider::OnTerminateRequest(nsITCPDeviceInfo* aDeviceInfo,
return NS_OK;
}
NS_IMETHODIMP
DisplayDeviceProvider::OnReconnectRequest(nsITCPDeviceInfo* aDeviceInfo,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aDeviceInfo);
MOZ_ASSERT(aControlChannel);
nsresult rv;
nsCOMPtr<nsIPresentationDeviceListener> listener;
rv = GetListener(getter_AddRefs(listener));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(!listener);
rv = listener->OnReconnectRequest(mDevice,
aUrl,
aPresentationId,
aControlChannel);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
// nsIObserver
NS_IMETHODIMP
DisplayDeviceProvider::Observe(nsISupports* aSubject,

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

@ -474,6 +474,12 @@ LegacyTCPControlChannel.prototype = {
}
},
reconnect: function() {
// Legacy protocol doesn't support extra reconnect protocol.
// Trigger error handling for browser to shutdown all the resource locally.
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
classID: Components.ID("{4027ce3d-06e3-4d06-a235-df329cb0d411}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel,
Ci.nsIStreamListener]),

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

@ -873,63 +873,13 @@ MulticastDNSDeviceProvider::OnPortChange(uint16_t aPort)
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel)
// Create a new device if we were unable to find one with the address.
already_AddRefed<MulticastDNSDeviceProvider::Device>
MulticastDNSDeviceProvider::GetOrCreateDevice(nsITCPDeviceInfo* aDeviceInfo)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoCString address;
Unused << aDeviceInfo->GetAddress(address);
LOG_I("OnSessionRequest: %s", address.get());
RefPtr<Device> device;
uint32_t index;
if (FindDeviceByAddress(address, index)) {
device = mDevices[index];
} else {
// create a one-time device object for non-discoverable controller
// this device will not be listed in available device list and cannot
// be used for requesting session.
nsAutoCString id;
Unused << aDeviceInfo->GetId(id);
uint16_t port;
Unused << aDeviceInfo->GetPort(&port);
device = new Device(id,
/* aName = */ id,
/* aType = */ EmptyCString(),
address,
port,
DeviceState::eActive,
/* aProvider = */ nullptr);
}
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
Unused << listener->OnSessionRequest(device, aUrl, aPresentationId,
aControlChannel);
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnTerminateRequest(nsITCPDeviceInfo* aDeviceInfo,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel,
bool aIsFromReceiver)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoCString address;
Unused << aDeviceInfo->GetAddress(address);
LOG_I("OnTerminateRequest: %s", address.get());
RefPtr<Device> device;
uint32_t index;
if (FindDeviceByAddress(address, index)) {
@ -952,6 +902,46 @@ MulticastDNSDeviceProvider::OnTerminateRequest(nsITCPDeviceInfo* aDeviceInfo,
/* aProvider = */ nullptr);
}
return device.forget();
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoCString address;
Unused << aDeviceInfo->GetAddress(address);
LOG_I("OnSessionRequest: %s", address.get());
RefPtr<Device> device = GetOrCreateDevice(aDeviceInfo);
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
Unused << listener->OnSessionRequest(device, aUrl, aPresentationId,
aControlChannel);
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnTerminateRequest(nsITCPDeviceInfo* aDeviceInfo,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel,
bool aIsFromReceiver)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoCString address;
Unused << aDeviceInfo->GetAddress(address);
LOG_I("OnTerminateRequest: %s", address.get());
RefPtr<Device> device = GetOrCreateDevice(aDeviceInfo);
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
Unused << listener->OnTerminateRequest(device, aPresentationId,
@ -961,6 +951,29 @@ MulticastDNSDeviceProvider::OnTerminateRequest(nsITCPDeviceInfo* aDeviceInfo,
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnReconnectRequest(nsITCPDeviceInfo* aDeviceInfo,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoCString address;
Unused << aDeviceInfo->GetAddress(address);
LOG_I("OnReconnectRequest: %s", address.get());
RefPtr<Device> device = GetOrCreateDevice(aDeviceInfo);
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
Unused << listener->OnReconnectRequest(device, aUrl, aPresentationId,
aControlChannel);
}
return NS_OK;
}
// nsIObserver
NS_IMETHODIMP
MulticastDNSDeviceProvider::Observe(nsISupports* aSubject,

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

@ -19,6 +19,8 @@
#include "nsTArray.h"
#include "nsWeakPtr.h"
class nsITCPDeviceInfo;
namespace mozilla {
namespace dom {
namespace presentation {
@ -162,6 +164,9 @@ private:
bool FindDeviceByAddress(const nsACString& aAddress,
uint32_t& aIndex);
already_AddRefed<Device>
GetOrCreateDevice(nsITCPDeviceInfo* aDeviceInfo);
void MarkAllDevicesUnknown();
void ClearUnknownDevices();
void ClearDevices();

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

@ -193,6 +193,21 @@ PresentationControlService.prototype = {
this.releaseControlChannel(aControlChannel);
},
onSessionReconnect: function(aDeviceInfo, aUrl, aPresentationId, aControlChannel) {
DEBUG && log("TCPPresentationServer - onSessionReconnect: " +
aDeviceInfo.address + ":" + aDeviceInfo.port); // jshint ignore:line
if (!this.listener) {
this.releaseControlChannel(aControlChannel);
return;
}
this.listener.onReconnectRequest(aDeviceInfo,
aUrl,
aPresentationId,
aControlChannel);
this.releaseControlChannel(aControlChannel);
},
// nsIServerSocketListener (Triggered by nsIServerSocket.init)
onSocketAccepted: function(aServerSocket, aClientSocket) {
DEBUG && log("PresentationControlService - onSocketAccepted: " +
@ -393,6 +408,7 @@ TCPControlChannel.prototype = {
_pendingAnswer: null,
_pendingClose: null,
_pendingCloseReason: null,
_pendingReconnect: false,
sendOffer: function(aOffer) {
this._stateMachine.sendOffer(discriptionAsJson(aOffer));
@ -555,6 +571,12 @@ TCPControlChannel.prototype = {
this._notifyDisconnected(this._pendingCloseReason);
this._pendingClose = null;
}
if (this._pendingReconnect) {
DEBUG && log("TCPControlChannel - notify pending reconnected"); // jshint ignore:line
this._notifyReconnected();
this._pendingReconnect = false;
}
},
/**
@ -624,6 +646,17 @@ TCPControlChannel.prototype = {
this._listener.notifyDisconnected(aReason);
},
_notifyReconnected: function() {
if (!this._listener) {
this._pendingReconnect = true;
return;
}
DEBUG && log("TCPControlChannel - notify reconnected with role: " +
this._direction); // jshint ignore:line
this._listener.notifyReconnected();
},
_closeTransport: function() {
if (this._connected) {
this._transport.setEventSink(null, null);
@ -649,6 +682,16 @@ TCPControlChannel.prototype = {
}
},
reconnect: function(aPresentationId, aUrl) {
DEBUG && log("TCPControlChannel - reconnect with role: " +
this._direction); // jshint ignore:line
if (this._direction != "sender") {
return Cr.NS_ERROR_FAILURE;
}
this._stateMachine.reconnect(aPresentationId, aUrl);
},
// callback from state machine
sendCommand: function(command) {
this._send(command);
@ -684,9 +727,9 @@ TCPControlChannel.prototype = {
if (!this._terminatingId) {
this._terminatingId = presentationId;
this._presentationService.onSessionTerminate(this._deviceInfo,
presentationId,
this,
this._direction === "sender");
presentationId,
this,
this._direction === "sender");
return;
}
@ -700,6 +743,20 @@ TCPControlChannel.prototype = {
delete this._terminatingId;
},
notifyReconnect: function(presentationId, url) {
switch (this._direction) {
case "receiver":
this._presentationService.onSessionReconnect(this._deviceInfo,
url,
presentationId,
this);
break;
case "sender":
this._notifyReconnected();
break;
}
},
notifyOffer: function(offer) {
this._onOffer(offer);
},

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

@ -68,6 +68,14 @@ var handlers = [
case CommandType.ICE_CANDIDATE:
stateMachine._notifyChannelDescriptor(command);
break;
case CommandType.RECONNECT:
stateMachine._notifyReconnect(command.presentationId,
command.url);
stateMachine._sendCommand({
type: CommandType.RECONNECT_ACK,
presentationId: command.presentationId
});
break;
default:
debug("unexpected command: " + JSON.stringify(command));
// ignore unexpected command
@ -113,6 +121,10 @@ ReceiverStateMachine.prototype = {
}
},
reconnect: function _reconnect() {
debug("receiver shouldn't trigger reconnect");
},
sendOffer: function _sendOffer() {
// offer can only be sent by controlling UA.
debug("receiver shouldn't generate offer");
@ -199,6 +211,10 @@ ReceiverStateMachine.prototype = {
this._channel.notifyTerminate(presentationId);
},
_notifyReconnect: function _notifyReconnect(presentationId, url) {
this._channel.notifyReconnect(presentationId, url);
},
_notifyChannelDescriptor: function _notifyChannelDescriptor(command) {
switch (command.type) {
case CommandType.OFFER:

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

@ -27,6 +27,8 @@ const CommandType = Object.freeze({
LAUNCH_ACK: "launch-ack", // { presentationId: <string> }
TERMINATE: "terminate", // { presentationId: <string> }
TERMINATE_ACK: "terminate-ack", // { presentationId: <string> }
RECONNECT: "reconnect", // { presentationId: <string> }
RECONNECT_ACK: "reconnect-ack", // { presentationId: <string> }
// session transport establishment
OFFER: "offer", // { offer: <json> }
ANSWER: "answer", // { answer: <json> }

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

@ -147,6 +147,14 @@ const mockedControlChannel = {
terminate: function(presentationId) {
sendAsyncMessage('sender-terminate', presentationId);
},
reconnect: function(presentationId, url) {
sendAsyncMessage('start-reconnect', url);
},
notifyReconnected: function() {
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyReconnected();
},
disconnect: function(reason) {
sendAsyncMessage('control-channel-closed', reason);
this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyDisconnected(reason);
@ -403,6 +411,10 @@ addMessageListener('trigger-incoming-terminate-request', function() {
.onTerminateRequest(mockedDevice, sessionId, mockedControlChannel, true);
});
addMessageListener('trigger-reconnected-acked', function(url) {
mockedControlChannel.notifyReconnected();
});
addMessageListener('trigger-incoming-offer', function() {
mockedControlChannel.simulateOnOffer();
});
@ -435,6 +447,16 @@ addMessageListener('teardown', function() {
tearDown();
});
var controlChannelListener;
addMessageListener('save-control-channel-listener', function() {
controlChannelListener = mockedControlChannel.listener;
});
addMessageListener('restore-control-channel-listener', function(message) {
mockedControlChannel.listener = controlChannelListener;
controlChannelListener = null;
});
var obs = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
obs.addObserver(function observer(aSubject, aTopic, aData) {

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

@ -176,6 +176,12 @@ const mockControlChannelOfSender = {
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyConnected();
},
notifyReconnected: function() {
// send offer after notifyOpened immediately
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyReconnected();
},
sendOffer: function(offer) {
sendAsyncMessage('offer-sent');
},
@ -200,6 +206,9 @@ const mockControlChannelOfSender = {
terminate: function(presentationId) {
sendAsyncMessage('sender-terminate');
},
reconnect: function(presentationId, url) {
sendAsyncMessage('start-reconnect', url);
},
};
// control channel of receiver
@ -406,6 +415,18 @@ function initMockAndListener() {
triggerControlChannelError = true;
});
addMessageListener('trigger-reconnected-acked', function(url) {
debug('Got message: trigger-reconnected-acked');
mockControlChannelOfSender.notifyReconnected();
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
.onReconnectRequest(mockDevice,
url,
sessionId,
mockControlChannelOfReceiver);
});
addMessageListener('trigger-on-offer', function() {
debug('Got message: trigger-on-offer');
mockControlChannelOfReceiver.onOffer(mockChannelDescriptionOfSender);

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

@ -118,11 +118,25 @@ function testConnectionClosed() {
});
}
function testReconnectConnection() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testReconnectConnection ---');
command('forward-command', JSON.stringify({ name: 'ready-to-reconnect' }));
connection.onconnect = function() {
connection.onconnect = null;
ok(true, "The connection is reconnected.")
aResolve();
};
});
}
function runTests() {
testConnectionAvailable()
.then(testConnectionReady)
.then(testIncomingMessage)
.then(testSendMessage)
.then(testConnectionClosed)
.then(testReconnectConnection)
.then(testConnectionClosed);
}

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