mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
b700491232
@ -136,7 +136,7 @@ MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Accessible constructors
|
// Accessible constructors
|
||||||
|
|
||||||
Accessible*
|
static Accessible*
|
||||||
New_HTMLLink(nsIContent* aContent, Accessible* aContext)
|
New_HTMLLink(nsIContent* aContent, Accessible* aContext)
|
||||||
{
|
{
|
||||||
// Only some roles truly enjoy life as HTMLLinkAccessibles, for details
|
// Only some roles truly enjoy life as HTMLLinkAccessibles, for details
|
||||||
@ -150,28 +150,28 @@ New_HTMLLink(nsIContent* aContent, Accessible* aContext)
|
|||||||
return new HTMLLinkAccessible(aContent, aContext->Document());
|
return new HTMLLinkAccessible(aContent, aContext->Document());
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessible* New_HyperText(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HyperText(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HyperTextAccessibleWrap(aContent, aContext->Document()); }
|
{ return new HyperTextAccessibleWrap(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLFigcaption(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLFigcaption(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLFigcaptionAccessible(aContent, aContext->Document()); }
|
{ return new HTMLFigcaptionAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLFigure(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLFigure(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLFigureAccessible(aContent, aContext->Document()); }
|
{ return new HTMLFigureAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLLegend(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLLegend(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLLegendAccessible(aContent, aContext->Document()); }
|
{ return new HTMLLegendAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLOption(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLOption(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLSelectOptionAccessible(aContent, aContext->Document()); }
|
{ return new HTMLSelectOptionAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLOptgroup(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLOptgroup(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLSelectOptGroupAccessible(aContent, aContext->Document()); }
|
{ return new HTMLSelectOptGroupAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLList(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLList(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLListAccessible(aContent, aContext->Document()); }
|
{ return new HTMLListAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible*
|
static Accessible*
|
||||||
New_HTMLListitem(nsIContent* aContent, Accessible* aContext)
|
New_HTMLListitem(nsIContent* aContent, Accessible* aContext)
|
||||||
{
|
{
|
||||||
// If list item is a child of accessible list then create an accessible for
|
// If list item is a child of accessible list then create an accessible for
|
||||||
@ -183,7 +183,7 @@ New_HTMLListitem(nsIContent* aContent, Accessible* aContext)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessible*
|
static Accessible*
|
||||||
New_HTMLDefinition(nsIContent* aContent, Accessible* aContext)
|
New_HTMLDefinition(nsIContent* aContent, Accessible* aContext)
|
||||||
{
|
{
|
||||||
if (aContext->IsList())
|
if (aContext->IsList())
|
||||||
@ -191,16 +191,16 @@ New_HTMLDefinition(nsIContent* aContent, Accessible* aContext)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessible* New_HTMLLabel(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLLabel(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLLabelAccessible(aContent, aContext->Document()); }
|
{ return new HTMLLabelAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLOutputAccessible(aContent, aContext->Document()); }
|
{ return new HTMLOutputAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
|
static Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
|
||||||
{ return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
|
{ return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
|
||||||
|
|
||||||
Accessible*
|
static Accessible*
|
||||||
New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
|
New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
|
||||||
{
|
{
|
||||||
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent())
|
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent())
|
||||||
@ -208,7 +208,7 @@ New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessible*
|
static Accessible*
|
||||||
New_HTMLTableHeaderCellIfScope(nsIContent* aContent, Accessible* aContext)
|
New_HTMLTableHeaderCellIfScope(nsIContent* aContent, Accessible* aContext)
|
||||||
{
|
{
|
||||||
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent() &&
|
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent() &&
|
||||||
|
@ -42,6 +42,9 @@ public:
|
|||||||
|
|
||||||
uint32_t ChildrenCount() const { return mChildren.Length(); }
|
uint32_t ChildrenCount() const { return mChildren.Length(); }
|
||||||
ProxyAccessible* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
|
ProxyAccessible* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
|
||||||
|
|
||||||
|
// XXX evaluate if this is fast enough.
|
||||||
|
size_t IndexInParent() const { return mParent->mChildren.IndexOf(this); }
|
||||||
bool MustPruneChildren() const;
|
bool MustPruneChildren() const;
|
||||||
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
@ -301,22 +301,22 @@ this.Utils = { // jshint ignore:line
|
|||||||
},
|
},
|
||||||
|
|
||||||
getContentResolution: function _getContentResolution(aAccessible) {
|
getContentResolution: function _getContentResolution(aAccessible) {
|
||||||
let resX = { value: 1 }, resY = { value: 1 };
|
let res = { value: 1 };
|
||||||
aAccessible.document.window.QueryInterface(
|
aAccessible.document.window.QueryInterface(
|
||||||
Ci.nsIInterfaceRequestor).getInterface(
|
Ci.nsIInterfaceRequestor).getInterface(
|
||||||
Ci.nsIDOMWindowUtils).getResolution(resX, resY);
|
Ci.nsIDOMWindowUtils).getResolution(res);
|
||||||
return [resX.value, resY.value];
|
return res.value;
|
||||||
},
|
},
|
||||||
|
|
||||||
getBounds: function getBounds(aAccessible, aPreserveContentScale) {
|
getBounds: function getBounds(aAccessible, aPreserveContentScale) {
|
||||||
let objX = {}, objY = {}, objW = {}, objH = {};
|
let objX = {}, objY = {}, objW = {}, objH = {};
|
||||||
aAccessible.getBounds(objX, objY, objW, objH);
|
aAccessible.getBounds(objX, objY, objW, objH);
|
||||||
|
|
||||||
let [scaleX, scaleY] = aPreserveContentScale ? [1, 1] :
|
let scale = aPreserveContentScale ? 1 :
|
||||||
this.getContentResolution(aAccessible);
|
this.getContentResolution(aAccessible);
|
||||||
|
|
||||||
return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
|
return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
|
||||||
scaleX, scaleY);
|
scale, scale);
|
||||||
},
|
},
|
||||||
|
|
||||||
getTextBounds: function getTextBounds(aAccessible, aStart, aEnd,
|
getTextBounds: function getTextBounds(aAccessible, aStart, aEnd,
|
||||||
@ -326,11 +326,11 @@ this.Utils = { // jshint ignore:line
|
|||||||
accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
|
accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
|
||||||
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
|
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
|
||||||
|
|
||||||
let [scaleX, scaleY] = aPreserveContentScale ? [1, 1] :
|
let scale = aPreserveContentScale ? 1 :
|
||||||
this.getContentResolution(aAccessible);
|
this.getContentResolution(aAccessible);
|
||||||
|
|
||||||
return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
|
return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
|
||||||
scaleX, scaleY);
|
scale, scale);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -370,7 +370,8 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
|
|||||||
|
|
||||||
// Test accessible properties.
|
// Test accessible properties.
|
||||||
for (var prop in accTree) {
|
for (var prop in accTree) {
|
||||||
var msg = "Wrong value of property '" + prop + "' for " + prettyName(acc) + ".";
|
var msg = "Wrong value of property '" + prop + "' for " +
|
||||||
|
prettyName(acc) + ".";
|
||||||
|
|
||||||
switch (prop) {
|
switch (prop) {
|
||||||
case "actions": {
|
case "actions": {
|
||||||
@ -451,10 +452,29 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
|
|||||||
var children = acc.children;
|
var children = acc.children;
|
||||||
var childCount = children.length;
|
var childCount = children.length;
|
||||||
|
|
||||||
is(childCount, accTree.children.length,
|
|
||||||
"Different amount of expected children of " + prettyName(acc) + ".");
|
|
||||||
|
|
||||||
if (accTree.children.length == childCount) {
|
if (accTree.children.length != childCount) {
|
||||||
|
for (var i = 0; i < Math.max(accTree.children.length, childCount); i++) {
|
||||||
|
var accChild;
|
||||||
|
try {
|
||||||
|
accChild = children.queryElementAt(i, nsIAccessible);
|
||||||
|
if (!accTree.children[i]) {
|
||||||
|
ok(false, prettyName(acc) + " has an extra child at index " + i +
|
||||||
|
" : " + prettyName(accChild));
|
||||||
|
}
|
||||||
|
if (accChild.role !== accTree.children[i].role) {
|
||||||
|
ok(false, prettyName(accTree) + " and " + prettyName(acc) +
|
||||||
|
" have different children at index " + i + " : " +
|
||||||
|
prettyName(accTree.children[i]) + ", " + prettyName(accChild));
|
||||||
|
}
|
||||||
|
info("Matching " + prettyName(accTree) + " and " + prettyName(acc) +
|
||||||
|
" child at index " + i + " : " + prettyName(accChild));
|
||||||
|
} catch (e) {
|
||||||
|
ok(false, prettyName(accTree) + " has an extra child at index " + i +
|
||||||
|
" : " + prettyName(accTree.children[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (aFlags & kSkipTreeFullCheck) {
|
if (aFlags & kSkipTreeFullCheck) {
|
||||||
for (var i = 0; i < childCount; i++) {
|
for (var i = 0; i < childCount; i++) {
|
||||||
var child = children.queryElementAt(i, nsIAccessible);
|
var child = children.queryElementAt(i, nsIAccessible);
|
||||||
@ -537,7 +557,8 @@ function testDefunctAccessible(aAcc, aNodeOrId)
|
|||||||
ok(!isAccessible(aNodeOrId),
|
ok(!isAccessible(aNodeOrId),
|
||||||
"Accessible for " + aNodeOrId + " wasn't properly shut down!");
|
"Accessible for " + aNodeOrId + " wasn't properly shut down!");
|
||||||
|
|
||||||
var msg = " doesn't fail for shut down accessible " + prettyName(aNodeOrId) + "!";
|
var msg = " doesn't fail for shut down accessible " +
|
||||||
|
prettyName(aNodeOrId) + "!";
|
||||||
|
|
||||||
// firstChild
|
// firstChild
|
||||||
var success = false;
|
var success = false;
|
||||||
@ -720,6 +741,10 @@ function prettyName(aIdentifier)
|
|||||||
if (aIdentifier instanceof nsIDOMNode)
|
if (aIdentifier instanceof nsIDOMNode)
|
||||||
return "[ " + getNodePrettyName(aIdentifier) + " ]";
|
return "[ " + getNodePrettyName(aIdentifier) + " ]";
|
||||||
|
|
||||||
|
if (aIdentifier && typeof aIdentifier === "object" ) {
|
||||||
|
return JSON.stringify(aIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
return " '" + aIdentifier + "' ";
|
return " '" + aIdentifier + "' ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "IUnknownImpl.h"
|
#include "IUnknownImpl.h"
|
||||||
#include "nsCoreUtils.h"
|
#include "nsCoreUtils.h"
|
||||||
#include "nsIAccessibleTypes.h"
|
#include "nsIAccessibleTypes.h"
|
||||||
|
#include "mozilla/a11y/PDocAccessible.h"
|
||||||
#include "Relation.h"
|
#include "Relation.h"
|
||||||
|
|
||||||
#include "nsIPersistentProperties2.h"
|
#include "nsIPersistentProperties2.h"
|
||||||
@ -24,6 +25,8 @@
|
|||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::a11y;
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
template<typename String> static void EscapeAttributeChars(String& aStr);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// ia2Accessible
|
// ia2Accessible
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -65,6 +68,15 @@ ia2Accessible::get_nRelations(long* aNRelations)
|
|||||||
if (acc->IsDefunct())
|
if (acc->IsDefunct())
|
||||||
return CO_E_OBJNOTCONNECTED;
|
return CO_E_OBJNOTCONNECTED;
|
||||||
|
|
||||||
|
if (acc->IsProxy()) {
|
||||||
|
// XXX evaluate performance of collecting all relation targets.
|
||||||
|
nsTArray<RelationType> types;
|
||||||
|
nsTArray<nsTArray<ProxyAccessible*>> targetSets;
|
||||||
|
acc->Proxy()->Relations(&types, &targetSets);
|
||||||
|
*aNRelations = types.Length();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
|
for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
|
||||||
if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
|
if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
|
||||||
continue;
|
continue;
|
||||||
@ -84,7 +96,7 @@ ia2Accessible::get_relation(long aRelationIndex,
|
|||||||
{
|
{
|
||||||
A11Y_TRYBLOCK_BEGIN
|
A11Y_TRYBLOCK_BEGIN
|
||||||
|
|
||||||
if (!aRelation)
|
if (!aRelation || aRelationIndex < 0)
|
||||||
return E_INVALIDARG;
|
return E_INVALIDARG;
|
||||||
*aRelation = nullptr;
|
*aRelation = nullptr;
|
||||||
|
|
||||||
@ -92,6 +104,34 @@ ia2Accessible::get_relation(long aRelationIndex,
|
|||||||
if (acc->IsDefunct())
|
if (acc->IsDefunct())
|
||||||
return CO_E_OBJNOTCONNECTED;
|
return CO_E_OBJNOTCONNECTED;
|
||||||
|
|
||||||
|
if (acc->IsProxy()) {
|
||||||
|
nsTArray<RelationType> types;
|
||||||
|
nsTArray<nsTArray<ProxyAccessible*>> targetSets;
|
||||||
|
acc->Proxy()->Relations(&types, &targetSets);
|
||||||
|
|
||||||
|
size_t targetSetCount = targetSets.Length();
|
||||||
|
for (size_t i = 0; i < targetSetCount; i++) {
|
||||||
|
uint32_t relTypeIdx = static_cast<uint32_t>(types[i]);
|
||||||
|
MOZ_ASSERT(sRelationTypePairs[relTypeIdx].first == types[i]);
|
||||||
|
if (sRelationTypePairs[relTypeIdx].second == IA2_RELATION_NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (static_cast<size_t>(aRelationIndex) == i) {
|
||||||
|
nsTArray<nsRefPtr<Accessible>> targets;
|
||||||
|
size_t targetCount = targetSets[i].Length();
|
||||||
|
for (size_t j = 0; j < targetCount; j++)
|
||||||
|
targets.AppendElement(WrapperFor(targetSets[i][j]));
|
||||||
|
|
||||||
|
nsRefPtr<ia2AccessibleRelation> rel =
|
||||||
|
new ia2AccessibleRelation(types[i], Move(targets));
|
||||||
|
rel.forget(aRelation);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
long relIdx = 0;
|
long relIdx = 0;
|
||||||
for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
|
for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
|
||||||
if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
|
if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
|
||||||
@ -123,7 +163,7 @@ ia2Accessible::get_relations(long aMaxRelations,
|
|||||||
{
|
{
|
||||||
A11Y_TRYBLOCK_BEGIN
|
A11Y_TRYBLOCK_BEGIN
|
||||||
|
|
||||||
if (!aRelation || !aNRelations)
|
if (!aRelation || !aNRelations || aMaxRelations <= 0)
|
||||||
return E_INVALIDARG;
|
return E_INVALIDARG;
|
||||||
*aNRelations = 0;
|
*aNRelations = 0;
|
||||||
|
|
||||||
@ -131,6 +171,34 @@ ia2Accessible::get_relations(long aMaxRelations,
|
|||||||
if (acc->IsDefunct())
|
if (acc->IsDefunct())
|
||||||
return CO_E_OBJNOTCONNECTED;
|
return CO_E_OBJNOTCONNECTED;
|
||||||
|
|
||||||
|
if (acc->IsProxy()) {
|
||||||
|
nsTArray<RelationType> types;
|
||||||
|
nsTArray<nsTArray<ProxyAccessible*>> targetSets;
|
||||||
|
acc->Proxy()->Relations(&types, &targetSets);
|
||||||
|
|
||||||
|
size_t count = std::min(targetSets.Length(),
|
||||||
|
static_cast<size_t>(aMaxRelations));
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
uint32_t relTypeIdx = static_cast<uint32_t>(types[i]);
|
||||||
|
if (sRelationTypePairs[relTypeIdx].second == IA2_RELATION_NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t targetCount = targetSets[i].Length();
|
||||||
|
nsTArray<nsRefPtr<Accessible>> targets(targetCount);
|
||||||
|
for (size_t j = 0; j < targetCount; j++)
|
||||||
|
targets.AppendElement(WrapperFor(targetSets[i][j]));
|
||||||
|
|
||||||
|
nsRefPtr<ia2AccessibleRelation> rel =
|
||||||
|
new ia2AccessibleRelation(types[i], Move(targets));
|
||||||
|
rel.forget(aRelation + i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aNRelations = i;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) &&
|
for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) &&
|
||||||
*aNRelations < aMaxRelations; idx++) {
|
*aNRelations < aMaxRelations; idx++) {
|
||||||
if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
|
if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
|
||||||
@ -169,7 +237,11 @@ ia2Accessible::role(long* aRole)
|
|||||||
*aRole = ia2Role; \
|
*aRole = ia2Role; \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
a11y::role geckoRole = acc->Role();
|
a11y::role geckoRole;
|
||||||
|
if (acc->IsProxy())
|
||||||
|
geckoRole = acc->Proxy()->Role();
|
||||||
|
else
|
||||||
|
geckoRole = acc->Role();
|
||||||
switch (geckoRole) {
|
switch (geckoRole) {
|
||||||
#include "RoleMap.h"
|
#include "RoleMap.h"
|
||||||
default:
|
default:
|
||||||
@ -180,10 +252,16 @@ ia2Accessible::role(long* aRole)
|
|||||||
|
|
||||||
// Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
|
// Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
|
||||||
// the IA2 role a ROLE_OUTLINEITEM.
|
// the IA2 role a ROLE_OUTLINEITEM.
|
||||||
if (geckoRole == roles::ROW) {
|
if (acc->IsProxy()) {
|
||||||
Accessible* xpParent = acc->Parent();
|
if (geckoRole == roles::ROW && acc->Proxy()->Parent() &&
|
||||||
if (xpParent && xpParent->Role() == roles::TREE_TABLE)
|
acc->Proxy()->Parent()->Role() == roles::TREE_TABLE)
|
||||||
*aRole = ROLE_SYSTEM_OUTLINEITEM;
|
*aRole = ROLE_SYSTEM_OUTLINEITEM;
|
||||||
|
} else {
|
||||||
|
if (geckoRole == roles::ROW) {
|
||||||
|
Accessible* xpParent = acc->Parent();
|
||||||
|
if (xpParent && xpParent->Role() == roles::TREE_TABLE)
|
||||||
|
*aRole = ROLE_SYSTEM_OUTLINEITEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
@ -274,7 +352,16 @@ ia2Accessible::get_states(AccessibleStates* aStates)
|
|||||||
// XXX: bug 344674 should come with better approach that we have here.
|
// XXX: bug 344674 should come with better approach that we have here.
|
||||||
|
|
||||||
AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
|
AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
|
||||||
uint64_t state = acc->State();
|
if (acc->IsDefunct()) {
|
||||||
|
*aStates = IA2_STATE_DEFUNCT;
|
||||||
|
return CO_E_OBJNOTCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t state;
|
||||||
|
if (acc->IsProxy())
|
||||||
|
state = acc->Proxy()->State();
|
||||||
|
else
|
||||||
|
state = acc->State();
|
||||||
|
|
||||||
if (state & states::INVALID)
|
if (state & states::INVALID)
|
||||||
*aStates |= IA2_STATE_INVALID_ENTRY;
|
*aStates |= IA2_STATE_INVALID_ENTRY;
|
||||||
@ -446,7 +533,11 @@ ia2Accessible::get_indexInParent(long* aIndexInParent)
|
|||||||
if (acc->IsDefunct())
|
if (acc->IsDefunct())
|
||||||
return CO_E_OBJNOTCONNECTED;
|
return CO_E_OBJNOTCONNECTED;
|
||||||
|
|
||||||
*aIndexInParent = acc->IndexInParent();
|
if (acc->IsProxy())
|
||||||
|
*aIndexInParent = acc->Proxy()->IndexInParent();
|
||||||
|
else
|
||||||
|
*aIndexInParent = acc->IndexInParent();
|
||||||
|
|
||||||
if (*aIndexInParent == -1)
|
if (*aIndexInParent == -1)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
@ -521,8 +612,29 @@ ia2Accessible::get_attributes(BSTR* aAttributes)
|
|||||||
|
|
||||||
// The format is name:value;name:value; with \ for escaping these
|
// The format is name:value;name:value; with \ for escaping these
|
||||||
// characters ":;=,\".
|
// characters ":;=,\".
|
||||||
nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes();
|
if (!acc->IsProxy()) {
|
||||||
return ConvertToIA2Attributes(attributes, aAttributes);
|
nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes();
|
||||||
|
return ConvertToIA2Attributes(attributes, aAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<Attribute> attrs;
|
||||||
|
acc->Proxy()->Attributes(&attrs);
|
||||||
|
nsString attrStr;
|
||||||
|
size_t attrCount = attrs.Length();
|
||||||
|
for (size_t i = 0; i < attrCount; i++) {
|
||||||
|
EscapeAttributeChars(attrs[i].Name());
|
||||||
|
EscapeAttributeChars(attrs[i].Value());
|
||||||
|
AppendUTF8toUTF16(attrs[i].Name(), attrStr);
|
||||||
|
attrStr.Append(':');
|
||||||
|
attrStr.Append(attrs[i].Value());
|
||||||
|
attrStr.Append(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrStr.IsEmpty())
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
*aAttributes = ::SysAllocStringLen(attrStr.get(), attrStr.Length());
|
||||||
|
return *aAttributes ? S_OK : E_OUTOFMEMORY;
|
||||||
|
|
||||||
A11Y_TRYBLOCK_END
|
A11Y_TRYBLOCK_END
|
||||||
}
|
}
|
||||||
@ -567,7 +679,7 @@ ia2Accessible::get_relationTargetsOfType(BSTR aType,
|
|||||||
{
|
{
|
||||||
A11Y_TRYBLOCK_BEGIN
|
A11Y_TRYBLOCK_BEGIN
|
||||||
|
|
||||||
if (!aTargets || !aNTargets)
|
if (!aTargets || !aNTargets || aMaxTargets < 0)
|
||||||
return E_INVALIDARG;
|
return E_INVALIDARG;
|
||||||
*aNTargets = 0;
|
*aNTargets = 0;
|
||||||
|
|
||||||
@ -585,13 +697,23 @@ ia2Accessible::get_relationTargetsOfType(BSTR aType,
|
|||||||
if (acc->IsDefunct())
|
if (acc->IsDefunct())
|
||||||
return CO_E_OBJNOTCONNECTED;
|
return CO_E_OBJNOTCONNECTED;
|
||||||
|
|
||||||
Relation rel = acc->RelationByType(*relationType);
|
|
||||||
|
|
||||||
nsTArray<Accessible*> targets;
|
nsTArray<Accessible*> targets;
|
||||||
Accessible* target = nullptr;
|
if (acc->IsProxy()) {
|
||||||
while ((target = rel.Next()) &&
|
nsTArray<ProxyAccessible*> targetProxies =
|
||||||
static_cast<long>(targets.Length()) <= aMaxTargets)
|
acc->Proxy()->RelationByType(*relationType);
|
||||||
targets.AppendElement(target);
|
|
||||||
|
size_t targetCount = aMaxTargets;
|
||||||
|
if (targetProxies.Length() < targetCount)
|
||||||
|
targetCount = targetProxies.Length();
|
||||||
|
for (size_t i = 0; i < targetCount; i++)
|
||||||
|
targets.AppendElement(WrapperFor(targetProxies[i]));
|
||||||
|
} else {
|
||||||
|
Relation rel = acc->RelationByType(*relationType);
|
||||||
|
Accessible* target = nullptr;
|
||||||
|
while ((target = rel.Next()) &&
|
||||||
|
static_cast<long>(targets.Length()) <= aMaxTargets)
|
||||||
|
targets.AppendElement(target);
|
||||||
|
}
|
||||||
|
|
||||||
*aNTargets = targets.Length();
|
*aNTargets = targets.Length();
|
||||||
*aTargets = static_cast<IUnknown**>(
|
*aTargets = static_cast<IUnknown**>(
|
||||||
@ -613,6 +735,18 @@ ia2Accessible::get_relationTargetsOfType(BSTR aType,
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
|
template<typename String>
|
||||||
|
static inline void
|
||||||
|
EscapeAttributeChars(String& aStr)
|
||||||
|
{
|
||||||
|
int32_t offset = 0;
|
||||||
|
static const char kCharsToEscape[] = ":;=,\\";
|
||||||
|
while ((offset = aStr.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
|
||||||
|
aStr.Insert('\\', offset);
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
|
ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
|
||||||
BSTR* aIA2Attributes)
|
BSTR* aIA2Attributes)
|
||||||
@ -632,8 +766,6 @@ ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
|
|||||||
|
|
||||||
nsAutoString strAttrs;
|
nsAutoString strAttrs;
|
||||||
|
|
||||||
const char kCharsToEscape[] = ":;=,\\";
|
|
||||||
|
|
||||||
bool hasMore = false;
|
bool hasMore = false;
|
||||||
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
||||||
nsCOMPtr<nsISupports> propSupports;
|
nsCOMPtr<nsISupports> propSupports;
|
||||||
@ -647,21 +779,13 @@ ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
|
|||||||
if (NS_FAILED(propElem->GetKey(name)))
|
if (NS_FAILED(propElem->GetKey(name)))
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
int32_t offset = 0;
|
EscapeAttributeChars(name);
|
||||||
while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
|
|
||||||
name.Insert('\\', offset);
|
|
||||||
offset += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString value;
|
nsAutoString value;
|
||||||
if (NS_FAILED(propElem->GetValue(value)))
|
if (NS_FAILED(propElem->GetValue(value)))
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
offset = 0;
|
EscapeAttributeChars(value);
|
||||||
while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
|
|
||||||
value.Insert('\\', offset);
|
|
||||||
offset += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppendUTF8toUTF16(name, strAttrs);
|
AppendUTF8toUTF16(name, strAttrs);
|
||||||
strAttrs.Append(':');
|
strAttrs.Append(':');
|
||||||
|
@ -24,6 +24,10 @@ class ia2AccessibleRelation MOZ_FINAL : public IAccessibleRelation
|
|||||||
public:
|
public:
|
||||||
ia2AccessibleRelation(RelationType aType, Relation* aRel);
|
ia2AccessibleRelation(RelationType aType, Relation* aRel);
|
||||||
|
|
||||||
|
ia2AccessibleRelation(RelationType aType,
|
||||||
|
nsTArray<nsRefPtr<Accessible>>&& aTargets) :
|
||||||
|
mType(aType), mTargets(Move(aTargets)) {}
|
||||||
|
|
||||||
// IUnknown
|
// IUnknown
|
||||||
DECL_IUNKNOWN
|
DECL_IUNKNOWN
|
||||||
|
|
||||||
|
@ -52,3 +52,5 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||||||
DEFINES['NOMINMAX'] = True
|
DEFINES['NOMINMAX'] = True
|
||||||
|
|
||||||
FAIL_ON_WARNINGS = True
|
FAIL_ON_WARNINGS = True
|
||||||
|
|
||||||
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
@ -694,6 +694,9 @@ pref("ui.scrollbarFadeDuration", 200);
|
|||||||
// Scrollbar position follows the document `dir` attribute
|
// Scrollbar position follows the document `dir` attribute
|
||||||
pref("layout.scrollbar.side", 1);
|
pref("layout.scrollbar.side", 1);
|
||||||
|
|
||||||
|
// CSS Scroll Snapping
|
||||||
|
pref("layout.css.scroll-snap.enabled", true);
|
||||||
|
|
||||||
// Enable the ProcessPriorityManager, and give processes with no visible
|
// Enable the ProcessPriorityManager, and give processes with no visible
|
||||||
// documents a 1s grace period before they're eligible to be marked as
|
// documents a 1s grace period before they're eligible to be marked as
|
||||||
// background. Background processes that are perceivable due to playing
|
// background. Background processes that are perceivable due to playing
|
||||||
|
@ -128,39 +128,39 @@ window.addEventListener('ContentStart', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resize(width, height, ratio, shouldFlip) {
|
Services.prefs.setCharPref('layout.css.devPixelsPerPx',
|
||||||
|
ratio == 1 ? -1 : ratio);
|
||||||
|
let defaultOrientation = width < height ? 'portrait' : 'landscape';
|
||||||
|
GlobalSimulatorScreen.mozOrientation = GlobalSimulatorScreen.screenOrientation = defaultOrientation;
|
||||||
|
|
||||||
|
function resize() {
|
||||||
GlobalSimulatorScreen.width = width;
|
GlobalSimulatorScreen.width = width;
|
||||||
GlobalSimulatorScreen.height = height;
|
GlobalSimulatorScreen.height = height;
|
||||||
|
|
||||||
Services.prefs.setCharPref('layout.css.devPixelsPerPx',
|
|
||||||
ratio == 1 ? -1 : ratio);
|
|
||||||
|
|
||||||
// In order to do rescaling, we set the <browser> tag to the specified
|
|
||||||
// width and height, and then use a CSS transform to scale it so that
|
|
||||||
// it appears at the correct size on the host display. We also set
|
|
||||||
// the size of the <window> element to that scaled target size.
|
|
||||||
let scale = 1.0;
|
|
||||||
|
|
||||||
// Set the window width and height to desired size plus chrome
|
// Set the window width and height to desired size plus chrome
|
||||||
// Include the size of the toolbox displayed under the system app
|
// Include the size of the toolbox displayed under the system app
|
||||||
let controls = document.getElementById('controls');
|
let controls = document.getElementById('controls');
|
||||||
let controlsHeight = 0;
|
let controlsHeight = controls ? controls.getBoundingClientRect().height : 0;
|
||||||
if (controls) {
|
|
||||||
controlsHeight = controls.getBoundingClientRect().height;
|
|
||||||
}
|
|
||||||
let chromewidth = window.outerWidth - window.innerWidth;
|
|
||||||
let chromeheight = window.outerHeight - window.innerHeight + controlsHeight;
|
|
||||||
if (isMulet) {
|
if (isMulet) {
|
||||||
let tab = browserWindow.gBrowser.selectedTab;
|
let tab = browserWindow.gBrowser.selectedTab;
|
||||||
let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab);
|
let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab);
|
||||||
responsive.setSize((Math.round(width * scale) + 16*2),
|
responsive.setSize(width + 16*2,
|
||||||
(Math.round(height * scale) + controlsHeight + 61));
|
height + controlsHeight + 61);
|
||||||
} else {
|
} else {
|
||||||
window.resizeTo(Math.round(width * scale) + chromewidth,
|
let chromewidth = window.outerWidth - window.innerWidth;
|
||||||
Math.round(height * scale) + chromeheight);
|
let chromeheight = window.outerHeight - window.innerHeight + controlsHeight;
|
||||||
|
window.resizeTo(width + chromewidth,
|
||||||
|
height + chromeheight);
|
||||||
}
|
}
|
||||||
|
|
||||||
let frameWidth = width, frameHeight = height;
|
let frameWidth = width, frameHeight = height;
|
||||||
|
|
||||||
|
// If the current app doesn't supports the current screen orientation
|
||||||
|
// still resize the window, but rotate its frame so that
|
||||||
|
// it is displayed rotated on the side
|
||||||
|
let shouldFlip = GlobalSimulatorScreen.mozOrientation != GlobalSimulatorScreen.screenOrientation;
|
||||||
|
|
||||||
if (shouldFlip) {
|
if (shouldFlip) {
|
||||||
frameWidth = height;
|
frameWidth = height;
|
||||||
frameHeight = width;
|
frameHeight = width;
|
||||||
@ -172,30 +172,29 @@ window.addEventListener('ContentStart', function() {
|
|||||||
style.height = 'calc(100% - ' + controlsHeight + 'px)';
|
style.height = 'calc(100% - ' + controlsHeight + 'px)';
|
||||||
style.bottom = controlsHeight;
|
style.bottom = controlsHeight;
|
||||||
|
|
||||||
|
style.width = frameWidth + "px";
|
||||||
|
style.height = frameHeight + "px";
|
||||||
|
|
||||||
if (shouldFlip) {
|
if (shouldFlip) {
|
||||||
// Display the system app with a 90° clockwise rotation
|
// Display the system app with a 90° clockwise rotation
|
||||||
let shift = Math.floor(Math.abs(frameWidth-frameHeight) / 2);
|
let shift = Math.floor(Math.abs(frameWidth - frameHeight) / 2);
|
||||||
style.transform +=
|
style.transform +=
|
||||||
' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)';
|
' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize on startup
|
// Resize on startup
|
||||||
resize(width, height, ratio, false);
|
resize();
|
||||||
|
|
||||||
let defaultOrientation = width < height ? 'portrait' : 'landscape';
|
|
||||||
GlobalSimulatorScreen.mozOrientation = GlobalSimulatorScreen.screenOrientation = defaultOrientation;
|
|
||||||
|
|
||||||
// Catch manual resizes to update the internal device size.
|
// Catch manual resizes to update the internal device size.
|
||||||
window.onresize = function() {
|
window.onresize = function() {
|
||||||
width = browser.clientWidth;
|
let controls = document.getElementById('controls');
|
||||||
height = browser.clientHeight;
|
let controlsHeight = controls ? controls.getBoundingClientRect().height : 0;
|
||||||
if ((defaultOrientation == 'portrait' && width > height) ||
|
|
||||||
(defaultOrientation == 'landscape' && width < height)) {
|
width = window.innerWidth;
|
||||||
let w = width;
|
height = window.innerHeight - controlsHeight;
|
||||||
width = height;
|
|
||||||
height = w;
|
queueResize();
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Then resize on each rotation button click,
|
// Then resize on each rotation button click,
|
||||||
@ -204,23 +203,31 @@ window.addEventListener('ContentStart', function() {
|
|||||||
let screen = subject.wrappedJSObject;
|
let screen = subject.wrappedJSObject;
|
||||||
let { mozOrientation, screenOrientation } = screen;
|
let { mozOrientation, screenOrientation } = screen;
|
||||||
|
|
||||||
let newWidth = width;
|
// If we have an orientation different than the current one,
|
||||||
let newHeight = height;
|
|
||||||
// If we have an orientation different than the startup one,
|
|
||||||
// we switch the sizes
|
// we switch the sizes
|
||||||
if (screenOrientation != defaultOrientation) {
|
if (screenOrientation != defaultOrientation) {
|
||||||
newWidth = height;
|
let w = width;
|
||||||
newHeight = width;
|
width = height;
|
||||||
|
height = w;
|
||||||
}
|
}
|
||||||
|
defaultOrientation = screenOrientation;
|
||||||
|
|
||||||
// If the current app doesn't supports the current screen orientation
|
queueResize();
|
||||||
// still resize the window, but rotate its frame so that
|
|
||||||
// it is displayed rotated on the side
|
|
||||||
let shouldFlip = mozOrientation != screenOrientation;
|
|
||||||
|
|
||||||
resize(newWidth, newHeight, ratio, shouldFlip);
|
|
||||||
}, 'simulator-adjust-window-size', false);
|
}, 'simulator-adjust-window-size', false);
|
||||||
|
|
||||||
|
// Queue resize request in order to prevent race and slowdowns
|
||||||
|
// by requesting resize multiple times per loop
|
||||||
|
let resizeTimeout;
|
||||||
|
function queueResize() {
|
||||||
|
if (resizeTimeout) {
|
||||||
|
clearTimeout(resizeTimeout);
|
||||||
|
}
|
||||||
|
resizeTimeout = setTimeout(function () {
|
||||||
|
resizeTimeout = null;
|
||||||
|
resize();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// A utility function like console.log() for printing to the terminal window
|
// A utility function like console.log() for printing to the terminal window
|
||||||
// Uses dump(), but enables it first, if necessary
|
// Uses dump(), but enables it first, if necessary
|
||||||
function print() {
|
function print() {
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||||
@ -128,7 +128,7 @@
|
|||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/>
|
<project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/>
|
||||||
<!-- dolphin specific things -->
|
<!-- dolphin specific things -->
|
||||||
<project name="device/sprd" path="device/sprd" revision="e37e2ab9e0ac5fd78607cbbe3505f9a0a40d7a14"/>
|
<project name="device/sprd" path="device/sprd" revision="1eb575040af22c58a16f90ecd04b6e1ebdee5c80"/>
|
||||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="2ea7f18a7bc45e16cb97a835dc86ee64d2d6b0b3"/>
|
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="2ea7f18a7bc45e16cb97a835dc86ee64d2d6b0b3"/>
|
||||||
<project name="platform/frameworks/av" path="frameworks/av" revision="fd359e3a74a658d9eaab1c683440ba5412535777"/>
|
<project name="platform/frameworks/av" path="frameworks/av" revision="fd359e3a74a658d9eaab1c683440ba5412535777"/>
|
||||||
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
|
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="97c3d9b8b87774ca7a08c89145e95b55652459ef"/>
|
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8b21ae3a28067fd69fc02271029bb1828e69e795"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||||
<project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
|
<project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="50d1ca4ab8add54523b7bc692860d57e8ee4c0d1"/>
|
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="50d1ca4ab8add54523b7bc692860d57e8ee4c0d1"/>
|
||||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="fb3845864573857677f9b500040a8f011eaf5078"/>
|
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="fb3845864573857677f9b500040a8f011eaf5078"/>
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="97c3d9b8b87774ca7a08c89145e95b55652459ef"/>
|
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8b21ae3a28067fd69fc02271029bb1828e69e795"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||||
<project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
|
<project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"git": {
|
"git": {
|
||||||
"git_revision": "4868c56c0a3b7a1e51d55b24457e44a7709ea1ae",
|
"git_revision": "738987bd80b0ddb4ccf853855388c2627e19dcc1",
|
||||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||||
"branch": ""
|
"branch": ""
|
||||||
},
|
},
|
||||||
"revision": "dbbbfe84294377ef3a7efaebcf57696a30b58cdb",
|
"revision": "00ea00a8e98d73a6556ece5d68c781fefec93810",
|
||||||
"repo_path": "integration/gaia-central"
|
"repo_path": "integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4868c56c0a3b7a1e51d55b24457e44a7709ea1ae"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="738987bd80b0ddb4ccf853855388c2627e19dcc1"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e9f0341416e97926d4cfdb1ff961ec4d4069b0a"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="33d5be1dca607d3a5cca5d87f53951cd991e1cdb"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="50d1ca4ab8add54523b7bc692860d57e8ee4c0d1"/>
|
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="50d1ca4ab8add54523b7bc692860d57e8ee4c0d1"/>
|
||||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="fb3845864573857677f9b500040a8f011eaf5078"/>
|
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="fb3845864573857677f9b500040a8f011eaf5078"/>
|
||||||
@ -149,7 +149,7 @@
|
|||||||
<project name="platform/hardware/broadcom/libbt" path="hardware/broadcom/libbt" revision="3e856528121ae0af0ca26c97cb563160c7e16d85"/>
|
<project name="platform/hardware/broadcom/libbt" path="hardware/broadcom/libbt" revision="3e856528121ae0af0ca26c97cb563160c7e16d85"/>
|
||||||
<project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="d9e716e14e685f4fc124ae591a1cd0899bc4d7b5"/>
|
<project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="d9e716e14e685f4fc124ae591a1cd0899bc4d7b5"/>
|
||||||
<project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="505aa92674337b76ce7d038800f2a6d7dc340ac9"/>
|
<project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="505aa92674337b76ce7d038800f2a6d7dc340ac9"/>
|
||||||
<project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="0a21f566d8c9b01b9754d639e13358bdcb6c7650"/>
|
<project name="hardware_qcom_display" path="hardware/qcom/display" remote="b2g" revision="c43952000d57f08b93a0e4fb77052871ce587976"/>
|
||||||
<project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="028649652cd8f8f18cfb47d34bd78c435eb030ca"/>
|
<project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="028649652cd8f8f18cfb47d34bd78c435eb030ca"/>
|
||||||
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="758a80fbb178b5663d4edbb46944b2dc553cb1ca"/>
|
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="758a80fbb178b5663d4edbb46944b2dc553cb1ca"/>
|
||||||
<project name="platform/hardware/qcom/msm8x74" path="hardware/qcom/msm8x74" revision="aa0124820e22302149b1f2db603a9a72f1972527"/>
|
<project name="platform/hardware/qcom/msm8x74" path="hardware/qcom/msm8x74" revision="aa0124820e22302149b1f2db603a9a72f1972527"/>
|
||||||
|
@ -1231,7 +1231,7 @@ pref("security.sandbox.windows.log.stackTraceDepth", 0);
|
|||||||
// This setting is read when the content process is started. On Mac the content
|
// This setting is read when the content process is started. On Mac the content
|
||||||
// process is killed when all windows are closed, so a change will take effect
|
// process is killed when all windows are closed, so a change will take effect
|
||||||
// when the 1st window is opened.
|
// when the 1st window is opened.
|
||||||
pref("security.sandbox.content.level", 0);
|
pref("security.sandbox.content.level", 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This pref governs whether we attempt to work around problems caused by
|
// This pref governs whether we attempt to work around problems caused by
|
||||||
|
@ -182,7 +182,6 @@ skip-if = e10s # Bug 866413 - PageInfo doesn't work in e10s
|
|||||||
[browser_bug462289.js]
|
[browser_bug462289.js]
|
||||||
skip-if = toolkit == "cocoa" || e10s # Bug 1102017 - middle-button mousedown on selected tab2 does not activate tab - Didn't expect [object XULElement], but got it
|
skip-if = toolkit == "cocoa" || e10s # Bug 1102017 - middle-button mousedown on selected tab2 does not activate tab - Didn't expect [object XULElement], but got it
|
||||||
[browser_bug462673.js]
|
[browser_bug462673.js]
|
||||||
skip-if = e10s # Bug 1093404 - test expects sync window opening from content and is disappointed in that expectation
|
|
||||||
[browser_bug477014.js]
|
[browser_bug477014.js]
|
||||||
[browser_bug479408.js]
|
[browser_bug479408.js]
|
||||||
skip-if = buildapp == 'mulet'
|
skip-if = buildapp == 'mulet'
|
||||||
|
@ -1,61 +1,36 @@
|
|||||||
var runs = [
|
add_task(function* () {
|
||||||
function (win, tabbrowser, tab) {
|
|
||||||
is(tabbrowser.browsers.length, 2, "test_bug462673.html has opened a second tab");
|
|
||||||
is(tabbrowser.selectedTab, tab.nextSibling, "dependent tab is selected");
|
|
||||||
tabbrowser.removeTab(tab);
|
|
||||||
// Closing a tab will also close its parent chrome window, but async
|
|
||||||
executeSoon(function() {
|
|
||||||
ok(win.closed, "Window is closed");
|
|
||||||
testComplete(win);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
function (win, tabbrowser, tab) {
|
|
||||||
var newTab = tabbrowser.addTab();
|
|
||||||
var newBrowser = newTab.linkedBrowser;
|
|
||||||
tabbrowser.removeTab(tab);
|
|
||||||
ok(!win.closed, "Window stays open");
|
|
||||||
if (!win.closed) {
|
|
||||||
is(tabbrowser.tabContainer.childElementCount, 1, "Window has one tab");
|
|
||||||
is(tabbrowser.browsers.length, 1, "Window has one browser");
|
|
||||||
is(tabbrowser.selectedTab, newTab, "Remaining tab is selected");
|
|
||||||
is(tabbrowser.selectedBrowser, newBrowser, "Browser for remaining tab is selected");
|
|
||||||
is(tabbrowser.mTabBox.selectedPanel, newBrowser.parentNode.parentNode.parentNode.parentNode, "Panel for remaining tab is selected");
|
|
||||||
}
|
|
||||||
testComplete(win);
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
runOneTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
function testComplete(win) {
|
|
||||||
win.close();
|
|
||||||
if (runs.length)
|
|
||||||
runOneTest();
|
|
||||||
else
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function runOneTest() {
|
|
||||||
var win = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
|
var win = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
|
||||||
|
yield SimpleTest.promiseFocus(win);
|
||||||
|
|
||||||
win.addEventListener("load", function () {
|
let tab = win.gBrowser.tabContainer.firstChild;
|
||||||
win.removeEventListener("load", arguments.callee, false);
|
yield promiseTabLoadEvent(tab, getRootDirectory(gTestPath) + "test_bug462673.html");
|
||||||
|
|
||||||
var tab = win.gBrowser.tabContainer.firstChild;
|
is(win.gBrowser.browsers.length, 2, "test_bug462673.html has opened a second tab");
|
||||||
var browser = tab.linkedBrowser;
|
is(win.gBrowser.selectedTab, tab.nextSibling, "dependent tab is selected");
|
||||||
|
win.gBrowser.removeTab(tab);
|
||||||
|
|
||||||
browser.addEventListener("load", function () {
|
// Closing a tab will also close its parent chrome window, but async
|
||||||
browser.removeEventListener("load", arguments.callee, true);
|
yield promiseWindowWillBeClosed(win);
|
||||||
|
});
|
||||||
|
|
||||||
executeSoon(function () {
|
add_task(function* () {
|
||||||
runs.shift()(win, win.gBrowser, tab);
|
var win = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
|
||||||
});
|
yield SimpleTest.promiseFocus(win);
|
||||||
}, true);
|
|
||||||
|
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
let tab = win.gBrowser.tabContainer.firstChild;
|
||||||
browser.contentWindow.location = rootDir + "test_bug462673.html"
|
yield promiseTabLoadEvent(tab, getRootDirectory(gTestPath) + "test_bug462673.html");
|
||||||
}, false);
|
|
||||||
}
|
var newTab = win.gBrowser.addTab();
|
||||||
|
var newBrowser = newTab.linkedBrowser;
|
||||||
|
win.gBrowser.removeTab(tab);
|
||||||
|
ok(!win.closed, "Window stays open");
|
||||||
|
if (!win.closed) {
|
||||||
|
is(win.gBrowser.tabContainer.childElementCount, 1, "Window has one tab");
|
||||||
|
is(win.gBrowser.browsers.length, 1, "Window has one browser");
|
||||||
|
is(win.gBrowser.selectedTab, newTab, "Remaining tab is selected");
|
||||||
|
is(win.gBrowser.selectedBrowser, newBrowser, "Browser for remaining tab is selected");
|
||||||
|
is(win.gBrowser.mTabBox.selectedPanel, newBrowser.parentNode.parentNode.parentNode.parentNode, "Panel for remaining tab is selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
yield promiseWindowClosed(win);
|
||||||
|
});
|
||||||
|
@ -34,7 +34,7 @@ function test() {
|
|||||||
chain: null,
|
chain: null,
|
||||||
loc: [[1, 4], [1, 7]]
|
loc: [[1, 4], [1, 7]]
|
||||||
});
|
});
|
||||||
verify("\nvar\nfoo\n=\n(\n)\n=>\n{\n}\n", e => e.type == "ArrowFunctionExpression", {
|
verify("\nvar\nfoo\n=\n(\n)=>\n{\n}\n", e => e.type == "ArrowFunctionExpression", {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
chain: null,
|
chain: null,
|
||||||
loc: [[3, 0], [3, 3]]
|
loc: [[3, 0], [3, 3]]
|
||||||
@ -45,31 +45,31 @@ function test() {
|
|||||||
verify("foo=()=>{}", e => e.type == "ArrowFunctionExpression",
|
verify("foo=()=>{}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "foo", chain: [], loc: [[1, 0], [1, 3]] });
|
{ name: "foo", chain: [], loc: [[1, 0], [1, 3]] });
|
||||||
|
|
||||||
verify("\nfoo\n=\n(\n)\n=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nfoo\n=\n(\n)=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "foo", chain: [], loc: [[2, 0], [2, 3]] });
|
{ name: "foo", chain: [], loc: [[2, 0], [2, 3]] });
|
||||||
|
|
||||||
verify("foo.bar=()=>{}", e => e.type == "ArrowFunctionExpression",
|
verify("foo.bar=()=>{}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[1, 0], [1, 7]] });
|
{ name: "bar", chain: ["foo"], loc: [[1, 0], [1, 7]] });
|
||||||
|
|
||||||
verify("\nfoo.bar\n=\n(\n)\n=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nfoo.bar\n=\n(\n)=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[2, 0], [2, 7]] });
|
{ name: "bar", chain: ["foo"], loc: [[2, 0], [2, 7]] });
|
||||||
|
|
||||||
verify("this.foo=()=>{}", e => e.type == "ArrowFunctionExpression",
|
verify("this.foo=()=>{}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "foo", chain: ["this"], loc: [[1, 0], [1, 8]] });
|
{ name: "foo", chain: ["this"], loc: [[1, 0], [1, 8]] });
|
||||||
|
|
||||||
verify("\nthis.foo\n=\n(\n)\n=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.foo\n=\n(\n)=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "foo", chain: ["this"], loc: [[2, 0], [2, 8]] });
|
{ name: "foo", chain: ["this"], loc: [[2, 0], [2, 8]] });
|
||||||
|
|
||||||
verify("this.foo.bar=()=>{}", e => e.type == "ArrowFunctionExpression",
|
verify("this.foo.bar=()=>{}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["this", "foo"], loc: [[1, 0], [1, 12]] });
|
{ name: "bar", chain: ["this", "foo"], loc: [[1, 0], [1, 12]] });
|
||||||
|
|
||||||
verify("\nthis.foo.bar\n=\n(\n)\n=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.foo.bar\n=\n(\n)=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["this", "foo"], loc: [[2, 0], [2, 12]] });
|
{ name: "bar", chain: ["this", "foo"], loc: [[2, 0], [2, 12]] });
|
||||||
|
|
||||||
verify("foo.this.bar=()=>{}", e => e.type == "ArrowFunctionExpression",
|
verify("foo.this.bar=()=>{}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo", "this"], loc: [[1, 0], [1, 12]] });
|
{ name: "bar", chain: ["foo", "this"], loc: [[1, 0], [1, 12]] });
|
||||||
|
|
||||||
verify("\nfoo.this.bar\n=\n(\n)\n=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nfoo.this.bar\n=\n(\n)=>\n{\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo", "this"], loc: [[2, 0], [2, 12]] });
|
{ name: "bar", chain: ["foo", "this"], loc: [[2, 0], [2, 12]] });
|
||||||
|
|
||||||
// ObjectExpression
|
// ObjectExpression
|
||||||
@ -77,13 +77,13 @@ function test() {
|
|||||||
verify("({foo:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("({foo:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "foo", chain: [], loc: [[1, 2], [1, 5]] });
|
{ name: "foo", chain: [], loc: [[1, 2], [1, 5]] });
|
||||||
|
|
||||||
verify("(\n{\nfoo\n:\n(\n)\n=>\n{\n}\n}\n)", e => e.type == "ArrowFunctionExpression",
|
verify("(\n{\nfoo\n:\n(\n)=>\n{\n}\n}\n)", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "foo", chain: [], loc: [[3, 0], [3, 3]] });
|
{ name: "foo", chain: [], loc: [[3, 0], [3, 3]] });
|
||||||
|
|
||||||
verify("({foo:{bar:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("({foo:{bar:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[1, 7], [1, 10]] });
|
{ name: "bar", chain: ["foo"], loc: [[1, 7], [1, 10]] });
|
||||||
|
|
||||||
verify("(\n{\nfoo\n:\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n}\n)", e => e.type == "ArrowFunctionExpression",
|
verify("(\n{\nfoo\n:\n{\nbar\n:\n(\n)=>\n{\n}\n}\n}\n)", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[6, 0], [6, 3]] });
|
{ name: "bar", chain: ["foo"], loc: [[6, 0], [6, 3]] });
|
||||||
|
|
||||||
// AssignmentExpression + ObjectExpression
|
// AssignmentExpression + ObjectExpression
|
||||||
@ -91,61 +91,61 @@ function test() {
|
|||||||
verify("foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
verify("foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[1, 5], [1, 8]] });
|
{ name: "bar", chain: ["foo"], loc: [[1, 5], [1, 8]] });
|
||||||
|
|
||||||
verify("\nfoo\n=\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nfoo\n=\n{\nbar\n:\n(\n)=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: ["foo"], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
verify("foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["foo", "bar"], loc: [[1, 10], [1, 13]] });
|
{ name: "baz", chain: ["foo", "bar"], loc: [[1, 10], [1, 13]] });
|
||||||
|
|
||||||
verify("\nfoo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nfoo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["foo", "bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["foo", "bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("nested.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
verify("nested.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["nested", "foo"], loc: [[1, 12], [1, 15]] });
|
{ name: "bar", chain: ["nested", "foo"], loc: [[1, 12], [1, 15]] });
|
||||||
|
|
||||||
verify("\nnested.foo\n=\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.foo\n=\n{\nbar\n:\n(\n)=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["nested", "foo"], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: ["nested", "foo"], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("nested.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
verify("nested.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["nested", "foo", "bar"], loc: [[1, 17], [1, 20]] });
|
{ name: "baz", chain: ["nested", "foo", "bar"], loc: [[1, 17], [1, 20]] });
|
||||||
|
|
||||||
verify("\nnested.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["nested", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["nested", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("this.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
verify("this.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["this", "foo"], loc: [[1, 10], [1, 13]] });
|
{ name: "bar", chain: ["this", "foo"], loc: [[1, 10], [1, 13]] });
|
||||||
|
|
||||||
verify("\nthis.foo\n=\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.foo\n=\n{\nbar\n:\n(\n)=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["this", "foo"], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: ["this", "foo"], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("this.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
verify("this.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["this", "foo", "bar"], loc: [[1, 15], [1, 18]] });
|
{ name: "baz", chain: ["this", "foo", "bar"], loc: [[1, 15], [1, 18]] });
|
||||||
|
|
||||||
verify("\nthis.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["this", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["this", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("this.nested.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
verify("this.nested.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["this", "nested", "foo"], loc: [[1, 17], [1, 20]] });
|
{ name: "bar", chain: ["this", "nested", "foo"], loc: [[1, 17], [1, 20]] });
|
||||||
|
|
||||||
verify("\nthis.nested.foo\n=\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.nested.foo\n=\n{\nbar\n:\n(\n)=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["this", "nested", "foo"], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: ["this", "nested", "foo"], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("this.nested.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
verify("this.nested.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["this", "nested", "foo", "bar"], loc: [[1, 22], [1, 25]] });
|
{ name: "baz", chain: ["this", "nested", "foo", "bar"], loc: [[1, 22], [1, 25]] });
|
||||||
|
|
||||||
verify("\nthis.nested.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.nested.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["this", "nested", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["this", "nested", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("nested.this.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
verify("nested.this.foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["nested", "this", "foo"], loc: [[1, 17], [1, 20]] });
|
{ name: "bar", chain: ["nested", "this", "foo"], loc: [[1, 17], [1, 20]] });
|
||||||
|
|
||||||
verify("\nnested.this.foo\n=\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.this.foo\n=\n{\nbar\n:\n(\n)=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["nested", "this", "foo"], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: ["nested", "this", "foo"], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("nested.this.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
verify("nested.this.foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["nested", "this", "foo", "bar"], loc: [[1, 22], [1, 25]] });
|
{ name: "baz", chain: ["nested", "this", "foo", "bar"], loc: [[1, 22], [1, 25]] });
|
||||||
|
|
||||||
verify("\nnested.this.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.this.foo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["nested", "this", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["nested", "this", "foo", "bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
// VariableDeclarator + AssignmentExpression + ObjectExpression
|
// VariableDeclarator + AssignmentExpression + ObjectExpression
|
||||||
@ -153,13 +153,13 @@ function test() {
|
|||||||
verify("let foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
verify("let foo={bar:()=>{}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[1, 9], [1, 12]] });
|
{ name: "bar", chain: ["foo"], loc: [[1, 9], [1, 12]] });
|
||||||
|
|
||||||
verify("\nlet\nfoo\n=\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\nfoo\n=\n{\nbar\n:\n(\n)=>\n{\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["foo"], loc: [[6, 0], [6, 3]] });
|
{ name: "bar", chain: ["foo"], loc: [[6, 0], [6, 3]] });
|
||||||
|
|
||||||
verify("let foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
verify("let foo={bar:{baz:()=>{}}}", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["foo", "bar"], loc: [[1, 14], [1, 17]] });
|
{ name: "baz", chain: ["foo", "bar"], loc: [[1, 14], [1, 17]] });
|
||||||
|
|
||||||
verify("\nlet\nfoo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\nfoo\n=\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["foo", "bar"], loc: [[9, 0], [9, 3]] });
|
{ name: "baz", chain: ["foo", "bar"], loc: [[9, 0], [9, 3]] });
|
||||||
|
|
||||||
// New/CallExpression + AssignmentExpression + ObjectExpression
|
// New/CallExpression + AssignmentExpression + ObjectExpression
|
||||||
@ -167,61 +167,61 @@ function test() {
|
|||||||
verify("foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[1, 5], [1, 8]] });
|
{ name: "bar", chain: [], loc: [[1, 5], [1, 8]] });
|
||||||
|
|
||||||
verify("\nfoo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nfoo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[1, 10], [1, 13]] });
|
{ name: "baz", chain: ["bar"], loc: [[1, 10], [1, 13]] });
|
||||||
|
|
||||||
verify("\nfoo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nfoo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[1, 12], [1, 15]] });
|
{ name: "bar", chain: [], loc: [[1, 12], [1, 15]] });
|
||||||
|
|
||||||
verify("\nnested.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[1, 17], [1, 20]] });
|
{ name: "baz", chain: ["bar"], loc: [[1, 17], [1, 20]] });
|
||||||
|
|
||||||
verify("\nnested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[1, 10], [1, 13]] });
|
{ name: "bar", chain: [], loc: [[1, 10], [1, 13]] });
|
||||||
|
|
||||||
verify("\nthis.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[1, 15], [1, 18]] });
|
{ name: "baz", chain: ["bar"], loc: [[1, 15], [1, 18]] });
|
||||||
|
|
||||||
verify("\nthis.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("this.nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("this.nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[1, 17], [1, 20]] });
|
{ name: "bar", chain: [], loc: [[1, 17], [1, 20]] });
|
||||||
|
|
||||||
verify("\nthis.nested.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.nested.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("this.nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("this.nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[1, 22], [1, 25]] });
|
{ name: "baz", chain: ["bar"], loc: [[1, 22], [1, 25]] });
|
||||||
|
|
||||||
verify("\nthis.nested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nthis.nested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
verify("nested.this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("nested.this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[1, 17], [1, 20]] });
|
{ name: "bar", chain: [], loc: [[1, 17], [1, 20]] });
|
||||||
|
|
||||||
verify("\nnested.this.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.this.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
{ name: "bar", chain: [], loc: [[5, 0], [5, 3]] });
|
||||||
|
|
||||||
verify("nested.this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("nested.this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[1, 22], [1, 25]] });
|
{ name: "baz", chain: ["bar"], loc: [[1, 22], [1, 25]] });
|
||||||
|
|
||||||
verify("\nnested.this.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nnested.this.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
{ name: "baz", chain: ["bar"], loc: [[8, 0], [8, 3]] });
|
||||||
|
|
||||||
// New/CallExpression + VariableDeclarator + AssignmentExpression + ObjectExpression
|
// New/CallExpression + VariableDeclarator + AssignmentExpression + ObjectExpression
|
||||||
@ -229,61 +229,61 @@ function test() {
|
|||||||
verify("let target=foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[1, 16], [1, 19]] });
|
{ name: "bar", chain: ["target"], loc: [[1, 16], [1, 19]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nfoo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nfoo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
||||||
|
|
||||||
verify("let target=foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[1, 21], [1, 24]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[1, 21], [1, 24]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nfoo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nfoo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
||||||
|
|
||||||
verify("let target=nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[1, 23], [1, 26]] });
|
{ name: "bar", chain: ["target"], loc: [[1, 23], [1, 26]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nnested.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nnested.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
||||||
|
|
||||||
verify("let target=nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[1, 28], [1, 31]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[1, 28], [1, 31]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nnested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nnested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
||||||
|
|
||||||
verify("let target=this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[1, 21], [1, 24]] });
|
{ name: "bar", chain: ["target"], loc: [[1, 21], [1, 24]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nthis.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nthis.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
||||||
|
|
||||||
verify("let target=this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[1, 26], [1, 29]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[1, 26], [1, 29]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nthis.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nthis.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
||||||
|
|
||||||
verify("let target=this.nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=this.nested.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[1, 28], [1, 31]] });
|
{ name: "bar", chain: ["target"], loc: [[1, 28], [1, 31]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nthis.nested.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nthis.nested.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
||||||
|
|
||||||
verify("let target=this.nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=this.nested.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[1, 33], [1, 36]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[1, 33], [1, 36]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nthis.nested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nthis.nested.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
||||||
|
|
||||||
verify("let target=nested.this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=nested.this.foo({bar:()=>{}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[1, 28], [1, 31]] });
|
{ name: "bar", chain: ["target"], loc: [[1, 28], [1, 31]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nnested.this.foo\n(\n{\nbar\n:\n(\n)\n=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nnested.this.foo\n(\n{\nbar\n:\n(\n)=>\n{\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
{ name: "bar", chain: ["target"], loc: [[7, 0], [7, 3]] });
|
||||||
|
|
||||||
verify("let target=nested.this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
verify("let target=nested.this.foo({bar:{baz:()=>{}}})", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[1, 33], [1, 36]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[1, 33], [1, 36]] });
|
||||||
|
|
||||||
verify("\nlet\ntarget=\nnested.this.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)\n=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
verify("\nlet\ntarget=\nnested.this.foo\n(\n{\nbar\n:\n{\nbaz\n:\n(\n)=>\n{\n}\n}\n}\n)\n", e => e.type == "ArrowFunctionExpression",
|
||||||
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
{ name: "baz", chain: ["target", "bar"], loc: [[10, 0], [10, 3]] });
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
|
@ -737,6 +737,18 @@
|
|||||||
@RESPATH@/res/table-remove-row-active.gif
|
@RESPATH@/res/table-remove-row-active.gif
|
||||||
@RESPATH@/res/table-remove-row-hover.gif
|
@RESPATH@/res/table-remove-row-hover.gif
|
||||||
@RESPATH@/res/table-remove-row.gif
|
@RESPATH@/res/table-remove-row.gif
|
||||||
|
@RESPATH@/res/text_caret.png
|
||||||
|
@RESPATH@/res/text_caret@1.5x.png
|
||||||
|
@RESPATH@/res/text_caret@2.25x.png
|
||||||
|
@RESPATH@/res/text_caret@2x.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_left.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_left@1.5x.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_left@2.25x.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_left@2x.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_right.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_right@1.5x.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_right@2.25x.png
|
||||||
|
@RESPATH@/res/text_caret_tilt_right@2x.png
|
||||||
@RESPATH@/res/grabber.gif
|
@RESPATH@/res/grabber.gif
|
||||||
#ifdef XP_MACOSX
|
#ifdef XP_MACOSX
|
||||||
@RESPATH@/res/cursors/*
|
@RESPATH@/res/cursors/*
|
||||||
|
@ -339,10 +339,9 @@
|
|||||||
.defaultView
|
.defaultView
|
||||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||||
let resx = {}, resy = {};
|
let res = {};
|
||||||
cwu.getResolution(resx, resy);
|
cwu.getResolution(res);
|
||||||
// Resolution set by the apzc and is symmetric.
|
return res.value;
|
||||||
return resx.value;
|
|
||||||
]]></getter>
|
]]></getter>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
@ -852,9 +852,15 @@ nsContentSink::PrefetchDNS(const nsAString &aHref)
|
|||||||
if (!uri) {
|
if (!uri) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nsAutoCString host;
|
nsresult rv;
|
||||||
uri->GetHost(host);
|
bool isLocalResource = false;
|
||||||
CopyUTF8toUTF16(host, hostname);
|
rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
|
||||||
|
&isLocalResource);
|
||||||
|
if (NS_SUCCEEDED(rv) && !isLocalResource) {
|
||||||
|
nsAutoCString host;
|
||||||
|
uri->GetHost(host);
|
||||||
|
CopyUTF8toUTF16(host, hostname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
|
if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
|
||||||
|
@ -6491,6 +6491,11 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
|||||||
AutoJSAPI jsapi;
|
AutoJSAPI jsapi;
|
||||||
jsapi.Init();
|
jsapi.Init();
|
||||||
JSContext* cx = jsapi.cx();
|
JSContext* cx = jsapi.cx();
|
||||||
|
|
||||||
|
// Failure to create or run the regexp results in the invalid pattern
|
||||||
|
// matching, but we can still report the error to the console.
|
||||||
|
jsapi.TakeOwnershipOfErrorReporting();
|
||||||
|
|
||||||
// We can use the junk scope here, because we're just using it for
|
// We can use the junk scope here, because we're just using it for
|
||||||
// regexp evaluation, not actual script execution.
|
// regexp evaluation, not actual script execution.
|
||||||
JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope());
|
JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope());
|
||||||
@ -6504,7 +6509,6 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
|||||||
static_cast<char16_t*>(aPattern.BeginWriting()),
|
static_cast<char16_t*>(aPattern.BeginWriting()),
|
||||||
aPattern.Length(), 0));
|
aPattern.Length(), 0));
|
||||||
if (!re) {
|
if (!re) {
|
||||||
JS_ClearPendingException(cx);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6513,7 +6517,6 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
|||||||
if (!JS_ExecuteRegExpNoStatics(cx, re,
|
if (!JS_ExecuteRegExpNoStatics(cx, re,
|
||||||
static_cast<char16_t*>(aValue.BeginWriting()),
|
static_cast<char16_t*>(aValue.BeginWriting()),
|
||||||
aValue.Length(), &idx, true, &rval)) {
|
aValue.Length(), &idx, true, &rval)) {
|
||||||
JS_ClearPendingException(cx);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,7 +490,7 @@ nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX,
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
|
nsDOMWindowUtils::SetResolution(float aResolution)
|
||||||
{
|
{
|
||||||
if (!nsContentUtils::IsCallerChrome()) {
|
if (!nsContentUtils::IsCallerChrome()) {
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
@ -503,15 +503,15 @@ nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
|
|||||||
|
|
||||||
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
||||||
if (sf) {
|
if (sf) {
|
||||||
sf->SetResolution(gfxSize(aXResolution, aYResolution));
|
sf->SetResolution(aResolution);
|
||||||
presShell->SetResolution(aXResolution, aYResolution);
|
presShell->SetResolution(aResolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::SetResolutionAndScaleTo(float aXResolution, float aYResolution)
|
nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution)
|
||||||
{
|
{
|
||||||
if (!nsContentUtils::IsCallerChrome()) {
|
if (!nsContentUtils::IsCallerChrome()) {
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
@ -524,15 +524,15 @@ nsDOMWindowUtils::SetResolutionAndScaleTo(float aXResolution, float aYResolution
|
|||||||
|
|
||||||
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
||||||
if (sf) {
|
if (sf) {
|
||||||
sf->SetResolutionAndScaleTo(gfxSize(aXResolution, aYResolution));
|
sf->SetResolutionAndScaleTo(aResolution);
|
||||||
presShell->SetResolutionAndScaleTo(aXResolution, aYResolution);
|
presShell->SetResolutionAndScaleTo(aResolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
|
nsDOMWindowUtils::GetResolution(float* aResolution)
|
||||||
{
|
{
|
||||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
||||||
|
|
||||||
@ -543,12 +543,9 @@ nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
|
|||||||
|
|
||||||
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
||||||
if (sf) {
|
if (sf) {
|
||||||
const gfxSize& res = sf->GetResolution();
|
*aResolution = sf->GetResolution();
|
||||||
*aXResolution = res.width;
|
|
||||||
*aYResolution = res.height;
|
|
||||||
} else {
|
} else {
|
||||||
*aXResolution = presShell->GetXResolution();
|
*aResolution = presShell->GetResolution();
|
||||||
*aYResolution = presShell->GetYResolution();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -12844,6 +12844,35 @@ nsIDocument::CreateHTMLElement(nsIAtom* aTag)
|
|||||||
return element.forget();
|
return element.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsIDocument::GetId(nsAString& aId)
|
||||||
|
{
|
||||||
|
if (mId.IsEmpty()) {
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsIUUIDGenerator> uuidgen = do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsID id;
|
||||||
|
rv = uuidgen->GenerateUUIDInPlace(&id);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format
|
||||||
|
char buffer[NSID_LENGTH];
|
||||||
|
id.ToProvidedString(buffer);
|
||||||
|
NS_ConvertASCIItoUTF16 uuid(buffer);
|
||||||
|
|
||||||
|
// Remove {} and the null terminator
|
||||||
|
mId.Assign(Substring(uuid, 1, NSID_LENGTH - 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
aId = mId;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
|
MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include "nsILoadGroup.h" // for member (in nsCOMPtr)
|
#include "nsILoadGroup.h" // for member (in nsCOMPtr)
|
||||||
#include "nsINode.h" // for base class
|
#include "nsINode.h" // for base class
|
||||||
#include "nsIScriptGlobalObject.h" // for member (in nsCOMPtr)
|
#include "nsIScriptGlobalObject.h" // for member (in nsCOMPtr)
|
||||||
|
#include "nsIServiceManager.h"
|
||||||
|
#include "nsIUUIDGenerator.h"
|
||||||
#include "nsPIDOMWindow.h" // for use in inline functions
|
#include "nsPIDOMWindow.h" // for use in inline functions
|
||||||
#include "nsPropertyTable.h" // for member
|
#include "nsPropertyTable.h" // for member
|
||||||
#include "nsTHashtable.h" // for member
|
#include "nsTHashtable.h" // for member
|
||||||
@ -747,6 +749,8 @@ public:
|
|||||||
return mAnonymousContents;
|
return mAnonymousContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult GetId(nsAString& aId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Element *GetRootElementInternal() const = 0;
|
virtual Element *GetRootElementInternal() const = 0;
|
||||||
|
|
||||||
@ -2798,6 +2802,7 @@ protected:
|
|||||||
nsCOMPtr<nsIChannel> mChannel;
|
nsCOMPtr<nsIChannel> mChannel;
|
||||||
private:
|
private:
|
||||||
nsCString mContentType;
|
nsCString mContentType;
|
||||||
|
nsString mId;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// The document's security info
|
// The document's security info
|
||||||
|
@ -1117,9 +1117,9 @@ PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU)
|
|||||||
return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
|
return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
|
||||||
}
|
}
|
||||||
|
|
||||||
PRUint32 clen = cstr.Length() + 1; /* include \0 character */
|
uint32_t clen = cstr.Length() + 1; /* include \0 character */
|
||||||
|
|
||||||
rv = PackPDU(PackConversion<PRUint32, uint8_t>(clen), aPDU);
|
rv = PackPDU(PackConversion<uint32_t, uint8_t>(clen), aPDU);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -853,54 +853,45 @@ BluetoothAdapter::HandleDeviceFound(const BluetoothValue& aValue)
|
|||||||
void
|
void
|
||||||
BluetoothAdapter::HandleDevicePaired(const BluetoothValue& aValue)
|
BluetoothAdapter::HandleDevicePaired(const BluetoothValue& aValue)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
|
if (NS_WARN_IF(mState != BluetoothAdapterState::Enabled)) {
|
||||||
|
|
||||||
if (mState != BluetoothAdapterState::Enabled) {
|
|
||||||
BT_WARNING("HandleDevicePaired() is called when adapter isn't enabled.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
|
||||||
|
|
||||||
const InfallibleTArray<BluetoothNamedValue>& arr =
|
const InfallibleTArray<BluetoothNamedValue>& arr =
|
||||||
aValue.get_ArrayOfBluetoothNamedValue();
|
aValue.get_ArrayOfBluetoothNamedValue();
|
||||||
|
|
||||||
MOZ_ASSERT(arr.Length() == 3 &&
|
MOZ_ASSERT(arr.Length() == 3 &&
|
||||||
arr[0].value().type() == BluetoothValue::TnsString && // Address
|
arr[0].value().type() == BluetoothValue::TnsString && // Address
|
||||||
arr[1].value().type() == BluetoothValue::Tbool && // Paired
|
arr[1].value().type() == BluetoothValue::TnsString && // Name
|
||||||
arr[2].value().type() == BluetoothValue::TnsString); // Name
|
arr[2].value().type() == BluetoothValue::Tbool); // Paired
|
||||||
MOZ_ASSERT(!arr[0].value().get_nsString().IsEmpty() &&
|
MOZ_ASSERT(!arr[0].value().get_nsString().IsEmpty() &&
|
||||||
arr[1].value().get_bool());
|
arr[2].value().get_bool());
|
||||||
|
|
||||||
nsString deviceAddress = arr[0].value().get_nsString();
|
// Append the paired device if it doesn't exist in adapter's devices array
|
||||||
|
size_t index = mDevices.IndexOf(arr[0].value().get_nsString());
|
||||||
nsRefPtr<BluetoothDevice> pairedDevice = nullptr;
|
|
||||||
|
|
||||||
// Check whether or not the address exists in mDevices.
|
|
||||||
size_t index = mDevices.IndexOf(deviceAddress);
|
|
||||||
if (index == mDevices.NoIndex) {
|
if (index == mDevices.NoIndex) {
|
||||||
// Create a new device and append it to adapter's device array
|
index = mDevices.Length(); // the new device's index
|
||||||
pairedDevice = BluetoothDevice::Create(GetOwner(), aValue);
|
mDevices.AppendElement(
|
||||||
mDevices.AppendElement(pairedDevice);
|
BluetoothDevice::Create(GetOwner(), aValue));
|
||||||
} else {
|
|
||||||
// Use existing device
|
|
||||||
pairedDevice = mDevices[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify application of paired device
|
// Notify application of paired device
|
||||||
BluetoothDeviceEventInit init;
|
BluetoothDeviceEventInit init;
|
||||||
init.mDevice = pairedDevice;
|
init.mDevice = mDevices[index];
|
||||||
DispatchDeviceEvent(NS_LITERAL_STRING("devicepaired"), init);
|
DispatchDeviceEvent(NS_LITERAL_STRING(DEVICE_PAIRED_ID), init);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothAdapter::HandleDeviceUnpaired(const BluetoothValue& aValue)
|
BluetoothAdapter::HandleDeviceUnpaired(const BluetoothValue& aValue)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
|
if (NS_WARN_IF(mState != BluetoothAdapterState::Enabled)) {
|
||||||
|
|
||||||
if (mState != BluetoothAdapterState::Enabled) {
|
|
||||||
BT_WARNING("HandleDeviceUnpaired() is called when adapter isn't enabled.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
|
||||||
|
|
||||||
const InfallibleTArray<BluetoothNamedValue>& arr =
|
const InfallibleTArray<BluetoothNamedValue>& arr =
|
||||||
aValue.get_ArrayOfBluetoothNamedValue();
|
aValue.get_ArrayOfBluetoothNamedValue();
|
||||||
|
|
||||||
@ -910,15 +901,14 @@ BluetoothAdapter::HandleDeviceUnpaired(const BluetoothValue& aValue)
|
|||||||
MOZ_ASSERT(!arr[0].value().get_nsString().IsEmpty() &&
|
MOZ_ASSERT(!arr[0].value().get_nsString().IsEmpty() &&
|
||||||
!arr[1].value().get_bool());
|
!arr[1].value().get_bool());
|
||||||
|
|
||||||
nsString deviceAddress = arr[0].value().get_nsString();
|
|
||||||
|
|
||||||
// Remove the device with the same address
|
// Remove the device with the same address
|
||||||
|
nsString deviceAddress = arr[0].value().get_nsString();
|
||||||
mDevices.RemoveElement(deviceAddress);
|
mDevices.RemoveElement(deviceAddress);
|
||||||
|
|
||||||
// Notify application of unpaired device
|
// Notify application of unpaired device
|
||||||
BluetoothDeviceEventInit init;
|
BluetoothDeviceEventInit init;
|
||||||
init.mAddress = deviceAddress;
|
init.mAddress = deviceAddress;
|
||||||
DispatchDeviceEvent(NS_LITERAL_STRING("deviceunpaired"), init);
|
DispatchDeviceEvent(NS_LITERAL_STRING(DEVICE_UNPAIRED_ID), init);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -338,19 +338,20 @@ private:
|
|||||||
nsRefPtr<BluetoothDiscoveryHandle> mDiscoveryHandleInUse;
|
nsRefPtr<BluetoothDiscoveryHandle> mDiscoveryHandleInUse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arrays of references to BluetoothDevices created by this adapter.
|
* nsRefPtr array of BluetoothDevices created by this adapter. The array is
|
||||||
* This array is empty when adapter state is Disabled.
|
* empty when adapter state is Disabled.
|
||||||
*
|
*
|
||||||
* Devices will be appended when
|
* Devices will be appended when
|
||||||
* 1) Enabling BT: Paired devices reported by stack.
|
* 1) adapter is enabling: Paired devices reported by stack.
|
||||||
* 2) Discovering: Discovered devices during discovery operation.
|
* 2) adapter is discovering: Discovered devices during discovery operation.
|
||||||
* A device won't be appended if a device object with the same
|
* 3) adapter paired with a device: The paired device reported by stack.
|
||||||
* address already exists.
|
* Note devices with identical address won't be appended.
|
||||||
*
|
*
|
||||||
* Devices will be removed when
|
* Devices will be removed when
|
||||||
* 1) Starting discovery: All unpaired devices will be removed before this
|
* 1) adapter is disabling: All devices will be removed.
|
||||||
* adapter starts a new discovery.
|
* 2) adapter starts discovery: All unpaired devices will be removed before
|
||||||
* 2) Disabling BT: All devices will be removed.
|
* this new discovery starts.
|
||||||
|
* 3) adapter unpaired with a device: The unpaired device will be removed.
|
||||||
*/
|
*/
|
||||||
nsTArray<nsRefPtr<BluetoothDevice> > mDevices;
|
nsTArray<nsRefPtr<BluetoothDevice> > mDevices;
|
||||||
};
|
};
|
||||||
|
@ -167,6 +167,55 @@ BluetoothGatt::Disconnect(ErrorResult& aRv)
|
|||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReadRemoteRssiTask MOZ_FINAL : public BluetoothReplyRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReadRemoteRssiTask(Promise* aPromise)
|
||||||
|
: BluetoothReplyRunnable(nullptr, aPromise,
|
||||||
|
NS_LITERAL_STRING("GattClientReadRemoteRssi"))
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
|
||||||
|
{
|
||||||
|
aValue.setUndefined();
|
||||||
|
|
||||||
|
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
|
||||||
|
NS_ENSURE_TRUE(v.type() == BluetoothValue::Tuint32_t, false);
|
||||||
|
|
||||||
|
aValue.setInt32(static_cast<int32_t>(v.get_uint32_t()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
BluetoothGatt::ReadRemoteRssi(ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||||
|
if (!global) {
|
||||||
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||||
|
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||||
|
|
||||||
|
BT_ENSURE_TRUE_REJECT(
|
||||||
|
mConnectionState == BluetoothConnectionState::Connected,
|
||||||
|
NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
|
||||||
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
|
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
|
||||||
|
|
||||||
|
nsRefPtr<BluetoothReplyRunnable> result =
|
||||||
|
new ReadRemoteRssiTask(promise);
|
||||||
|
bs->GattClientReadRemoteRssiInternal(mClientIf, mDeviceAddr, result);
|
||||||
|
|
||||||
|
return promise.forget();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothGatt::UpdateConnectionState(BluetoothConnectionState aState)
|
BluetoothGatt::UpdateConnectionState(BluetoothConnectionState aState)
|
||||||
{
|
{
|
||||||
|
@ -51,6 +51,7 @@ public:
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
already_AddRefed<Promise> Connect(ErrorResult& aRv);
|
already_AddRefed<Promise> Connect(ErrorResult& aRv);
|
||||||
already_AddRefed<Promise> Disconnect(ErrorResult& aRv);
|
already_AddRefed<Promise> Disconnect(ErrorResult& aRv);
|
||||||
|
already_AddRefed<Promise> ReadRemoteRssi(ErrorResult& aRv);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Others
|
* Others
|
||||||
|
@ -349,6 +349,13 @@ public:
|
|||||||
UnregisterGattClientInternal(int aClientIf,
|
UnregisterGattClientInternal(int aClientIf,
|
||||||
BluetoothReplyRunnable* aRunnable) = 0;
|
BluetoothReplyRunnable* aRunnable) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request RSSI for a remote GATT server. (platform specific implementation)
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
GattClientReadRemoteRssiInternal(int aClientIf,
|
||||||
|
const nsAString& aDeviceAddress,
|
||||||
|
BluetoothReplyRunnable* aRunnable) = 0;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsEnabled() const
|
IsEnabled() const
|
||||||
|
@ -1070,9 +1070,9 @@ PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU)
|
|||||||
return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
|
return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
|
||||||
}
|
}
|
||||||
|
|
||||||
PRUint32 clen = cstr.Length() + 1; /* include \0 character */
|
uint32_t clen = cstr.Length() + 1; /* include \0 character */
|
||||||
|
|
||||||
rv = PackPDU(PackConversion<PRUint32, uint8_t>(clen), aPDU);
|
rv = PackPDU(PackConversion<uint32_t, uint8_t>(clen), aPDU);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ public:
|
|||||||
mConnectRunnable = nullptr;
|
mConnectRunnable = nullptr;
|
||||||
mDisconnectRunnable = nullptr;
|
mDisconnectRunnable = nullptr;
|
||||||
mUnregisterClientRunnable = nullptr;
|
mUnregisterClientRunnable = nullptr;
|
||||||
|
mReadRemoteRssiRunnable = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsString mAppUuid;
|
nsString mAppUuid;
|
||||||
@ -66,6 +67,7 @@ public:
|
|||||||
nsRefPtr<BluetoothReplyRunnable> mConnectRunnable;
|
nsRefPtr<BluetoothReplyRunnable> mConnectRunnable;
|
||||||
nsRefPtr<BluetoothReplyRunnable> mDisconnectRunnable;
|
nsRefPtr<BluetoothReplyRunnable> mDisconnectRunnable;
|
||||||
nsRefPtr<BluetoothReplyRunnable> mUnregisterClientRunnable;
|
nsRefPtr<BluetoothReplyRunnable> mUnregisterClientRunnable;
|
||||||
|
nsRefPtr<BluetoothReplyRunnable> mReadRemoteRssiRunnable;
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS0(BluetoothGattClient)
|
NS_IMPL_ISUPPORTS0(BluetoothGattClient)
|
||||||
@ -484,6 +486,63 @@ BluetoothGattManager::Disconnect(const nsAString& aAppUuid,
|
|||||||
new DisconnectResultHandler(client));
|
new DisconnectResultHandler(client));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BluetoothGattManager::ReadRemoteRssiResultHandler MOZ_FINAL
|
||||||
|
: public BluetoothGattClientResultHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReadRemoteRssiResultHandler(BluetoothGattClient* aClient)
|
||||||
|
: mClient(aClient)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
BT_WARNING("BluetoothGattClientInterface::ReadRemoteRssi failed: %d",
|
||||||
|
(int)aStatus);
|
||||||
|
MOZ_ASSERT(mClient->mReadRemoteRssiRunnable);
|
||||||
|
|
||||||
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
|
NS_ENSURE_TRUE_VOID(bs);
|
||||||
|
|
||||||
|
// Reject the read remote rssi request
|
||||||
|
DispatchReplyError(mClient->mReadRemoteRssiRunnable,
|
||||||
|
NS_LITERAL_STRING("ReadRemoteRssi failed"));
|
||||||
|
mClient->mReadRemoteRssiRunnable = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsRefPtr<BluetoothGattClient> mClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothGattManager::ReadRemoteRssi(int aClientIf,
|
||||||
|
const nsAString& aDeviceAddr,
|
||||||
|
BluetoothReplyRunnable* aRunnable)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aRunnable);
|
||||||
|
|
||||||
|
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
|
||||||
|
|
||||||
|
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
|
||||||
|
ClientIfComparator());
|
||||||
|
|
||||||
|
// Reject the read remote rssi request if the client is not found
|
||||||
|
if (index == sClients->NoIndex) {
|
||||||
|
DispatchReplyError(aRunnable,
|
||||||
|
NS_LITERAL_STRING("Read remote RSSI failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||||
|
client->mReadRemoteRssiRunnable = aRunnable;
|
||||||
|
|
||||||
|
sBluetoothGattClientInterface->ReadRemoteRssi(
|
||||||
|
aClientIf, aDeviceAddr,
|
||||||
|
new ReadRemoteRssiResultHandler(client));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Notification Handlers
|
// Notification Handlers
|
||||||
//
|
//
|
||||||
@ -728,7 +787,40 @@ BluetoothGattManager::ReadRemoteRssiNotification(int aClientIf,
|
|||||||
const nsAString& aBdAddr,
|
const nsAString& aBdAddr,
|
||||||
int aRssi,
|
int aRssi,
|
||||||
BluetoothGattStatus aStatus)
|
BluetoothGattStatus aStatus)
|
||||||
{ }
|
{
|
||||||
|
BT_API2_LOGR();
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
|
NS_ENSURE_TRUE_VOID(bs);
|
||||||
|
|
||||||
|
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
|
||||||
|
ClientIfComparator());
|
||||||
|
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
|
||||||
|
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||||
|
|
||||||
|
if (aStatus != GATT_STATUS_SUCCESS) { // operation failed
|
||||||
|
BT_API2_LOGR("ReadRemoteRssi failed, clientIf = %d, bdAddr = %s, " \
|
||||||
|
"rssi = %d, status = %d", aClientIf,
|
||||||
|
NS_ConvertUTF16toUTF8(aBdAddr).get(), aRssi, (int)aStatus);
|
||||||
|
|
||||||
|
// Reject the read remote rssi request
|
||||||
|
if (client->mReadRemoteRssiRunnable) {
|
||||||
|
DispatchReplyError(client->mReadRemoteRssiRunnable,
|
||||||
|
NS_LITERAL_STRING("ReadRemoteRssi failed"));
|
||||||
|
client->mReadRemoteRssiRunnable = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the read remote rssi request
|
||||||
|
if (client->mReadRemoteRssiRunnable) {
|
||||||
|
DispatchReplySuccess(client->mReadRemoteRssiRunnable,
|
||||||
|
BluetoothValue(static_cast<uint32_t>(aRssi)));
|
||||||
|
client->mReadRemoteRssiRunnable = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothGattManager::ListenNotification(BluetoothGattStatus aStatus,
|
BluetoothGattManager::ListenNotification(BluetoothGattStatus aStatus,
|
||||||
|
@ -38,6 +38,10 @@ public:
|
|||||||
void UnregisterClient(int aClientIf,
|
void UnregisterClient(int aClientIf,
|
||||||
BluetoothReplyRunnable* aRunnable);
|
BluetoothReplyRunnable* aRunnable);
|
||||||
|
|
||||||
|
void ReadRemoteRssi(int aClientIf,
|
||||||
|
const nsAString& aDeviceAddr,
|
||||||
|
BluetoothReplyRunnable* aRunnable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class CleanupResultHandler;
|
class CleanupResultHandler;
|
||||||
class CleanupResultHandlerRunnable;
|
class CleanupResultHandlerRunnable;
|
||||||
@ -46,6 +50,7 @@ private:
|
|||||||
class UnregisterClientResultHandler;
|
class UnregisterClientResultHandler;
|
||||||
class ConnectResultHandler;
|
class ConnectResultHandler;
|
||||||
class DisconnectResultHandler;
|
class DisconnectResultHandler;
|
||||||
|
class ReadRemoteRssiResultHandler;
|
||||||
|
|
||||||
BluetoothGattManager();
|
BluetoothGattManager();
|
||||||
|
|
||||||
|
@ -1131,6 +1131,21 @@ BluetoothServiceBluedroid::UnregisterGattClientInternal(
|
|||||||
gatt->UnregisterClient(aClientIf, aRunnable);
|
gatt->UnregisterClient(aClientIf, aRunnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothServiceBluedroid::GattClientReadRemoteRssiInternal(
|
||||||
|
int aClientIf, const nsAString& aDeviceAddress,
|
||||||
|
BluetoothReplyRunnable* aRunnable)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
|
||||||
|
|
||||||
|
BluetoothGattManager* gatt = BluetoothGattManager::Get();
|
||||||
|
ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
|
||||||
|
|
||||||
|
gatt->ReadRemoteRssi(aClientIf, aDeviceAddress, aRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Bluetooth notifications
|
// Bluetooth notifications
|
||||||
//
|
//
|
||||||
|
@ -188,6 +188,11 @@ public:
|
|||||||
UnregisterGattClientInternal(int aClientIf,
|
UnregisterGattClientInternal(int aClientIf,
|
||||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
GattClientReadRemoteRssiInternal(
|
||||||
|
int aClientIf, const nsAString& aDeviceAddress,
|
||||||
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Bluetooth notifications
|
// Bluetooth notifications
|
||||||
//
|
//
|
||||||
|
@ -4296,3 +4296,10 @@ BluetoothDBusService::UnregisterGattClientInternal(
|
|||||||
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothDBusService::GattClientReadRemoteRssiInternal(
|
||||||
|
int aClientIf, const nsAString& aDeviceAddress,
|
||||||
|
BluetoothReplyRunnable* aRunnable)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -198,6 +198,11 @@ public:
|
|||||||
UnregisterGattClientInternal(int aClientIf,
|
UnregisterGattClientInternal(int aClientIf,
|
||||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
GattClientReadRemoteRssiInternal(
|
||||||
|
int aClientIf, const nsAString& aDeviceAddress,
|
||||||
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsresult SendGetPropertyMessage(const nsAString& aPath,
|
nsresult SendGetPropertyMessage(const nsAString& aPath,
|
||||||
const char* aInterface,
|
const char* aInterface,
|
||||||
|
@ -256,6 +256,8 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
|
|||||||
return actor->DoRequest(aRequest.get_DisconnectGattClientRequest());
|
return actor->DoRequest(aRequest.get_DisconnectGattClientRequest());
|
||||||
case Request::TUnregisterGattClientRequest:
|
case Request::TUnregisterGattClientRequest:
|
||||||
return actor->DoRequest(aRequest.get_UnregisterGattClientRequest());
|
return actor->DoRequest(aRequest.get_UnregisterGattClientRequest());
|
||||||
|
case Request::TGattClientReadRemoteRssiRequest:
|
||||||
|
return actor->DoRequest(aRequest.get_GattClientReadRemoteRssiRequest());
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("Unknown type!");
|
MOZ_CRASH("Unknown type!");
|
||||||
}
|
}
|
||||||
@ -728,3 +730,17 @@ BluetoothRequestParent::DoRequest(const UnregisterGattClientRequest& aRequest)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BluetoothRequestParent::DoRequest(
|
||||||
|
const GattClientReadRemoteRssiRequest& aRequest)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mService);
|
||||||
|
MOZ_ASSERT(mRequestType == Request::TGattClientReadRemoteRssiRequest);
|
||||||
|
|
||||||
|
mService->GattClientReadRemoteRssiInternal(aRequest.clientIf(),
|
||||||
|
aRequest.deviceAddress(),
|
||||||
|
mReplyRunnable.get());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -225,6 +225,9 @@ protected:
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
DoRequest(const UnregisterGattClientRequest& aRequest);
|
DoRequest(const UnregisterGattClientRequest& aRequest);
|
||||||
|
|
||||||
|
bool
|
||||||
|
DoRequest(const GattClientReadRemoteRssiRequest& aRequest);
|
||||||
};
|
};
|
||||||
|
|
||||||
END_BLUETOOTH_NAMESPACE
|
END_BLUETOOTH_NAMESPACE
|
||||||
|
@ -404,6 +404,16 @@ BluetoothServiceChildProcess::UnregisterGattClientInternal(
|
|||||||
SendRequest(aRunnable, UnregisterGattClientRequest(aClientIf));
|
SendRequest(aRunnable, UnregisterGattClientRequest(aClientIf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothServiceChildProcess::GattClientReadRemoteRssiInternal(
|
||||||
|
int aClientIf, const nsAString& aDeviceAddress,
|
||||||
|
BluetoothReplyRunnable* aRunnable)
|
||||||
|
{
|
||||||
|
SendRequest(aRunnable,
|
||||||
|
GattClientReadRemoteRssiRequest(aClientIf,
|
||||||
|
nsString(aDeviceAddress)));
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothServiceChildProcess::HandleStartup()
|
BluetoothServiceChildProcess::HandleStartup()
|
||||||
{
|
{
|
||||||
|
@ -206,6 +206,11 @@ public:
|
|||||||
UnregisterGattClientInternal(int aClientIf,
|
UnregisterGattClientInternal(int aClientIf,
|
||||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
GattClientReadRemoteRssiInternal(int aClientIf,
|
||||||
|
const nsAString& aDeviceAddress,
|
||||||
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BluetoothServiceChildProcess();
|
BluetoothServiceChildProcess();
|
||||||
virtual ~BluetoothServiceChildProcess();
|
virtual ~BluetoothServiceChildProcess();
|
||||||
|
@ -193,6 +193,12 @@ struct UnregisterGattClientRequest
|
|||||||
int clientIf;
|
int clientIf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GattClientReadRemoteRssiRequest
|
||||||
|
{
|
||||||
|
int clientIf;
|
||||||
|
nsString deviceAddress;
|
||||||
|
};
|
||||||
|
|
||||||
union Request
|
union Request
|
||||||
{
|
{
|
||||||
GetAdaptersRequest;
|
GetAdaptersRequest;
|
||||||
@ -228,6 +234,7 @@ union Request
|
|||||||
ConnectGattClientRequest;
|
ConnectGattClientRequest;
|
||||||
DisconnectGattClientRequest;
|
DisconnectGattClientRequest;
|
||||||
UnregisterGattClientRequest;
|
UnregisterGattClientRequest;
|
||||||
|
GattClientReadRemoteRssiRequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
protocol PBluetooth
|
protocol PBluetooth
|
||||||
|
4
dom/cache/ActorChild.cpp
vendored
4
dom/cache/ActorChild.cpp
vendored
@ -50,6 +50,10 @@ ActorChild::FeatureNotified() const
|
|||||||
return mFeature && mFeature->Notified();
|
return mFeature && mFeature->Notified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActorChild::ActorChild()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ActorChild::~ActorChild()
|
ActorChild::~ActorChild()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mFeature);
|
MOZ_ASSERT(!mFeature);
|
||||||
|
1
dom/cache/ActorChild.h
vendored
1
dom/cache/ActorChild.h
vendored
@ -34,6 +34,7 @@ public:
|
|||||||
FeatureNotified() const;
|
FeatureNotified() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ActorChild();
|
||||||
~ActorChild();
|
~ActorChild();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
3
dom/cache/test/mochitest/driver.js
vendored
3
dom/cache/test/mochitest/driver.js
vendored
@ -81,7 +81,8 @@ function runTests(testFile, order) {
|
|||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
if (typeof order == "undefined") {
|
if (typeof order == "undefined") {
|
||||||
order = "both"; // both by default
|
order = "sequential"; // sequential by default, see bug 1143222.
|
||||||
|
// TODO: Make this "both".
|
||||||
}
|
}
|
||||||
|
|
||||||
ok(order == "parallel" || order == "sequential" || order == "both",
|
ok(order == "parallel" || order == "sequential" || order == "both",
|
||||||
|
2
dom/cache/test/mochitest/mochitest.ini
vendored
2
dom/cache/test/mochitest/mochitest.ini
vendored
@ -14,6 +14,4 @@ support-files =
|
|||||||
[test_cache.html]
|
[test_cache.html]
|
||||||
[test_cache_add.html]
|
[test_cache_add.html]
|
||||||
[test_cache_match_request.html]
|
[test_cache_match_request.html]
|
||||||
skip-if = true # bug 1143222
|
|
||||||
[test_cache_matchAll_request.html]
|
[test_cache_matchAll_request.html]
|
||||||
skip-if = true # bug 1143222
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
var request1 = new Request("//mochi.test:8888/?1&" + context);
|
var request1 = new Request("//mochi.test:8888/?1&" + context + "#fragment");
|
||||||
var request2 = new Request("//mochi.test:8888/?2&" + context);
|
var request2 = new Request("//mochi.test:8888/?2&" + context);
|
||||||
var request3 = new Request("//mochi.test:8888/?3&" + context);
|
var request3 = new Request("//mochi.test:8888/?3&" + context);
|
||||||
|
var requestWithAltQS = new Request("//mochi.test:8888/?queryString");
|
||||||
|
var unknownRequest = new Request("//mochi.test:8888/non/existing/path?" + context);
|
||||||
var response1, response3;
|
var response1, response3;
|
||||||
var c;
|
var c;
|
||||||
var response1Text, response3Text;
|
var response1Text, response3Text;
|
||||||
@ -8,7 +10,8 @@ var name = "matchAll-request" + context;
|
|||||||
|
|
||||||
function checkResponse(r, response, responseText) {
|
function checkResponse(r, response, responseText) {
|
||||||
ok(r !== response, "The objects should not be the same");
|
ok(r !== response, "The objects should not be the same");
|
||||||
is(r.url, response.url, "The URLs should be the same");
|
is(r.url, response.url.replace("#fragment", ""),
|
||||||
|
"The URLs should be the same");
|
||||||
is(r.status, response.status, "The status codes should be the same");
|
is(r.status, response.status, "The status codes should be the same");
|
||||||
is(r.type, response.type, "The response types should be the same");
|
is(r.type, response.type, "The response types should be the same");
|
||||||
is(r.ok, response.ok, "Both responses should have succeeded");
|
is(r.ok, response.ok, "Both responses should have succeeded");
|
||||||
@ -30,64 +33,110 @@ fetch(new Request(request1)).then(function(r) {
|
|||||||
return response3.text();
|
return response3.text();
|
||||||
}).then(function(text) {
|
}).then(function(text) {
|
||||||
response3Text = text;
|
response3Text = text;
|
||||||
return caches.open(name);
|
return testRequest(request1, request2, request3, unknownRequest,
|
||||||
}).then(function(cache) {
|
requestWithAltQS,
|
||||||
c = cache;
|
request1.url.replace("#fragment", "#other"));
|
||||||
return c.add(request1);
|
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
return c.add(request3);
|
return testRequest(request1.url, request2.url, request3.url,
|
||||||
}).then(function() {
|
unknownRequest.url, requestWithAltQS.url,
|
||||||
return c.matchAll(request1);
|
request1.url.replace("#fragment", "#other"));
|
||||||
}).then(function(r) {
|
|
||||||
is(r.length, 1, "Should only find 1 item");
|
|
||||||
return checkResponse(r[0], response1, response1Text);
|
|
||||||
}).then(function() {
|
|
||||||
return c.matchAll(request3);
|
|
||||||
}).then(function(r) {
|
|
||||||
is(r.length, 1, "Should only find 1 item");
|
|
||||||
return checkResponse(r[0], response3, response3Text);
|
|
||||||
}).then(function() {
|
|
||||||
return c.matchAll();
|
|
||||||
}).then(function(r) {
|
|
||||||
is(r.length, 2, "Should find 2 items");
|
|
||||||
return Promise.all([
|
|
||||||
checkResponse(r[0], response1, response1Text),
|
|
||||||
checkResponse(r[1], response3, response3Text)
|
|
||||||
]);
|
|
||||||
}).then(function() {
|
|
||||||
return c.matchAll({cacheName: name + "mambojambo"});
|
|
||||||
}).catch(function(err) {
|
|
||||||
is(err.name, "NotFoundError", "Searching in the wrong cache should not succeed");
|
|
||||||
}).then(function() {
|
|
||||||
return caches.delete(name);
|
|
||||||
}).then(function(success) {
|
|
||||||
ok(success, "We should be able to delete the cache successfully");
|
|
||||||
// Make sure that the cache is still usable after deletion.
|
|
||||||
return c.matchAll(request1);
|
|
||||||
}).then(function(r) {
|
|
||||||
is(r.length, 1, "Should only find 1 item");
|
|
||||||
return checkResponse(r[0], response1, response1Text);
|
|
||||||
}).then(function() {
|
|
||||||
return c.matchAll(request3);
|
|
||||||
}).then(function(r) {
|
|
||||||
is(r.length, 1, "Should only find 1 item");
|
|
||||||
return checkResponse(r[0], response3, response3Text);
|
|
||||||
}).then(function() {
|
|
||||||
return c.matchAll();
|
|
||||||
}).then(function(r) {
|
|
||||||
is(r.length, 2, "Should find 2 items");
|
|
||||||
return Promise.all([
|
|
||||||
checkResponse(r[0], response1, response1Text),
|
|
||||||
checkResponse(r[1], response3, response3Text)
|
|
||||||
]);
|
|
||||||
}).then(function() {
|
|
||||||
// Now, drop the cache, reopen and verify that we can't find the request any more.
|
|
||||||
c = null;
|
|
||||||
return caches.open(name);
|
|
||||||
}).then(function(cache) {
|
|
||||||
return cache.matchAll();
|
|
||||||
}).catch(function(err) {
|
|
||||||
is(err.name, "NotFoundError", "Searching in the cache after deletion should not succeed");
|
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
testDone();
|
testDone();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The request arguments can either be a URL string, or a Request object.
|
||||||
|
function testRequest(request1, request2, request3, unknownRequest,
|
||||||
|
requestWithAlternateQueryString,
|
||||||
|
requestWithDifferentFragment) {
|
||||||
|
return caches.open(name).then(function(cache) {
|
||||||
|
c = cache;
|
||||||
|
return c.add(request1);
|
||||||
|
}).then(function() {
|
||||||
|
return c.add(request3);
|
||||||
|
}).then(function() {
|
||||||
|
return Promise.all(
|
||||||
|
["HEAD", "POST", "PUT", "DELETE", "OPTIONS"]
|
||||||
|
.map(function(method) {
|
||||||
|
var r = new Request(request1, {method: method});
|
||||||
|
return c.add(r)
|
||||||
|
.then(function() {
|
||||||
|
ok(false, "Promise should be rejected");
|
||||||
|
}, function(err) {
|
||||||
|
is(err.name, "TypeError", "Adding a request with type '" + method + "' should fail");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll(request1);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 1, "Should only find 1 item");
|
||||||
|
return checkResponse(r[0], response1, response1Text);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll(requestWithDifferentFragment);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 1, "Should only find 1 item");
|
||||||
|
return checkResponse(r[0], response1, response1Text);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll(requestWithAlternateQueryString,
|
||||||
|
{ignoreSearch: true, cacheName: name});
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 2, "Should find 2 items");
|
||||||
|
return Promise.all([
|
||||||
|
checkResponse(r[0], response1, response1Text),
|
||||||
|
checkResponse(r[1], response3, response3Text)
|
||||||
|
]);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll(request3);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 1, "Should only find 1 item");
|
||||||
|
return checkResponse(r[0], response3, response3Text);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll();
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 2, "Should find 2 items");
|
||||||
|
return Promise.all([
|
||||||
|
checkResponse(r[0], response1, response1Text),
|
||||||
|
checkResponse(r[1], response3, response3Text)
|
||||||
|
]);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll({cacheName: name + "mambojambo"});
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 0, "Searching in the wrong cache should not succeed");
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll(unknownRequest);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 0, "Searching for an unknown request should not succeed");
|
||||||
|
return c.matchAll(unknownRequest, {cacheName: name});
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 0, "Searching for an unknown request should not succeed");
|
||||||
|
return caches.delete(name);
|
||||||
|
}).then(function(success) {
|
||||||
|
ok(success, "We should be able to delete the cache successfully");
|
||||||
|
// Make sure that the cache is still usable after deletion.
|
||||||
|
return c.matchAll(request1);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 1, "Should only find 1 item");
|
||||||
|
return checkResponse(r[0], response1, response1Text);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll(request3);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 1, "Should only find 1 item");
|
||||||
|
return checkResponse(r[0], response3, response3Text);
|
||||||
|
}).then(function() {
|
||||||
|
return c.matchAll();
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 2, "Should find 2 items");
|
||||||
|
return Promise.all([
|
||||||
|
checkResponse(r[0], response1, response1Text),
|
||||||
|
checkResponse(r[1], response3, response3Text)
|
||||||
|
]);
|
||||||
|
}).then(function() {
|
||||||
|
// Now, drop the cache, reopen and verify that we can't find the request any more.
|
||||||
|
c = null;
|
||||||
|
return caches.open(name);
|
||||||
|
}).then(function(cache) {
|
||||||
|
return cache.matchAll();
|
||||||
|
}).then(function(r) {
|
||||||
|
is(r.length, 0, "Searching in the cache after deletion should not succeed");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
121
dom/cache/test/mochitest/test_cache_match_request.js
vendored
121
dom/cache/test/mochitest/test_cache_match_request.js
vendored
@ -1,4 +1,6 @@
|
|||||||
var request = new Request("//mochi.test:8888/?" + context);
|
var request = new Request("//mochi.test:8888/?" + context + "#fragment");
|
||||||
|
var requestWithAltQS = new Request("//mochi.test:8888/?queryString");
|
||||||
|
var unknownRequest = new Request("//mochi.test:8888/non/existing/path?" + context);
|
||||||
var response;
|
var response;
|
||||||
var c;
|
var c;
|
||||||
var responseText;
|
var responseText;
|
||||||
@ -6,7 +8,8 @@ var name = "match-request" + context;
|
|||||||
|
|
||||||
function checkResponse(r) {
|
function checkResponse(r) {
|
||||||
ok(r !== response, "The objects should not be the same");
|
ok(r !== response, "The objects should not be the same");
|
||||||
is(r.url, response.url, "The URLs should be the same");
|
is(r.url, response.url.replace("#fragment", ""),
|
||||||
|
"The URLs should be the same");
|
||||||
is(r.status, response.status, "The status codes should be the same");
|
is(r.status, response.status, "The status codes should be the same");
|
||||||
is(r.type, response.type, "The response types should be the same");
|
is(r.type, response.type, "The response types should be the same");
|
||||||
is(r.ok, response.ok, "Both responses should have succeeded");
|
is(r.ok, response.ok, "Both responses should have succeeded");
|
||||||
@ -22,42 +25,86 @@ fetch(new Request(request)).then(function(r) {
|
|||||||
return response.text();
|
return response.text();
|
||||||
}).then(function(text) {
|
}).then(function(text) {
|
||||||
responseText = text;
|
responseText = text;
|
||||||
return caches.open(name);
|
return testRequest(request, unknownRequest, requestWithAltQS,
|
||||||
}).then(function(cache) {
|
request.url.replace("#fragment", "#other"));
|
||||||
c = cache;
|
|
||||||
return c.add(request);
|
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
return c.match(request);
|
return testRequest(request.url, unknownRequest.url, requestWithAltQS.url,
|
||||||
}).then(function(r) {
|
request.url.replace("#fragment", "#other"));
|
||||||
return checkResponse(r);
|
|
||||||
}).then(function() {
|
|
||||||
return caches.match(request);
|
|
||||||
}).then(function(r) {
|
|
||||||
return checkResponse(r);
|
|
||||||
}).then(function() {
|
|
||||||
return caches.match(request, {cacheName: name});
|
|
||||||
}).then(function(r) {
|
|
||||||
return checkResponse(r);
|
|
||||||
}).then(function() {
|
|
||||||
return caches.match(request, {cacheName: name + "mambojambo"});
|
|
||||||
}).catch(function(err) {
|
|
||||||
is(err.name, "NotFoundError", "Searching in the wrong cache should not succeed");
|
|
||||||
}).then(function() {
|
|
||||||
return caches.delete(name);
|
|
||||||
}).then(function(success) {
|
|
||||||
ok(success, "We should be able to delete the cache successfully");
|
|
||||||
// Make sure that the cache is still usable after deletion.
|
|
||||||
return c.match(request);
|
|
||||||
}).then(function(r) {
|
|
||||||
return checkResponse(r);
|
|
||||||
}).then(function() {
|
|
||||||
// Now, drop the cache, reopen and verify that we can't find the request any more.
|
|
||||||
c = null;
|
|
||||||
return caches.open(name);
|
|
||||||
}).then(function(cache) {
|
|
||||||
return cache.match(request);
|
|
||||||
}).catch(function(err) {
|
|
||||||
is(err.name, "NotFoundError", "Searching in the cache after deletion should not succeed");
|
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
testDone();
|
testDone();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The request argument can either be a URL string, or a Request object.
|
||||||
|
function testRequest(request, unknownRequest, requestWithAlternateQueryString,
|
||||||
|
requestWithDifferentFragment) {
|
||||||
|
return caches.open(name).then(function(cache) {
|
||||||
|
c = cache;
|
||||||
|
return c.add(request);
|
||||||
|
}).then(function() {
|
||||||
|
return Promise.all(
|
||||||
|
["HEAD", "POST", "PUT", "DELETE", "OPTIONS"]
|
||||||
|
.map(function(method) {
|
||||||
|
var r = new Request(request, {method: method});
|
||||||
|
return c.add(r)
|
||||||
|
.then(function() {
|
||||||
|
ok(false, "Promise should be rejected");
|
||||||
|
}, function(err) {
|
||||||
|
is(err.name, "TypeError", "Adding a request with type '" + method + "' should fail");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}).then(function() {
|
||||||
|
return c.match(request);
|
||||||
|
}).then(function(r) {
|
||||||
|
return checkResponse(r);
|
||||||
|
}).then(function() {
|
||||||
|
return caches.match(request);
|
||||||
|
}).then(function(r) {
|
||||||
|
return checkResponse(r);
|
||||||
|
}).then(function() {
|
||||||
|
return caches.match(requestWithDifferentFragment);
|
||||||
|
}).then(function(r) {
|
||||||
|
return checkResponse(r);
|
||||||
|
}).then(function() {
|
||||||
|
return caches.match(requestWithAlternateQueryString,
|
||||||
|
{ignoreSearch: true, cacheName: name});
|
||||||
|
}).then(function(r) {
|
||||||
|
return checkResponse(r);
|
||||||
|
}).then(function() {
|
||||||
|
return caches.match(request, {cacheName: name});
|
||||||
|
}).then(function(r) {
|
||||||
|
return checkResponse(r);
|
||||||
|
}).then(function() {
|
||||||
|
return caches.match(request, {cacheName: name + "mambojambo"})
|
||||||
|
.then(function() {
|
||||||
|
ok(false, "Promise should be rejected");
|
||||||
|
}, function(err) {
|
||||||
|
is(err.name, "NotFoundError", "Searching in the wrong cache should not succeed");
|
||||||
|
});
|
||||||
|
}).then(function() {
|
||||||
|
return c.match(unknownRequest);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(typeof r, "undefined", "Searching for an unknown request should not succeed");
|
||||||
|
return caches.match(unknownRequest);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(typeof r, "undefined", "Searching for an unknown request should not succeed");
|
||||||
|
return caches.match(unknownRequest, {cacheName: name});
|
||||||
|
}).then(function(r) {
|
||||||
|
is(typeof r, "undefined", "Searching for an unknown request should not succeed");
|
||||||
|
return caches.delete(name);
|
||||||
|
}).then(function(success) {
|
||||||
|
ok(success, "We should be able to delete the cache successfully");
|
||||||
|
// Make sure that the cache is still usable after deletion.
|
||||||
|
return c.match(request);
|
||||||
|
}).then(function(r) {
|
||||||
|
return checkResponse(r);
|
||||||
|
}).then(function() {
|
||||||
|
// Now, drop the cache, reopen and verify that we can't find the request any more.
|
||||||
|
c = null;
|
||||||
|
return caches.open(name);
|
||||||
|
}).then(function(cache) {
|
||||||
|
return cache.match(request);
|
||||||
|
}).then(function(r) {
|
||||||
|
is(typeof r, "undefined", "Searching in the cache after deletion should not succeed");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -81,7 +81,6 @@ static const gl::GLFeature kRequiredFeatures[] = {
|
|||||||
gl::GLFeature::gpu_shader4,
|
gl::GLFeature::gpu_shader4,
|
||||||
gl::GLFeature::instanced_arrays,
|
gl::GLFeature::instanced_arrays,
|
||||||
gl::GLFeature::instanced_non_arrays,
|
gl::GLFeature::instanced_non_arrays,
|
||||||
gl::GLFeature::invalidate_framebuffer,
|
|
||||||
gl::GLFeature::map_buffer_range,
|
gl::GLFeature::map_buffer_range,
|
||||||
gl::GLFeature::occlusion_query2,
|
gl::GLFeature::occlusion_query2,
|
||||||
gl::GLFeature::packed_depth_stencil,
|
gl::GLFeature::packed_depth_stencil,
|
||||||
|
@ -398,6 +398,13 @@ WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvalidateFramebuffer is a hint to the driver. Should be OK to
|
||||||
|
// skip calls if not supported, for example by OSX 10.9 GL
|
||||||
|
// drivers.
|
||||||
|
static bool invalidateFBSupported = gl->IsSupported(gl::GLFeature::invalidate_framebuffer);
|
||||||
|
if (!invalidateFBSupported)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!fb && !isDefaultFB) {
|
if (!fb && !isDefaultFB) {
|
||||||
dom::Sequence<GLenum> tmpAttachments;
|
dom::Sequence<GLenum> tmpAttachments;
|
||||||
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
||||||
@ -445,6 +452,13 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvalidateFramebuffer is a hint to the driver. Should be OK to
|
||||||
|
// skip calls if not supported, for example by OSX 10.9 GL
|
||||||
|
// drivers.
|
||||||
|
static bool invalidateFBSupported = gl->IsSupported(gl::GLFeature::invalidate_framebuffer);
|
||||||
|
if (!invalidateFBSupported)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!fb && !isDefaultFB) {
|
if (!fb && !isDefaultFB) {
|
||||||
dom::Sequence<GLenum> tmpAttachments;
|
dom::Sequence<GLenum> tmpAttachments;
|
||||||
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
||||||
|
@ -921,6 +921,8 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
|||||||
mViewportWidth = mWidth;
|
mViewportWidth = mWidth;
|
||||||
mViewportHeight = mHeight;
|
mViewportHeight = mHeight;
|
||||||
|
|
||||||
|
gl->fScissor(0, 0, mWidth, mHeight);
|
||||||
|
|
||||||
// Make sure that we clear this out, otherwise
|
// Make sure that we clear this out, otherwise
|
||||||
// we'll end up displaying random memory
|
// we'll end up displaying random memory
|
||||||
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
|
||||||
|
@ -264,9 +264,6 @@ bool
|
|||||||
WebGLContext::IsFormatValidForFB(GLenum sizedFormat) const
|
WebGLContext::IsFormatValidForFB(GLenum sizedFormat) const
|
||||||
{
|
{
|
||||||
switch (sizedFormat) {
|
switch (sizedFormat) {
|
||||||
case LOCAL_GL_ALPHA8:
|
|
||||||
case LOCAL_GL_LUMINANCE8:
|
|
||||||
case LOCAL_GL_LUMINANCE8_ALPHA8:
|
|
||||||
case LOCAL_GL_RGB8:
|
case LOCAL_GL_RGB8:
|
||||||
case LOCAL_GL_RGBA8:
|
case LOCAL_GL_RGBA8:
|
||||||
case LOCAL_GL_RGB565:
|
case LOCAL_GL_RGB565:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Mark failing tests in mochi-single.html.
|
# Mark failing tests in mochi-single.html.
|
||||||
|
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
skip-if = e10s || os == 'b2g' || ((os == 'linux') && (buildapp == 'b2g')) || ((os == 'linux') && (buildapp == 'mulet')) # Bug 1136181 disabled on B2G Desktop and Mulet for intermittent failures
|
skip-if = e10s || os == 'b2g' || ((os == 'linux') && (buildapp == 'b2g')) || ((os == 'linux') && (buildapp == 'mulet'))
|
||||||
|
|
||||||
support-files = webgl-conformance/../webgl-mochitest/driver-info.js
|
support-files = webgl-conformance/../webgl-mochitest/driver-info.js
|
||||||
webgl-conformance/always-fail.html
|
webgl-conformance/always-fail.html
|
||||||
@ -526,7 +526,6 @@ fail-if = (os == 'linux')
|
|||||||
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-shaders.html]
|
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-shaders.html]
|
||||||
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html]
|
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html]
|
||||||
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html]
|
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html]
|
||||||
fail-if = (os == 'mac' && os_version == '10.10')
|
|
||||||
[webgl-conformance/_wrappers/test_conformance__extensions__ext-sRGB.html]
|
[webgl-conformance/_wrappers/test_conformance__extensions__ext-sRGB.html]
|
||||||
[webgl-conformance/_wrappers/test_conformance__extensions__ext-shader-texture-lod.html]
|
[webgl-conformance/_wrappers/test_conformance__extensions__ext-shader-texture-lod.html]
|
||||||
[webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function.html]
|
[webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function.html]
|
||||||
|
@ -59,11 +59,11 @@ fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersG
|
|||||||
== webgl-color-test.html?frame=6&__&________&_______&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&__&________&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
== webgl-color-test.html?frame=6&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
== webgl-color-test.html?frame=6&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
fails-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-color-test.html?frame=6&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
== webgl-color-test.html?frame=6&__&________&premult&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&__&________&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
== webgl-color-test.html?frame=6&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
== webgl-color-test.html?frame=6&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
fails-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-color-test.html?frame=6&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
== webgl-color-test.html?frame=6&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) == webgl-color-test.html?frame=6&__&________&_______&alpha wrapper.html?colors-non-premult.png
|
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) == webgl-color-test.html?frame=6&__&________&_______&alpha wrapper.html?colors-non-premult.png
|
||||||
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) == webgl-color-test.html?frame=6&aa&________&_______&alpha wrapper.html?colors-non-premult.png
|
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) == webgl-color-test.html?frame=6&aa&________&_______&alpha wrapper.html?colors-non-premult.png
|
||||||
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) == webgl-color-test.html?frame=6&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
|
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) == webgl-color-test.html?frame=6&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
|
||||||
@ -93,11 +93,11 @@ fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersG
|
|||||||
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
fails-if(winWidget&&layersGPUAccelerated&&d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
|
||||||
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
random-if(winWidget&&layersGPUAccelerated&&d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
|
||||||
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
|
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
|
||||||
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
|
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
|
||||||
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
|
fuzzy(1,30000) fails-if(gtk2Widget&&browserIsRemote) fails-if(winWidget&&layersGPUAccelerated&&!d2d) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
# *** WARNING! ***
|
||||||
|
# Modification to this file only take effect after running
|
||||||
|
# generate-wrappers-and-manifest.py
|
||||||
|
|
||||||
# See python/mozbuild/mozbuild/mozinfo.py for incoming data.
|
# See python/mozbuild/mozbuild/mozinfo.py for incoming data.
|
||||||
|
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
@ -96,9 +100,6 @@ fail-if = (os == 'linux')
|
|||||||
[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
|
[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
|
||||||
# Intermittent crash on OSX.
|
# Intermittent crash on OSX.
|
||||||
skip-if = os == 'mac'
|
skip-if = os == 'mac'
|
||||||
[_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html]
|
|
||||||
# Fails on OS X 10.10
|
|
||||||
fail-if = (os == 'mac' && os_version == '10.10')
|
|
||||||
[_wrappers/test_conformance__misc__object-deletion-behaviour.html]
|
[_wrappers/test_conformance__misc__object-deletion-behaviour.html]
|
||||||
# Fails on OS X 10.10
|
# Fails on OS X 10.10
|
||||||
fail-if = (os == 'mac' && os_version == '10.10')
|
fail-if = (os == 'mac' && os_version == '10.10')
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource
|
#include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource
|
||||||
|
|
||||||
|
#include "ServiceWorker.h"
|
||||||
|
#include "ServiceWorkerClient.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
@ -103,12 +106,14 @@ MessageEvent::GetSource(nsIDOMWindow** aSource)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const
|
MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePortOrClient>& aValue) const
|
||||||
{
|
{
|
||||||
if (mWindowSource) {
|
if (mWindowSource) {
|
||||||
aValue.SetValue().SetAsWindowProxy() = mWindowSource;
|
aValue.SetValue().SetAsWindowProxy() = mWindowSource;
|
||||||
} else if (mPortSource) {
|
} else if (mPortSource) {
|
||||||
aValue.SetValue().SetAsMessagePort() = mPortSource;
|
aValue.SetValue().SetAsMessagePort() = mPortSource;
|
||||||
|
} else if (mClientSource) {
|
||||||
|
aValue.SetValue().SetAsClient() = mClientSource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +211,12 @@ MessageEvent::SetSource(mozilla::dom::MessagePort* aPort)
|
|||||||
mPortSource = aPort;
|
mPortSource = aPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessageEvent::SetSource(mozilla::dom::workers::ServiceWorkerClient* aClient)
|
||||||
|
{
|
||||||
|
mClientSource = aClient;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
@ -18,7 +18,13 @@ struct MessageEventInit;
|
|||||||
class MessagePort;
|
class MessagePort;
|
||||||
class MessagePortBase;
|
class MessagePortBase;
|
||||||
class MessagePortList;
|
class MessagePortList;
|
||||||
class OwningWindowProxyOrMessagePort;
|
class OwningWindowProxyOrMessagePortOrClient;
|
||||||
|
|
||||||
|
namespace workers {
|
||||||
|
|
||||||
|
class ServiceWorkerClient;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the MessageEvent event, used for cross-document messaging and
|
* Implements the MessageEvent event, used for cross-document messaging and
|
||||||
@ -48,7 +54,7 @@ public:
|
|||||||
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
|
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const;
|
void GetSource(Nullable<OwningWindowProxyOrMessagePortOrClient>& aValue) const;
|
||||||
|
|
||||||
MessagePortList* GetPorts()
|
MessagePortList* GetPorts()
|
||||||
{
|
{
|
||||||
@ -60,6 +66,8 @@ public:
|
|||||||
// Non WebIDL methods
|
// Non WebIDL methods
|
||||||
void SetSource(mozilla::dom::MessagePort* aPort);
|
void SetSource(mozilla::dom::MessagePort* aPort);
|
||||||
|
|
||||||
|
void SetSource(workers::ServiceWorkerClient* aClient);
|
||||||
|
|
||||||
void SetSource(nsPIDOMWindow* aWindow)
|
void SetSource(nsPIDOMWindow* aWindow)
|
||||||
{
|
{
|
||||||
mWindowSource = aWindow;
|
mWindowSource = aWindow;
|
||||||
@ -86,6 +94,7 @@ private:
|
|||||||
nsString mLastEventId;
|
nsString mLastEventId;
|
||||||
nsCOMPtr<nsIDOMWindow> mWindowSource;
|
nsCOMPtr<nsIDOMWindow> mWindowSource;
|
||||||
nsRefPtr<MessagePortBase> mPortSource;
|
nsRefPtr<MessagePortBase> mPortSource;
|
||||||
|
nsRefPtr<workers::ServiceWorkerClient> mClientSource;
|
||||||
nsRefPtr<MessagePortList> mPorts;
|
nsRefPtr<MessagePortList> mPorts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ interface nsITranslationNodeList;
|
|||||||
interface nsIJSRAIIHelper;
|
interface nsIJSRAIIHelper;
|
||||||
interface nsIContentPermissionRequest;
|
interface nsIContentPermissionRequest;
|
||||||
|
|
||||||
[scriptable, uuid(b39cb73f-ff99-4744-9780-2c26f830c6f7)]
|
[scriptable, uuid(dde97573-f4cf-45ce-bbb0-5af4e5f77440)]
|
||||||
interface nsIDOMWindowUtils : nsISupports {
|
interface nsIDOMWindowUtils : nsISupports {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,15 +205,14 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||||||
*
|
*
|
||||||
* The effect of this API is for gfx code to allocate more or fewer
|
* The effect of this API is for gfx code to allocate more or fewer
|
||||||
* pixels for rescalable content by a factor of |resolution| in
|
* pixels for rescalable content by a factor of |resolution| in
|
||||||
* either or both dimensions. The scale at which the content is
|
* both dimensions. The scale at which the content is displayed does
|
||||||
* displayed does not change; if that is desired, use
|
* not change; if that is desired, use setResolutionAndScaleTo() instead.
|
||||||
* setResolutionAndScaleTo() instead.
|
|
||||||
*
|
*
|
||||||
* The caller of this method must have chrome privileges.
|
* The caller of this method must have chrome privileges.
|
||||||
*/
|
*/
|
||||||
void setResolution(in float aXResolution, in float aYResolution);
|
void setResolution(in float aResolution);
|
||||||
|
|
||||||
void getResolution(out float aXResolution, out float aYResolution);
|
void getResolution(out float aResolution);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to setResolution(), but also scales the content by the
|
* Similar to setResolution(), but also scales the content by the
|
||||||
@ -226,7 +225,7 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||||||
*
|
*
|
||||||
* The caller of this method must have chrome privileges.
|
* The caller of this method must have chrome privileges.
|
||||||
*/
|
*/
|
||||||
void setResolutionAndScaleTo(in float aXResolution, in float aYResolution);
|
void setResolutionAndScaleTo(in float aResolution);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the resolution has been set by the user.
|
* Whether the resolution has been set by the user.
|
||||||
|
@ -19,7 +19,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
|
|||||||
[noscript] void UnregisterFailed();
|
[noscript] void UnregisterFailed();
|
||||||
};
|
};
|
||||||
|
|
||||||
[builtinclass, uuid(464882c8-81c0-4620-b9c4-44c12085b65b)]
|
[builtinclass, uuid(706c3e6b-c9d2-4857-893d-4b4845fec48f)]
|
||||||
interface nsIServiceWorkerManager : nsISupports
|
interface nsIServiceWorkerManager : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -30,7 +30,7 @@ interface nsIServiceWorkerManager : nsISupports
|
|||||||
*
|
*
|
||||||
* Returns a Promise.
|
* Returns a Promise.
|
||||||
*/
|
*/
|
||||||
nsISupports register(in nsIDOMWindow aWindow, in DOMString aScope, in DOMString aScriptURI);
|
nsISupports register(in nsIDOMWindow aWindow, in nsIURI aScope, in nsIURI aScriptURI);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister an existing ServiceWorker registration for `aScope`.
|
* Unregister an existing ServiceWorker registration for `aScope`.
|
||||||
|
@ -390,7 +390,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
|
|||||||
// This is the root layer, so the cumulative resolution is the same
|
// This is the root layer, so the cumulative resolution is the same
|
||||||
// as the resolution.
|
// as the resolution.
|
||||||
metrics.SetPresShellResolution(metrics.GetCumulativeResolution().ToScaleFactor().scale);
|
metrics.SetPresShellResolution(metrics.GetCumulativeResolution().ToScaleFactor().scale);
|
||||||
utils->SetResolutionAndScaleTo(metrics.GetPresShellResolution(), metrics.GetPresShellResolution());
|
utils->SetResolutionAndScaleTo(metrics.GetPresShellResolution());
|
||||||
|
|
||||||
CSSSize scrollPort = metrics.CalculateCompositedSizeInCssPixels();
|
CSSSize scrollPort = metrics.CalculateCompositedSizeInCssPixels();
|
||||||
utils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
|
utils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
|
||||||
@ -917,8 +917,7 @@ TabChild::Observe(nsISupports *aSubject,
|
|||||||
// until we we get an inner size.
|
// until we we get an inner size.
|
||||||
if (HasValidInnerSize()) {
|
if (HasValidInnerSize()) {
|
||||||
InitializeRootMetrics();
|
InitializeRootMetrics();
|
||||||
utils->SetResolutionAndScaleTo(mLastRootMetrics.GetPresShellResolution(),
|
utils->SetResolutionAndScaleTo(mLastRootMetrics.GetPresShellResolution());
|
||||||
mLastRootMetrics.GetPresShellResolution());
|
|
||||||
HandlePossibleViewportChange(mInnerSize);
|
HandlePossibleViewportChange(mInnerSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2344,7 +2343,7 @@ TabChild::GetPresShellResolution() const
|
|||||||
if (!shell) {
|
if (!shell) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
return shell->GetXResolution();
|
return shell->GetResolution();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -236,8 +236,6 @@ private:
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
TabParent* sEventCapturer;
|
|
||||||
|
|
||||||
TabParent *TabParent::mIMETabParent = nullptr;
|
TabParent *TabParent::mIMETabParent = nullptr;
|
||||||
TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
|
TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
|
||||||
|
|
||||||
@ -262,7 +260,6 @@ TabParent::TabParent(nsIContentParent* aManager,
|
|||||||
, mIMECompositionStart(0)
|
, mIMECompositionStart(0)
|
||||||
, mIMESeqno(0)
|
, mIMESeqno(0)
|
||||||
, mIMECompositionRectOffset(0)
|
, mIMECompositionRectOffset(0)
|
||||||
, mEventCaptureDepth(0)
|
|
||||||
, mRect(0, 0, 0, 0)
|
, mRect(0, 0, 0, 0)
|
||||||
, mDimensions(0, 0)
|
, mDimensions(0, 0)
|
||||||
, mOrientation(0)
|
, mOrientation(0)
|
||||||
@ -401,9 +398,6 @@ TabParent::Recv__delete__()
|
|||||||
void
|
void
|
||||||
TabParent::ActorDestroy(ActorDestroyReason why)
|
TabParent::ActorDestroy(ActorDestroyReason why)
|
||||||
{
|
{
|
||||||
if (sEventCapturer == this) {
|
|
||||||
sEventCapturer = nullptr;
|
|
||||||
}
|
|
||||||
if (mIMETabParent == this) {
|
if (mIMETabParent == this) {
|
||||||
mIMETabParent = nullptr;
|
mIMETabParent = nullptr;
|
||||||
}
|
}
|
||||||
@ -1325,22 +1319,7 @@ bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (event.message == NS_TOUCH_START) {
|
if (event.message == NS_TOUCH_START) {
|
||||||
// Adjust the widget coordinates to be relative to our frame.
|
|
||||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
|
||||||
if (!frameLoader) {
|
|
||||||
// No frame anymore?
|
|
||||||
sEventCapturer = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mChildProcessOffsetAtTouchStart = GetChildProcessOffset();
|
mChildProcessOffsetAtTouchStart = GetChildProcessOffset();
|
||||||
|
|
||||||
MOZ_ASSERT((!sEventCapturer && mEventCaptureDepth == 0) ||
|
|
||||||
(sEventCapturer == this && mEventCaptureDepth > 0));
|
|
||||||
// We want to capture all remaining touch events in this series
|
|
||||||
// for fast-path dispatch.
|
|
||||||
sEventCapturer = this;
|
|
||||||
++mEventCaptureDepth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PresShell::HandleEventInternal adds touches on touch end/cancel. This
|
// PresShell::HandleEventInternal adds touches on touch end/cancel. This
|
||||||
@ -1373,41 +1352,6 @@ bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
|
|||||||
PBrowserParent::SendRealTouchEvent(event, guid, blockId);
|
PBrowserParent::SendRealTouchEvent(event, guid, blockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ TabParent*
|
|
||||||
TabParent::GetEventCapturer()
|
|
||||||
{
|
|
||||||
return sEventCapturer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TabParent::TryCapture(const WidgetGUIEvent& aEvent)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(sEventCapturer == this && mEventCaptureDepth > 0);
|
|
||||||
|
|
||||||
if (aEvent.mClass != eTouchEventClass) {
|
|
||||||
// Only capture of touch events is implemented, for now.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
WidgetTouchEvent event(*aEvent.AsTouchEvent());
|
|
||||||
|
|
||||||
bool isTouchPointUp = (event.message == NS_TOUCH_END ||
|
|
||||||
event.message == NS_TOUCH_CANCEL);
|
|
||||||
if (event.message == NS_TOUCH_START || isTouchPointUp) {
|
|
||||||
// Let the DOM see touch start/end events so that its touch-point
|
|
||||||
// state stays consistent.
|
|
||||||
if (isTouchPointUp && 0 == --mEventCaptureDepth) {
|
|
||||||
// All event series are un-captured, don't try to catch any
|
|
||||||
// more.
|
|
||||||
sEventCapturer = nullptr;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SendRealTouchEvent(event);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TabParent::RecvSyncMessage(const nsString& aMessage,
|
TabParent::RecvSyncMessage(const nsString& aMessage,
|
||||||
const ClonedMessageData& aData,
|
const ClonedMessageData& aData,
|
||||||
@ -2550,11 +2494,6 @@ TabParent::GetLoadContext()
|
|||||||
return loadContext.forget();
|
return loadContext.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Be careful if you call this method while proceding a real touch event. For
|
|
||||||
* example sending a touchstart during a real touchend may results into
|
|
||||||
* a busted mEventCaptureDepth and following touch events may not do what you
|
|
||||||
* expect.
|
|
||||||
*/
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
TabParent::InjectTouchEvent(const nsAString& aType,
|
TabParent::InjectTouchEvent(const nsAString& aType,
|
||||||
uint32_t* aIdentifiers,
|
uint32_t* aIdentifiers,
|
||||||
@ -2614,11 +2553,6 @@ TabParent::InjectTouchEvent(const nsAString& aType,
|
|||||||
event.touches.AppendElement(t);
|
event.touches.AppendElement(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((msg == NS_TOUCH_END || msg == NS_TOUCH_CANCEL) && sEventCapturer) {
|
|
||||||
WidgetGUIEvent* guiEvent = event.AsGUIEvent();
|
|
||||||
TryCapture(*guiEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
SendRealTouchEvent(event);
|
SendRealTouchEvent(event);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -102,30 +102,6 @@ public:
|
|||||||
|
|
||||||
nsIXULBrowserWindow* GetXULBrowserWindow();
|
nsIXULBrowserWindow* GetXULBrowserWindow();
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the TabParent that has decided it wants to capture an
|
|
||||||
* event series for fast-path dispatch to its subprocess, if one
|
|
||||||
* has.
|
|
||||||
*
|
|
||||||
* DOM event dispatch and widget are free to ignore capture
|
|
||||||
* requests from TabParents; the end result wrt remote content is
|
|
||||||
* (must be) always the same, albeit usually slower without
|
|
||||||
* subprocess capturing. This allows frontends/widget backends to
|
|
||||||
* "opt in" to faster cross-process dispatch.
|
|
||||||
*/
|
|
||||||
static TabParent* GetEventCapturer();
|
|
||||||
/**
|
|
||||||
* If this is the current event capturer, give this a chance to
|
|
||||||
* capture the event. If it was captured, return true, false
|
|
||||||
* otherwise. Un-captured events should follow normal DOM
|
|
||||||
* dispatch; captured events should result in no further
|
|
||||||
* processing from the caller of TryCapture().
|
|
||||||
*
|
|
||||||
* It's an error to call TryCapture() if this isn't the event
|
|
||||||
* capturer.
|
|
||||||
*/
|
|
||||||
bool TryCapture(const WidgetGUIEvent& aEvent);
|
|
||||||
|
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE;
|
virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE;
|
||||||
@ -440,9 +416,6 @@ protected:
|
|||||||
LayoutDeviceIntRect mIMECaretRect;
|
LayoutDeviceIntRect mIMECaretRect;
|
||||||
LayoutDeviceIntRect mIMEEditorRect;
|
LayoutDeviceIntRect mIMEEditorRect;
|
||||||
|
|
||||||
// The number of event series we're currently capturing.
|
|
||||||
int32_t mEventCaptureDepth;
|
|
||||||
|
|
||||||
nsIntRect mRect;
|
nsIntRect mRect;
|
||||||
ScreenIntSize mDimensions;
|
ScreenIntSize mDimensions;
|
||||||
ScreenOrientation mOrientation;
|
ScreenOrientation mOrientation;
|
||||||
|
@ -191,12 +191,12 @@ void MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
|
|||||||
if (mIsDormant) {
|
if (mIsDormant) {
|
||||||
DECODER_LOG("UpdateDormantState() entering DORMANT state");
|
DECODER_LOG("UpdateDormantState() entering DORMANT state");
|
||||||
// enter dormant state
|
// enter dormant state
|
||||||
nsCOMPtr<nsIRunnable> event =
|
RefPtr<nsRunnable> event =
|
||||||
NS_NewRunnableMethodWithArg<bool>(
|
NS_NewRunnableMethodWithArg<bool>(
|
||||||
mDecoderStateMachine,
|
mDecoderStateMachine,
|
||||||
&MediaDecoderStateMachine::SetDormant,
|
&MediaDecoderStateMachine::SetDormant,
|
||||||
true);
|
true);
|
||||||
mDecoderStateMachine->GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
|
mDecoderStateMachine->TaskQueue()->Dispatch(event);
|
||||||
|
|
||||||
if (IsEnded()) {
|
if (IsEnded()) {
|
||||||
mWasEndedWhenEnteredDormant = true;
|
mWasEndedWhenEnteredDormant = true;
|
||||||
@ -207,12 +207,12 @@ void MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
|
|||||||
DECODER_LOG("UpdateDormantState() leaving DORMANT state");
|
DECODER_LOG("UpdateDormantState() leaving DORMANT state");
|
||||||
// exit dormant state
|
// exit dormant state
|
||||||
// trigger to state machine.
|
// trigger to state machine.
|
||||||
nsCOMPtr<nsIRunnable> event =
|
RefPtr<nsRunnable> event =
|
||||||
NS_NewRunnableMethodWithArg<bool>(
|
NS_NewRunnableMethodWithArg<bool>(
|
||||||
mDecoderStateMachine,
|
mDecoderStateMachine,
|
||||||
&MediaDecoderStateMachine::SetDormant,
|
&MediaDecoderStateMachine::SetDormant,
|
||||||
false);
|
false);
|
||||||
mDecoderStateMachine->GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
|
mDecoderStateMachine->TaskQueue()->Dispatch(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -750,7 +750,8 @@ nsresult MediaDecoder::ScheduleStateMachineThread()
|
|||||||
if (mShuttingDown)
|
if (mShuttingDown)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
return mDecoderStateMachine->ScheduleStateMachine();
|
mDecoderStateMachine->ScheduleStateMachine();
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult MediaDecoder::Play()
|
nsresult MediaDecoder::Play()
|
||||||
@ -763,8 +764,7 @@ nsresult MediaDecoder::Play()
|
|||||||
if (mPausedForPlaybackRateNull) {
|
if (mPausedForPlaybackRateNull) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
nsresult res = ScheduleStateMachineThread();
|
ScheduleStateMachineThread();
|
||||||
NS_ENSURE_SUCCESS(res,res);
|
|
||||||
if (IsEnded()) {
|
if (IsEnded()) {
|
||||||
return Seek(0, SeekTarget::PrevSyncPoint);
|
return Seek(0, SeekTarget::PrevSyncPoint);
|
||||||
} else if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) {
|
} else if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) {
|
||||||
@ -1317,7 +1317,7 @@ void MediaDecoder::ApplyStateToStateMachine(PlayState aState)
|
|||||||
mDecoderStateMachine->Play();
|
mDecoderStateMachine->Play();
|
||||||
break;
|
break;
|
||||||
case PLAY_STATE_SEEKING:
|
case PLAY_STATE_SEEKING:
|
||||||
mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->GetStateMachineThread(),
|
mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->TaskQueue(),
|
||||||
mDecoderStateMachine.get(), __func__,
|
mDecoderStateMachine.get(), __func__,
|
||||||
&MediaDecoderStateMachine::Seek, mRequestedSeekTarget)
|
&MediaDecoderStateMachine::Seek, mRequestedSeekTarget)
|
||||||
->RefableThen(NS_GetCurrentThread(), __func__, this,
|
->RefableThen(NS_GetCurrentThread(), __func__, this,
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "MediaDecoderStateMachine.h"
|
#include "MediaDecoderStateMachine.h"
|
||||||
#include "MediaDecoderStateMachineScheduler.h"
|
#include "MediaTimer.h"
|
||||||
#include "AudioSink.h"
|
#include "AudioSink.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "MediaDecoder.h"
|
#include "MediaDecoder.h"
|
||||||
@ -201,9 +201,9 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||||||
MediaDecoderReader* aReader,
|
MediaDecoderReader* aReader,
|
||||||
bool aRealTime) :
|
bool aRealTime) :
|
||||||
mDecoder(aDecoder),
|
mDecoder(aDecoder),
|
||||||
mScheduler(new MediaDecoderStateMachineScheduler(
|
mRealTime(aRealTime),
|
||||||
aDecoder->GetReentrantMonitor(),
|
mDispatchedStateMachine(false),
|
||||||
&MediaDecoderStateMachine::TimeoutExpired, this, aRealTime)),
|
mDelayedScheduler(this),
|
||||||
mState(DECODER_STATE_DECODING_NONE),
|
mState(DECODER_STATE_DECODING_NONE),
|
||||||
mPlayDuration(0),
|
mPlayDuration(0),
|
||||||
mStartTime(-1),
|
mStartTime(-1),
|
||||||
@ -248,6 +248,11 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||||||
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
|
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||||
|
|
||||||
|
// Set up our task queue.
|
||||||
|
RefPtr<SharedThreadPool> threadPool(
|
||||||
|
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
|
||||||
|
mTaskQueue = new MediaTaskQueue(threadPool.forget());
|
||||||
|
|
||||||
static bool sPrefCacheInit = false;
|
static bool sPrefCacheInit = false;
|
||||||
if (!sPrefCacheInit) {
|
if (!sPrefCacheInit) {
|
||||||
sPrefCacheInit = true;
|
sPrefCacheInit = true;
|
||||||
@ -387,7 +392,7 @@ void MediaDecoderStateMachine::SendStreamData()
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(OnStateMachineThread(), "Should be on state machine thread");
|
MOZ_ASSERT(OnStateMachineThread(), "Should be on state machine thread");
|
||||||
AssertCurrentThreadInMonitor();
|
AssertCurrentThreadInMonitor();
|
||||||
MOZ_ASSERT(!mAudioSink, "Should've been stopped in CallRunStateMachine()");
|
MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
|
||||||
|
|
||||||
DecodedStreamData* stream = mDecoder->GetDecodedStream();
|
DecodedStreamData* stream = mDecoder->GetDecodedStream();
|
||||||
|
|
||||||
@ -405,7 +410,7 @@ void MediaDecoderStateMachine::SendStreamData()
|
|||||||
mediaStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
|
mediaStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
|
||||||
SourceMediaStream::ADDTRACK_QUEUED);
|
SourceMediaStream::ADDTRACK_QUEUED);
|
||||||
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
|
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
|
||||||
GetStateMachineThread(), GetWakeDecoderRunnable());
|
TaskQueue(), GetWakeDecoderRunnable());
|
||||||
stream->mNextAudioTime = mStartTime + stream->mInitialTime;
|
stream->mNextAudioTime = mStartTime + stream->mInitialTime;
|
||||||
}
|
}
|
||||||
if (mInfo.HasVideo()) {
|
if (mInfo.HasVideo()) {
|
||||||
@ -414,7 +419,7 @@ void MediaDecoderStateMachine::SendStreamData()
|
|||||||
mediaStream->AddTrack(videoTrackId, 0, video,
|
mediaStream->AddTrack(videoTrackId, 0, video,
|
||||||
SourceMediaStream::ADDTRACK_QUEUED);
|
SourceMediaStream::ADDTRACK_QUEUED);
|
||||||
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
|
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
|
||||||
GetStateMachineThread(), GetWakeDecoderRunnable());
|
TaskQueue(), GetWakeDecoderRunnable());
|
||||||
|
|
||||||
// TODO: We can't initialize |mNextVideoTime| until |mStartTime|
|
// TODO: We can't initialize |mNextVideoTime| until |mStartTime|
|
||||||
// is set. This is a good indication that DecodedStreamData is in
|
// is set. This is a good indication that DecodedStreamData is in
|
||||||
@ -570,7 +575,7 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
|
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
|
||||||
GetStateMachineThread(), GetWakeDecoderRunnable());
|
TaskQueue(), GetWakeDecoderRunnable());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -593,7 +598,7 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
|
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
|
||||||
GetStateMachineThread(), GetWakeDecoderRunnable());
|
TaskQueue(), GetWakeDecoderRunnable());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -855,7 +860,7 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
|||||||
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
|
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
|
||||||
WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||||
&MediaDecoderReader::WaitForData, aType)
|
&MediaDecoderReader::WaitForData, aType)
|
||||||
->RefableThen(mScheduler.get(), __func__, this,
|
->RefableThen(TaskQueue(), __func__, this,
|
||||||
&MediaDecoderStateMachine::OnWaitForDataResolved,
|
&MediaDecoderStateMachine::OnWaitForDataResolved,
|
||||||
&MediaDecoderStateMachine::OnWaitForDataRejected));
|
&MediaDecoderStateMachine::OnWaitForDataRejected));
|
||||||
return;
|
return;
|
||||||
@ -1084,7 +1089,7 @@ MediaDecoderStateMachine::CheckIfSeekComplete()
|
|||||||
mDecodeToSeekTarget = false;
|
mDecodeToSeekTarget = false;
|
||||||
RefPtr<nsIRunnable> task(
|
RefPtr<nsIRunnable> task(
|
||||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
|
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
|
||||||
nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
|
nsresult rv = TaskQueue()->Dispatch(task);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
DecodeError();
|
DecodeError();
|
||||||
}
|
}
|
||||||
@ -1146,10 +1151,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
|||||||
cloneReader = aCloneDonor->mReader;
|
cloneReader = aCloneDonor->mReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = mScheduler->Init();
|
nsresult rv = mReader->Init(cloneReader);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
rv = mReader->Init(cloneReader);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -1343,7 +1345,7 @@ int64_t MediaDecoderStateMachine::GetCurrentTimeUs() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MediaDecoderStateMachine::IsRealTime() const {
|
bool MediaDecoderStateMachine::IsRealTime() const {
|
||||||
return mScheduler->IsRealTime();
|
return mRealTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t MediaDecoderStateMachine::GetDuration()
|
int64_t MediaDecoderStateMachine::GetDuration()
|
||||||
@ -1492,8 +1494,18 @@ void MediaDecoderStateMachine::SetDormant(bool aDormant)
|
|||||||
}
|
}
|
||||||
mPendingSeek.RejectIfExists(__func__);
|
mPendingSeek.RejectIfExists(__func__);
|
||||||
mCurrentSeek.RejectIfExists(__func__);
|
mCurrentSeek.RejectIfExists(__func__);
|
||||||
ScheduleStateMachine();
|
|
||||||
SetState(DECODER_STATE_DORMANT);
|
SetState(DECODER_STATE_DORMANT);
|
||||||
|
if (IsPlaying()) {
|
||||||
|
StopPlayback();
|
||||||
|
}
|
||||||
|
StopAudioThread();
|
||||||
|
FlushDecoding();
|
||||||
|
// Now that those threads are stopped, there's no possibility of
|
||||||
|
// mPendingWakeDecoder being needed again. Revoke it.
|
||||||
|
mPendingWakeDecoder = nullptr;
|
||||||
|
DebugOnly<nsresult> rv = DecodeTaskQueue()->Dispatch(
|
||||||
|
NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources));
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||||
} else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
|
} else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
|
||||||
mDecodingFrozenAtStateDecoding = true;
|
mDecodingFrozenAtStateDecoding = true;
|
||||||
@ -1513,9 +1525,8 @@ void MediaDecoderStateMachine::Shutdown()
|
|||||||
|
|
||||||
// Change state before issuing shutdown request to threads so those
|
// Change state before issuing shutdown request to threads so those
|
||||||
// threads can start exiting cleanly during the Shutdown call.
|
// threads can start exiting cleanly during the Shutdown call.
|
||||||
DECODER_LOG("Changed state to SHUTDOWN");
|
ScheduleStateMachine();
|
||||||
SetState(DECODER_STATE_SHUTDOWN);
|
SetState(DECODER_STATE_SHUTDOWN);
|
||||||
mScheduler->ScheduleAndShutdown();
|
|
||||||
if (mAudioSink) {
|
if (mAudioSink) {
|
||||||
mAudioSink->PrepareToShutdown();
|
mAudioSink->PrepareToShutdown();
|
||||||
}
|
}
|
||||||
@ -1774,7 +1785,7 @@ MediaDecoderStateMachine::EnqueueDecodeFirstFrameTask()
|
|||||||
|
|
||||||
RefPtr<nsIRunnable> task(
|
RefPtr<nsIRunnable> task(
|
||||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
|
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
|
||||||
nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
|
nsresult rv = TaskQueue()->Dispatch(task);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -1921,7 +1932,7 @@ MediaDecoderStateMachine::InitiateSeek()
|
|||||||
mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||||
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
|
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
|
||||||
GetEndTime())
|
GetEndTime())
|
||||||
->RefableThen(mScheduler.get(), __func__, this,
|
->RefableThen(TaskQueue(), __func__, this,
|
||||||
&MediaDecoderStateMachine::OnSeekCompleted,
|
&MediaDecoderStateMachine::OnSeekCompleted,
|
||||||
&MediaDecoderStateMachine::OnSeekFailed));
|
&MediaDecoderStateMachine::OnSeekFailed));
|
||||||
}
|
}
|
||||||
@ -1969,7 +1980,7 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
|
|||||||
|
|
||||||
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
||||||
__func__, &MediaDecoderReader::RequestAudioData)
|
__func__, &MediaDecoderReader::RequestAudioData)
|
||||||
->RefableThen(mScheduler.get(), __func__, this,
|
->RefableThen(TaskQueue(), __func__, this,
|
||||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||||
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
||||||
|
|
||||||
@ -2029,7 +2040,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
|
|||||||
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||||
&MediaDecoderReader::RequestVideoData,
|
&MediaDecoderReader::RequestVideoData,
|
||||||
skipToNextKeyFrame, currentTime)
|
skipToNextKeyFrame, currentTime)
|
||||||
->RefableThen(mScheduler.get(), __func__, this,
|
->RefableThen(TaskQueue(), __func__, this,
|
||||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -2167,9 +2178,9 @@ MediaDecoderStateMachine::DecodeError()
|
|||||||
// Change state to shutdown before sending error report to MediaDecoder
|
// Change state to shutdown before sending error report to MediaDecoder
|
||||||
// and the HTMLMediaElement, so that our pipeline can start exiting
|
// and the HTMLMediaElement, so that our pipeline can start exiting
|
||||||
// cleanly during the sync dispatch below.
|
// cleanly during the sync dispatch below.
|
||||||
DECODER_WARN("Decode error, changed state to SHUTDOWN due to error");
|
ScheduleStateMachine();
|
||||||
SetState(DECODER_STATE_SHUTDOWN);
|
SetState(DECODER_STATE_SHUTDOWN);
|
||||||
mScheduler->ScheduleAndShutdown();
|
DECODER_WARN("Decode error, changed state to SHUTDOWN due to error");
|
||||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||||
|
|
||||||
// Dispatch the event to call DecodeError synchronously. This ensures
|
// Dispatch the event to call DecodeError synchronously. This ensures
|
||||||
@ -2322,12 +2333,12 @@ MediaDecoderStateMachine::DecodeFirstFrame()
|
|||||||
if (HasAudio()) {
|
if (HasAudio()) {
|
||||||
RefPtr<nsIRunnable> decodeTask(
|
RefPtr<nsIRunnable> decodeTask(
|
||||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded));
|
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded));
|
||||||
AudioQueue().AddPopListener(decodeTask, GetStateMachineThread());
|
AudioQueue().AddPopListener(decodeTask, TaskQueue());
|
||||||
}
|
}
|
||||||
if (HasVideo()) {
|
if (HasVideo()) {
|
||||||
RefPtr<nsIRunnable> decodeTask(
|
RefPtr<nsIRunnable> decodeTask(
|
||||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
|
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
|
||||||
VideoQueue().AddPopListener(decodeTask, GetStateMachineThread());
|
VideoQueue().AddPopListener(decodeTask, TaskQueue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsRealTime()) {
|
if (IsRealTime()) {
|
||||||
@ -2345,7 +2356,7 @@ MediaDecoderStateMachine::DecodeFirstFrame()
|
|||||||
if (HasAudio()) {
|
if (HasAudio()) {
|
||||||
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
||||||
__func__, &MediaDecoderReader::RequestAudioData)
|
__func__, &MediaDecoderReader::RequestAudioData)
|
||||||
->RefableThen(mScheduler.get(), __func__, this,
|
->RefableThen(TaskQueue(), __func__, this,
|
||||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||||
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
||||||
}
|
}
|
||||||
@ -2353,7 +2364,7 @@ MediaDecoderStateMachine::DecodeFirstFrame()
|
|||||||
mVideoDecodeStartTime = TimeStamp::Now();
|
mVideoDecodeStartTime = TimeStamp::Now();
|
||||||
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
||||||
__func__, &MediaDecoderReader::RequestVideoData, false, int64_t(0))
|
__func__, &MediaDecoderReader::RequestVideoData, false, int64_t(0))
|
||||||
->RefableThen(mScheduler.get(), __func__, this,
|
->RefableThen(TaskQueue(), __func__, this,
|
||||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||||
}
|
}
|
||||||
@ -2550,42 +2561,26 @@ MediaDecoderStateMachine::SeekCompleted()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runnable to dispose of the decoder and state machine on the main thread.
|
class DecoderDisposer
|
||||||
class nsDecoderDisposeEvent : public nsRunnable {
|
{
|
||||||
public:
|
public:
|
||||||
nsDecoderDisposeEvent(already_AddRefed<MediaDecoder> aDecoder,
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecoderDisposer)
|
||||||
already_AddRefed<MediaDecoderStateMachine> aStateMachine)
|
DecoderDisposer(MediaDecoder* aDecoder, MediaDecoderStateMachine* aStateMachine)
|
||||||
: mDecoder(aDecoder), mStateMachine(aStateMachine) {}
|
: mDecoder(aDecoder), mStateMachine(aStateMachine) {}
|
||||||
NS_IMETHOD Run() {
|
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
void OnTaskQueueShutdown()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mStateMachine);
|
MOZ_ASSERT(mStateMachine);
|
||||||
MOZ_ASSERT(mDecoder);
|
MOZ_ASSERT(mDecoder);
|
||||||
mStateMachine->BreakCycles();
|
mStateMachine->BreakCycles();
|
||||||
mDecoder->BreakCycles();
|
mDecoder->BreakCycles();
|
||||||
mStateMachine = nullptr;
|
mStateMachine = nullptr;
|
||||||
mDecoder = nullptr;
|
mDecoder = nullptr;
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
nsRefPtr<MediaDecoder> mDecoder;
|
|
||||||
nsRefPtr<MediaDecoderStateMachine> mStateMachine;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Runnable which dispatches an event to the main thread to dispose of the
|
|
||||||
// decoder and state machine. This runs on the state machine thread after
|
|
||||||
// the state machine has shutdown, and all events for that state machine have
|
|
||||||
// finished running.
|
|
||||||
class nsDispatchDisposeEvent : public nsRunnable {
|
|
||||||
public:
|
|
||||||
nsDispatchDisposeEvent(MediaDecoder* aDecoder,
|
|
||||||
MediaDecoderStateMachine* aStateMachine)
|
|
||||||
: mDecoder(aDecoder), mStateMachine(aStateMachine) {}
|
|
||||||
NS_IMETHOD Run() {
|
|
||||||
NS_DispatchToMainThread(new nsDecoderDisposeEvent(mDecoder.forget(),
|
|
||||||
mStateMachine.forget()));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
|
virtual ~DecoderDisposer() {}
|
||||||
nsRefPtr<MediaDecoder> mDecoder;
|
nsRefPtr<MediaDecoder> mDecoder;
|
||||||
nsRefPtr<MediaDecoderStateMachine> mStateMachine;
|
nsRefPtr<MediaDecoderStateMachine> mStateMachine;
|
||||||
};
|
};
|
||||||
@ -2594,7 +2589,7 @@ void
|
|||||||
MediaDecoderStateMachine::ShutdownReader()
|
MediaDecoderStateMachine::ShutdownReader()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(OnDecodeThread());
|
MOZ_ASSERT(OnDecodeThread());
|
||||||
mReader->Shutdown()->Then(mScheduler.get(), __func__, this,
|
mReader->Shutdown()->Then(TaskQueue(), __func__, this,
|
||||||
&MediaDecoderStateMachine::FinishShutdown,
|
&MediaDecoderStateMachine::FinishShutdown,
|
||||||
&MediaDecoderStateMachine::FinishShutdown);
|
&MediaDecoderStateMachine::FinishShutdown);
|
||||||
}
|
}
|
||||||
@ -2630,15 +2625,27 @@ MediaDecoderStateMachine::FinishShutdown()
|
|||||||
// finished and released its monitor/references. That event then will
|
// finished and released its monitor/references. That event then will
|
||||||
// dispatch an event to the main thread to release the decoder and
|
// dispatch an event to the main thread to release the decoder and
|
||||||
// state machine.
|
// state machine.
|
||||||
GetStateMachineThread()->Dispatch(
|
DECODER_LOG("Shutting down state machine task queue");
|
||||||
new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL);
|
nsCOMPtr<nsIThread> mainThread;
|
||||||
|
NS_GetMainThread(getter_AddRefs(mainThread));
|
||||||
DECODER_LOG("Dispose Event Dispatched");
|
RefPtr<DecoderDisposer> disposer = new DecoderDisposer(mDecoder, this);
|
||||||
|
TaskQueue()->BeginShutdown()->Then(mainThread.get(), __func__, disposer.get(),
|
||||||
|
&DecoderDisposer::OnTaskQueueShutdown,
|
||||||
|
&DecoderDisposer::OnTaskQueueShutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult MediaDecoderStateMachine::RunStateMachine()
|
nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||||
{
|
{
|
||||||
AssertCurrentThreadInMonitor();
|
MOZ_ASSERT(OnStateMachineThread());
|
||||||
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||||
|
|
||||||
|
mDelayedScheduler.Reset(); // Must happen on state machine thread.
|
||||||
|
mDispatchedStateMachine = false;
|
||||||
|
|
||||||
|
// If audio is being captured, stop the audio sink if it's running
|
||||||
|
if (mAudioCaptured) {
|
||||||
|
StopAudioThread();
|
||||||
|
}
|
||||||
|
|
||||||
MediaResource* resource = mDecoder->GetResource();
|
MediaResource* resource = mDecoder->GetResource();
|
||||||
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
|
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
|
||||||
@ -2668,17 +2675,6 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||||||
}
|
}
|
||||||
|
|
||||||
case DECODER_STATE_DORMANT: {
|
case DECODER_STATE_DORMANT: {
|
||||||
if (IsPlaying()) {
|
|
||||||
StopPlayback();
|
|
||||||
}
|
|
||||||
StopAudioThread();
|
|
||||||
FlushDecoding();
|
|
||||||
// Now that those threads are stopped, there's no possibility of
|
|
||||||
// mPendingWakeDecoder being needed again. Revoke it.
|
|
||||||
mPendingWakeDecoder = nullptr;
|
|
||||||
DebugOnly<nsresult> rv = DecodeTaskQueue()->Dispatch(
|
|
||||||
NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources));
|
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2739,7 +2735,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||||||
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
|
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
|
||||||
mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
|
mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
|
||||||
(mQuickBuffering ? "(quick exit)" : ""));
|
(mQuickBuffering ? "(quick exit)" : ""));
|
||||||
ScheduleStateMachine(USECS_PER_S);
|
ScheduleStateMachineIn(USECS_PER_S);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
} else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
|
} else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
|
||||||
@ -3063,7 +3059,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
|||||||
// Don't go straight back to the state machine loop since that might
|
// Don't go straight back to the state machine loop since that might
|
||||||
// cause us to start decoding again and we could flip-flop between
|
// cause us to start decoding again and we could flip-flop between
|
||||||
// decoding and quick-buffering.
|
// decoding and quick-buffering.
|
||||||
ScheduleStateMachine(USECS_PER_S);
|
ScheduleStateMachineIn(USECS_PER_S);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3125,7 +3121,12 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
|||||||
// ready state. Post an update to do so.
|
// ready state. Post an update to do so.
|
||||||
UpdateReadyState();
|
UpdateReadyState();
|
||||||
|
|
||||||
ScheduleStateMachine(remainingTime / mPlaybackRate);
|
int64_t delay = remainingTime / mPlaybackRate;
|
||||||
|
if (delay > 0) {
|
||||||
|
ScheduleStateMachineIn(delay);
|
||||||
|
} else {
|
||||||
|
ScheduleStateMachine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -3371,33 +3372,59 @@ void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult MediaDecoderStateMachine::CallRunStateMachine()
|
|
||||||
{
|
|
||||||
AssertCurrentThreadInMonitor();
|
|
||||||
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
|
||||||
|
|
||||||
// If audio is being captured, stop the audio sink if it's running
|
|
||||||
if (mAudioCaptured) {
|
|
||||||
StopAudioThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
return RunStateMachine();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult MediaDecoderStateMachine::TimeoutExpired(void* aClosure)
|
|
||||||
{
|
|
||||||
MediaDecoderStateMachine* p = static_cast<MediaDecoderStateMachine*>(aClosure);
|
|
||||||
return p->CallRunStateMachine();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
|
void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
|
||||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||||
DispatchAudioDecodeTaskIfNeeded();
|
DispatchAudioDecodeTaskIfNeeded();
|
||||||
DispatchVideoDecodeTaskIfNeeded();
|
DispatchVideoDecodeTaskIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) {
|
void
|
||||||
return mScheduler->Schedule(aUsecs);
|
MediaDecoderStateMachine::ScheduleStateMachine() {
|
||||||
|
AssertCurrentThreadInMonitor();
|
||||||
|
if (mState == DECODER_STATE_SHUTDOWN) {
|
||||||
|
NS_WARNING("Refusing to schedule shutdown state machine");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDispatchedStateMachine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mDispatchedStateMachine = true;
|
||||||
|
|
||||||
|
RefPtr<nsIRunnable> task =
|
||||||
|
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::RunStateMachine);
|
||||||
|
nsresult rv = TaskQueue()->Dispatch(task);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
(void) rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaDecoderStateMachine::ScheduleStateMachineIn(int64_t aMicroseconds)
|
||||||
|
{
|
||||||
|
AssertCurrentThreadInMonitor();
|
||||||
|
MOZ_ASSERT(OnStateMachineThread()); // mDelayedScheduler.Ensure() may Disconnect()
|
||||||
|
// the promise, which must happen on the state
|
||||||
|
// machine thread.
|
||||||
|
MOZ_ASSERT(aMicroseconds > 0);
|
||||||
|
if (mState == DECODER_STATE_SHUTDOWN) {
|
||||||
|
NS_WARNING("Refusing to schedule shutdown state machine");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDispatchedStateMachine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real-time weirdness.
|
||||||
|
if (IsRealTime()) {
|
||||||
|
aMicroseconds = std::min(aMicroseconds, int64_t(40000));
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeStamp now = TimeStamp::Now();
|
||||||
|
TimeStamp target = now + TimeDuration::FromMicroseconds(aMicroseconds);
|
||||||
|
|
||||||
|
SAMPLE_LOG("Scheduling state machine for %lf ms from now", (target - now).ToMilliseconds());
|
||||||
|
mDelayedScheduler.Ensure(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaDecoderStateMachine::OnDecodeThread() const
|
bool MediaDecoderStateMachine::OnDecodeThread() const
|
||||||
@ -3407,17 +3434,12 @@ bool MediaDecoderStateMachine::OnDecodeThread() const
|
|||||||
|
|
||||||
bool MediaDecoderStateMachine::OnStateMachineThread() const
|
bool MediaDecoderStateMachine::OnStateMachineThread() const
|
||||||
{
|
{
|
||||||
return mScheduler->OnStateMachineThread();
|
return TaskQueue()->IsCurrentThreadIn();
|
||||||
}
|
|
||||||
|
|
||||||
nsIEventTarget* MediaDecoderStateMachine::GetStateMachineThread() const
|
|
||||||
{
|
|
||||||
return mScheduler->GetStateMachineThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaDecoderStateMachine::IsStateMachineScheduled() const
|
bool MediaDecoderStateMachine::IsStateMachineScheduled() const
|
||||||
{
|
{
|
||||||
return mScheduler->IsScheduled();
|
return mDispatchedStateMachine || mDelayedScheduler.IsScheduled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate)
|
void MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate)
|
||||||
|
@ -89,8 +89,8 @@ hardware (via AudioStream).
|
|||||||
#include "MediaDecoderReader.h"
|
#include "MediaDecoderReader.h"
|
||||||
#include "MediaDecoderOwner.h"
|
#include "MediaDecoderOwner.h"
|
||||||
#include "MediaMetadataManager.h"
|
#include "MediaMetadataManager.h"
|
||||||
#include "MediaDecoderStateMachineScheduler.h"
|
|
||||||
#include "mozilla/RollingMean.h"
|
#include "mozilla/RollingMean.h"
|
||||||
|
#include "MediaTimer.h"
|
||||||
|
|
||||||
class nsITimer;
|
class nsITimer;
|
||||||
|
|
||||||
@ -211,8 +211,8 @@ public:
|
|||||||
void Play()
|
void Play()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
nsRefPtr<nsRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::PlayInternal);
|
RefPtr<nsRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::PlayInternal);
|
||||||
GetStateMachineThread()->Dispatch(r, NS_DISPATCH_NORMAL);
|
TaskQueue()->Dispatch(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -311,21 +311,30 @@ public:
|
|||||||
|
|
||||||
void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
|
void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
|
||||||
|
|
||||||
// Returns the shared state machine thread.
|
// Returns the state machine task queue.
|
||||||
nsIEventTarget* GetStateMachineThread() const;
|
MediaTaskQueue* TaskQueue() const { return mTaskQueue; }
|
||||||
|
|
||||||
// Calls ScheduleStateMachine() after taking the decoder lock. Also
|
// Calls ScheduleStateMachine() after taking the decoder lock. Also
|
||||||
// notifies the decoder thread in case it's waiting on the decoder lock.
|
// notifies the decoder thread in case it's waiting on the decoder lock.
|
||||||
void ScheduleStateMachineWithLockAndWakeDecoder();
|
void ScheduleStateMachineWithLockAndWakeDecoder();
|
||||||
|
|
||||||
// Schedules the shared state machine thread to run the state machine
|
// Schedules the shared state machine thread to run the state machine.
|
||||||
// in aUsecs microseconds from now, if it's not already scheduled to run
|
void ScheduleStateMachine();
|
||||||
// earlier, in which case the request is discarded.
|
|
||||||
nsresult ScheduleStateMachine(int64_t aUsecs = 0);
|
|
||||||
|
|
||||||
// Callback function registered with MediaDecoderStateMachineScheduler
|
// Invokes ScheduleStateMachine to run in |aMicroseconds| microseconds,
|
||||||
// to run state machine cycles.
|
// unless it's already scheduled to run earlier, in which case the
|
||||||
static nsresult TimeoutExpired(void* aClosure);
|
// request is discarded.
|
||||||
|
void ScheduleStateMachineIn(int64_t aMicroseconds);
|
||||||
|
|
||||||
|
void OnDelayedSchedule()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(OnStateMachineThread());
|
||||||
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||||
|
mDelayedScheduler.CompleteRequest();
|
||||||
|
ScheduleStateMachine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotReached() { MOZ_DIAGNOSTIC_ASSERT(false); }
|
||||||
|
|
||||||
// Set the media fragment end time. aEndTime is in microseconds.
|
// Set the media fragment end time. aEndTime is in microseconds.
|
||||||
void SetFragmentEndTime(int64_t aEndTime);
|
void SetFragmentEndTime(int64_t aEndTime);
|
||||||
@ -689,9 +698,6 @@ protected:
|
|||||||
void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
|
void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
|
||||||
AudioSegment* aOutput);
|
AudioSegment* aOutput);
|
||||||
|
|
||||||
// State machine thread run function. Defers to RunStateMachine().
|
|
||||||
nsresult CallRunStateMachine();
|
|
||||||
|
|
||||||
// Performs one "cycle" of the state machine. Polls the state, and may send
|
// Performs one "cycle" of the state machine. Polls the state, and may send
|
||||||
// a video frame to be displayed, and generally manages the decode. Called
|
// a video frame to be displayed, and generally manages the decode. Called
|
||||||
// periodically via timer to ensure the video stays in sync.
|
// periodically via timer to ensure the video stays in sync.
|
||||||
@ -745,9 +751,60 @@ protected:
|
|||||||
// state machine, audio and main threads.
|
// state machine, audio and main threads.
|
||||||
nsRefPtr<MediaDecoder> mDecoder;
|
nsRefPtr<MediaDecoder> mDecoder;
|
||||||
|
|
||||||
// Used to schedule state machine cycles. This should never outlive
|
// Task queue for running the state machine.
|
||||||
// the life cycle of the state machine.
|
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||||
const nsRefPtr<MediaDecoderStateMachineScheduler> mScheduler;
|
|
||||||
|
// True is we are decoding a realtime stream, like a camera stream.
|
||||||
|
bool mRealTime;
|
||||||
|
|
||||||
|
// True if we've dispatched a task to run the state machine but the task has
|
||||||
|
// yet to run.
|
||||||
|
bool mDispatchedStateMachine;
|
||||||
|
|
||||||
|
// Class for managing delayed dispatches of the state machine.
|
||||||
|
class DelayedScheduler {
|
||||||
|
public:
|
||||||
|
explicit DelayedScheduler(MediaDecoderStateMachine* aSelf)
|
||||||
|
: mSelf(aSelf), mMediaTimer(new MediaTimer()) {}
|
||||||
|
|
||||||
|
bool IsScheduled() const { return !mTarget.IsNull(); }
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mSelf->OnStateMachineThread(),
|
||||||
|
"Must be on state machine queue to disconnect");
|
||||||
|
if (IsScheduled()) {
|
||||||
|
mRequest.Disconnect();
|
||||||
|
mTarget = TimeStamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ensure(mozilla::TimeStamp& aTarget)
|
||||||
|
{
|
||||||
|
if (IsScheduled() && mTarget <= aTarget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Reset();
|
||||||
|
mTarget = aTarget;
|
||||||
|
mRequest.Begin(mMediaTimer->WaitUntil(mTarget, __func__)->RefableThen(
|
||||||
|
mSelf->TaskQueue(), __func__, mSelf,
|
||||||
|
&MediaDecoderStateMachine::OnDelayedSchedule,
|
||||||
|
&MediaDecoderStateMachine::NotReached));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompleteRequest()
|
||||||
|
{
|
||||||
|
mRequest.Complete();
|
||||||
|
mTarget = TimeStamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MediaDecoderStateMachine* mSelf;
|
||||||
|
nsRefPtr<MediaTimer> mMediaTimer;
|
||||||
|
MediaPromiseConsumerHolder<mozilla::MediaTimerPromise> mRequest;
|
||||||
|
TimeStamp mTarget;
|
||||||
|
|
||||||
|
} mDelayedScheduler;
|
||||||
|
|
||||||
// Time at which the last video sample was requested. If it takes too long
|
// Time at which the last video sample was requested. If it takes too long
|
||||||
// before the sample arrives, we will increase the amount of audio we buffer.
|
// before the sample arrives, we will increase the amount of audio we buffer.
|
||||||
@ -955,7 +1012,7 @@ protected:
|
|||||||
// samples we must consume before are considered to be finished prerolling.
|
// samples we must consume before are considered to be finished prerolling.
|
||||||
uint32_t AudioPrerollUsecs() const
|
uint32_t AudioPrerollUsecs() const
|
||||||
{
|
{
|
||||||
if (mScheduler->IsRealTime()) {
|
if (IsRealTime()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -966,7 +1023,7 @@ protected:
|
|||||||
|
|
||||||
uint32_t VideoPrerollFrames() const
|
uint32_t VideoPrerollFrames() const
|
||||||
{
|
{
|
||||||
return mScheduler->IsRealTime() ? 0 : GetAmpleVideoFrames() / 2;
|
return IsRealTime() ? 0 : GetAmpleVideoFrames() / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DonePrerollingAudio()
|
bool DonePrerollingAudio()
|
||||||
|
@ -1,194 +0,0 @@
|
|||||||
/* 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 "MediaDecoderStateMachineScheduler.h"
|
|
||||||
#include "SharedThreadPool.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/ReentrantMonitor.h"
|
|
||||||
#include "nsITimer.h"
|
|
||||||
#include "nsComponentManagerUtils.h"
|
|
||||||
#include "VideoUtils.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class TimerEvent : public nsITimerCallback, public nsRunnable {
|
|
||||||
typedef mozilla::MediaDecoderStateMachineScheduler Scheduler;
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
|
||||||
public:
|
|
||||||
TimerEvent(Scheduler* aScheduler, int aTimerId)
|
|
||||||
: mScheduler(aScheduler), mTimerId(aTimerId) {}
|
|
||||||
|
|
||||||
NS_IMETHOD Run() MOZ_OVERRIDE {
|
|
||||||
return mScheduler->TimeoutExpired(mTimerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD Notify(nsITimer* aTimer) MOZ_OVERRIDE {
|
|
||||||
return mScheduler->TimeoutExpired(mTimerId);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
~TimerEvent() {}
|
|
||||||
Scheduler* const mScheduler;
|
|
||||||
const int mTimerId;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS_INHERITED(TimerEvent, nsRunnable, nsITimerCallback);
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
static already_AddRefed<nsIEventTarget>
|
|
||||||
CreateStateMachineThread()
|
|
||||||
{
|
|
||||||
using mozilla::SharedThreadPool;
|
|
||||||
using mozilla::RefPtr;
|
|
||||||
RefPtr<SharedThreadPool> threadPool(
|
|
||||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
|
|
||||||
nsCOMPtr<nsIEventTarget> rv = threadPool.get();
|
|
||||||
return rv.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
MediaDecoderStateMachineScheduler::MediaDecoderStateMachineScheduler(
|
|
||||||
ReentrantMonitor& aMonitor,
|
|
||||||
nsresult (*aTimeoutCallback)(void*),
|
|
||||||
void* aClosure, bool aRealTime)
|
|
||||||
: mTimeoutCallback(aTimeoutCallback)
|
|
||||||
, mClosure(aClosure)
|
|
||||||
// Only enable realtime mode when "media.realtime_decoder.enabled" is true.
|
|
||||||
, mRealTime(aRealTime &&
|
|
||||||
Preferences::GetBool("media.realtime_decoder.enabled", false))
|
|
||||||
, mMonitor(aMonitor)
|
|
||||||
, mEventTarget(CreateStateMachineThread())
|
|
||||||
, mTimer(do_CreateInstance("@mozilla.org/timer;1"))
|
|
||||||
, mTimerId(0)
|
|
||||||
, mState(SCHEDULER_STATE_NONE)
|
|
||||||
, mInRunningStateMachine(false)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
MOZ_COUNT_CTOR(MediaDecoderStateMachineScheduler);
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaDecoderStateMachineScheduler::~MediaDecoderStateMachineScheduler()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
MOZ_COUNT_DTOR(MediaDecoderStateMachineScheduler);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
MediaDecoderStateMachineScheduler::Init()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
NS_ENSURE_TRUE(mEventTarget, NS_ERROR_FAILURE);
|
|
||||||
nsresult rv = mTimer->SetTarget(mEventTarget);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
MediaDecoderStateMachineScheduler::Schedule(int64_t aUsecs)
|
|
||||||
{
|
|
||||||
mMonitor.AssertCurrentThreadIn();
|
|
||||||
|
|
||||||
if (NS_WARN_IF(mState == SCHEDULER_STATE_SHUTDOWN)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
aUsecs = std::max<int64_t>(aUsecs, 0);
|
|
||||||
|
|
||||||
TimeStamp timeout = TimeStamp::Now() +
|
|
||||||
TimeDuration::FromMilliseconds(static_cast<double>(aUsecs) / USECS_PER_MS);
|
|
||||||
|
|
||||||
if (!mTimeout.IsNull() && timeout >= mTimeout) {
|
|
||||||
// We've already scheduled a timer set to expire at or before this time,
|
|
||||||
// or have an event dispatched to run the state machine.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ms = static_cast<uint32_t>((aUsecs / USECS_PER_MS) & 0xFFFFFFFF);
|
|
||||||
if (IsRealTime() && ms > 40) {
|
|
||||||
ms = 40;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't cancel the timer here for this function will be called from
|
|
||||||
// different threads.
|
|
||||||
|
|
||||||
nsresult rv = NS_ERROR_FAILURE;
|
|
||||||
nsRefPtr<TimerEvent> event = new TimerEvent(this, mTimerId+1);
|
|
||||||
|
|
||||||
if (ms == 0) {
|
|
||||||
// Dispatch a runnable to the state machine thread when delay is 0.
|
|
||||||
// It will has less latency than dispatching a runnable to the state
|
|
||||||
// machine thread which will then schedule a zero-delay timer.
|
|
||||||
rv = mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
|
||||||
} else if (OnStateMachineThread()) {
|
|
||||||
rv = mTimer->InitWithCallback(event, ms, nsITimer::TYPE_ONE_SHOT);
|
|
||||||
} else {
|
|
||||||
MOZ_ASSERT(false, "non-zero delay timer should be only "
|
|
||||||
"scheduled in state machine thread");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
mTimeout = timeout;
|
|
||||||
++mTimerId;
|
|
||||||
} else {
|
|
||||||
NS_WARNING("Failed to schedule state machine");
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
MediaDecoderStateMachineScheduler::TimeoutExpired(int aTimerId)
|
|
||||||
{
|
|
||||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
|
||||||
MOZ_ASSERT(OnStateMachineThread());
|
|
||||||
MOZ_ASSERT(!mInRunningStateMachine,
|
|
||||||
"State machine cycles must run in sequence!");
|
|
||||||
|
|
||||||
mInRunningStateMachine = true;
|
|
||||||
// Only run state machine cycles when id matches.
|
|
||||||
nsresult rv = NS_OK;
|
|
||||||
if (mTimerId == aTimerId) {
|
|
||||||
ResetTimer();
|
|
||||||
rv = mTimeoutCallback(mClosure);
|
|
||||||
}
|
|
||||||
mInRunningStateMachine = false;
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MediaDecoderStateMachineScheduler::ScheduleAndShutdown()
|
|
||||||
{
|
|
||||||
mMonitor.AssertCurrentThreadIn();
|
|
||||||
// Schedule next cycle to handle SHUTDOWN in state machine thread.
|
|
||||||
Schedule();
|
|
||||||
// This must be set after calling Schedule()
|
|
||||||
// which does nothing in shutdown state.
|
|
||||||
mState = SCHEDULER_STATE_SHUTDOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
MediaDecoderStateMachineScheduler::OnStateMachineThread() const
|
|
||||||
{
|
|
||||||
bool rv = false;
|
|
||||||
mEventTarget->IsOnCurrentThread(&rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
MediaDecoderStateMachineScheduler::IsScheduled() const
|
|
||||||
{
|
|
||||||
mMonitor.AssertCurrentThreadIn();
|
|
||||||
return !mTimeout.IsNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MediaDecoderStateMachineScheduler::ResetTimer()
|
|
||||||
{
|
|
||||||
mMonitor.AssertCurrentThreadIn();
|
|
||||||
mTimer->Cancel();
|
|
||||||
mTimeout = TimeStamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
@ -1,78 +0,0 @@
|
|||||||
/* -*- 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 MediaDecoderStateMachineScheduler_h__
|
|
||||||
#define MediaDecoderStateMachineScheduler_h__
|
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
#include "mozilla/TimeStamp.h"
|
|
||||||
#include "mozilla/DebugOnly.h"
|
|
||||||
|
|
||||||
class nsITimer;
|
|
||||||
class nsIEventTarget;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
class ReentrantMonitor;
|
|
||||||
|
|
||||||
class MediaDecoderStateMachineScheduler {
|
|
||||||
enum State {
|
|
||||||
SCHEDULER_STATE_NONE,
|
|
||||||
SCHEDULER_STATE_SHUTDOWN
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachineScheduler)
|
|
||||||
MediaDecoderStateMachineScheduler(ReentrantMonitor& aMonitor,
|
|
||||||
nsresult (*aTimeoutCallback)(void*),
|
|
||||||
void* aClosure, bool aRealTime);
|
|
||||||
nsresult Init();
|
|
||||||
nsresult Schedule(int64_t aUsecs = 0);
|
|
||||||
void ScheduleAndShutdown();
|
|
||||||
nsresult TimeoutExpired(int aTimerId);
|
|
||||||
|
|
||||||
bool OnStateMachineThread() const;
|
|
||||||
bool IsScheduled() const;
|
|
||||||
|
|
||||||
bool IsRealTime() const {
|
|
||||||
return mRealTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIEventTarget* GetStateMachineThread() const {
|
|
||||||
return mEventTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
~MediaDecoderStateMachineScheduler();
|
|
||||||
void ResetTimer();
|
|
||||||
|
|
||||||
// Callback function provided by MediaDecoderStateMachine to run
|
|
||||||
// state machine cycles.
|
|
||||||
nsresult (*const mTimeoutCallback)(void*);
|
|
||||||
// Since StateMachineScheduler will never outlive the state machine,
|
|
||||||
// it is safe to keep a raw pointer only to avoid reference cycles.
|
|
||||||
void* const mClosure;
|
|
||||||
// True is we are decoding a realtime stream, like a camera stream
|
|
||||||
const bool mRealTime;
|
|
||||||
// Monitor of the decoder
|
|
||||||
ReentrantMonitor& mMonitor;
|
|
||||||
// State machine thread
|
|
||||||
const nsCOMPtr<nsIEventTarget> mEventTarget;
|
|
||||||
// Timer to schedule callbacks to run the state machine cycles.
|
|
||||||
nsCOMPtr<nsITimer> mTimer;
|
|
||||||
// Timestamp at which the next state machine cycle will run.
|
|
||||||
TimeStamp mTimeout;
|
|
||||||
// The id of timer tasks, timer callback will only run if id matches.
|
|
||||||
int mTimerId;
|
|
||||||
// No more state machine cycles in shutdown state.
|
|
||||||
State mState;
|
|
||||||
|
|
||||||
// Used to check if state machine cycles are running in sequence.
|
|
||||||
DebugOnly<bool> mInRunningStateMachine;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // MediaDecoderStateMachineScheduler_h__
|
|
@ -112,8 +112,8 @@ using dom::SupportedVideoConstraints;
|
|||||||
static bool
|
static bool
|
||||||
HostInDomain(const nsCString &aHost, const nsCString &aPattern)
|
HostInDomain(const nsCString &aHost, const nsCString &aPattern)
|
||||||
{
|
{
|
||||||
PRInt32 patternOffset = 0;
|
int32_t patternOffset = 0;
|
||||||
PRInt32 hostOffset = 0;
|
int32_t hostOffset = 0;
|
||||||
|
|
||||||
// Act on '*.' wildcard in the left-most position in a domain pattern.
|
// Act on '*.' wildcard in the left-most position in a domain pattern.
|
||||||
if (aPattern.Length() > 2 && aPattern[0] == '*' && aPattern[1] == '.') {
|
if (aPattern.Length() > 2 && aPattern[0] == '*' && aPattern[1] == '.') {
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "MediaPromise.h"
|
#include "MediaPromise.h"
|
||||||
|
|
||||||
#include "MediaDecoderStateMachineScheduler.h"
|
|
||||||
#include "MediaTaskQueue.h"
|
#include "MediaTaskQueue.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
@ -25,12 +24,6 @@ DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnabl
|
|||||||
return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
DispatchMediaPromiseRunnable(MediaDecoderStateMachineScheduler* aScheduler, nsIRunnable* aRunnable)
|
|
||||||
{
|
|
||||||
return aScheduler->GetStateMachineThread()->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AssertOnThread(MediaTaskQueue* aQueue)
|
AssertOnThread(MediaTaskQueue* aQueue)
|
||||||
{
|
{
|
||||||
@ -44,11 +37,5 @@ void AssertOnThread(nsIEventTarget* aTarget)
|
|||||||
MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
|
MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AssertOnThread(MediaDecoderStateMachineScheduler* aScheduler)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aScheduler->OnStateMachineThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
#include "mozilla/Monitor.h"
|
#include "mozilla/Monitor.h"
|
||||||
|
#include "mozilla/unused.h"
|
||||||
|
|
||||||
/* Polyfill __func__ on MSVC for consumers to pass to the MediaPromise API. */
|
/* Polyfill __func__ on MSVC for consumers to pass to the MediaPromise API. */
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -32,17 +33,14 @@ extern PRLogModuleInfo* gMediaPromiseLog;
|
|||||||
PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
|
PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
|
||||||
|
|
||||||
class MediaTaskQueue;
|
class MediaTaskQueue;
|
||||||
class MediaDecoderStateMachineScheduler;
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
|
nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
|
||||||
nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
|
nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
|
||||||
nsresult DispatchMediaPromiseRunnable(MediaDecoderStateMachineScheduler* aScheduler, nsIRunnable* aRunnable);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void AssertOnThread(MediaTaskQueue* aQueue);
|
void AssertOnThread(MediaTaskQueue* aQueue);
|
||||||
void AssertOnThread(nsIEventTarget* aTarget);
|
void AssertOnThread(nsIEventTarget* aTarget);
|
||||||
void AssertOnThread(MediaDecoderStateMachineScheduler* aScheduler);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -108,18 +106,11 @@ public:
|
|||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Consumer)
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Consumer)
|
||||||
|
|
||||||
void Disconnect()
|
virtual void Disconnect() = 0;
|
||||||
{
|
|
||||||
AssertOnDispatchThread();
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!mComplete);
|
|
||||||
mDisconnected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
// MSVC complains when an inner class (ThenValueBase::{Resolve,Reject}Runnable)
|
||||||
virtual void AssertOnDispatchThread() = 0;
|
// tries to access an inherited protected member.
|
||||||
#else
|
bool IsDisconnected() const { return mDisconnected; }
|
||||||
void AssertOnDispatchThread() {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Consumer() : mComplete(false), mDisconnected(false) {}
|
Consumer() : mComplete(false), mDisconnected(false) {}
|
||||||
@ -149,7 +140,7 @@ protected:
|
|||||||
|
|
||||||
~ResolveRunnable()
|
~ResolveRunnable()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mThenValue);
|
MOZ_DIAGNOSTIC_ASSERT(!mThenValue || mThenValue->IsDisconnected());
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP Run()
|
NS_IMETHODIMP Run()
|
||||||
@ -174,7 +165,7 @@ protected:
|
|||||||
|
|
||||||
~RejectRunnable()
|
~RejectRunnable()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mThenValue);
|
MOZ_DIAGNOSTIC_ASSERT(!mThenValue || mThenValue->IsDisconnected());
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP Run()
|
NS_IMETHODIMP Run()
|
||||||
@ -252,35 +243,54 @@ protected:
|
|||||||
PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
|
PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
|
||||||
resolved ? "Resolving" : "Rejecting", ThenValueBase::mCallSite,
|
resolved ? "Resolving" : "Rejecting", ThenValueBase::mCallSite,
|
||||||
runnable.get(), aPromise, this);
|
runnable.get(), aPromise, this);
|
||||||
DebugOnly<nsresult> rv = detail::DispatchMediaPromiseRunnable(mResponseTarget, runnable);
|
nsresult rv = detail::DispatchMediaPromiseRunnable(mResponseTarget, runnable);
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
unused << rv;
|
||||||
|
|
||||||
|
// NB: mDisconnected is only supposed to be accessed on the dispatch
|
||||||
|
// thread. However, we require the consumer to have disconnected any
|
||||||
|
// oustanding promise requests _before_ initiating shutdown on the
|
||||||
|
// thread or task queue. So the only non-buggy scenario for dispatch
|
||||||
|
// failing involves the target thread being unable to manipulate the
|
||||||
|
// ThenValue (since it's been disconnected), so it's safe to read here.
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv) || Consumer::mDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
virtual void AssertOnDispatchThread() MOZ_OVERRIDE
|
void AssertOnDispatchThread()
|
||||||
{
|
{
|
||||||
detail::AssertOnThread(mResponseTarget);
|
detail::AssertOnThread(mResponseTarget);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
void AssertOnDispatchThread() {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
virtual void Disconnect() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
AssertOnDispatchThread();
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!Consumer::mComplete);
|
||||||
|
Consumer::mDisconnected = true;
|
||||||
|
|
||||||
|
// If a Consumer has been disconnected, we don't guarantee that the
|
||||||
|
// resolve/reject runnable will be dispatched. Null out our refcounted
|
||||||
|
// this-value now so that it's released predictably on the dispatch thread.
|
||||||
|
mThisVal = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void DoResolve(ResolveValueType aResolveValue) MOZ_OVERRIDE
|
virtual void DoResolve(ResolveValueType aResolveValue) MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
Consumer::mComplete = true;
|
Consumer::mComplete = true;
|
||||||
if (Consumer::mDisconnected) {
|
if (Consumer::mDisconnected) {
|
||||||
|
MOZ_ASSERT(!mThisVal);
|
||||||
PROMISE_LOG("ThenValue::DoResolve disconnected - bailing out [this=%p]", this);
|
PROMISE_LOG("ThenValue::DoResolve disconnected - bailing out [this=%p]", this);
|
||||||
// Null these out for the same reasons described below.
|
|
||||||
mResponseTarget = nullptr;
|
|
||||||
mThisVal = nullptr;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aResolveValue);
|
InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aResolveValue);
|
||||||
|
|
||||||
// Null these out after invoking the callback so that any references are
|
// Null out mThisVal after invoking the callback so that any references are
|
||||||
// released predictably on the target thread. Otherwise, they would be
|
// released predictably on the dispatch thread. Otherwise, it would be
|
||||||
// released on whatever thread last drops its reference to the ThenValue,
|
// released on whatever thread last drops its reference to the ThenValue,
|
||||||
// which may or may not be ok.
|
// which may or may not be ok.
|
||||||
mResponseTarget = nullptr;
|
|
||||||
mThisVal = nullptr;
|
mThisVal = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,25 +298,22 @@ protected:
|
|||||||
{
|
{
|
||||||
Consumer::mComplete = true;
|
Consumer::mComplete = true;
|
||||||
if (Consumer::mDisconnected) {
|
if (Consumer::mDisconnected) {
|
||||||
|
MOZ_ASSERT(!mThisVal);
|
||||||
PROMISE_LOG("ThenValue::DoReject disconnected - bailing out [this=%p]", this);
|
PROMISE_LOG("ThenValue::DoReject disconnected - bailing out [this=%p]", this);
|
||||||
// Null these out for the same reasons described below.
|
|
||||||
mResponseTarget = nullptr;
|
|
||||||
mThisVal = nullptr;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aRejectValue);
|
InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aRejectValue);
|
||||||
|
|
||||||
// Null these out after invoking the callback so that any references are
|
// Null out mThisVal after invoking the callback so that any references are
|
||||||
// released predictably on the target thread. Otherwise, they would be
|
// released predictably on the dispatch thread. Otherwise, it would be
|
||||||
// released on whatever thread last drops its reference to the ThenValue,
|
// released on whatever thread last drops its reference to the ThenValue,
|
||||||
// which may or may not be ok.
|
// which may or may not be ok.
|
||||||
mResponseTarget = nullptr;
|
|
||||||
mThisVal = nullptr;
|
mThisVal = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsRefPtr<TargetType> mResponseTarget;
|
nsRefPtr<TargetType> mResponseTarget; // May be released on any thread.
|
||||||
nsRefPtr<ThisType> mThisVal;
|
nsRefPtr<ThisType> mThisVal; // Only accessed and refcounted on dispatch thread.
|
||||||
ResolveMethodType mResolveMethod;
|
ResolveMethodType mResolveMethod;
|
||||||
RejectMethodType mRejectMethod;
|
RejectMethodType mRejectMethod;
|
||||||
};
|
};
|
||||||
@ -661,7 +668,7 @@ ProxyInternal(TargetType* aTarget, MethodCallBase<PromiseType>* aMethodCall, con
|
|||||||
nsRefPtr<ProxyRunnable<PromiseType>> r = new ProxyRunnable<PromiseType>(p, aMethodCall);
|
nsRefPtr<ProxyRunnable<PromiseType>> r = new ProxyRunnable<PromiseType>(p, aMethodCall);
|
||||||
nsresult rv = detail::DispatchMediaPromiseRunnable(aTarget, r);
|
nsresult rv = detail::DispatchMediaPromiseRunnable(aTarget, r);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||||
(void) rv; // Avoid compilation failures in builds with MOZ_DIAGNOSTIC_ASSERT disabled.
|
unused << rv;
|
||||||
return Move(p);
|
return Move(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ template <class T> class MediaQueue : private nsDeque {
|
|||||||
mPopListeners.Clear();
|
mPopListeners.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddPopListener(nsIRunnable* aRunnable, nsIEventTarget* aTarget) {
|
void AddPopListener(nsIRunnable* aRunnable, MediaTaskQueue* aTarget) {
|
||||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||||
mPopListeners.AppendElement(Listener(aRunnable, aTarget));
|
mPopListeners.AppendElement(Listener(aRunnable, aTarget));
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ private:
|
|||||||
mutable ReentrantMonitor mReentrantMonitor;
|
mutable ReentrantMonitor mReentrantMonitor;
|
||||||
|
|
||||||
struct Listener {
|
struct Listener {
|
||||||
Listener(nsIRunnable* aRunnable, nsIEventTarget* aTarget)
|
Listener(nsIRunnable* aRunnable, MediaTaskQueue* aTarget)
|
||||||
: mRunnable(aRunnable)
|
: mRunnable(aRunnable)
|
||||||
, mTarget(aTarget)
|
, mTarget(aTarget)
|
||||||
{
|
{
|
||||||
@ -177,7 +177,7 @@ private:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
RefPtr<nsIRunnable> mRunnable;
|
RefPtr<nsIRunnable> mRunnable;
|
||||||
RefPtr<nsIEventTarget> mTarget;
|
RefPtr<MediaTaskQueue> mTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
nsTArray<Listener> mPopListeners;
|
nsTArray<Listener> mPopListeners;
|
||||||
@ -185,7 +185,7 @@ private:
|
|||||||
void NotifyPopListeners() {
|
void NotifyPopListeners() {
|
||||||
for (uint32_t i = 0; i < mPopListeners.Length(); i++) {
|
for (uint32_t i = 0; i < mPopListeners.Length(); i++) {
|
||||||
Listener& l = mPopListeners[i];
|
Listener& l = mPopListeners[i];
|
||||||
l.mTarget->Dispatch(l.mRunnable, NS_DISPATCH_NORMAL);
|
l.mTarget->Dispatch(l.mRunnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ MediaStreamGraphImpl::UpdateBufferSufficiencyState(SourceMediaStream* aStream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < runnables.Length(); ++i) {
|
for (uint32_t i = 0; i < runnables.Length(); ++i) {
|
||||||
runnables[i].mTarget->Dispatch(runnables[i].mRunnable, 0);
|
runnables[i].mTarget->Dispatch(runnables[i].mRunnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1084,6 +1084,23 @@ SetImageToBlackPixel(PlanarYCbCrImage* aImage)
|
|||||||
aImage->SetData(data);
|
aImage->SetData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class VideoFrameContainerInvalidateRunnable : public nsRunnable {
|
||||||
|
public:
|
||||||
|
explicit VideoFrameContainerInvalidateRunnable(VideoFrameContainer* aVideoFrameContainer)
|
||||||
|
: mVideoFrameContainer(aVideoFrameContainer)
|
||||||
|
{}
|
||||||
|
NS_IMETHOD Run()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
mVideoFrameContainer->Invalidate();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
||||||
{
|
{
|
||||||
@ -1147,7 +1164,7 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> event =
|
nsCOMPtr<nsIRunnable> event =
|
||||||
NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate);
|
new VideoFrameContainerInvalidateRunnable(output);
|
||||||
DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||||
}
|
}
|
||||||
if (!aStream->mNotifiedFinished) {
|
if (!aStream->mNotifiedFinished) {
|
||||||
@ -2476,21 +2493,21 @@ SourceMediaStream::GetEndOfAppendedData(TrackID aID)
|
|||||||
|
|
||||||
void
|
void
|
||||||
SourceMediaStream::DispatchWhenNotEnoughBuffered(TrackID aID,
|
SourceMediaStream::DispatchWhenNotEnoughBuffered(TrackID aID,
|
||||||
nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable)
|
MediaTaskQueue* aSignalQueue, nsIRunnable* aSignalRunnable)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
TrackData* data = FindDataForTrack(aID);
|
TrackData* data = FindDataForTrack(aID);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
aSignalThread->Dispatch(aSignalRunnable, 0);
|
aSignalQueue->Dispatch(aSignalRunnable);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->mHaveEnough) {
|
if (data->mHaveEnough) {
|
||||||
if (data->mDispatchWhenNotEnough.IsEmpty()) {
|
if (data->mDispatchWhenNotEnough.IsEmpty()) {
|
||||||
data->mDispatchWhenNotEnough.AppendElement()->Init(aSignalThread, aSignalRunnable);
|
data->mDispatchWhenNotEnough.AppendElement()->Init(aSignalQueue, aSignalRunnable);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
aSignalThread->Dispatch(aSignalRunnable, 0);
|
aSignalQueue->Dispatch(aSignalRunnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "VideoFrameContainer.h"
|
#include "VideoFrameContainer.h"
|
||||||
#include "VideoSegment.h"
|
#include "VideoSegment.h"
|
||||||
#include "MainThreadUtils.h"
|
#include "MainThreadUtils.h"
|
||||||
|
#include "MediaTaskQueue.h"
|
||||||
#include "nsAutoRef.h"
|
#include "nsAutoRef.h"
|
||||||
#include "GraphDriver.h"
|
#include "GraphDriver.h"
|
||||||
#include <speex/speex_resampler.h>
|
#include <speex/speex_resampler.h>
|
||||||
@ -783,7 +784,7 @@ public:
|
|||||||
* does not exist. No op if a runnable is already present for this track.
|
* does not exist. No op if a runnable is already present for this track.
|
||||||
*/
|
*/
|
||||||
void DispatchWhenNotEnoughBuffered(TrackID aID,
|
void DispatchWhenNotEnoughBuffered(TrackID aID,
|
||||||
nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable);
|
MediaTaskQueue* aSignalQueue, nsIRunnable* aSignalRunnable);
|
||||||
/**
|
/**
|
||||||
* Indicate that a track has ended. Do not do any more API calls
|
* Indicate that a track has ended. Do not do any more API calls
|
||||||
* affecting this track.
|
* affecting this track.
|
||||||
@ -847,14 +848,14 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct ThreadAndRunnable {
|
struct ThreadAndRunnable {
|
||||||
void Init(nsIEventTarget* aTarget, nsIRunnable* aRunnable)
|
void Init(MediaTaskQueue* aTarget, nsIRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
mTarget = aTarget;
|
mTarget = aTarget;
|
||||||
mRunnable = aRunnable;
|
mRunnable = aRunnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIEventTarget> mTarget;
|
nsRefPtr<MediaTaskQueue> mTarget;
|
||||||
nsCOMPtr<nsIRunnable> mRunnable;
|
RefPtr<nsIRunnable> mRunnable;
|
||||||
};
|
};
|
||||||
enum TrackCommands {
|
enum TrackCommands {
|
||||||
TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,
|
TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,
|
||||||
|
165
dom/media/MediaTimer.cpp
Normal file
165
dom/media/MediaTimer.cpp
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/* -*- 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 "MediaTimer.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "nsComponentManagerUtils.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
NS_IMPL_ADDREF(MediaTimer)
|
||||||
|
NS_IMPL_RELEASE_WITH_DESTROY(MediaTimer, DispatchDestroy())
|
||||||
|
|
||||||
|
MediaTimer::MediaTimer()
|
||||||
|
: mMonitor("MediaTimer Monitor")
|
||||||
|
, mTimer(do_CreateInstance("@mozilla.org/timer;1"))
|
||||||
|
, mUpdateScheduled(false)
|
||||||
|
{
|
||||||
|
// Use the SharedThreadPool to create an nsIThreadPool with a maximum of one
|
||||||
|
// thread, which is equivalent to an nsIThread for our purposes.
|
||||||
|
RefPtr<SharedThreadPool> threadPool(
|
||||||
|
SharedThreadPool::Get(NS_LITERAL_CSTRING("MediaTimer"), 1));
|
||||||
|
mThread = threadPool.get();
|
||||||
|
mTimer->SetTarget(mThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaTimer::DispatchDestroy()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIRunnable> task = NS_NewNonOwningRunnableMethod(this, &MediaTimer::Destroy);
|
||||||
|
nsresult rv = mThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
(void) rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaTimer::Destroy()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(OnMediaTimerThread());
|
||||||
|
|
||||||
|
// Reject any outstanding entries. There's no need to acquire the monitor
|
||||||
|
// here, because we're on the timer thread and all other references to us
|
||||||
|
// must be gone.
|
||||||
|
while (!mEntries.empty()) {
|
||||||
|
mEntries.top().mPromise->Reject(false, __func__);
|
||||||
|
mEntries.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel the timer if necessary.
|
||||||
|
CancelTimerIfArmed();
|
||||||
|
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MediaTimer::OnMediaTimerThread()
|
||||||
|
{
|
||||||
|
bool rv = false;
|
||||||
|
mThread->IsOnCurrentThread(&rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<MediaTimerPromise>
|
||||||
|
MediaTimer::WaitUntil(const TimeStamp& aTimeStamp, const char* aCallSite)
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
Entry e(aTimeStamp, aCallSite);
|
||||||
|
nsRefPtr<MediaTimerPromise> p = e.mPromise.get();
|
||||||
|
mEntries.push(e);
|
||||||
|
ScheduleUpdate();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaTimer::ScheduleUpdate()
|
||||||
|
{
|
||||||
|
mMonitor.AssertCurrentThreadOwns();
|
||||||
|
if (mUpdateScheduled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mUpdateScheduled = true;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(this, &MediaTimer::Update);
|
||||||
|
nsresult rv = mThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
(void) rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaTimer::Update()
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
UpdateLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaTimer::UpdateLocked()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(OnMediaTimerThread());
|
||||||
|
mMonitor.AssertCurrentThreadOwns();
|
||||||
|
mUpdateScheduled = false;
|
||||||
|
|
||||||
|
// Resolve all the promises whose time is up.
|
||||||
|
TimeStamp now = TimeStamp::Now();
|
||||||
|
while (!mEntries.empty() && mEntries.top().mTimeStamp <= now) {
|
||||||
|
mEntries.top().mPromise->Resolve(true, __func__);
|
||||||
|
mEntries.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've got no more entries, cancel any pending timer and bail out.
|
||||||
|
if (mEntries.empty()) {
|
||||||
|
CancelTimerIfArmed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've got more entries - (re)arm the timer for the soonest one.
|
||||||
|
if (!TimerIsArmed() || mEntries.top().mTimeStamp < mCurrentTimerTarget) {
|
||||||
|
CancelTimerIfArmed();
|
||||||
|
ArmTimer(mEntries.top().mTimeStamp, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use a callback function, rather than a callback method, to ensure that
|
||||||
|
* the nsITimer does not artifically keep the refcount of the MediaTimer above
|
||||||
|
* zero. When the MediaTimer is destroyed, it safely cancels the nsITimer so that
|
||||||
|
* we never fire against a dangling closure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
MediaTimer::TimerCallback(nsITimer* aTimer, void* aClosure)
|
||||||
|
{
|
||||||
|
static_cast<MediaTimer*>(aClosure)->TimerFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaTimer::TimerFired()
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
MOZ_ASSERT(OnMediaTimerThread());
|
||||||
|
mCurrentTimerTarget = TimeStamp();
|
||||||
|
UpdateLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaTimer::ArmTimer(const TimeStamp& aTarget, const TimeStamp& aNow)
|
||||||
|
{
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!TimerIsArmed());
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aTarget > aNow);
|
||||||
|
|
||||||
|
// XPCOM timer resolution is in milliseconds. It's important to never resolve
|
||||||
|
// a timer when mTarget might compare < now (even if very close), so round up.
|
||||||
|
unsigned long delay = std::ceil((aTarget - aNow).ToMilliseconds());
|
||||||
|
mCurrentTimerTarget = aTarget;
|
||||||
|
nsresult rv = mTimer->InitWithFuncCallback(&TimerCallback, this, delay, nsITimer::TYPE_ONE_SHOT);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
(void) rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
99
dom/media/MediaTimer.h
Normal file
99
dom/media/MediaTimer.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/* -*- 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/. */
|
||||||
|
|
||||||
|
#if !defined(MediaTimer_h_)
|
||||||
|
#define MediaTimer_h_
|
||||||
|
|
||||||
|
#include "MediaPromise.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include "nsITimer.h"
|
||||||
|
#include "nsRefPtr.h"
|
||||||
|
|
||||||
|
#include "mozilla/Monitor.h"
|
||||||
|
#include "mozilla/TimeStamp.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
// This promise type is only exclusive because so far there isn't a reason for
|
||||||
|
// it not to be. Feel free to change that.
|
||||||
|
typedef MediaPromise<bool, bool, /* IsExclusive = */ true> MediaTimerPromise;
|
||||||
|
|
||||||
|
// Timers only know how to fire at a given thread, which creates an impedence
|
||||||
|
// mismatch with code that operates with MediaTaskQueues. This class solves
|
||||||
|
// that mismatch with a dedicated (but shared) thread and a nice MediaPromise-y
|
||||||
|
// interface.
|
||||||
|
class MediaTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MediaTimer();
|
||||||
|
|
||||||
|
// We use a release with a custom Destroy().
|
||||||
|
NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
|
||||||
|
NS_IMETHOD_(MozExternalRefCountType) Release(void);
|
||||||
|
|
||||||
|
nsRefPtr<MediaTimerPromise> WaitUntil(const TimeStamp& aTimeStamp, const char* aCallSite);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~MediaTimer() { MOZ_ASSERT(OnMediaTimerThread()); }
|
||||||
|
|
||||||
|
void DispatchDestroy(); // Invoked by Release on an arbitrary thread.
|
||||||
|
void Destroy(); // Runs on the timer thread.
|
||||||
|
|
||||||
|
bool OnMediaTimerThread();
|
||||||
|
void ScheduleUpdate();
|
||||||
|
void Update();
|
||||||
|
void UpdateLocked();
|
||||||
|
|
||||||
|
static void TimerCallback(nsITimer* aTimer, void* aClosure);
|
||||||
|
void TimerFired();
|
||||||
|
void ArmTimer(const TimeStamp& aTarget, const TimeStamp& aNow);
|
||||||
|
|
||||||
|
bool TimerIsArmed()
|
||||||
|
{
|
||||||
|
return !mCurrentTimerTarget.IsNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CancelTimerIfArmed()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(OnMediaTimerThread());
|
||||||
|
if (TimerIsArmed()) {
|
||||||
|
mTimer->Cancel();
|
||||||
|
mCurrentTimerTarget = TimeStamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
TimeStamp mTimeStamp;
|
||||||
|
nsRefPtr<MediaTimerPromise::Private> mPromise;
|
||||||
|
|
||||||
|
explicit Entry(const TimeStamp& aTimeStamp, const char* aCallSite)
|
||||||
|
: mTimeStamp(aTimeStamp)
|
||||||
|
, mPromise(new MediaTimerPromise::Private(aCallSite))
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator<(const Entry& aOther) const
|
||||||
|
{
|
||||||
|
return mTimeStamp < aOther.mTimeStamp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ThreadSafeAutoRefCnt mRefCnt;
|
||||||
|
NS_DECL_OWNINGTHREAD
|
||||||
|
nsCOMPtr<nsIEventTarget> mThread;
|
||||||
|
std::priority_queue<Entry> mEntries;
|
||||||
|
Monitor mMonitor;
|
||||||
|
nsCOMPtr<nsITimer> mTimer;
|
||||||
|
TimeStamp mCurrentTimerTarget;
|
||||||
|
bool mUpdateScheduled;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
@ -136,7 +136,9 @@ nsresult
|
|||||||
AVCCMediaDataDecoder::Shutdown()
|
AVCCMediaDataDecoder::Shutdown()
|
||||||
{
|
{
|
||||||
if (mDecoder) {
|
if (mDecoder) {
|
||||||
return mDecoder->Shutdown();
|
nsresult rv = mDecoder->Shutdown();
|
||||||
|
mDecoder = nullptr;
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -165,10 +167,7 @@ AVCCMediaDataDecoder::AllocateMediaResources()
|
|||||||
void
|
void
|
||||||
AVCCMediaDataDecoder::ReleaseMediaResources()
|
AVCCMediaDataDecoder::ReleaseMediaResources()
|
||||||
{
|
{
|
||||||
if (mDecoder) {
|
Shutdown();
|
||||||
mDecoder->Shutdown();
|
|
||||||
mDecoder = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -280,7 +279,8 @@ AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aCo
|
|||||||
{
|
{
|
||||||
nsRefPtr<MediaDataDecoder> decoder;
|
nsRefPtr<MediaDataDecoder> decoder;
|
||||||
|
|
||||||
if (strcmp(aConfig.mime_type, "video/avc") ||
|
if ((strcmp(aConfig.mime_type, "video/avc") &&
|
||||||
|
strcmp(aConfig.mime_type, "video/mp4")) ||
|
||||||
!mPDM->DecoderNeedsAVCC(aConfig)) {
|
!mPDM->DecoderNeedsAVCC(aConfig)) {
|
||||||
// There is no need for an AVCC wrapper for non-AVC content.
|
// There is no need for an AVCC wrapper for non-AVC content.
|
||||||
decoder = mPDM->CreateVideoDecoder(aConfig,
|
decoder = mPDM->CreateVideoDecoder(aConfig,
|
||||||
|
@ -39,8 +39,8 @@ PRLogModuleInfo* GetDemuxerLog() {
|
|||||||
}
|
}
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
#define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
#define LOG(arg, ...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, ("MP4Reader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||||
#define VLOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
|
#define VLOG(arg, ...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, ("MP4Reader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||||
#else
|
#else
|
||||||
#define LOG(...)
|
#define LOG(...)
|
||||||
#define VLOG(...)
|
#define VLOG(...)
|
||||||
@ -322,7 +322,7 @@ bool MP4Reader::IsWaitingOnCDMResource() {
|
|||||||
// We'll keep waiting if the CDM hasn't informed Gecko of its capabilities.
|
// We'll keep waiting if the CDM hasn't informed Gecko of its capabilities.
|
||||||
{
|
{
|
||||||
CDMCaps::AutoLock caps(proxy->Capabilites());
|
CDMCaps::AutoLock caps(proxy->Capabilites());
|
||||||
LOG("MP4Reader::IsWaitingMediaResources() capsKnown=%d", caps.AreCapsKnown());
|
LOG("capsKnown=%d", caps.AreCapsKnown());
|
||||||
return !caps.AreCapsKnown();
|
return !caps.AreCapsKnown();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -618,7 +618,7 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
|
|||||||
int64_t aTimeThreshold)
|
int64_t aTimeThreshold)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||||
VLOG("RequestVideoData skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
|
VLOG("skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
|
||||||
|
|
||||||
if (mShutdown) {
|
if (mShutdown) {
|
||||||
NS_WARNING("RequestVideoData on shutdown MP4Reader!");
|
NS_WARNING("RequestVideoData on shutdown MP4Reader!");
|
||||||
@ -654,7 +654,7 @@ nsRefPtr<MediaDecoderReader::AudioDataPromise>
|
|||||||
MP4Reader::RequestAudioData()
|
MP4Reader::RequestAudioData()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||||
VLOG("RequestAudioData");
|
VLOG("");
|
||||||
if (mShutdown) {
|
if (mShutdown) {
|
||||||
NS_WARNING("RequestAudioData on shutdown MP4Reader!");
|
NS_WARNING("RequestAudioData on shutdown MP4Reader!");
|
||||||
return AudioDataPromise::CreateAndReject(CANCELED, __func__);
|
return AudioDataPromise::CreateAndReject(CANCELED, __func__);
|
||||||
@ -789,7 +789,7 @@ MP4Reader::ReturnOutput(MediaData* aData, TrackType aTrack)
|
|||||||
|
|
||||||
if (audioData->mChannels != mInfo.mAudio.mChannels ||
|
if (audioData->mChannels != mInfo.mAudio.mChannels ||
|
||||||
audioData->mRate != mInfo.mAudio.mRate) {
|
audioData->mRate != mInfo.mAudio.mRate) {
|
||||||
LOG("MP4Reader::ReturnOutput change of sampling rate:%d->%d",
|
LOG("change of sampling rate:%d->%d",
|
||||||
mInfo.mAudio.mRate, audioData->mRate);
|
mInfo.mAudio.mRate, audioData->mRate);
|
||||||
mInfo.mAudio.mRate = audioData->mRate;
|
mInfo.mAudio.mRate = audioData->mRate;
|
||||||
mInfo.mAudio.mChannels = audioData->mChannels;
|
mInfo.mAudio.mChannels = audioData->mChannels;
|
||||||
@ -999,7 +999,7 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed
|
|||||||
nsRefPtr<MediaDecoderReader::SeekPromise>
|
nsRefPtr<MediaDecoderReader::SeekPromise>
|
||||||
MP4Reader::Seek(int64_t aTime, int64_t aEndTime)
|
MP4Reader::Seek(int64_t aTime, int64_t aEndTime)
|
||||||
{
|
{
|
||||||
LOG("MP4Reader::Seek(%lld)", aTime);
|
LOG("aTime=(%lld)", aTime);
|
||||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||||
MonitorAutoLock mon(mDemuxerMonitor);
|
MonitorAutoLock mon(mDemuxerMonitor);
|
||||||
if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) {
|
if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) {
|
||||||
@ -1019,7 +1019,7 @@ MP4Reader::Seek(int64_t aTime, int64_t aEndTime)
|
|||||||
if (mDemuxer->HasValidAudio()) {
|
if (mDemuxer->HasValidAudio()) {
|
||||||
mAudio.mTrackDemuxer->Seek(seekTime);
|
mAudio.mTrackDemuxer->Seek(seekTime);
|
||||||
}
|
}
|
||||||
LOG("MP4Reader::Seek(%lld) exit", aTime);
|
LOG("aTime=%lld exit", aTime);
|
||||||
return SeekPromise::CreateAndResolve(seekTime, __func__);
|
return SeekPromise::CreateAndResolve(seekTime, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1083,8 +1083,9 @@ bool MP4Reader::IsDormantNeeded()
|
|||||||
#endif
|
#endif
|
||||||
mVideo.mDecoder &&
|
mVideo.mDecoder &&
|
||||||
mVideo.mDecoder->IsDormantNeeded();
|
mVideo.mDecoder->IsDormantNeeded();
|
||||||
#endif
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MP4Reader::ReleaseMediaResources()
|
void MP4Reader::ReleaseMediaResources()
|
||||||
|
@ -289,7 +289,7 @@ FFmpegH264Decoder<LIBAV_VER>::~FFmpegH264Decoder()
|
|||||||
AVCodecID
|
AVCodecID
|
||||||
FFmpegH264Decoder<LIBAV_VER>::GetCodecId(const char* aMimeType)
|
FFmpegH264Decoder<LIBAV_VER>::GetCodecId(const char* aMimeType)
|
||||||
{
|
{
|
||||||
if (!strcmp(aMimeType, "video/avc")) {
|
if (!strcmp(aMimeType, "video/avc") || !strcmp(aMimeType, "video/mp4")) {
|
||||||
return AV_CODEC_ID_H264;
|
return AV_CODEC_ID_H264;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,19 @@ static const int MAX_VOUCHER_LENGTH = 500000;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
#undef LOG
|
||||||
|
#undef LOGD
|
||||||
|
|
||||||
|
#ifdef PR_LOGGING
|
||||||
|
extern PRLogModuleInfo* GetGMPLog();
|
||||||
|
#define LOG(level, x, ...) PR_LOG(GetGMPLog(), (level), (x, ##__VA_ARGS__))
|
||||||
|
#define LOGD(x, ...) LOG(PR_LOG_DEBUG, "GMPChild[pid=%d] " x, (int)base::GetCurrentProcId(), ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define LOG(level, x, ...)
|
||||||
|
#define LOGD(x, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace gmp {
|
namespace gmp {
|
||||||
|
|
||||||
GMPChild::GMPChild()
|
GMPChild::GMPChild()
|
||||||
@ -50,11 +63,13 @@ GMPChild::GMPChild()
|
|||||||
, mGMPMessageLoop(MessageLoop::current())
|
, mGMPMessageLoop(MessageLoop::current())
|
||||||
, mGMPLoader(nullptr)
|
, mGMPLoader(nullptr)
|
||||||
{
|
{
|
||||||
|
LOGD("GMPChild ctor");
|
||||||
nsDebugImpl::SetMultiprocessMode("GMP");
|
nsDebugImpl::SetMultiprocessMode("GMP");
|
||||||
}
|
}
|
||||||
|
|
||||||
GMPChild::~GMPChild()
|
GMPChild::~GMPChild()
|
||||||
{
|
{
|
||||||
|
LOGD("GMPChild dtor");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -257,7 +272,9 @@ GMPChild::Init(const std::string& aPluginPath,
|
|||||||
MessageLoop* aIOLoop,
|
MessageLoop* aIOLoop,
|
||||||
IPC::Channel* aChannel)
|
IPC::Channel* aChannel)
|
||||||
{
|
{
|
||||||
if (!Open(aChannel, aParentProcessHandle, aIOLoop)) {
|
LOGD("%s pluginPath=%s", __FUNCTION__, aPluginPath.c_str());
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!Open(aChannel, aParentProcessHandle, aIOLoop))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +290,8 @@ GMPChild::Init(const std::string& aPluginPath,
|
|||||||
bool
|
bool
|
||||||
GMPChild::RecvSetNodeId(const nsCString& aNodeId)
|
GMPChild::RecvSetNodeId(const nsCString& aNodeId)
|
||||||
{
|
{
|
||||||
|
LOGD("%s nodeId=%s", __FUNCTION__, aNodeId.Data());
|
||||||
|
|
||||||
// Store the per origin salt for the node id. Note: we do this in a
|
// Store the per origin salt for the node id. Note: we do this in a
|
||||||
// separate message than RecvStartPlugin() so that the string is not
|
// separate message than RecvStartPlugin() so that the string is not
|
||||||
// sitting in a string on the IPC code's call stack.
|
// sitting in a string on the IPC code's call stack.
|
||||||
@ -393,6 +412,8 @@ GMPChild::GetLibPath(nsACString& aOutLibPath)
|
|||||||
bool
|
bool
|
||||||
GMPChild::RecvStartPlugin()
|
GMPChild::RecvStartPlugin()
|
||||||
{
|
{
|
||||||
|
LOGD("%s", __FUNCTION__);
|
||||||
|
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
PreLoadLibraries(mPluginPath);
|
PreLoadLibraries(mPluginPath);
|
||||||
#endif
|
#endif
|
||||||
@ -447,6 +468,8 @@ GMPChild::GMPMessageLoop()
|
|||||||
void
|
void
|
||||||
GMPChild::ActorDestroy(ActorDestroyReason aWhy)
|
GMPChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
{
|
{
|
||||||
|
LOGD("%s reason=%d", __FUNCTION__, aWhy);
|
||||||
|
|
||||||
if (mGMPLoader) {
|
if (mGMPLoader) {
|
||||||
mGMPLoader->Shutdown();
|
mGMPLoader->Shutdown();
|
||||||
}
|
}
|
||||||
@ -678,6 +701,8 @@ GMPChild::RecvCrashPluginNow()
|
|||||||
bool
|
bool
|
||||||
GMPChild::RecvBeginAsyncShutdown()
|
GMPChild::RecvBeginAsyncShutdown()
|
||||||
{
|
{
|
||||||
|
LOGD("%s AsyncShutdown=%d", __FUNCTION__, mAsyncShutdown!=nullptr);
|
||||||
|
|
||||||
MOZ_ASSERT(mGMPMessageLoop == MessageLoop::current());
|
MOZ_ASSERT(mGMPMessageLoop == MessageLoop::current());
|
||||||
if (mAsyncShutdown) {
|
if (mAsyncShutdown) {
|
||||||
mAsyncShutdown->BeginShutdown();
|
mAsyncShutdown->BeginShutdown();
|
||||||
@ -690,6 +715,7 @@ GMPChild::RecvBeginAsyncShutdown()
|
|||||||
void
|
void
|
||||||
GMPChild::ShutdownComplete()
|
GMPChild::ShutdownComplete()
|
||||||
{
|
{
|
||||||
|
LOGD("%s", __FUNCTION__);
|
||||||
MOZ_ASSERT(mGMPMessageLoop == MessageLoop::current());
|
MOZ_ASSERT(mGMPMessageLoop == MessageLoop::current());
|
||||||
SendAsyncShutdownComplete();
|
SendAsyncShutdownComplete();
|
||||||
}
|
}
|
||||||
@ -775,3 +801,6 @@ GMPChild::PreLoadSandboxVoucher()
|
|||||||
|
|
||||||
} // namespace gmp
|
} // namespace gmp
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#undef LOG
|
||||||
|
#undef LOGD
|
||||||
|
@ -293,7 +293,7 @@ public:
|
|||||||
// consumers of ParseStartAndEndTimestamps to add their timestamp offset
|
// consumers of ParseStartAndEndTimestamps to add their timestamp offset
|
||||||
// manually. This allows the ContainerParser to be shared across different
|
// manually. This allows the ContainerParser to be shared across different
|
||||||
// timestampOffsets.
|
// timestampOffsets.
|
||||||
mParser = new mp4_demuxer::MoofParser(mStream, 0, &mMonitor);
|
mParser = new mp4_demuxer::MoofParser(mStream, 0, /* aIsAudio = */ false, &mMonitor);
|
||||||
mInitData = new LargeDataBuffer();
|
mInitData = new LargeDataBuffer();
|
||||||
} else if (!mStream || !mParser) {
|
} else if (!mStream || !mParser) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -102,7 +102,6 @@ EXPORTS += [
|
|||||||
'MediaDecoderOwner.h',
|
'MediaDecoderOwner.h',
|
||||||
'MediaDecoderReader.h',
|
'MediaDecoderReader.h',
|
||||||
'MediaDecoderStateMachine.h',
|
'MediaDecoderStateMachine.h',
|
||||||
'MediaDecoderStateMachineScheduler.h',
|
|
||||||
'MediaInfo.h',
|
'MediaInfo.h',
|
||||||
'MediaMetadataManager.h',
|
'MediaMetadataManager.h',
|
||||||
'MediaPromise.h',
|
'MediaPromise.h',
|
||||||
@ -112,6 +111,7 @@ EXPORTS += [
|
|||||||
'MediaSegment.h',
|
'MediaSegment.h',
|
||||||
'MediaStreamGraph.h',
|
'MediaStreamGraph.h',
|
||||||
'MediaTaskQueue.h',
|
'MediaTaskQueue.h',
|
||||||
|
'MediaTimer.h',
|
||||||
'MediaTrack.h',
|
'MediaTrack.h',
|
||||||
'MediaTrackList.h',
|
'MediaTrackList.h',
|
||||||
'MP3FrameParser.h',
|
'MP3FrameParser.h',
|
||||||
@ -181,7 +181,6 @@ UNIFIED_SOURCES += [
|
|||||||
'MediaDecoder.cpp',
|
'MediaDecoder.cpp',
|
||||||
'MediaDecoderReader.cpp',
|
'MediaDecoderReader.cpp',
|
||||||
'MediaDecoderStateMachine.cpp',
|
'MediaDecoderStateMachine.cpp',
|
||||||
'MediaDecoderStateMachineScheduler.cpp',
|
|
||||||
'MediaDevices.cpp',
|
'MediaDevices.cpp',
|
||||||
'MediaManager.cpp',
|
'MediaManager.cpp',
|
||||||
'MediaPromise.cpp',
|
'MediaPromise.cpp',
|
||||||
@ -192,6 +191,7 @@ UNIFIED_SOURCES += [
|
|||||||
'MediaStreamGraph.cpp',
|
'MediaStreamGraph.cpp',
|
||||||
'MediaStreamTrack.cpp',
|
'MediaStreamTrack.cpp',
|
||||||
'MediaTaskQueue.cpp',
|
'MediaTaskQueue.cpp',
|
||||||
|
'MediaTimer.cpp',
|
||||||
'MediaTrack.cpp',
|
'MediaTrack.cpp',
|
||||||
'MediaTrackList.cpp',
|
'MediaTrackList.cpp',
|
||||||
'MP3FrameParser.cpp',
|
'MP3FrameParser.cpp',
|
||||||
|
@ -17,12 +17,24 @@ createHTML({
|
|||||||
// output side. We then sanity check the audio by comparing the frequency domain
|
// output side. We then sanity check the audio by comparing the frequency domain
|
||||||
// data from both analysers.
|
// data from both analysers.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use as callback to Array.reduce to get an object { value, index }
|
||||||
|
* that contains the largest element in the array.
|
||||||
|
*/
|
||||||
|
var maxWithIndex = function(a, b, i) {
|
||||||
|
if (b >= a.value) {
|
||||||
|
return { value: b, index: i };
|
||||||
|
} else {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
runNetworkTest(function() {
|
runNetworkTest(function() {
|
||||||
var test = new PeerConnectionTest();
|
var test = new PeerConnectionTest();
|
||||||
|
|
||||||
var audioContext = new AudioContext();
|
var audioContext = new AudioContext();
|
||||||
var inputAnalyser;
|
var inputAnalyser, outputAnalyser;
|
||||||
var outputAnalyser;
|
var inputData, outputData;
|
||||||
|
|
||||||
test.setMediaConstraints([{audio: true}], []);
|
test.setMediaConstraints([{audio: true}], []);
|
||||||
test.chain.replace("PC_LOCAL_GUM", [
|
test.chain.replace("PC_LOCAL_GUM", [
|
||||||
@ -56,45 +68,38 @@ runNetworkTest(function() {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}]);
|
}]);
|
||||||
test.chain.append([
|
test.chain.append([
|
||||||
function WAIT_FOR_CLEAN_AUDIO(test) {
|
function GET_INPUT_DATA(test) {
|
||||||
|
inputData = new Uint8Array(inputAnalyser.frequencyBinCount);
|
||||||
|
inputAnalyser.getByteFrequencyData(inputData);
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
function GET_OUTPUT_DATA(test) {
|
||||||
// We've seen completely silent output with e10s, suggesting that the
|
// We've seen completely silent output with e10s, suggesting that the
|
||||||
// machine is overloaded. Here we wait for the media element on the
|
// machine is overloaded. Here we wait for actual audio data on the
|
||||||
// output side to progress a bit after all previous steps finish to
|
// output side before we proceed.
|
||||||
// ensure we have healthy data to check.
|
return new Promise(resolve => {
|
||||||
var wait = function(elem, startTime, resolve) {
|
is(test.pcRemote.mediaCheckers.length, 1, "One media element on remote side");
|
||||||
elem.ontimeupdate = function(ev) {
|
var elem = test.pcRemote.mediaCheckers[0].element;
|
||||||
info("Waiting... current: " + elem.currentTime + ", start: " + startTime);
|
var data = new Uint8Array(outputAnalyser.frequencyBinCount);
|
||||||
if (elem.currentTime - startTime < 0.5) {
|
elem.ontimeupdate = ev => {
|
||||||
|
outputAnalyser.getByteFrequencyData(data);
|
||||||
|
if (data.reduce(maxWithIndex, { value: -1, index: -1 }).value === 0) {
|
||||||
|
info("Waiting for output data... time: " + elem.currentTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
elem.ontimeupdate = null;
|
elem.ontimeupdate = null;
|
||||||
|
outputData = data;
|
||||||
resolve();
|
resolve();
|
||||||
}
|
};
|
||||||
};
|
});
|
||||||
return Promise.all(test.pcRemote.mediaCheckers.map(function(checker) {
|
|
||||||
var elem = checker.element;
|
|
||||||
var startTime = elem.currentTime;
|
|
||||||
return new Promise((y, n) => wait(elem, startTime, y));
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
function CHECK_AUDIO_FLOW(test) {
|
function CHECK_AUDIO_FLOW(test) {
|
||||||
// This is for sanity check only. We'll deem that the streams are working
|
// This is for sanity check only. We'll deem that the streams are working
|
||||||
// if the global maxima in the frequency domain for both the input and
|
// if the global maxima in the frequency domain for both the input and
|
||||||
// the output are within 10 (out of 1024) steps of each other.
|
// the output are within 10 (out of 1024) steps of each other.
|
||||||
|
|
||||||
var inputData = new Uint8Array(inputAnalyser.frequencyBinCount);
|
|
||||||
inputAnalyser.getByteFrequencyData(inputData);
|
|
||||||
var outputData = new Uint8Array(outputAnalyser.frequencyBinCount);
|
|
||||||
outputAnalyser.getByteFrequencyData(outputData);
|
|
||||||
is(inputData.length, outputData.length, "Equally sized datasets");
|
is(inputData.length, outputData.length, "Equally sized datasets");
|
||||||
|
|
||||||
var maxWithIndex = function(a, b, i) {
|
|
||||||
if (b >= a.value) {
|
|
||||||
return { value: b, index: i };
|
|
||||||
} else {
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var initialValue = { value: -1, index: -1 };
|
var initialValue = { value: -1, index: -1 };
|
||||||
var inputMax = inputData.reduce(maxWithIndex, initialValue);
|
var inputMax = inputData.reduce(maxWithIndex, initialValue);
|
||||||
var outputMax = outputData.reduce(maxWithIndex, initialValue);
|
var outputMax = outputData.reduce(maxWithIndex, initialValue);
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(UDPSocket::ListenerProxy,
|
||||||
|
nsIUDPSocketListener,
|
||||||
|
nsIUDPSocketInternal)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(UDPSocket)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(UDPSocket)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
|
||||||
@ -175,6 +179,11 @@ UDPSocket::CloseWithReason(nsresult aReason)
|
|||||||
|
|
||||||
mReadyState = SocketReadyState::Closed;
|
mReadyState = SocketReadyState::Closed;
|
||||||
|
|
||||||
|
if (mListenerProxy) {
|
||||||
|
mListenerProxy->Disconnect();
|
||||||
|
mListenerProxy = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (mSocket) {
|
if (mSocket) {
|
||||||
mSocket->Close();
|
mSocket->Close();
|
||||||
mSocket = nullptr;
|
mSocket = nullptr;
|
||||||
@ -430,7 +439,9 @@ UDPSocket::InitLocal(const nsAString& aLocalAddress,
|
|||||||
}
|
}
|
||||||
mLocalPort.SetValue(localPort);
|
mLocalPort.SetValue(localPort);
|
||||||
|
|
||||||
rv = mSocket->AsyncListen(this);
|
mListenerProxy = new ListenerProxy(this);
|
||||||
|
|
||||||
|
rv = mSocket->AsyncListen(mListenerProxy);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -458,7 +469,14 @@ UDPSocket::InitRemote(const nsAString& aLocalAddress,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = sock->Bind(this, NS_ConvertUTF16toUTF8(aLocalAddress), aLocalPort, mAddressReuse, mLoopback);
|
mListenerProxy = new ListenerProxy(this);
|
||||||
|
|
||||||
|
rv = sock->Bind(mListenerProxy,
|
||||||
|
NS_ConvertUTF16toUTF8(aLocalAddress),
|
||||||
|
aLocalPort,
|
||||||
|
mAddressReuse,
|
||||||
|
mLoopback);
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,30 @@ public:
|
|||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class ListenerProxy : public nsIUDPSocketListener
|
||||||
|
, public nsIUDPSocketInternal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_FORWARD_SAFE_NSIUDPSOCKETLISTENER(mSocket)
|
||||||
|
NS_FORWARD_SAFE_NSIUDPSOCKETINTERNAL(mSocket)
|
||||||
|
|
||||||
|
explicit ListenerProxy(UDPSocket* aSocket)
|
||||||
|
: mSocket(aSocket)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disconnect()
|
||||||
|
{
|
||||||
|
mSocket = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~ListenerProxy() {}
|
||||||
|
|
||||||
|
UDPSocket* mSocket;
|
||||||
|
};
|
||||||
|
|
||||||
UDPSocket(nsPIDOMWindow* aOwner,
|
UDPSocket(nsPIDOMWindow* aOwner,
|
||||||
const nsCString& aRemoteAddress,
|
const nsCString& aRemoteAddress,
|
||||||
const Nullable<uint16_t>& aRemotePort);
|
const Nullable<uint16_t>& aRemotePort);
|
||||||
@ -176,6 +200,7 @@ private:
|
|||||||
|
|
||||||
nsCOMPtr<nsIUDPSocket> mSocket;
|
nsCOMPtr<nsIUDPSocket> mSocket;
|
||||||
nsCOMPtr<nsIUDPSocketChild> mSocketChild;
|
nsCOMPtr<nsIUDPSocketChild> mSocketChild;
|
||||||
|
nsRefPtr<ListenerProxy> mListenerProxy;
|
||||||
|
|
||||||
struct MulticastCommand {
|
struct MulticastCommand {
|
||||||
enum CommandType { Join, Leave };
|
enum CommandType { Join, Leave };
|
||||||
|
@ -24,4 +24,3 @@ skip-if = true # Bug 958689
|
|||||||
[test_networkstats_enabled_perm.html]
|
[test_networkstats_enabled_perm.html]
|
||||||
skip-if = toolkit != "gonk"
|
skip-if = toolkit != "gonk"
|
||||||
[test_udpsocket.html]
|
[test_udpsocket.html]
|
||||||
skip-if = toolkit != "gonk" || (toolkit == 'gonk' && debug) # Bug 1061174 for B2G debug
|
|
||||||
|
@ -146,15 +146,9 @@ function testSendBigArray(socket) {
|
|||||||
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
|
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
|
||||||
if (byteReceived >= BIG_TYPED_ARRAY.length) {
|
if (byteReceived >= BIG_TYPED_ARRAY.length) {
|
||||||
socket.removeEventListener('message', recv_callback);
|
socket.removeEventListener('message', recv_callback);
|
||||||
clearTimeout(timeout);
|
|
||||||
resolve(socket);
|
resolve(socket);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let timeout = setTimeout(function() {
|
|
||||||
ok(false, 'timeout for sending big array');
|
|
||||||
resolve(socket);
|
|
||||||
}, 5000);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,15 +167,9 @@ function testSendBigBlob(socket) {
|
|||||||
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
|
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
|
||||||
if (byteReceived >= BIG_TYPED_ARRAY.length) {
|
if (byteReceived >= BIG_TYPED_ARRAY.length) {
|
||||||
socket.removeEventListener('message', recv_callback);
|
socket.removeEventListener('message', recv_callback);
|
||||||
clearTimeout(timeout);
|
|
||||||
resolve(socket);
|
resolve(socket);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let timeout = setTimeout(function() {
|
|
||||||
ok(false, 'timeout for sending big blob');
|
|
||||||
resolve(socket);
|
|
||||||
}, 5000);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,21 +122,26 @@ NPObjectIsOutOfProcessProxy(NPObject *obj)
|
|||||||
// Helper class that reports any JS exceptions that were thrown while
|
// Helper class that reports any JS exceptions that were thrown while
|
||||||
// the plugin executed JS.
|
// the plugin executed JS.
|
||||||
|
|
||||||
class AutoJSExceptionReporter
|
class MOZ_STACK_CLASS AutoJSExceptionReporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AutoJSExceptionReporter(JSContext* aCx)
|
AutoJSExceptionReporter(dom::AutoJSAPI& jsapi, nsJSObjWrapper* aWrapper)
|
||||||
: mCx(aCx)
|
: mJsapi(jsapi)
|
||||||
|
, mIsDestroyPending(aWrapper->mDestroyPending)
|
||||||
{
|
{
|
||||||
|
jsapi.TakeOwnershipOfErrorReporting();
|
||||||
}
|
}
|
||||||
|
|
||||||
~AutoJSExceptionReporter()
|
~AutoJSExceptionReporter()
|
||||||
{
|
{
|
||||||
JS_ReportPendingException(mCx);
|
if (mIsDestroyPending) {
|
||||||
|
mJsapi.ClearException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
JSContext *mCx;
|
dom::AutoJSAPI& mJsapi;
|
||||||
|
bool mIsDestroyPending;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -746,7 +751,7 @@ nsJSObjWrapper::NP_HasMethod(NPObject *npobj, NPIdentifier id)
|
|||||||
|
|
||||||
JSAutoCompartment ac(cx, npjsobj->mJSObj);
|
JSAutoCompartment ac(cx, npjsobj->mJSObj);
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(jsapi, npjsobj);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> v(cx);
|
JS::Rooted<JS::Value> v(cx);
|
||||||
bool ok = GetProperty(cx, npjsobj->mJSObj, id, &v);
|
bool ok = GetProperty(cx, npjsobj->mJSObj, id, &v);
|
||||||
@ -786,7 +791,7 @@ doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args,
|
|||||||
JSAutoCompartment ac(cx, jsobj);
|
JSAutoCompartment ac(cx, jsobj);
|
||||||
JS::Rooted<JS::Value> fv(cx);
|
JS::Rooted<JS::Value> fv(cx);
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(aes, npjsobj);
|
||||||
|
|
||||||
if (method != NPIdentifier_VOID) {
|
if (method != NPIdentifier_VOID) {
|
||||||
if (!GetProperty(cx, jsobj, method, &fv) ||
|
if (!GetProperty(cx, jsobj, method, &fv) ||
|
||||||
@ -871,7 +876,7 @@ nsJSObjWrapper::NP_HasProperty(NPObject *npobj, NPIdentifier npid)
|
|||||||
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
||||||
bool found, ok = false;
|
bool found, ok = false;
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(jsapi, npjsobj);
|
||||||
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
||||||
JSAutoCompartment ac(cx, jsobj);
|
JSAutoCompartment ac(cx, jsobj);
|
||||||
|
|
||||||
@ -908,7 +913,7 @@ nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier id,
|
|||||||
|
|
||||||
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(aes, npjsobj);
|
||||||
JSAutoCompartment ac(cx, npjsobj->mJSObj);
|
JSAutoCompartment ac(cx, npjsobj->mJSObj);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> v(cx);
|
JS::Rooted<JS::Value> v(cx);
|
||||||
@ -943,7 +948,7 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier npid,
|
|||||||
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(aes, npjsobj);
|
||||||
JS::Rooted<JSObject*> jsObj(cx, npjsobj->mJSObj);
|
JS::Rooted<JSObject*> jsObj(cx, npjsobj->mJSObj);
|
||||||
JSAutoCompartment ac(cx, jsObj);
|
JSAutoCompartment ac(cx, jsObj);
|
||||||
|
|
||||||
@ -977,7 +982,7 @@ nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier npid)
|
|||||||
|
|
||||||
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(jsapi, npjsobj);
|
||||||
JS::ObjectOpResult result;
|
JS::ObjectOpResult result;
|
||||||
JS::Rooted<JSObject*> obj(cx, npjsobj->mJSObj);
|
JS::Rooted<JSObject*> obj(cx, npjsobj->mJSObj);
|
||||||
JSAutoCompartment ac(cx, obj);
|
JSAutoCompartment ac(cx, obj);
|
||||||
@ -1029,7 +1034,7 @@ nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **idarray,
|
|||||||
|
|
||||||
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(jsapi, npjsobj);
|
||||||
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
||||||
JSAutoCompartment ac(cx, jsobj);
|
JSAutoCompartment ac(cx, jsobj);
|
||||||
|
|
||||||
@ -1120,6 +1125,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle<JSObject*> obj)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're running out-of-process and initializing asynchronously, and if
|
||||||
|
// the plugin has been asked to destroy itself during initialization,
|
||||||
|
// don't return any new NPObjects.
|
||||||
|
nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(npp->ndata);
|
||||||
|
if (inst->GetPlugin()->GetLibrary()->IsOOP()) {
|
||||||
|
PluginAsyncSurrogate* surrogate = PluginAsyncSurrogate::Cast(npp);
|
||||||
|
if (surrogate && surrogate->IsDestroyPending()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!cx) {
|
if (!cx) {
|
||||||
cx = GetJSContext(npp);
|
cx = GetJSContext(npp);
|
||||||
|
|
||||||
@ -2029,6 +2045,23 @@ nsJSNPRuntime::OnPluginDestroy(NPP npp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void
|
||||||
|
nsJSNPRuntime::OnPluginDestroyPending(NPP npp)
|
||||||
|
{
|
||||||
|
if (sJSObjWrappersAccessible) {
|
||||||
|
// Prevent modification of sJSObjWrappers table if we go reentrant.
|
||||||
|
sJSObjWrappersAccessible = false;
|
||||||
|
for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) {
|
||||||
|
nsJSObjWrapper *npobj = e.front().value();
|
||||||
|
MOZ_ASSERT(npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass);
|
||||||
|
if (npobj->mNpp == npp) {
|
||||||
|
npobj->mDestroyPending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sJSObjWrappersAccessible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the NPP for a NPObject.
|
// Find the NPP for a NPObject.
|
||||||
static NPP
|
static NPP
|
||||||
@ -2291,7 +2324,7 @@ nsJSObjWrapper::HasOwnProperty(NPObject *npobj, NPIdentifier npid)
|
|||||||
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
||||||
bool found, ok = false;
|
bool found, ok = false;
|
||||||
|
|
||||||
AutoJSExceptionReporter reporter(cx);
|
AutoJSExceptionReporter reporter(jsapi, npjsobj);
|
||||||
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
||||||
JSAutoCompartment ac(cx, jsobj);
|
JSAutoCompartment ac(cx, jsobj);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ class nsJSNPRuntime
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void OnPluginDestroy(NPP npp);
|
static void OnPluginDestroy(NPP npp);
|
||||||
|
static void OnPluginDestroyPending(NPP npp);
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsJSObjWrapperKey
|
class nsJSObjWrapperKey
|
||||||
@ -41,6 +42,7 @@ class nsJSObjWrapper : public NPObject
|
|||||||
public:
|
public:
|
||||||
JS::Heap<JSObject *> mJSObj;
|
JS::Heap<JSObject *> mJSObj;
|
||||||
const NPP mNpp;
|
const NPP mNpp;
|
||||||
|
bool mDestroyPending;
|
||||||
|
|
||||||
static NPObject *GetNewOrUsed(NPP npp, JSContext *cx,
|
static NPObject *GetNewOrUsed(NPP npp, JSContext *cx,
|
||||||
JS::Handle<JSObject*> obj);
|
JS::Handle<JSObject*> obj);
|
||||||
|
@ -230,8 +230,8 @@ nsPluginInstanceOwner::GetImageContainer()
|
|||||||
|
|
||||||
// NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
|
// NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
|
||||||
// into, set y-flip flags, etc, so we do this at the beginning.
|
// into, set y-flip flags, etc, so we do this at the beginning.
|
||||||
gfxSize resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
|
float resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
|
||||||
ScreenSize screenSize = (r * LayoutDeviceToScreenScale2D(resolution.width, resolution.height)).Size();
|
ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution)).Size();
|
||||||
mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
|
mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
|
||||||
|
|
||||||
container = LayerManager::CreateImageContainer();
|
container = LayerManager::CreateImageContainer();
|
||||||
@ -1468,6 +1468,23 @@ nsPluginInstanceOwner::NotifyHostCreateWidget()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsPluginInstanceOwner::NotifyDestroyPending()
|
||||||
|
{
|
||||||
|
if (!mInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool isOOP = false;
|
||||||
|
if (NS_FAILED(mInstance->GetIsOOP(&isOOP)) || !isOOP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NPP npp = nullptr;
|
||||||
|
if (NS_FAILED(mInstance->GetNPP(&npp)) || !npp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PluginAsyncSurrogate::NotifyDestroyPending(npp);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
|
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
|
||||||
{
|
{
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
@ -258,6 +258,7 @@ public:
|
|||||||
|
|
||||||
void NotifyHostAsyncInitFailed();
|
void NotifyHostAsyncInitFailed();
|
||||||
void NotifyHostCreateWidget();
|
void NotifyHostCreateWidget();
|
||||||
|
void NotifyDestroyPending();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~nsPluginInstanceOwner();
|
virtual ~nsPluginInstanceOwner();
|
||||||
|
@ -99,6 +99,7 @@ PluginAsyncSurrogate::PluginAsyncSurrogate(PluginModuleParent* aParent)
|
|||||||
, mInstantiated(false)
|
, mInstantiated(false)
|
||||||
, mAsyncSetWindow(false)
|
, mAsyncSetWindow(false)
|
||||||
, mInitCancelled(false)
|
, mInitCancelled(false)
|
||||||
|
, mDestroyPending(false)
|
||||||
, mAsyncCallsInFlight(0)
|
, mAsyncCallsInFlight(0)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aParent);
|
MOZ_ASSERT(aParent);
|
||||||
@ -179,9 +180,27 @@ PluginAsyncSurrogate::NP_GetEntryPoints(NPPluginFuncs* aFuncs)
|
|||||||
aFuncs->asfile = &PluginModuleParent::NPP_StreamAsFile;
|
aFuncs->asfile = &PluginModuleParent::NPP_StreamAsFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
PluginAsyncSurrogate::NotifyDestroyPending(NPP aInstance)
|
||||||
|
{
|
||||||
|
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||||
|
if (!surrogate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
surrogate->NotifyDestroyPending();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PluginAsyncSurrogate::NotifyDestroyPending()
|
||||||
|
{
|
||||||
|
mDestroyPending = true;
|
||||||
|
nsJSNPRuntime::OnPluginDestroyPending(mInstance);
|
||||||
|
}
|
||||||
|
|
||||||
NPError
|
NPError
|
||||||
PluginAsyncSurrogate::NPP_Destroy(NPSavedData** aSave)
|
PluginAsyncSurrogate::NPP_Destroy(NPSavedData** aSave)
|
||||||
{
|
{
|
||||||
|
NotifyDestroyPending();
|
||||||
if (!WaitForInit()) {
|
if (!WaitForInit()) {
|
||||||
return NPERR_GENERIC_ERROR;
|
return NPERR_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
@ -417,7 +436,7 @@ PluginAsyncSurrogate::SetStreamType(NPStream* aStream, uint16_t aStreamType)
|
|||||||
void
|
void
|
||||||
PluginAsyncSurrogate::OnInstanceCreated(PluginInstanceParent* aInstance)
|
PluginAsyncSurrogate::OnInstanceCreated(PluginInstanceParent* aInstance)
|
||||||
{
|
{
|
||||||
for (PRUint32 i = 0, len = mPendingNewStreamCalls.Length(); i < len; ++i) {
|
for (uint32_t i = 0, len = mPendingNewStreamCalls.Length(); i < len; ++i) {
|
||||||
PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[i];
|
PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[i];
|
||||||
uint16_t streamType = NP_NORMAL;
|
uint16_t streamType = NP_NORMAL;
|
||||||
NPError curError = aInstance->NPP_NewStream(
|
NPError curError = aInstance->NPP_NewStream(
|
||||||
|
@ -50,6 +50,8 @@ public:
|
|||||||
static const NPClass* GetClass() { return &sNPClass; }
|
static const NPClass* GetClass() { return &sNPClass; }
|
||||||
static void NP_GetEntryPoints(NPPluginFuncs* aFuncs);
|
static void NP_GetEntryPoints(NPPluginFuncs* aFuncs);
|
||||||
static PluginAsyncSurrogate* Cast(NPP aInstance);
|
static PluginAsyncSurrogate* Cast(NPP aInstance);
|
||||||
|
static void NotifyDestroyPending(NPP aInstance);
|
||||||
|
void NotifyDestroyPending();
|
||||||
|
|
||||||
virtual PluginAsyncSurrogate*
|
virtual PluginAsyncSurrogate*
|
||||||
GetAsyncSurrogate() { return this; }
|
GetAsyncSurrogate() { return this; }
|
||||||
@ -63,8 +65,9 @@ public:
|
|||||||
bool* aHasProperty, bool* aHasMethod,
|
bool* aHasProperty, bool* aHasMethod,
|
||||||
NPVariant* aResult);
|
NPVariant* aResult);
|
||||||
|
|
||||||
PluginModuleParent*
|
PluginModuleParent* GetParent() { return mParent; }
|
||||||
GetParent() { return mParent; }
|
|
||||||
|
bool IsDestroyPending() const { return mDestroyPending; }
|
||||||
|
|
||||||
bool SetAcceptingCalls(bool aAccept)
|
bool SetAcceptingCalls(bool aAccept)
|
||||||
{
|
{
|
||||||
@ -151,6 +154,7 @@ private:
|
|||||||
bool mInstantiated;
|
bool mInstantiated;
|
||||||
bool mAsyncSetWindow;
|
bool mAsyncSetWindow;
|
||||||
bool mInitCancelled;
|
bool mInitCancelled;
|
||||||
|
bool mDestroyPending;
|
||||||
int32_t mAsyncCallsInFlight;
|
int32_t mAsyncCallsInFlight;
|
||||||
|
|
||||||
static const NPClass sNPClass;
|
static const NPClass sNPClass;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define mozilla_dom_PromiseNativeHandler_h
|
#define mozilla_dom_PromiseNativeHandler_h
|
||||||
|
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
|
#include "js/TypeDecls.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user