mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 15:25:52 +00:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
bac91f37d2
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1186748 needed a CLOBBER yet again
|
||||
Bug 1191675 to fix xpcshell failures
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "ProxyAccessible.h"
|
||||
#include "Relation.h"
|
||||
#include "HyperTextAccessible-inl.h"
|
||||
#include "TextLeafAccessible.h"
|
||||
#include "ImageAccessible.h"
|
||||
#include "TableAccessible.h"
|
||||
#include "TableCellAccessible.h"
|
||||
@ -97,6 +98,13 @@ DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID) const
|
||||
return acc && acc->IsHyperText() ? acc->AsHyperText() : nullptr;
|
||||
}
|
||||
|
||||
TextLeafAccessible*
|
||||
DocAccessibleChild::IdToTextLeafAccessible(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
return acc && acc->IsTextLeaf() ? acc->AsTextLeaf() : nullptr;
|
||||
}
|
||||
|
||||
ImageAccessible*
|
||||
DocAccessibleChild::IdToImageAccessible(const uint64_t& aID) const
|
||||
{
|
||||
@ -342,6 +350,24 @@ DocAccessibleChild::RecvARIARoleAtom(const uint64_t& aID, nsString* aRole)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvGetLevelInternal(const uint64_t& aID, int32_t* aLevel)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc) {
|
||||
*aLevel = acc->GetLevelInternal();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
|
||||
{
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
*aLineNumber = acc && acc->IsTextRole() ? acc->CaretLineNumber() : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
|
||||
{
|
||||
@ -636,6 +662,17 @@ DocAccessibleChild::RecvScrollSubstringToPoint(const uint64_t& aID,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvText(const uint64_t& aID,
|
||||
nsString* aText)
|
||||
{
|
||||
TextLeafAccessible* acc = IdToTextLeafAccessible(aID);
|
||||
if (acc) {
|
||||
*aText = acc->Text();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvReplaceText(const uint64_t& aID,
|
||||
@ -1799,6 +1836,19 @@ DocAccessibleChild::RecvDocType(const uint64_t& aID,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTitle(const uint64_t& aID,
|
||||
nsString* aTitle)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc) {
|
||||
mozilla::ErrorResult rv;
|
||||
acc->GetContent()->GetTextContent(*aTitle, rv);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvURL(const uint64_t& aID,
|
||||
nsString* aURL)
|
||||
|
@ -15,6 +15,7 @@ namespace mozilla {
|
||||
namespace a11y {
|
||||
class Accessible;
|
||||
class HyperTextAccessible;
|
||||
class TextLeafAccessible;
|
||||
class ImageAccessible;
|
||||
class TableAccessible;
|
||||
class TableCellAccessible;
|
||||
@ -93,9 +94,13 @@ public:
|
||||
|
||||
virtual bool RecvARIARoleAtom(const uint64_t& aID, nsString* aRole) override;
|
||||
|
||||
virtual bool RecvGetLevelInternal(const uint64_t& aID, int32_t* aLevel) override;
|
||||
|
||||
virtual bool RecvAttributes(const uint64_t& aID,
|
||||
nsTArray<Attribute> *aAttributes) override;
|
||||
|
||||
virtual bool RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
|
||||
override;
|
||||
virtual bool RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
|
||||
override;
|
||||
virtual bool RecvSetCaretOffset(const uint64_t& aID, const int32_t& aOffset,
|
||||
@ -194,6 +199,9 @@ public:
|
||||
const int32_t& aX,
|
||||
const int32_t& aY) override;
|
||||
|
||||
virtual bool RecvText(const uint64_t& aID,
|
||||
nsString* aText) override;
|
||||
|
||||
virtual bool RecvReplaceText(const uint64_t& aID,
|
||||
const nsString& aText) override;
|
||||
|
||||
@ -448,6 +456,7 @@ public:
|
||||
|
||||
virtual bool RecvLanguage(const uint64_t& aID, nsString* aLocale) override;
|
||||
virtual bool RecvDocType(const uint64_t& aID, nsString* aType) override;
|
||||
virtual bool RecvTitle(const uint64_t& aID, nsString* aTitle) override;
|
||||
virtual bool RecvURL(const uint64_t& aID, nsString* aURL) override;
|
||||
virtual bool RecvMimeType(const uint64_t& aID, nsString* aMime) override;
|
||||
virtual bool RecvURLDocTypeMimeType(const uint64_t& aID,
|
||||
@ -460,6 +469,7 @@ private:
|
||||
Accessible* IdToAccessibleLink(const uint64_t& aID) const;
|
||||
Accessible* IdToAccessibleSelect(const uint64_t& aID) const;
|
||||
HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
|
||||
TextLeafAccessible* IdToTextLeafAccessible(const uint64_t& aID) const;
|
||||
ImageAccessible* IdToImageAccessible(const uint64_t& aID) const;
|
||||
TableCellAccessible* IdToTableCellAccessible(const uint64_t& aID) const;
|
||||
TableAccessible* IdToTableAccessible(const uint64_t& aID) const;
|
||||
|
@ -85,10 +85,12 @@ child:
|
||||
prio(high) sync IsSearchbox(uint64_t aID) returns(bool retval);
|
||||
prio(high) sync LandmarkRole(uint64_t aID) returns(nsString landmark);
|
||||
prio(high) sync ARIARoleAtom(uint64_t aID) returns(nsString role);
|
||||
prio(high) sync GetLevelInternal(uint64_t aID) returns(int32_t aLevel);
|
||||
|
||||
// AccessibleText
|
||||
|
||||
// TextSubstring is getText in IDL.
|
||||
prio(high) sync CaretLineNumber(uint64_t aID) returns(int32_t aLineNumber);
|
||||
prio(high) sync CaretOffset(uint64_t aID) returns(int32_t aOffset);
|
||||
prio(high) sync SetCaretOffset(uint64_t aID, int32_t aOffset) returns (bool aValid);
|
||||
prio(high) sync CharacterCount(uint64_t aID) returns(int32_t aCount);
|
||||
@ -135,6 +137,7 @@ child:
|
||||
uint32_t aCoordinateType,
|
||||
int32_t aX, int32_t aY);
|
||||
|
||||
prio(high) sync Text(uint64_t aID) returns(nsString aText);
|
||||
prio(high) sync ReplaceText(uint64_t aID, nsString aText);
|
||||
prio(high) sync InsertText(uint64_t aID, nsString aText, int32_t aPosition)
|
||||
returns(bool aValid);
|
||||
@ -235,6 +238,7 @@ child:
|
||||
|
||||
prio(high) sync Language(uint64_t aID) returns(nsString aLocale);
|
||||
prio(high) sync DocType(uint64_t aID) returns(nsString aType);
|
||||
prio(high) sync Title(uint64_t aID) returns(nsString aTitle);
|
||||
prio(high) sync URL(uint64_t aID) returns(nsString aURL);
|
||||
prio(high) sync MimeType(uint64_t aID) returns(nsString aMime);
|
||||
prio(high) sync URLDocTypeMimeType(uint64_t aID) returns(nsString aURL, nsString aDocType, nsString aMimeType);
|
||||
|
@ -33,7 +33,7 @@ ProxyAccessible::Shutdown()
|
||||
if (mChildren.Length() != 1)
|
||||
MOZ_CRASH("outer doc doesn't own adoc!");
|
||||
|
||||
static_cast<DocAccessibleParent*>(mChildren[0])->Unbind();
|
||||
mChildren[0]->AsDoc()->Unbind();
|
||||
}
|
||||
|
||||
mChildren.Clear();
|
||||
@ -191,6 +191,22 @@ ProxyAccessible::ARIARoleAtom() const
|
||||
return NS_GetStaticAtom(role);
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::GetLevelInternal()
|
||||
{
|
||||
int32_t level = 0;
|
||||
unused << mDoc->SendGetLevelInternal(mID, &level);
|
||||
return level;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::CaretLineNumber()
|
||||
{
|
||||
int32_t line = -1;
|
||||
unused << mDoc->SendCaretOffset(mID, &line);
|
||||
return line;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::CaretOffset()
|
||||
{
|
||||
@ -371,6 +387,12 @@ ProxyAccessible::ScrollSubstringToPoint(int32_t aStartOffset,
|
||||
aCoordinateType, aX, aY);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::Text(nsString* aText)
|
||||
{
|
||||
unused << mDoc->SendText(mID, aText);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::ReplaceText(const nsString& aText)
|
||||
{
|
||||
@ -1015,6 +1037,12 @@ ProxyAccessible::DocType(nsString& aType)
|
||||
unused << mDoc->SendDocType(mID, &aType);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::Title(nsString& aTitle)
|
||||
{
|
||||
unused << mDoc->SendTitle(mID, &aTitle);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::URL(nsString& aURL)
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/a11y/Role.h"
|
||||
#include "nsIAccessibleText.h"
|
||||
#include "nsIAccessibleTypes.h"
|
||||
#include "Accessible.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
@ -30,7 +31,7 @@ public:
|
||||
ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
|
||||
DocAccessibleParent* aDoc, role aRole) :
|
||||
mParent(aParent), mDoc(aDoc), mWrapper(0), mID(aID), mRole(aRole),
|
||||
mOuterDoc(false)
|
||||
mOuterDoc(false), mIsDoc(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ProxyAccessible);
|
||||
}
|
||||
@ -126,6 +127,9 @@ public:
|
||||
|
||||
nsIAtom* ARIARoleAtom() const;
|
||||
|
||||
int32_t GetLevelInternal();
|
||||
|
||||
int32_t CaretLineNumber();
|
||||
int32_t CaretOffset();
|
||||
bool SetCaretOffset(int32_t aOffset);
|
||||
|
||||
@ -160,7 +164,7 @@ public:
|
||||
void DefaultTextAttributes(nsTArray<Attribute>* aAttrs);
|
||||
|
||||
nsIntRect TextBounds(int32_t aStartOffset, int32_t aEndOffset,
|
||||
uint32_t aCoordType);
|
||||
uint32_t aCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE);
|
||||
|
||||
nsIntRect CharBounds(int32_t aOffset, uint32_t aCoordType);
|
||||
|
||||
@ -188,6 +192,8 @@ public:
|
||||
uint32_t aCoordinateType,
|
||||
int32_t aX, int32_t aY);
|
||||
|
||||
void Text(nsString* aText);
|
||||
|
||||
void ReplaceText(const nsString& aText);
|
||||
|
||||
bool InsertText(const nsString& aText, int32_t aPosition);
|
||||
@ -306,6 +312,7 @@ public:
|
||||
|
||||
void Language(nsString& aLocale);
|
||||
void DocType(nsString& aType);
|
||||
void Title(nsString& aTitle);
|
||||
void URL(nsString& aURL);
|
||||
void MimeType(nsString aMime);
|
||||
void URLDocTypeMimeType(nsString& aURL, nsString& aDocType,
|
||||
@ -322,10 +329,22 @@ public:
|
||||
*/
|
||||
uint64_t ID() const { return mID; }
|
||||
|
||||
/**
|
||||
* Return the document containing this proxy, or the proxy itself if it is a
|
||||
* document.
|
||||
*/
|
||||
DocAccessibleParent* Document() const { return mDoc; }
|
||||
|
||||
/**
|
||||
* Return true if this proxy is a DocAccessibleParent.
|
||||
*/
|
||||
bool IsDoc() const { return mIsDoc; }
|
||||
DocAccessibleParent* AsDoc() const { return IsDoc() ? mDoc : nullptr; }
|
||||
|
||||
protected:
|
||||
explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc) :
|
||||
mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
|
||||
mRole(roles::DOCUMENT), mOuterDoc(false)
|
||||
mRole(roles::DOCUMENT), mOuterDoc(false), mIsDoc(true)
|
||||
{ MOZ_COUNT_CTOR(ProxyAccessible); }
|
||||
|
||||
protected:
|
||||
@ -336,8 +355,9 @@ private:
|
||||
DocAccessibleParent* mDoc;
|
||||
uintptr_t mWrapper;
|
||||
uint64_t mID;
|
||||
role mRole : 31;
|
||||
role mRole : 30;
|
||||
bool mOuterDoc : 1;
|
||||
const bool mIsDoc: 1;
|
||||
};
|
||||
|
||||
enum Interfaces
|
||||
|
@ -17,22 +17,27 @@
|
||||
- (NSString*)title
|
||||
{
|
||||
nsAutoString title;
|
||||
mozilla::ErrorResult rv;
|
||||
// XXX use the flattening API when there are available
|
||||
// see bug 768298
|
||||
[self getGeckoAccessible]->GetContent()->GetTextContent(title, rv);
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
mozilla::ErrorResult rv;
|
||||
// XXX use the flattening API when there are available
|
||||
// see bug 768298
|
||||
accWrap->GetContent()->GetTextContent(title, rv);
|
||||
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
proxy->Title(title);
|
||||
}
|
||||
|
||||
return nsCocoaUtils::ToNSString(title);
|
||||
}
|
||||
|
||||
- (id)value
|
||||
{
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
uint32_t level = 0;
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
level = accWrap->GetLevelInternal();
|
||||
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
level = proxy->GetLevelInternal();
|
||||
}
|
||||
|
||||
if (!accWrap || !accWrap->IsHyperText())
|
||||
return nil;
|
||||
|
||||
uint32_t level = accWrap->AsHyperText()->GetLevelInternal();
|
||||
return [NSNumber numberWithInt:level];
|
||||
}
|
||||
|
||||
@ -47,11 +52,11 @@
|
||||
- (NSArray*)accessibilityAttributeNames
|
||||
{
|
||||
// if we're expired, we don't support any attributes.
|
||||
if (![self getGeckoAccessible])
|
||||
if (![self getGeckoAccessible] && ![self getProxyAccessible])
|
||||
return [NSArray array];
|
||||
|
||||
|
||||
static NSMutableArray* attributes = nil;
|
||||
|
||||
|
||||
if (!attributes) {
|
||||
attributes = [[super accessibilityAttributeNames] mutableCopy];
|
||||
[attributes addObject:NSAccessibilityURLAttribute];
|
||||
@ -68,10 +73,10 @@
|
||||
return [super accessibilityAttributeValue:attribute];
|
||||
}
|
||||
|
||||
- (NSArray*)accessibilityActionNames
|
||||
- (NSArray*)accessibilityActionNames
|
||||
{
|
||||
// if we're expired, we don't support any attributes.
|
||||
if (![self getGeckoAccessible])
|
||||
if (![self getGeckoAccessible] && ![self getProxyAccessible])
|
||||
return [NSArray array];
|
||||
|
||||
static NSArray* actionNames = nil;
|
||||
@ -84,17 +89,25 @@
|
||||
return actionNames;
|
||||
}
|
||||
|
||||
- (void)accessibilityPerformAction:(NSString*)action
|
||||
- (void)accessibilityPerformAction:(NSString*)action
|
||||
{
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
|
||||
if (!accWrap)
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
if (!accWrap && !proxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([action isEqualToString:NSAccessibilityPressAction]) {
|
||||
if (accWrap) {
|
||||
accWrap->DoAction(0);
|
||||
} else if (proxy) {
|
||||
proxy->DoAction(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
[super accessibilityPerformAction:action];
|
||||
|
||||
if ([action isEqualToString:NSAccessibilityPressAction])
|
||||
accWrap->DoAction(0);
|
||||
else
|
||||
[super accessibilityPerformAction:action];
|
||||
}
|
||||
|
||||
- (NSString*)customDescription
|
||||
@ -109,11 +122,12 @@
|
||||
|
||||
- (NSURL*)url
|
||||
{
|
||||
if (![self getGeckoAccessible] || [self getGeckoAccessible]->IsDefunct())
|
||||
return nil;
|
||||
|
||||
nsAutoString value;
|
||||
[self getGeckoAccessible]->Value(value);
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
accWrap->Value(value);
|
||||
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
proxy->Value(value);
|
||||
}
|
||||
|
||||
NSString* urlString = value.IsEmpty() ? nil : nsCocoaUtils::ToNSString(value);
|
||||
if (!urlString)
|
||||
|
@ -114,13 +114,23 @@ ToNSString(id aValue)
|
||||
return [self text];
|
||||
}
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
if ([attribute isEqualToString:@"AXRequired"]) {
|
||||
return [NSNumber numberWithBool:!!(accWrap->State() & states::REQUIRED)];
|
||||
}
|
||||
|
||||
if ([attribute isEqualToString:@"AXRequired"])
|
||||
return [NSNumber numberWithBool:!!(accWrap->State() & states::REQUIRED)];
|
||||
if ([attribute isEqualToString:@"AXInvalid"]) {
|
||||
return [NSNumber numberWithBool:!!(accWrap->State() & states::INVALID)];
|
||||
}
|
||||
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
if ([attribute isEqualToString:@"AXRequired"]) {
|
||||
return [NSNumber numberWithBool:!!(proxy->State() & states::REQUIRED)];
|
||||
}
|
||||
|
||||
if ([attribute isEqualToString:@"AXInvalid"])
|
||||
return [NSNumber numberWithBool:!!(accWrap->State() & states::INVALID)];
|
||||
if ([attribute isEqualToString:@"AXInvalid"]) {
|
||||
return [NSNumber numberWithBool:!!(proxy->State() & states::INVALID)];
|
||||
}
|
||||
}
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute])
|
||||
return [self visibleCharacterRange];
|
||||
@ -157,8 +167,10 @@ ToNSString(id aValue)
|
||||
- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
|
||||
{
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!textAcc)
|
||||
if (!textAcc && !proxy)
|
||||
return nil;
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
|
||||
@ -206,7 +218,12 @@ ToNSString(id aValue)
|
||||
|
||||
int32_t start = range.location;
|
||||
int32_t end = start + range.length;
|
||||
nsIntRect bounds = textAcc->TextBounds(start, end);
|
||||
nsIntRect bounds;
|
||||
if (textAcc) {
|
||||
bounds = textAcc->TextBounds(start, end);
|
||||
} else if (proxy) {
|
||||
bounds = proxy->TextBounds(start, end);
|
||||
}
|
||||
|
||||
return [NSValue valueWithRect:nsCocoaUtils::GeckoRectToCocoaRect(bounds)];
|
||||
}
|
||||
@ -240,8 +257,10 @@ ToNSString(id aValue)
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!textAcc)
|
||||
if (!textAcc && !proxy)
|
||||
return;
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
|
||||
@ -256,12 +275,19 @@ ToNSString(id aValue)
|
||||
return;
|
||||
|
||||
int32_t start = 0, end = 0;
|
||||
textAcc->SelectionBoundsAt(0, &start, &end);
|
||||
textAcc->DeleteText(start, end - start);
|
||||
|
||||
nsString text;
|
||||
nsCocoaUtils::GetStringForNSString(stringValue, text);
|
||||
textAcc->InsertText(text, start);
|
||||
if (textAcc) {
|
||||
textAcc->SelectionBoundsAt(0, &start, &end);
|
||||
textAcc->DeleteText(start, end - start);
|
||||
nsCocoaUtils::GetStringForNSString(stringValue, text);
|
||||
textAcc->InsertText(text, start);
|
||||
} else if (proxy) {
|
||||
nsString data;
|
||||
proxy->SelectionBoundsAt(0, data, &start, &end);
|
||||
proxy->DeleteText(start, end - start);
|
||||
nsCocoaUtils::GetStringForNSString(stringValue, text);
|
||||
proxy->InsertText(text, start);
|
||||
}
|
||||
}
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
|
||||
@ -269,8 +295,13 @@ ToNSString(id aValue)
|
||||
if (!ToNSRange(value, &range))
|
||||
return;
|
||||
|
||||
textAcc->SetSelectionBoundsAt(0, range.location,
|
||||
if (textAcc) {
|
||||
textAcc->SetSelectionBoundsAt(0, range.location,
|
||||
range.location + range.length);
|
||||
} else if (proxy) {
|
||||
proxy->SetSelectionBoundsAt(0, range.location,
|
||||
range.location + range.length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -279,8 +310,13 @@ ToNSString(id aValue)
|
||||
if (!ToNSRange(value, &range))
|
||||
return;
|
||||
|
||||
textAcc->ScrollSubstringTo(range.location, range.location + range.length,
|
||||
if (textAcc) {
|
||||
textAcc->ScrollSubstringTo(range.location, range.location + range.length,
|
||||
nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
|
||||
} else if (proxy) {
|
||||
proxy->ScrollSubstringTo(range.location, range.location + range.length,
|
||||
nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -311,6 +347,9 @@ ToNSString(id aValue)
|
||||
if (textAcc)
|
||||
return (accWrap->State() & states::READONLY) == 0;
|
||||
|
||||
if (ProxyAccessible* proxy = [self getProxyAccessible])
|
||||
return (proxy->State() & states::READONLY) == 0;
|
||||
|
||||
return NO;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
|
||||
@ -320,8 +359,13 @@ ToNSString(id aValue)
|
||||
{
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
int32_t lineNumber = textAcc ?
|
||||
textAcc->CaretLineNumber() - 1 : -1;
|
||||
|
||||
int32_t lineNumber = -1;
|
||||
if (textAcc) {
|
||||
lineNumber = textAcc->CaretLineNumber() - 1;
|
||||
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
lineNumber = proxy->CaretLineNumber() - 1;
|
||||
}
|
||||
|
||||
return (lineNumber >= 0) ? [NSNumber numberWithInt:lineNumber] : nil;
|
||||
}
|
||||
@ -332,10 +376,13 @@ ToNSString(id aValue)
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
|
||||
nsString text;
|
||||
nsCocoaUtils::GetStringForNSString(aNewString, text);
|
||||
if (textAcc) {
|
||||
nsString text;
|
||||
nsCocoaUtils::GetStringForNSString(aNewString, text);
|
||||
textAcc->ReplaceText(text);
|
||||
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
proxy->ReplaceText(text);
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
@ -344,8 +391,9 @@ ToNSString(id aValue)
|
||||
- (NSString*)text
|
||||
{
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!accWrap || !textAcc)
|
||||
if (!textAcc && !proxy)
|
||||
return nil;
|
||||
|
||||
// A password text field returns an empty value
|
||||
@ -353,7 +401,12 @@ ToNSString(id aValue)
|
||||
return @"";
|
||||
|
||||
nsAutoString text;
|
||||
textAcc->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text);
|
||||
if (textAcc) {
|
||||
textAcc->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text);
|
||||
} else if (proxy) {
|
||||
proxy->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text);
|
||||
}
|
||||
|
||||
return nsCocoaUtils::ToNSString(text);
|
||||
}
|
||||
|
||||
@ -362,11 +415,12 @@ ToNSString(id aValue)
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!accWrap || !textAcc)
|
||||
if (!textAcc && !proxy)
|
||||
return 0;
|
||||
|
||||
return textAcc ? textAcc->CharacterCount() : 0;
|
||||
return textAcc ? textAcc->CharacterCount() : proxy->CharacterCount();
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
||||
}
|
||||
@ -376,13 +430,19 @@ ToNSString(id aValue)
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!textAcc && !proxy)
|
||||
return 0;
|
||||
|
||||
int32_t start = 0, end = 0;
|
||||
if (textAcc) {
|
||||
int32_t start = 0, end = 0;
|
||||
textAcc->SelectionBoundsAt(0, &start, &end);
|
||||
return (end - start);
|
||||
} else if (proxy) {
|
||||
nsString data;
|
||||
proxy->SelectionBoundsAt(0, data, &start, &end);
|
||||
}
|
||||
return 0;
|
||||
return (end - start);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
||||
}
|
||||
@ -392,17 +452,23 @@ ToNSString(id aValue)
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!textAcc && !proxy)
|
||||
return nil;
|
||||
|
||||
int32_t start = 0, end = 0;
|
||||
nsAutoString selText;
|
||||
if (textAcc) {
|
||||
int32_t start = 0, end = 0;
|
||||
textAcc->SelectionBoundsAt(0, &start, &end);
|
||||
if (start != end) {
|
||||
nsAutoString selText;
|
||||
textAcc->TextSubstring(start, end, selText);
|
||||
return nsCocoaUtils::ToNSString(selText);
|
||||
}
|
||||
} else if (proxy) {
|
||||
proxy->SelectionBoundsAt(0, selText, &start, &end);
|
||||
}
|
||||
return nil;
|
||||
|
||||
return nsCocoaUtils::ToNSString(selText);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
@ -412,20 +478,35 @@ ToNSString(id aValue)
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (textAcc) {
|
||||
int32_t start = 0;
|
||||
int32_t end = 0;
|
||||
int32_t count = textAcc->SelectionCount();
|
||||
|
||||
int32_t start = 0;
|
||||
int32_t end = 0;
|
||||
int32_t count = 0;
|
||||
if (textAcc) {
|
||||
count = textAcc->SelectionCount();
|
||||
if (count) {
|
||||
textAcc->SelectionBoundsAt(0, &start, &end);
|
||||
return [NSValue valueWithRange:NSMakeRange(start, end - start)];
|
||||
}
|
||||
|
||||
start = textAcc->CaretOffset();
|
||||
return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)];
|
||||
return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)];
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
count = proxy->SelectionCount();
|
||||
if (count) {
|
||||
nsString data;
|
||||
proxy->SelectionBoundsAt(0, data, &start, &end);
|
||||
return [NSValue valueWithRange:NSMakeRange(start, end - start)];
|
||||
}
|
||||
|
||||
start = proxy->CaretOffset();
|
||||
return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)];
|
||||
}
|
||||
|
||||
return [NSValue valueWithRange:NSMakeRange(0, 0)];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
@ -436,10 +517,14 @@ ToNSString(id aValue)
|
||||
// XXX this won't work with Textarea and such as we actually don't give
|
||||
// the visible character range.
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!textAcc && !proxy)
|
||||
return 0;
|
||||
|
||||
return [NSValue valueWithRange:
|
||||
NSMakeRange(0, textAcc ?
|
||||
textAcc->CharacterCount() : 0)];
|
||||
textAcc->CharacterCount() : proxy->CharacterCount())];
|
||||
}
|
||||
|
||||
- (void)valueDidChange
|
||||
@ -463,13 +548,20 @@ ToNSString(id aValue)
|
||||
NS_PRECONDITION(range, "no range");
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
ProxyAccessible* proxy = [self getProxyAccessible];
|
||||
HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
|
||||
if (!textAcc)
|
||||
if (!textAcc && !proxy)
|
||||
return nil;
|
||||
|
||||
nsAutoString text;
|
||||
textAcc->TextSubstring(range->location,
|
||||
range->location + range->length, text);
|
||||
if (textAcc) {
|
||||
textAcc->TextSubstring(range->location,
|
||||
range->location + range->length, text);
|
||||
} else if (proxy) {
|
||||
proxy->TextSubstring(range->location,
|
||||
range->location + range->length, text);
|
||||
}
|
||||
|
||||
return nsCocoaUtils::ToNSString(text);
|
||||
}
|
||||
|
||||
@ -501,20 +593,32 @@ ToNSString(id aValue)
|
||||
|
||||
- (NSString*)text
|
||||
{
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
if (!accWrap)
|
||||
return nil;
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
return nsCocoaUtils::ToNSString(accWrap->AsTextLeaf()->Text());
|
||||
}
|
||||
|
||||
return nsCocoaUtils::ToNSString(accWrap->AsTextLeaf()->Text());
|
||||
if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
nsString text;
|
||||
proxy->Text(&text);
|
||||
return nsCocoaUtils::ToNSString(text);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (long)textLength
|
||||
{
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
if (!accWrap)
|
||||
return 0;
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
return accWrap->AsTextLeaf()->Text().Length();
|
||||
}
|
||||
|
||||
return accWrap->AsTextLeaf()->Text().Length();
|
||||
if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
nsString text;
|
||||
proxy->Text(&text);
|
||||
return text.Length();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<command id="cmd_newNavigatorTab" oncommand="BrowserOpenNewTabOrWindow(event);" reserved="true"/>
|
||||
<command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/>
|
||||
<command id="Browser:SavePage" oncommand="saveDocument(gBrowser.selectedBrowser.contentDocumentAsCPOW);"/>
|
||||
<command id="Browser:SavePage" oncommand="saveBrowser(gBrowser.selectedBrowser);"/>
|
||||
|
||||
<command id="Browser:SendLink"
|
||||
oncommand="MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);"/>
|
||||
|
@ -1796,7 +1796,7 @@ function HandleAppCommandEvent(evt) {
|
||||
gBrowser.selectedBrowser);
|
||||
break;
|
||||
case "Save":
|
||||
saveDocument(gBrowser.selectedBrowser.contentDocumentAsCPOW);
|
||||
saveBrowser(gBrowser.selectedBrowser);
|
||||
break;
|
||||
case "SendMail":
|
||||
MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);
|
||||
|
@ -1670,7 +1670,7 @@ nsContextMenu.prototype = {
|
||||
},
|
||||
|
||||
savePageAs: function CM_savePageAs() {
|
||||
saveDocument(this.browser.contentDocumentAsCPOW);
|
||||
saveBrowser(this.browser);
|
||||
},
|
||||
|
||||
saveLinkToPocket: function CM_saveLinkToPocket() {
|
||||
|
@ -681,6 +681,11 @@
|
||||
|
||||
// If the browser is loading it must not be crashed anymore
|
||||
this.mTab.removeAttribute("crashed");
|
||||
|
||||
// If the browser was previously muted, we should restore the muted state.
|
||||
if (this.mTab.hasAttribute("muted")) {
|
||||
this.mTab.linkedBrowser.mute();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._shouldShowProgress(aRequest)) {
|
||||
@ -1519,12 +1524,17 @@
|
||||
// Make sure the browser is destroyed so it unregisters from observer notifications
|
||||
aBrowser.destroy();
|
||||
|
||||
// Make sure to restore the original droppedLinkHandler.
|
||||
let droppedLinkHandler = aBrowser.droppedLinkHandler;
|
||||
|
||||
// Change the "remote" attribute.
|
||||
let parent = aBrowser.parentNode;
|
||||
parent.removeChild(aBrowser);
|
||||
aBrowser.setAttribute("remote", aShouldBeRemote ? "true" : "false");
|
||||
parent.appendChild(aBrowser);
|
||||
|
||||
aBrowser.droppedLinkHandler = droppedLinkHandler;
|
||||
|
||||
// Switching a browser's remoteness will create a new frameLoader.
|
||||
// As frameLoaders start out with an active docShell we have to
|
||||
// deactivate it if this is not the selected tab's browser or the
|
||||
@ -4265,6 +4275,7 @@
|
||||
browser.removeAttribute("crashedPageTitle");
|
||||
let tab = this.getTabForBrowser(browser);
|
||||
tab.setAttribute("crashed", true);
|
||||
tab.removeAttribute("soundplaying");
|
||||
this.setIcon(tab, icon);
|
||||
]]>
|
||||
</handler>
|
||||
|
@ -315,8 +315,8 @@ const CustomizableWidgets = [
|
||||
let win = aEvent.target &&
|
||||
aEvent.target.ownerDocument &&
|
||||
aEvent.target.ownerDocument.defaultView;
|
||||
if (win && typeof win.saveDocument == "function") {
|
||||
win.saveDocument(win.gBrowser.selectedBrowser.contentDocumentAsCPOW);
|
||||
if (win && typeof win.saveBrowser == "function") {
|
||||
win.saveBrowser(win.gBrowser.selectedBrowser);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
@ -63,8 +63,6 @@ support-files =
|
||||
test-bug-782653-css-errors-2.css
|
||||
test-bug-782653-css-errors.html
|
||||
test-bug-837351-security-errors.html
|
||||
test-bug-846918-hsts-invalid-headers.html
|
||||
test-bug-846918-hsts-invalid-headers.html^headers^
|
||||
test-bug-859170-longstring-hang.html
|
||||
test-bug-869003-iframe.html
|
||||
test-bug-869003-top-window.html
|
||||
@ -96,6 +94,8 @@ support-files =
|
||||
test-file-location.js
|
||||
test-filter.html
|
||||
test-for-of.html
|
||||
test_hpkp-invalid-headers.sjs
|
||||
test_hsts-invalid-headers.sjs
|
||||
test-iframe-762593-insecure-form-action.html
|
||||
test-iframe-762593-insecure-frame.html
|
||||
test-iframe1.html
|
||||
@ -302,8 +302,6 @@ skip-if = os != "mac"
|
||||
[browser_webconsole_bug_817834_add_edited_input_to_history.js]
|
||||
[browser_webconsole_bug_837351_securityerrors.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_webconsole_bug_846918_hsts_invalid-headers.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
|
||||
[browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js]
|
||||
[browser_webconsole_filter_buttons_contextmenu.js]
|
||||
[browser_webconsole_bug_1006027_message_timestamps_incorrect.js]
|
||||
@ -328,6 +326,9 @@ skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
|
||||
[browser_webconsole_execution_scope.js]
|
||||
[browser_webconsole_for_of.js]
|
||||
[browser_webconsole_history.js]
|
||||
[browser_webconsole_hpkp_invalid-headers.js]
|
||||
[browser_webconsole_hsts_invalid-headers.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
|
||||
[browser_webconsole_input_field_focus_on_panel_select.js]
|
||||
[browser_webconsole_inspect-parsed-documents.js]
|
||||
[browser_webconsole_js_input_expansion.js]
|
||||
|
@ -1,41 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* Tests that errors about invalid HSTS security headers are logged
|
||||
* to the web console */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/" +
|
||||
"test/test-bug-846918-hsts-invalid-headers.html";
|
||||
const HSTS_INVALID_HEADER_MSG = "The site specified an invalid " +
|
||||
"Strict-Transport-Security header.";
|
||||
const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/" +
|
||||
"HTTP_Strict_Transport_Security";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
yield loadTab(TEST_URI);
|
||||
|
||||
let hud = yield openConsole();
|
||||
|
||||
let results = yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
name: "Invalid HSTS header error displayed successfully",
|
||||
text: HSTS_INVALID_HEADER_MSG,
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_WARNING,
|
||||
objects: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
yield testClickOpenNewTab(hud, results);
|
||||
});
|
||||
|
||||
function testClickOpenNewTab(hud, results) {
|
||||
let warningNode = results[0].clickableElements[0];
|
||||
ok(warningNode, "link element");
|
||||
ok(warningNode.classList.contains("learn-more-link"), "link class name");
|
||||
return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* Tests that errors about invalid HPKP security headers are logged
|
||||
* to the web console */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,Web Console HPKP invalid " +
|
||||
"header test";
|
||||
const SJS_URL = "https://example.com/browser/browser/devtools/webconsole/" +
|
||||
"test/test_hpkp-invalid-headers.sjs";
|
||||
const NON_BUILTIN_ROOT_PREF = "security.cert_pinning.process_headers_from_" +
|
||||
"non_builtin_roots";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(NON_BUILTIN_ROOT_PREF);
|
||||
});
|
||||
// The root used for mochitests is not built-in, so set the relevant pref to
|
||||
// true to force all pinning error messages to appear.
|
||||
Services.prefs.setBoolPref(NON_BUILTIN_ROOT_PREF, true);
|
||||
|
||||
yield loadTab(TEST_URI);
|
||||
|
||||
let hud = yield openConsole();
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?badSyntax",
|
||||
name: "Could not parse header error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that could not be " +
|
||||
"parsed successfully."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?noMaxAge",
|
||||
name: "No max-age error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that did not include " +
|
||||
"a 'max-age' directive."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?invalidIncludeSubDomains",
|
||||
name: "Invalid includeSubDomains error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that included an " +
|
||||
"invalid 'includeSubDomains' directive."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?invalidMaxAge",
|
||||
name: "Invalid max-age error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that included an " +
|
||||
"invalid 'max-age' directive."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?multipleIncludeSubDomains",
|
||||
name: "Multiple includeSubDomains error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that included " +
|
||||
"multiple 'includeSubDomains' directives."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?multipleMaxAge",
|
||||
name: "Multiple max-age error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that included " +
|
||||
"multiple 'max-age' directives."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?multipleReportURIs",
|
||||
name: "Multiple report-uri error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that included " +
|
||||
"multiple 'report-uri' directives."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?pinsetDoesNotMatch",
|
||||
name: "Non-matching pinset error displayed successfully",
|
||||
text: "Public-Key-Pins: The site specified a header that did not include " +
|
||||
"a matching pin."
|
||||
}, hud);
|
||||
});
|
||||
|
||||
function* checkForMessage(curTest, hud) {
|
||||
hud.jsterm.clearOutput();
|
||||
|
||||
content.location = curTest.url;
|
||||
|
||||
yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
name: curTest.name,
|
||||
text: curTest.text,
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_WARNING,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* Tests that errors about invalid HSTS security headers are logged
|
||||
* to the web console */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,Web Console HSTS invalid " +
|
||||
"header test";
|
||||
const SJS_URL = "https://example.com/browser/browser/devtools/webconsole/" +
|
||||
"test/test_hsts-invalid-headers.sjs";
|
||||
const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/" +
|
||||
"HTTP_Strict_Transport_Security";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
yield loadTab(TEST_URI);
|
||||
|
||||
let hud = yield openConsole();
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?badSyntax",
|
||||
name: "Could not parse header error displayed successfully",
|
||||
text: "Strict-Transport-Security: The site specified a header that could " +
|
||||
"not be parsed successfully."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?noMaxAge",
|
||||
name: "No max-age error displayed successfully",
|
||||
text: "Strict-Transport-Security: The site specified a header that did " +
|
||||
"not include a 'max-age' directive."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?invalidIncludeSubDomains",
|
||||
name: "Invalid includeSubDomains error displayed successfully",
|
||||
text: "Strict-Transport-Security: The site specified a header that " +
|
||||
"included an invalid 'includeSubDomains' directive."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?invalidMaxAge",
|
||||
name: "Invalid max-age error displayed successfully",
|
||||
text: "Strict-Transport-Security: The site specified a header that " +
|
||||
"included an invalid 'max-age' directive."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?multipleIncludeSubDomains",
|
||||
name: "Multiple includeSubDomains error displayed successfully",
|
||||
text: "Strict-Transport-Security: The site specified a header that " +
|
||||
"included multiple 'includeSubDomains' directives."
|
||||
}, hud);
|
||||
|
||||
yield* checkForMessage({
|
||||
url: SJS_URL + "?multipleMaxAge",
|
||||
name: "Multiple max-age error displayed successfully",
|
||||
text: "Strict-Transport-Security: The site specified a header that " +
|
||||
"included multiple 'max-age' directives."
|
||||
}, hud);
|
||||
});
|
||||
|
||||
function* checkForMessage(curTest, hud) {
|
||||
hud.jsterm.clearOutput();
|
||||
|
||||
content.location = curTest.url;
|
||||
|
||||
let results = yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
name: curTest.name,
|
||||
text: curTest.text,
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_WARNING,
|
||||
objects: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
yield testClickOpenNewTab(hud, results);
|
||||
}
|
||||
|
||||
function testClickOpenNewTab(hud, results) {
|
||||
let warningNode = results[0].clickableElements[0];
|
||||
ok(warningNode, "link element");
|
||||
ok(warningNode.classList.contains("learn-more-link"), "link class name");
|
||||
return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
|
||||
}
|
@ -8,11 +8,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,Web Console subresource STS " +
|
||||
const TEST_URI = "data:text/html;charset=utf-8,Web Console subresource STS " +
|
||||
"warning test";
|
||||
const TEST_DOC = "https://example.com/browser/browser/devtools/webconsole/" +
|
||||
"test/test_bug1092055_shouldwarn.html";
|
||||
const SAMPLE_MSG = "invalid Strict-Transport-Security header";
|
||||
const SAMPLE_MSG = "specified a header that could not be parsed successfully.";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
let { browser } = yield loadTab(TEST_URI);
|
||||
|
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Bug 846918 - Report invalid strict-transport-security
|
||||
headers to the web console</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
</head>
|
||||
<body>
|
||||
<p>This page is served with an invalid STS header.</p>
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
Strict-Transport-Security: max-age444
|
@ -0,0 +1,53 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
|
||||
|
||||
let issue;
|
||||
switch (request.queryString) {
|
||||
case "badSyntax":
|
||||
response.setHeader("Public-Key-Pins", "\"");
|
||||
issue = "is not syntactically correct.";
|
||||
break;
|
||||
case "noMaxAge":
|
||||
response.setHeader("Public-Key-Pins", "max-age444");
|
||||
issue = "does not include a max-age directive.";
|
||||
break;
|
||||
case "invalidIncludeSubDomains":
|
||||
response.setHeader("Public-Key-Pins", "includeSubDomains=abc");
|
||||
issue = "includes an invalid includeSubDomains directive.";
|
||||
break;
|
||||
case "invalidMaxAge":
|
||||
response.setHeader("Public-Key-Pins", "max-age=abc");
|
||||
issue = "includes an invalid max-age directive.";
|
||||
break;
|
||||
case "multipleIncludeSubDomains":
|
||||
response.setHeader("Public-Key-Pins",
|
||||
"includeSubDomains; includeSubDomains");
|
||||
issue = "includes multiple includeSubDomains directives.";
|
||||
break;
|
||||
case "multipleMaxAge":
|
||||
response.setHeader("Public-Key-Pins",
|
||||
"max-age=444; max-age=999");
|
||||
issue = "includes multiple max-age directives.";
|
||||
break;
|
||||
case "multipleReportURIs":
|
||||
response.setHeader("Public-Key-Pins",
|
||||
'report-uri="http://example.com"; ' +
|
||||
'report-uri="http://example.com"');
|
||||
issue = "includes multiple report-uri directives.";
|
||||
break;
|
||||
case "pinsetDoesNotMatch":
|
||||
response.setHeader(
|
||||
"Public-Key-Pins",
|
||||
'max-age=999; ' +
|
||||
'pin-sha256="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; ' +
|
||||
'pin-sha256="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB="');
|
||||
issue = "does not include a matching pin.";
|
||||
break;
|
||||
}
|
||||
|
||||
response.write("This page is served with a PKP header that " + issue);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
|
||||
|
||||
let issue;
|
||||
switch (request.queryString) {
|
||||
case "badSyntax":
|
||||
response.setHeader("Strict-Transport-Security", "\"");
|
||||
issue = "is not syntactically correct.";
|
||||
break;
|
||||
case "noMaxAge":
|
||||
response.setHeader("Strict-Transport-Security", "max-age444");
|
||||
issue = "does not include a max-age directive.";
|
||||
break;
|
||||
case "invalidIncludeSubDomains":
|
||||
response.setHeader("Strict-Transport-Security", "includeSubDomains=abc");
|
||||
issue = "includes an invalid includeSubDomains directive.";
|
||||
break;
|
||||
case "invalidMaxAge":
|
||||
response.setHeader("Strict-Transport-Security", "max-age=abc");
|
||||
issue = "includes an invalid max-age directive.";
|
||||
break;
|
||||
case "multipleIncludeSubDomains":
|
||||
response.setHeader("Strict-Transport-Security",
|
||||
"includeSubDomains; includeSubDomains");
|
||||
issue = "includes multiple includeSubDomains directives.";
|
||||
break;
|
||||
case "multipleMaxAge":
|
||||
response.setHeader("Strict-Transport-Security",
|
||||
"max-age=444; max-age=999");
|
||||
issue = "includes multiple max-age directives.";
|
||||
break;
|
||||
}
|
||||
|
||||
response.write("This page is served with a STS header that " + issue);
|
||||
}
|
@ -248,7 +248,7 @@ if test -z "$MOZ_NATIVE_NSPR"; then
|
||||
export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
|
||||
fi
|
||||
export LDFLAGS="$LDFLAGS $NSPR_LDFLAGS"
|
||||
export CFLAGS="$CFLAGS $MOZ_FRAMEPTR_FLAGS"
|
||||
export CFLAGS="$CFLAGS $MOZ_FRAMEPTR_FLAGS $MOZ_FOLD_LIBS_FLAGS"
|
||||
|
||||
AC_OUTPUT_SUBDIRS(nsprpub)
|
||||
|
||||
|
4
config/external/nss/Makefile.in
vendored
4
config/external/nss/Makefile.in
vendored
@ -263,6 +263,10 @@ DEFAULT_GMAKE_FLAGS += MAKE_OBJDIR='$$(INSTALL) -D $$(OBJDIR)'
|
||||
# it, creating race conditions. See bug #836220
|
||||
DEFAULT_GMAKE_FLAGS += TARGETS='$$(LIBRARY) $$(SHARED_LIBRARY) $$(PROGRAM)'
|
||||
|
||||
ifdef MOZ_FOLD_LIBS_FLAGS
|
||||
DEFAULT_GMAKE_FLAGS += XCFLAGS='$(MOZ_FOLD_LIBS_FLAGS)'
|
||||
endif
|
||||
|
||||
NSS_SRCDIR = $(topsrcdir)
|
||||
|
||||
NSS_DIRS =
|
||||
|
10
configure.in
10
configure.in
@ -2201,6 +2201,12 @@ ia64*-hpux*)
|
||||
WIN32_CONSOLE_EXE_LDFLAGS=-mconsole
|
||||
WIN32_GUI_EXE_LDFLAGS=-mwindows
|
||||
|
||||
# GCC/binutils can't link to a function if we try to include dllexport function
|
||||
# in the same library as dllimport caller. To work around it, we build NSPR
|
||||
# and NSS with -mnop-fun-dllimport flag. The drawback of this solution is that
|
||||
# function thunks need to be generated for cross-DLL calls.
|
||||
MOZ_FOLD_LIBS_FLAGS=-mnop-fun-dllimport
|
||||
|
||||
# We use mix of both POSIX and Win32 printf format across the tree, so format
|
||||
# warnings are useless on mingw.
|
||||
MOZ_C_SUPPORTS_WARNING(-Wno-, format, ac_c_has_wno_format)
|
||||
@ -4195,9 +4201,6 @@ cairo-windows)
|
||||
MOZ_WIDGET_TOOLKIT=windows
|
||||
MOZ_PDF_PRINTING=1
|
||||
MOZ_INSTRUMENT_EVENT_LOOP=1
|
||||
if test -n "$GNU_CC"; then
|
||||
MOZ_FOLD_LIBS=
|
||||
fi
|
||||
;;
|
||||
|
||||
cairo-gtk3)
|
||||
@ -8980,6 +8983,7 @@ AC_SUBST_LIST(LIBAV_FFT_ASFLAGS)
|
||||
|
||||
AC_SUBST(MOZ_PACKAGE_JSSHELL)
|
||||
AC_SUBST(MOZ_FOLD_LIBS)
|
||||
AC_SUBST(MOZ_FOLD_LIBS_FLAGS)
|
||||
AC_SUBST(SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE)
|
||||
|
||||
AC_SUBST(MOZ_ENABLE_SZIP)
|
||||
|
@ -49,7 +49,7 @@ void
|
||||
AudioChannelAgent::Shutdown()
|
||||
{
|
||||
if (mIsRegToService) {
|
||||
NotifyStoppedPlaying();
|
||||
NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +127,8 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(float *aVolume,
|
||||
NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(uint32_t aNotifyPlayback,
|
||||
float *aVolume,
|
||||
bool* aMuted)
|
||||
{
|
||||
MOZ_ASSERT(aVolume);
|
||||
@ -139,7 +140,7 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(float *aVolume,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
service->RegisterAudioChannelAgent(this,
|
||||
service->RegisterAudioChannelAgent(this, aNotifyPlayback,
|
||||
static_cast<AudioChannel>(mAudioChannelType));
|
||||
|
||||
service->GetState(mWindow, mAudioChannelType, aVolume, aMuted);
|
||||
@ -148,7 +149,7 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(float *aVolume,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying(void)
|
||||
NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying(uint32_t aNotifyPlayback)
|
||||
{
|
||||
if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
|
||||
!mIsRegToService) {
|
||||
@ -156,7 +157,7 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying(void)
|
||||
}
|
||||
|
||||
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
||||
service->UnregisterAudioChannelAgent(this);
|
||||
service->UnregisterAudioChannelAgent(this, aNotifyPlayback);
|
||||
mIsRegToService = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -233,6 +233,7 @@ AudioChannelService::~AudioChannelService()
|
||||
|
||||
void
|
||||
AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
uint32_t aNotifyPlayback,
|
||||
AudioChannel aChannel)
|
||||
{
|
||||
uint64_t windowID = aAgent->WindowID();
|
||||
@ -253,7 +254,8 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
}
|
||||
|
||||
// If this is the first agent for this window, we must notify the observers.
|
||||
if (winData->mAgents.Length() == 1) {
|
||||
if (aNotifyPlayback == nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY &&
|
||||
winData->mAgents.Length() == 1) {
|
||||
nsRefPtr<MediaPlaybackRunnable> runnable =
|
||||
new MediaPlaybackRunnable(aAgent->Window(), true /* active */);
|
||||
NS_DispatchToCurrentThread(runnable);
|
||||
@ -263,7 +265,8 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
|
||||
AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
uint32_t aNotifyPlayback)
|
||||
{
|
||||
AudioChannelWindow* winData = GetWindowData(aAgent->WindowID());
|
||||
if (!winData) {
|
||||
@ -295,7 +298,8 @@ AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
|
||||
#endif
|
||||
|
||||
// If this is the last agent for this window, we must notify the observers.
|
||||
if (winData->mAgents.IsEmpty()) {
|
||||
if (aNotifyPlayback == nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY &&
|
||||
winData->mAgents.IsEmpty()) {
|
||||
nsRefPtr<MediaPlaybackRunnable> runnable =
|
||||
new MediaPlaybackRunnable(aAgent->Window(), false /* active */);
|
||||
NS_DispatchToCurrentThread(runnable);
|
||||
|
@ -49,13 +49,16 @@ public:
|
||||
* Any audio channel agent that starts playing should register itself to
|
||||
* this service, sharing the AudioChannel.
|
||||
*/
|
||||
void RegisterAudioChannelAgent(AudioChannelAgent* aAgent, AudioChannel aChannel);
|
||||
void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
uint32_t aNotifyPlayback,
|
||||
AudioChannel aChannel);
|
||||
|
||||
/**
|
||||
* Any audio channel agent that stops playing should unregister itself to
|
||||
* this service.
|
||||
*/
|
||||
void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
|
||||
void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
uint32_t aNotifyPlayback);
|
||||
|
||||
/**
|
||||
* Return the state to indicate this audioChannel for his window should keep
|
||||
|
@ -34,7 +34,7 @@ interface nsIAudioChannelAgentCallback : nsISupports
|
||||
* 1. Changes to the playable status of this channel.
|
||||
*/
|
||||
|
||||
[uuid(ee39a34b-a5c7-4b30-b1ac-cd64ceedef67)]
|
||||
[uuid(62e0037c-9786-4b79-b986-27111f6e553b)]
|
||||
interface nsIAudioChannelAgent : nsISupports
|
||||
{
|
||||
const long AUDIO_AGENT_CHANNEL_NORMAL = 0;
|
||||
@ -52,6 +52,9 @@ interface nsIAudioChannelAgent : nsISupports
|
||||
const long AUDIO_AGENT_STATE_MUTED = 1;
|
||||
const long AUDIO_AGENT_STATE_FADED = 2;
|
||||
|
||||
const long AUDIO_AGENT_DONT_NOTIFY = 0;
|
||||
const long AUDIO_AGENT_NOTIFY = 1;
|
||||
|
||||
/**
|
||||
* Before init() is called, this returns AUDIO_AGENT_CHANNEL_ERROR.
|
||||
*/
|
||||
@ -98,6 +101,9 @@ interface nsIAudioChannelAgent : nsISupports
|
||||
* Note: Gecko component SHOULD call this function first then start to
|
||||
* play audio stream only when return value is true.
|
||||
*
|
||||
* @param notifyPlaying
|
||||
* Whether to send audio-playback notifications, one of AUDIO_CHANNEL_NOTIFY
|
||||
* or AUDIO_CHANNEL_DONT_NOTIFY.
|
||||
*
|
||||
* @return
|
||||
* normal state: the agent has registered with audio channel service and
|
||||
@ -107,15 +113,19 @@ interface nsIAudioChannelAgent : nsISupports
|
||||
* faded state: the agent has registered with audio channel service the
|
||||
* component should start playback as well as reducing the volume.
|
||||
*/
|
||||
void notifyStartedPlaying(out float volume, out bool muted);
|
||||
void notifyStartedPlaying(in unsigned long notifyPlayback, out float volume, out bool muted);
|
||||
|
||||
/**
|
||||
* Notify the agent we no longer want to play.
|
||||
*
|
||||
* @param notifyPlaying
|
||||
* Whether to send audio-playback notifications, one of AUDIO_CHANNEL_NOTIFY
|
||||
* or AUDIO_CHANNEL_DONT_NOTIFY.
|
||||
*
|
||||
* Note : even if notifyStartedPlaying() returned false, the agent would
|
||||
* still be registered with the audio channel service and receive callbacks
|
||||
* for status changes. So notifyStoppedPlaying must still eventually be
|
||||
* called to unregister the agent with the channel service.
|
||||
*/
|
||||
void notifyStoppedPlaying();
|
||||
void notifyStoppedPlaying(in unsigned long notifyPlayback);
|
||||
};
|
||||
|
@ -372,7 +372,9 @@ nsContentPermissionUtils::AskPermission(nsIContentPermissionRequest* aRequest, n
|
||||
nsCOMPtr<nsIContentPermissionPrompt> prompt =
|
||||
do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
|
||||
if (prompt) {
|
||||
prompt->Prompt(aRequest);
|
||||
if (NS_FAILED(prompt->Prompt(aRequest))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -7,16 +7,18 @@
|
||||
#include "nsDOMMutationObserver.h"
|
||||
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using mozilla::dom::Animation;
|
||||
|
||||
nsAutoTArray<nsRefPtr<nsDOMMutationObserver>, 4>*
|
||||
|
@ -9233,6 +9233,8 @@ DispatchFullScreenChange(nsIDocument* aTarget)
|
||||
/* Bubbles */ true, /* OnlyChrome */ false);
|
||||
}
|
||||
|
||||
static void ClearPendingFullscreenRequests(nsIDocument* aDoc);
|
||||
|
||||
void
|
||||
nsDocument::OnPageHide(bool aPersisted,
|
||||
EventTarget* aDispatchStartTarget)
|
||||
@ -9297,6 +9299,7 @@ nsDocument::OnPageHide(bool aPersisted,
|
||||
EnumerateExternalResources(NotifyPageHide, &aPersisted);
|
||||
EnumerateActivityObservers(NotifyActivityChanged, nullptr);
|
||||
|
||||
ClearPendingFullscreenRequests(this);
|
||||
if (IsFullScreenDoc()) {
|
||||
// If this document was fullscreen, we should exit fullscreen in this
|
||||
// doctree branch. This ensures that if the user navigates while in
|
||||
@ -11008,37 +11011,6 @@ nsIDocument::MozCancelFullScreen()
|
||||
RestorePreviousFullScreenState();
|
||||
}
|
||||
|
||||
// Runnable to set window full-screen mode. Used as a script runner
|
||||
// to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to
|
||||
// run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event
|
||||
// (handled in chome code) which is unsafe to run if this is called in
|
||||
// Element::UnbindFromTree().
|
||||
class nsSetWindowFullScreen : public nsRunnable {
|
||||
public:
|
||||
nsSetWindowFullScreen(nsIDocument* aDoc, bool aValue, gfx::VRHMDInfo* aHMD = nullptr)
|
||||
: mDoc(aDoc), mValue(aValue), mHMD(aHMD) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mDoc->GetWindow()) {
|
||||
mDoc->GetWindow()->SetFullscreenInternal(
|
||||
nsPIDOMWindow::eForFullscreenAPI, mValue, mHMD);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDocument> mDoc;
|
||||
bool mValue;
|
||||
nsRefPtr<gfx::VRHMDInfo> mHMD;
|
||||
};
|
||||
|
||||
static void
|
||||
SetWindowFullScreen(nsIDocument* aDoc, bool aValue, gfx::VRHMDInfo *aVRHMD = nullptr)
|
||||
{
|
||||
nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc, aValue, aVRHMD));
|
||||
}
|
||||
|
||||
static void
|
||||
AskWindowToExitFullscreen(nsIDocument* aDoc)
|
||||
{
|
||||
@ -11048,7 +11020,9 @@ AskWindowToExitFullscreen(nsIDocument* aDoc)
|
||||
/* Bubbles */ true, /* Cancelable */ false,
|
||||
/* DefaultAction */ nullptr);
|
||||
} else {
|
||||
SetWindowFullScreen(aDoc, false);
|
||||
if (nsPIDOMWindow* win = aDoc->GetWindow()) {
|
||||
win->SetFullscreenInternal(nsPIDOMWindow::eForFullscreenAPI, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11115,13 +11089,43 @@ ResetFullScreen(nsIDocument* aDocument, void* aData)
|
||||
"Should have at most 1 fullscreen subdocument.");
|
||||
static_cast<nsDocument*>(aDocument)->CleanupFullscreenState();
|
||||
NS_ASSERTION(!aDocument->IsFullScreenDoc(), "Should reset full-screen");
|
||||
nsTArray<nsIDocument*>* changed = reinterpret_cast<nsTArray<nsIDocument*>*>(aData);
|
||||
auto changed = reinterpret_cast<nsCOMArray<nsIDocument>*>(aData);
|
||||
changed->AppendElement(aDocument);
|
||||
aDocument->EnumerateSubDocuments(ResetFullScreen, aData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Since nsIDocument::ExitFullscreenInDocTree() could be called from
|
||||
// Element::UnbindFromTree() where it is not safe to synchronously run
|
||||
// script. This runnable is the script part of that function.
|
||||
class ExitFullscreenScriptRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit ExitFullscreenScriptRunnable(nsCOMArray<nsIDocument>&& aDocuments)
|
||||
: mDocuments(Move(aDocuments)) { }
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
// Dispatch MozDOMFullscreen:Exited to the last document in
|
||||
// the list since we want this event to follow the same path
|
||||
// MozDOMFullscreen:Entered dispatched.
|
||||
nsIDocument* lastDocument = mDocuments[mDocuments.Length() - 1];
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
lastDocument, ToSupports(lastDocument),
|
||||
NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
|
||||
/* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
|
||||
// Ensure the window exits fullscreen.
|
||||
if (nsPIDOMWindow* win = mDocuments[0]->GetWindow()) {
|
||||
win->SetFullscreenInternal(nsPIDOMWindow::eForForceExitFullscreen, false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMArray<nsIDocument> mDocuments;
|
||||
};
|
||||
|
||||
/* static */ void
|
||||
nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
|
||||
{
|
||||
@ -11148,7 +11152,7 @@ nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
|
||||
// order when exiting fullscreen, but we traverse the doctree in a
|
||||
// root-to-leaf order, so we save references to the documents we must
|
||||
// dispatch to so that we dispatch in the specified order.
|
||||
nsAutoTArray<nsIDocument*, 8> changed;
|
||||
nsCOMArray<nsIDocument> changed;
|
||||
|
||||
// Walk the tree of fullscreen documents, and reset their fullscreen state.
|
||||
ResetFullScreen(root, static_cast<void*>(&changed));
|
||||
@ -11163,16 +11167,11 @@ nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
|
||||
NS_ASSERTION(!root->IsFullScreenDoc(),
|
||||
"Fullscreen root should no longer be a fullscreen doc...");
|
||||
|
||||
// Dispatch MozDOMFullscreen:Exited to the last document in
|
||||
// the list since we want this event to follow the same path
|
||||
// MozDOMFullscreen:Entered dispatched.
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
changed.LastElement(), ToSupports(changed.LastElement()),
|
||||
NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
|
||||
/* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
|
||||
// Move the top-level window out of fullscreen mode.
|
||||
FullscreenRoots::Remove(root);
|
||||
SetWindowFullScreen(root, false);
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new ExitFullscreenScriptRunnable(Move(changed)));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -11630,7 +11629,8 @@ nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
|
||||
} else {
|
||||
// Make the window fullscreen.
|
||||
FullscreenRequest* lastRequest = sPendingFullscreenRequests.getLast();
|
||||
SetWindowFullScreen(this, true, lastRequest->mVRHMDDevice);
|
||||
rootWin->SetFullscreenInternal(nsPIDOMWindow::eForFullscreenAPI, true,
|
||||
lastRequest->mVRHMDDevice);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11650,8 +11650,9 @@ nsIDocument::HandlePendingFullscreenRequest(const FullscreenRequest& aRequest,
|
||||
return false;
|
||||
}
|
||||
|
||||
doc->ApplyFullscreen(aRequest);
|
||||
*aHandled = true;
|
||||
if (doc->ApplyFullscreen(aRequest)) {
|
||||
*aHandled = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -11683,12 +11684,41 @@ nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc)
|
||||
return handled;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ClearPendingFullscreenRequests(nsIDocument* aDoc)
|
||||
{
|
||||
nsIDocShellTreeItem* shell = aDoc->GetDocShell();
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
|
||||
FullscreenRequest* request = sPendingFullscreenRequests.getFirst();
|
||||
while (request) {
|
||||
nsIDocument* doc = request->GetDocument();
|
||||
bool shouldRemove = false;
|
||||
for (nsCOMPtr<nsIDocShellTreeItem> docShell = doc->GetDocShell();
|
||||
docShell; docShell->GetParent(getter_AddRefs(docShell))) {
|
||||
if (docShell == shell) {
|
||||
shouldRemove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldRemove) {
|
||||
FullscreenRequest* thisRequest = request;
|
||||
request = request->getNext();
|
||||
delete thisRequest;
|
||||
} else {
|
||||
request = request->getNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::ApplyFullscreen(const FullscreenRequest& aRequest)
|
||||
{
|
||||
Element* elem = aRequest.GetElement();
|
||||
if (!FullscreenElementReadyCheck(elem, aRequest.mIsCallerChrome)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stash a reference to any existing fullscreen doc, we'll use this later
|
||||
@ -11784,6 +11814,7 @@ nsDocument::ApplyFullscreen(const FullscreenRequest& aRequest)
|
||||
for (uint32_t i = 0; i < changed.Length(); ++i) {
|
||||
DispatchFullScreenChange(changed[changed.Length() - i - 1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1529,8 +1529,10 @@ protected:
|
||||
|
||||
void NotifyStyleSheetApplicableStateChanged();
|
||||
|
||||
// Apply the fullscreen state to the document, and trigger related events.
|
||||
void ApplyFullscreen(const FullscreenRequest& aRequest);
|
||||
// Apply the fullscreen state to the document, and trigger related
|
||||
// events. It returns false if the fullscreen element ready check
|
||||
// fails and nothing gets changed.
|
||||
bool ApplyFullscreen(const FullscreenRequest& aRequest);
|
||||
|
||||
nsTArray<nsIObserver*> mCharSetObservers;
|
||||
|
||||
|
@ -93,6 +93,7 @@
|
||||
#include "mozilla/layers/CompositorChild.h"
|
||||
|
||||
#include "mozilla/dom/StructuredCloneUtils.h"
|
||||
#include "mozilla/WebBrowserPersistLocalDocument.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULPopupManager.h"
|
||||
@ -130,6 +131,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersistable)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
|
||||
@ -2847,3 +2849,20 @@ nsFrameLoader::InitializeBrowserAPI()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::StartPersistence(nsIWebBrowserPersistDocumentReceiver* aRecv)
|
||||
{
|
||||
if (mRemoteBrowser) {
|
||||
return mRemoteBrowser->StartPersistence(aRecv);
|
||||
}
|
||||
if (mDocShell) {
|
||||
nsCOMPtr<nsIDocument> doc = do_GetInterface(mDocShell);
|
||||
NS_ENSURE_STATE(doc);
|
||||
nsCOMPtr<nsIWebBrowserPersistDocument> pdoc =
|
||||
new mozilla::WebBrowserPersistLocalDocument(doc);
|
||||
aRecv->OnDocumentReady(pdoc);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_NO_CONTENT;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "Units.h"
|
||||
#include "nsIWebBrowserPersistable.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsSubDocumentFrame;
|
||||
@ -53,6 +54,7 @@ typedef struct _GtkWidget GtkWidget;
|
||||
#endif
|
||||
|
||||
class nsFrameLoader final : public nsIFrameLoader,
|
||||
public nsIWebBrowserPersistable,
|
||||
public nsStubMutationObserver,
|
||||
public mozilla::dom::ipc::MessageManagerCallback
|
||||
{
|
||||
@ -69,6 +71,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameLoader, nsIFrameLoader)
|
||||
NS_DECL_NSIFRAMELOADER
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIWEBBROWSERPERSISTABLE
|
||||
nsresult CheckForRecursiveLoad(nsIURI* aURI);
|
||||
nsresult ReallyStartLoading();
|
||||
void StartDestroy();
|
||||
|
@ -6302,11 +6302,18 @@ public:
|
||||
, mDuration(aDuration)
|
||||
, mStage(eBeforeToggle)
|
||||
, mFullscreen(aFullscreen)
|
||||
{}
|
||||
{
|
||||
MOZ_COUNT_CTOR(FullscreenTransitionTask);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
private:
|
||||
virtual ~FullscreenTransitionTask()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FullscreenTransitionTask);
|
||||
}
|
||||
|
||||
enum Stage {
|
||||
// BeforeToggle stage happens before we enter or leave fullscreen
|
||||
// state. In this stage, the task triggers the pre-toggle fullscreen
|
||||
@ -6358,6 +6365,12 @@ FullscreenTransitionTask::Run()
|
||||
{
|
||||
Stage stage = mStage;
|
||||
mStage = Stage(mStage + 1);
|
||||
if (MOZ_UNLIKELY(mWidget->Destroyed())) {
|
||||
// If the widget has been destroyed before we get here, don't try to
|
||||
// do anything more. Just let it go and release ourselves.
|
||||
NS_WARNING("The widget to fullscreen has been destroyed");
|
||||
return NS_OK;
|
||||
}
|
||||
if (stage == eBeforeToggle) {
|
||||
mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
|
||||
mDuration.mFadeIn, mTransitionData,
|
||||
@ -6474,9 +6487,16 @@ nsGlobalWindow::SetFullscreenInternal(FullscreenReason aReason,
|
||||
gfx::VRHMDInfo* aHMD)
|
||||
{
|
||||
MOZ_ASSERT(IsOuterWindow());
|
||||
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),
|
||||
"Requires safe to run script as it "
|
||||
"may call FinishDOMFullscreenChange");
|
||||
|
||||
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
|
||||
|
||||
MOZ_ASSERT(aReason != eForForceExitFullscreen || !aFullScreen,
|
||||
"FullscreenReason::eForForceExitFullscreen can "
|
||||
"only be used with exiting fullscreen");
|
||||
|
||||
// Only chrome can change our fullscreen mode. Otherwise, the state
|
||||
// can only be changed for DOM fullscreen.
|
||||
if (aReason == eForFullscreenMode && !nsContentUtils::IsCallerChrome()) {
|
||||
|
@ -467,7 +467,11 @@ public:
|
||||
// Toggling the fullscreen mode requires trusted context.
|
||||
eForFullscreenMode,
|
||||
// Fullscreen API is the API provided to untrusted content.
|
||||
eForFullscreenAPI
|
||||
eForFullscreenAPI,
|
||||
// This reason can only be used with exiting fullscreen.
|
||||
// It is otherwise identical to eForFullscreenAPI except it would
|
||||
// suppress the fullscreen transition.
|
||||
eForForceExitFullscreen
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -242,6 +242,7 @@ support-files =
|
||||
file_webaudioLoop.html
|
||||
file_webaudioLoop2.html
|
||||
file_pluginAudio.html
|
||||
noaudio.webm
|
||||
referrer_helper.js
|
||||
referrer_testserver.sjs
|
||||
script_postmessages_fileList.js
|
||||
@ -299,6 +300,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
|
||||
[test_named_frames.html]
|
||||
[test_navigator_resolve_identity.html]
|
||||
[test_navigator_language.html]
|
||||
[test_noAudioNotification.html]
|
||||
[test_noAudioNotificationOnMutedElement.html]
|
||||
[test_noAudioNotificationOnMutedOrVolume0Element.html]
|
||||
[test_noAudioNotificationOnVolume0Element.html]
|
||||
|
BIN
dom/base/test/noaudio.webm
Normal file
BIN
dom/base/test/noaudio.webm
Normal file
Binary file not shown.
81
dom/base/test/test_noAudioNotification.html
Normal file
81
dom/base/test/test_noAudioNotification.html
Normal file
@ -0,0 +1,81 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for video controller in windows</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var observer = {
|
||||
observe: function(subject, topic, data) {
|
||||
ok(false, "should not receive audio-playback notification!");
|
||||
}
|
||||
};
|
||||
|
||||
var observerService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIObserverService);
|
||||
|
||||
var video = document.createElement("video");
|
||||
video.loop = true;
|
||||
video.src = "noaudio.webm";
|
||||
|
||||
video.onplay = video.onpause = function() {
|
||||
// Yield to the event loop a few times to make sure that audio-playback is not dispatched.
|
||||
SimpleTest.executeSoon(function() {
|
||||
SimpleTest.executeSoon(function() {
|
||||
SimpleTest.executeSoon(function() {
|
||||
runTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var tests = [
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true]]}, runTest);
|
||||
},
|
||||
|
||||
function() {
|
||||
observerService.addObserver(observer, "audio-playback", false);
|
||||
ok(true, "Observer set");
|
||||
runTest();
|
||||
},
|
||||
|
||||
function() {
|
||||
video.play();
|
||||
},
|
||||
|
||||
function() {
|
||||
video.pause();
|
||||
},
|
||||
|
||||
function() {
|
||||
observerService.removeObserver(observer, "audio-playback");
|
||||
ok(true, "Observer removed");
|
||||
runTest();
|
||||
}
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,16 +13,19 @@
|
||||
#ifndef mozilla_dom_BindingDeclarations_h__
|
||||
#define mozilla_dom_BindingDeclarations_h__
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
#include "js/Value.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr member variables
|
||||
#include "mozilla/dom/DOMString.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
|
||||
#include "mozilla/dom/DOMString.h"
|
||||
|
||||
#include "nsAutoPtr.h" // for nsRefPtr member variables
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsWrapperCache;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -76,3 +76,4 @@ MSG_DEF(MSG_BAD_FORMDATA, 0, JSEXN_TYPEERR, "Could not parse content as FormData
|
||||
MSG_DEF(MSG_NO_ACTIVE_WORKER, 1, JSEXN_TYPEERR, "No active worker for scope {0}.")
|
||||
MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to show Notification denied.")
|
||||
MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")
|
||||
MSG_DEF(MSG_INVALID_SCOPE, 2, JSEXN_TYPEERR, "Invalid scope trying to resolve {0} with base URL {1}.")
|
||||
|
@ -654,10 +654,6 @@ BroadcastChannel::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
|
||||
// If the window is destroyed we have to release the reference that we are
|
||||
// keeping.
|
||||
if (!mIsKeptAlive) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
|
||||
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
|
||||
|
||||
|
@ -52,6 +52,11 @@ function runTest() {
|
||||
function iframeLoaded() {
|
||||
bc.postMessage("Hello world from the window!");
|
||||
}
|
||||
|
||||
// A leak test
|
||||
var dummyBc = new BroadcastChannel("dont_leak_this");
|
||||
dummyBc.foo = "bar";
|
||||
// don't add message listener!
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -71,7 +71,8 @@ let CopyPasteAssistent = {
|
||||
reason: e.reason,
|
||||
collapsed: e.collapsed,
|
||||
caretVisible: e.caretVisible,
|
||||
selectionVisible: e.selectionVisible
|
||||
selectionVisible: e.selectionVisible,
|
||||
selectionEditable: e.selectionEditable
|
||||
};
|
||||
|
||||
// Get correct geometry information if we have nested iframe.
|
||||
|
@ -452,6 +452,7 @@ BrowserElementParent.prototype = {
|
||||
// - collapsed: Indicate current selection is collapsed or not.
|
||||
// - caretVisible: Indicate the caret visiibility.
|
||||
// - selectionVisible: Indicate current selection is visible or not.
|
||||
// - selectionEditable: Indicate current selection is editable or not.
|
||||
_handleCaretStateChanged: function(data) {
|
||||
let evt = this._createEvent('caretstatechanged', data.json,
|
||||
/* cancelable = */ false);
|
||||
|
@ -1101,7 +1101,7 @@ nsDOMCameraControl::ReleaseAudioChannelAgent()
|
||||
{
|
||||
#ifdef MOZ_B2G
|
||||
if (mAudioChannelAgent) {
|
||||
mAudioChannelAgent->NotifyStoppedPlaying();
|
||||
mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY);
|
||||
mAudioChannelAgent = nullptr;
|
||||
}
|
||||
#endif
|
||||
@ -1137,7 +1137,8 @@ nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
|
||||
// Video recording doesn't output any sound, so it's not necessary to check canPlay.
|
||||
float volume = 0.0;
|
||||
bool muted = true;
|
||||
rv = mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
|
||||
rv = mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY,
|
||||
&volume, &muted);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -5446,12 +5446,7 @@ CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mBufferProvider = aManager->CreatePersistentBufferProvider(mTarget->GetSize(), mTarget->GetFormat());
|
||||
|
||||
RefPtr<SourceSurface> surf = mTarget->Snapshot();
|
||||
|
||||
mTarget = mBufferProvider->GetDT(IntRect(IntPoint(), mTarget->GetSize()));
|
||||
mTarget->CopySurface(surf, IntRect(IntPoint(), mTarget->GetSize()), IntPoint());
|
||||
mBufferProvider = new PersistentBufferProviderBasic(mTarget);
|
||||
|
||||
return mBufferProvider;
|
||||
}
|
||||
|
@ -20,13 +20,18 @@ WebGL1Context::Create()
|
||||
WebGL1Context::WebGL1Context()
|
||||
: WebGLContext()
|
||||
{
|
||||
mFormatUsage = Move(webgl::FormatUsageAuthority::CreateForWebGL1());
|
||||
}
|
||||
|
||||
WebGL1Context::~WebGL1Context()
|
||||
{
|
||||
}
|
||||
|
||||
UniquePtr<webgl::FormatUsageAuthority>
|
||||
WebGL1Context::CreateFormatUsage() const
|
||||
{
|
||||
return webgl::FormatUsageAuthority::CreateForWebGL1();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ public:
|
||||
|
||||
private:
|
||||
WebGL1Context();
|
||||
virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const override;
|
||||
|
||||
public:
|
||||
virtual ~WebGL1Context();
|
||||
|
@ -21,8 +21,6 @@ WebGL2Context::WebGL2Context()
|
||||
{
|
||||
MOZ_ASSERT(IsSupported(), "not supposed to create a WebGL2Context"
|
||||
"context when not supported");
|
||||
|
||||
mFormatUsage = Move(webgl::FormatUsageAuthority::CreateForWebGL2());
|
||||
}
|
||||
|
||||
WebGL2Context::~WebGL2Context()
|
||||
@ -30,6 +28,12 @@ WebGL2Context::~WebGL2Context()
|
||||
|
||||
}
|
||||
|
||||
UniquePtr<webgl::FormatUsageAuthority>
|
||||
WebGL2Context::CreateFormatUsage() const
|
||||
{
|
||||
return webgl::FormatUsageAuthority::CreateForWebGL2();
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
WebGL2Context::IsSupported()
|
||||
{
|
||||
|
@ -356,6 +356,7 @@ public:
|
||||
|
||||
private:
|
||||
WebGL2Context();
|
||||
virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const override;
|
||||
|
||||
virtual bool IsTexParamValid(GLenum pname) const override;
|
||||
|
||||
|
@ -1487,7 +1487,9 @@ public:
|
||||
void GenerateWarning(const char* fmt, ...);
|
||||
void GenerateWarning(const char* fmt, va_list ap);
|
||||
|
||||
public:
|
||||
UniquePtr<webgl::FormatUsageAuthority> mFormatUsage;
|
||||
virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const = 0;
|
||||
|
||||
// Friend list
|
||||
friend class WebGLTexture;
|
||||
|
@ -1653,6 +1653,11 @@ WebGLContext::InitAndValidateGL()
|
||||
if (!gl)
|
||||
return false;
|
||||
|
||||
// Unconditionally create a new format usage authority. This is
|
||||
// important when restoring contexts and extensions need to add
|
||||
// formats back into the authority.
|
||||
mFormatUsage = CreateFormatUsage();
|
||||
|
||||
GLenum error = gl->fGetError();
|
||||
if (error != LOCAL_GL_NO_ERROR) {
|
||||
GenerateWarning("GL error 0x%x occurred during OpenGL context"
|
||||
|
@ -195,7 +195,7 @@ FMRadio::Notify(const FMRadioEventType& aType)
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("enabled"));
|
||||
} else {
|
||||
if (mAudioChannelAgentEnabled) {
|
||||
mAudioChannelAgent->NotifyStoppedPlaying();
|
||||
mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
|
||||
mAudioChannelAgentEnabled = false;
|
||||
}
|
||||
|
||||
@ -457,7 +457,8 @@ FMRadio::EnableAudioChannelAgent()
|
||||
|
||||
float volume = 0.0;
|
||||
bool muted = true;
|
||||
mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
|
||||
mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY,
|
||||
&volume, &muted);
|
||||
WindowVolumeChanged(volume, muted);
|
||||
|
||||
mAudioChannelAgentEnabled = true;
|
||||
|
@ -4518,13 +4518,17 @@ HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying)
|
||||
// this method has some content JS in its stack.
|
||||
AutoNoJSAPI nojsapi;
|
||||
|
||||
// Don't notify playback if this element doesn't have any audio tracks.
|
||||
uint32_t notify = HasAudio() ? nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY :
|
||||
nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY;
|
||||
|
||||
if (aPlaying) {
|
||||
float volume = 0.0;
|
||||
bool muted = true;
|
||||
mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
|
||||
mAudioChannelAgent->NotifyStartedPlaying(notify, &volume, &muted);
|
||||
WindowVolumeChanged(volume, muted);
|
||||
} else {
|
||||
mAudioChannelAgent->NotifyStoppedPlaying();
|
||||
mAudioChannelAgent->NotifyStoppedPlaying(notify);
|
||||
mAudioChannelAgent = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ include protocol PFilePicker;
|
||||
include protocol PIndexedDBPermissionRequest;
|
||||
include protocol PRenderFrame;
|
||||
include protocol PPluginWidget;
|
||||
include protocol PWebBrowserPersistDocument;
|
||||
include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
include URIParams;
|
||||
@ -108,6 +109,7 @@ prio(normal upto urgent) sync protocol PBrowser
|
||||
manages PIndexedDBPermissionRequest;
|
||||
manages PRenderFrame;
|
||||
manages PPluginWidget;
|
||||
manages PWebBrowserPersistDocument;
|
||||
|
||||
both:
|
||||
AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows,
|
||||
@ -119,6 +121,8 @@ both:
|
||||
*/
|
||||
PRenderFrame();
|
||||
|
||||
PWebBrowserPersistDocument();
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Tell the parent process a new accessible document has been created.
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "mozilla/layout/RenderFrameChild.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/PWebBrowserPersistDocumentChild.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
@ -98,6 +99,7 @@
|
||||
#include "nsIScriptError.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "nsDeviceContext.h"
|
||||
#include "mozilla/WebBrowserPersistDocumentChild.h"
|
||||
|
||||
#define BROWSER_ELEMENT_CHILD_SCRIPT \
|
||||
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
|
||||
@ -3106,3 +3108,23 @@ TabChildGlobal::GetGlobalJSObject()
|
||||
return ref->GetJSObject();
|
||||
}
|
||||
|
||||
PWebBrowserPersistDocumentChild*
|
||||
TabChild::AllocPWebBrowserPersistDocumentChild()
|
||||
{
|
||||
return new WebBrowserPersistDocumentChild();
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvPWebBrowserPersistDocumentConstructor(PWebBrowserPersistDocumentChild *aActor)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = GetDocument();
|
||||
static_cast<WebBrowserPersistDocumentChild*>(aActor)->Start(doc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::DeallocPWebBrowserPersistDocumentChild(PWebBrowserPersistDocumentChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
@ -494,6 +494,10 @@ public:
|
||||
|
||||
virtual ScreenIntSize GetInnerSize() override;
|
||||
|
||||
virtual PWebBrowserPersistDocumentChild* AllocPWebBrowserPersistDocumentChild() override;
|
||||
virtual bool RecvPWebBrowserPersistDocumentConstructor(PWebBrowserPersistDocumentChild *aActor) override;
|
||||
virtual bool DeallocPWebBrowserPersistDocumentChild(PWebBrowserPersistDocumentChild* aActor) override;
|
||||
|
||||
protected:
|
||||
virtual ~TabChild();
|
||||
|
||||
|
@ -95,6 +95,7 @@
|
||||
#include "ImageOps.h"
|
||||
#include "UnitTransforms.h"
|
||||
#include <algorithm>
|
||||
#include "mozilla/WebBrowserPersistDocumentParent.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
@ -256,7 +257,8 @@ NS_IMPL_ISUPPORTS(TabParent,
|
||||
nsITabParent,
|
||||
nsIAuthPromptProvider,
|
||||
nsISecureBrowserUI,
|
||||
nsISupportsWeakReference)
|
||||
nsISupportsWeakReference,
|
||||
nsIWebBrowserPersistable)
|
||||
|
||||
TabParent::TabParent(nsIContentParent* aManager,
|
||||
const TabId& aTabId,
|
||||
@ -3345,6 +3347,29 @@ TabParent::AsyncPanZoomEnabled() const
|
||||
return widget && widget->AsyncPanZoomEnabled();
|
||||
}
|
||||
|
||||
PWebBrowserPersistDocumentParent*
|
||||
TabParent::AllocPWebBrowserPersistDocumentParent()
|
||||
{
|
||||
return new WebBrowserPersistDocumentParent();
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::StartPersistence(nsIWebBrowserPersistDocumentReceiver* aRecv)
|
||||
{
|
||||
auto* actor = new WebBrowserPersistDocumentParent();
|
||||
actor->SetOnReady(aRecv);
|
||||
return SendPWebBrowserPersistDocumentConstructor(actor)
|
||||
? NS_OK : NS_ERROR_FAILURE;
|
||||
// (The actor will be destroyed on constructor failure.)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
|
||||
{
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsITabParent.h"
|
||||
#include "nsIWebBrowserPersistable.h"
|
||||
#include "nsIXULBrowserWindow.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "nsWeakReference.h"
|
||||
@ -76,6 +77,7 @@ class TabParent final : public PBrowserParent
|
||||
, public nsSupportsWeakReference
|
||||
, public TabContext
|
||||
, public nsAPostRefreshObserver
|
||||
, public nsIWebBrowserPersistable
|
||||
{
|
||||
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
|
||||
typedef mozilla::OwningSerializedStructuredCloneBuffer OwningSerializedStructuredCloneBuffer;
|
||||
@ -368,6 +370,7 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTHPROMPTPROVIDER
|
||||
NS_DECL_NSISECUREBROWSERUI
|
||||
NS_DECL_NSIWEBBROWSERPERSISTABLE
|
||||
|
||||
bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
|
||||
bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
|
||||
@ -430,6 +433,10 @@ public:
|
||||
void TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
|
||||
int32_t& aDragAreaX, int32_t& aDragAreaY);
|
||||
layout::RenderFrameParent* GetRenderFrame();
|
||||
|
||||
virtual PWebBrowserPersistDocumentParent* AllocPWebBrowserPersistDocumentParent() override;
|
||||
virtual bool DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent* aActor) override;
|
||||
|
||||
protected:
|
||||
bool ReceiveMessage(const nsString& aMessage,
|
||||
bool aSync,
|
||||
|
@ -16,10 +16,32 @@ CORSInvalidAllowMethod=Cross-Origin Request Blocked: The Same Origin Policy disa
|
||||
CORSInvalidAllowHeader=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Headers').
|
||||
CORSMissingAllowHeaderFromPreflight=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: missing token '%2$S' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel).
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "Strict-Transport-Security" or "HSTS"
|
||||
InvalidSTSHeaders=The site specified an invalid Strict-Transport-Security header.
|
||||
# LOCALIZATION NOTE: Do not translate "Public-Key-Pins or HPKP"
|
||||
InvalidPKPHeaders=The site specified an invalid Public-Key-Pins header.
|
||||
# LOCALIZATION NOTE: Do not translate "Strict-Transport-Security", "HSTS", "max-age" or "includeSubDomains"
|
||||
STSUnknownError=Strict-Transport-Security: An unknown error occurred processing the header specified by the site.
|
||||
STSUntrustworthyConnection=Strict-Transport-Security: The connection to the site is untrustworthy, so the specified header was ignored.
|
||||
STSCouldNotParseHeader=Strict-Transport-Security: The site specified a header that could not be parsed successfully.
|
||||
STSNoMaxAge=Strict-Transport-Security: The site specified a header that did not include a 'max-age' directive.
|
||||
STSMultipleMaxAges=Strict-Transport-Security: The site specified a header that included multiple 'max-age' directives.
|
||||
STSInvalidMaxAge=Strict-Transport-Security: The site specified a header that included an invalid 'max-age' directive.
|
||||
STSMultipleIncludeSubdomains=Strict-Transport-Security: The site specified a header that included multiple 'includeSubDomains' directives.
|
||||
STSInvalidIncludeSubdomains=Strict-Transport-Security: The site specified a header that included an invalid 'includeSubDomains' directive.
|
||||
STSCouldNotSaveState=Strict-Transport-Security: An error occurred noting the site as a Strict-Transport-Security host.
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "Public-Key-Pins", "HPKP", "max-age" or "includeSubDomains"
|
||||
PKPUnknownError=Public-Key-Pins: An unknown error occurred processing the header specified by the site.
|
||||
PKPUntrustworthyConnection=Public-Key-Pins: The connection to the site is untrustworthy, so the specified header was ignored.
|
||||
PKPCouldNotParseHeader=Public-Key-Pins: The site specified a header that could not be parsed successfully.
|
||||
PKPNoMaxAge=Public-Key-Pins: The site specified a header that did not include a 'max-age' directive.
|
||||
PKPMultipleMaxAges=Public-Key-Pins: The site specified a header that included multiple 'max-age' directives.
|
||||
PKPInvalidMaxAge=Public-Key-Pins: The site specified a header that included an invalid 'max-age' directive.
|
||||
PKPMultipleIncludeSubdomains=Public-Key-Pins: The site specified a header that included multiple 'includeSubDomains' directives.
|
||||
PKPInvalidIncludeSubdomains=Public-Key-Pins: The site specified a header that included an invalid 'includeSubDomains' directive.
|
||||
PKPInvalidPin=Public-Key-Pins: The site specified a header that included an invalid pin.
|
||||
PKPMultipleReportURIs=Public-Key-Pins: The site specified a header that included multiple 'report-uri' directives.
|
||||
PKPPinsetDoesNotMatch=Public-Key-Pins: The site specified a header that did not include a matching pin.
|
||||
PKPNoBackupPin=Public-Key-Pins: The site specified a header that did not include a backup pin.
|
||||
PKPCouldNotSaveState=Public-Key-Pins: An error occurred noting the site as a Public-Key-Pins host.
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "SHA-1"
|
||||
SHA1Sig=This site makes use of a SHA-1 Certificate; it's recommended you use certificates with signature algorithms that use hash functions stronger than SHA-1.
|
||||
InsecurePasswordsPresentOnPage=Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.
|
||||
|
@ -57,6 +57,33 @@ AudioSink::DispatchTask(already_AddRefed<nsIRunnable>&& event)
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::OnAudioQueueEvent()
|
||||
{
|
||||
AssertOnAudioThread();
|
||||
if (!mAudioLoopScheduled) {
|
||||
AudioLoop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::ConnectListener()
|
||||
{
|
||||
AssertOnAudioThread();
|
||||
mPushListener = AudioQueue().PushEvent().Connect(
|
||||
mThread, this, &AudioSink::OnAudioQueueEvent);
|
||||
mFinishListener = AudioQueue().FinishEvent().Connect(
|
||||
mThread, this, &AudioSink::OnAudioQueueEvent);
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::DisconnectListener()
|
||||
{
|
||||
AssertOnAudioThread();
|
||||
mPushListener.Disconnect();
|
||||
mFinishListener.Disconnect();
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::ScheduleNextLoop()
|
||||
{
|
||||
@ -221,12 +248,6 @@ AudioSink::SetPlaying(bool aPlaying)
|
||||
DispatchTask(r.forget());
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::NotifyData()
|
||||
{
|
||||
ScheduleNextLoopCrossThread();
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioSink::InitializeAudioStream()
|
||||
{
|
||||
@ -316,12 +337,13 @@ AudioSink::AudioLoop()
|
||||
break;
|
||||
}
|
||||
SetState(AUDIOSINK_STATE_PLAYING);
|
||||
ConnectListener();
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDIOSINK_STATE_PLAYING: {
|
||||
if (WaitingForAudioToPlay()) {
|
||||
// NotifyData() will schedule next loop.
|
||||
// OnAudioQueueEvent() will schedule next loop.
|
||||
break;
|
||||
}
|
||||
if (!IsPlaybackContinuing()) {
|
||||
@ -338,6 +360,7 @@ AudioSink::AudioLoop()
|
||||
}
|
||||
|
||||
case AUDIOSINK_STATE_COMPLETE: {
|
||||
DisconnectListener();
|
||||
FinishAudioLoop();
|
||||
SetState(AUDIOSINK_STATE_SHUTDOWN);
|
||||
break;
|
||||
|
@ -53,10 +53,6 @@ public:
|
||||
void SetPreservesPitch(bool aPreservesPitch);
|
||||
void SetPlaying(bool aPlaying);
|
||||
|
||||
// Wake up the audio loop if it is waiting for data to play or the audio
|
||||
// queue is finished.
|
||||
void NotifyData();
|
||||
|
||||
private:
|
||||
enum State {
|
||||
AUDIOSINK_STATE_INIT,
|
||||
@ -73,6 +69,10 @@ private:
|
||||
void ScheduleNextLoop();
|
||||
void ScheduleNextLoopCrossThread();
|
||||
|
||||
void OnAudioQueueEvent();
|
||||
void ConnectListener();
|
||||
void DisconnectListener();
|
||||
|
||||
// The main loop for the audio thread. Sent to the thread as
|
||||
// an nsRunnableMethod. This continually does blocking writes to
|
||||
// to audio stream to play audio data.
|
||||
@ -175,6 +175,9 @@ private:
|
||||
bool mPlaying;
|
||||
|
||||
MozPromiseHolder<GenericPromise> mEndPromise;
|
||||
|
||||
MediaEventListener mPushListener;
|
||||
MediaEventListener mFinishListener;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -456,10 +456,10 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint32_t read = Read(frameWriter->mData, frame->mOffset, frame->mSize);
|
||||
const uint32_t read = Read(frameWriter->Data(), frame->mOffset, frame->Size());
|
||||
|
||||
if (read != aRange.Length()) {
|
||||
MP3DEMUXER_LOG("GetNext() Exit read=%u frame->mSize=%u", read, frame->mSize);
|
||||
MP3DEMUXER_LOG("GetNext() Exit read=%u frame->Size()=%u", read, frame->Size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -474,7 +474,7 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) {
|
||||
if (mNumParsedFrames == 1) {
|
||||
// First frame parsed, let's read VBR info if available.
|
||||
// TODO: read info that helps with seeking (bug 1163667).
|
||||
mParser.ParseVBRHeader(frame->mData, frame->mData + frame->mSize);
|
||||
mParser.ParseVBRHeader(frame->Data(), frame->Data() + frame->Size());
|
||||
mFirstFrameOffset = frame->mOffset;
|
||||
}
|
||||
|
||||
|
@ -485,34 +485,30 @@ VideoData::Create(const VideoInfo& aInfo,
|
||||
// For 32-bytes aligned, use 31U.
|
||||
#define RAW_DATA_ALIGNMENT 31U
|
||||
|
||||
#define RAW_DATA_DEFAULT_SIZE 4096
|
||||
|
||||
MediaRawData::MediaRawData()
|
||||
: MediaData(RAW_DATA, 0)
|
||||
, mCrypto(mCryptoInternal)
|
||||
, mData(nullptr)
|
||||
, mSize(0)
|
||||
, mCrypto(mCryptoInternal)
|
||||
, mBuffer(new MediaByteBuffer())
|
||||
, mPadding(0)
|
||||
, mBuffer(nullptr)
|
||||
, mCapacity(0)
|
||||
{
|
||||
unused << mBuffer->SetCapacity(RAW_DATA_DEFAULT_SIZE, fallible);
|
||||
}
|
||||
|
||||
MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize)
|
||||
: MediaData(RAW_DATA, 0)
|
||||
, mCrypto(mCryptoInternal)
|
||||
, mData(nullptr)
|
||||
, mSize(0)
|
||||
, mCrypto(mCryptoInternal)
|
||||
, mBuffer(new MediaByteBuffer())
|
||||
, mPadding(0)
|
||||
, mBuffer(nullptr)
|
||||
, mCapacity(0)
|
||||
{
|
||||
if (!EnsureCapacity(aSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We ensure sufficient capacity above so this shouldn't fail.
|
||||
MOZ_ALWAYS_TRUE(mBuffer->AppendElements(aData, aSize, fallible));
|
||||
MOZ_ALWAYS_TRUE(mBuffer->AppendElements(RAW_DATA_ALIGNMENT, fallible));
|
||||
memcpy(mData, aData, aSize);
|
||||
mSize = aSize;
|
||||
}
|
||||
|
||||
@ -533,42 +529,39 @@ MediaRawData::Clone() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We ensure sufficient capacity above so this shouldn't fail.
|
||||
MOZ_ALWAYS_TRUE(s->mBuffer->AppendElements(mData, mSize, fallible));
|
||||
MOZ_ALWAYS_TRUE(s->mBuffer->AppendElements(RAW_DATA_ALIGNMENT, fallible));
|
||||
memcpy(s->mData, mData, mSize);
|
||||
s->mSize = mSize;
|
||||
}
|
||||
return s.forget();
|
||||
}
|
||||
|
||||
// EnsureCapacity ensures that the buffer is big enough to hold
|
||||
// aSize. It doesn't set the mSize. It's up to the caller to adjust it.
|
||||
bool
|
||||
MediaRawData::EnsureCapacity(size_t aSize)
|
||||
{
|
||||
if (mData && mBuffer->Capacity() >= aSize + RAW_DATA_ALIGNMENT * 2) {
|
||||
const size_t sizeNeeded = aSize + RAW_DATA_ALIGNMENT * 2;
|
||||
|
||||
if (mData && mCapacity >= sizeNeeded) {
|
||||
return true;
|
||||
}
|
||||
if (!mBuffer->SetCapacity(aSize + RAW_DATA_ALIGNMENT * 2, fallible)) {
|
||||
nsAutoArrayPtr<uint8_t> newBuffer;
|
||||
newBuffer = new (fallible) uint8_t[sizeNeeded];
|
||||
if (!newBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find alignment address.
|
||||
const uintptr_t alignmask = RAW_DATA_ALIGNMENT;
|
||||
mData = reinterpret_cast<uint8_t*>(
|
||||
(reinterpret_cast<uintptr_t>(mBuffer->Elements()) + alignmask) & ~alignmask);
|
||||
MOZ_ASSERT(uintptr_t(mData) % (RAW_DATA_ALIGNMENT+1) == 0);
|
||||
uint8_t* newData = reinterpret_cast<uint8_t*>(
|
||||
(reinterpret_cast<uintptr_t>(newBuffer.get()) + alignmask) & ~alignmask);
|
||||
MOZ_ASSERT(uintptr_t(newData) % (RAW_DATA_ALIGNMENT+1) == 0);
|
||||
memcpy(newData, mData, mSize);
|
||||
|
||||
// Shift old data according to new padding.
|
||||
uint32_t oldpadding = int32_t(mPadding);
|
||||
mPadding = mData - mBuffer->Elements();
|
||||
int32_t shift = int32_t(mPadding) - int32_t(oldpadding);
|
||||
mBuffer = newBuffer.forget();
|
||||
mCapacity = sizeNeeded;
|
||||
mData = newData;
|
||||
|
||||
if (shift == 0) {
|
||||
// Nothing to do.
|
||||
} else if (shift > 0) {
|
||||
// We ensure sufficient capacity above so this shouldn't fail.
|
||||
MOZ_ALWAYS_TRUE(mBuffer->InsertElementsAt(oldpadding, shift, fallible));
|
||||
} else {
|
||||
mBuffer->RemoveElementsAt(mPadding, -shift);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -580,8 +573,7 @@ size_t
|
||||
MediaRawData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t size = aMallocSizeOf(this);
|
||||
|
||||
size += mBuffer->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
||||
size += aMallocSizeOf(mBuffer.get());
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -592,28 +584,20 @@ MediaRawData::CreateWriter()
|
||||
}
|
||||
|
||||
MediaRawDataWriter::MediaRawDataWriter(MediaRawData* aMediaRawData)
|
||||
: mData(nullptr)
|
||||
, mSize(0)
|
||||
, mCrypto(aMediaRawData->mCryptoInternal)
|
||||
: mCrypto(aMediaRawData->mCryptoInternal)
|
||||
, mTarget(aMediaRawData)
|
||||
, mBuffer(aMediaRawData->mBuffer.get())
|
||||
{
|
||||
if (aMediaRawData->mData) {
|
||||
mData = mBuffer->Elements() + mTarget->mPadding;
|
||||
mSize = mTarget->mSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MediaRawDataWriter::EnsureSize(size_t aSize)
|
||||
{
|
||||
if (aSize <= mSize) {
|
||||
if (aSize <= mTarget->mSize) {
|
||||
return true;
|
||||
}
|
||||
if (!mTarget->EnsureCapacity(aSize)) {
|
||||
return false;
|
||||
}
|
||||
mData = mBuffer->Elements() + mTarget->mPadding;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -624,11 +608,7 @@ MediaRawDataWriter::SetSize(size_t aSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pad our buffer. We ensure sufficient capacity above so this shouldn't fail.
|
||||
MOZ_ALWAYS_TRUE(
|
||||
mBuffer->SetLength(aSize + mTarget->mPadding + RAW_DATA_ALIGNMENT,
|
||||
fallible));
|
||||
mTarget->mSize = mSize = aSize;
|
||||
mTarget->mSize = aSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -639,34 +619,45 @@ MediaRawDataWriter::Prepend(const uint8_t* aData, size_t aSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
// We ensure sufficient capacity above so this shouldn't fail.
|
||||
MOZ_ALWAYS_TRUE(mBuffer->InsertElementsAt(mTarget->mPadding, aData, aSize,
|
||||
fallible));
|
||||
// Shift the data to the right by aSize to leave room for the new data.
|
||||
memmove(mTarget->mData + aSize, mTarget->mData, mTarget->mSize);
|
||||
memcpy(mTarget->mData, aData, aSize);
|
||||
|
||||
mTarget->mSize += aSize;
|
||||
mSize = mTarget->mSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaRawDataWriter::Replace(const uint8_t* aData, size_t aSize)
|
||||
{
|
||||
// If aSize is smaller than our current size, we leave the buffer as is,
|
||||
// only adjusting the reported size.
|
||||
if (!EnsureSize(aSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We ensure sufficient capacity above so this shouldn't fail.
|
||||
MOZ_ALWAYS_TRUE(mBuffer->ReplaceElementsAt(mTarget->mPadding, mTarget->mSize,
|
||||
aData, aSize, fallible));
|
||||
mTarget->mSize = mSize = aSize;
|
||||
memcpy(mTarget->mData, aData, aSize);
|
||||
mTarget->mSize = aSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaRawDataWriter::Clear()
|
||||
{
|
||||
mBuffer->RemoveElementsAt(mTarget->mPadding, mTarget->mSize);
|
||||
mTarget->mSize = mSize = 0;
|
||||
mTarget->mData = mData = nullptr;
|
||||
mTarget->mSize = 0;
|
||||
mTarget->mData = nullptr;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
MediaRawDataWriter::Data()
|
||||
{
|
||||
return mTarget->mData;
|
||||
}
|
||||
|
||||
size_t
|
||||
MediaRawDataWriter::Size()
|
||||
{
|
||||
return mTarget->Size();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -360,9 +360,9 @@ class MediaRawDataWriter
|
||||
{
|
||||
public:
|
||||
// Pointer to data or null if not-yet allocated
|
||||
uint8_t* mData;
|
||||
uint8_t* Data();
|
||||
// Writeable size of buffer.
|
||||
size_t mSize;
|
||||
size_t Size();
|
||||
// Writeable reference to MediaRawData::mCryptoInternal
|
||||
CryptoSample& mCrypto;
|
||||
|
||||
@ -375,7 +375,7 @@ public:
|
||||
bool Prepend(const uint8_t* aData, size_t aSize);
|
||||
// Replace current content with aData.
|
||||
bool Replace(const uint8_t* aData, size_t aSize);
|
||||
// Clear the memory buffer. Will set mData and mSize to 0.
|
||||
// Clear the memory buffer. Will set target mData and mSize to 0.
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
@ -383,7 +383,6 @@ private:
|
||||
explicit MediaRawDataWriter(MediaRawData* aMediaRawData);
|
||||
bool EnsureSize(size_t aSize);
|
||||
MediaRawData* mTarget;
|
||||
nsRefPtr<MediaByteBuffer> mBuffer;
|
||||
};
|
||||
|
||||
class MediaRawData : public MediaData {
|
||||
@ -392,9 +391,13 @@ public:
|
||||
MediaRawData(const uint8_t* aData, size_t mSize);
|
||||
|
||||
// Pointer to data or null if not-yet allocated
|
||||
const uint8_t* mData;
|
||||
const uint8_t* Data() const { return mData; }
|
||||
// Size of buffer.
|
||||
size_t mSize;
|
||||
size_t Size() const { return mSize; }
|
||||
size_t ComputedSizeOfIncludingThis() const
|
||||
{
|
||||
return sizeof(*this) + mCapacity;
|
||||
}
|
||||
|
||||
const CryptoSample& mCrypto;
|
||||
nsRefPtr<MediaByteBuffer> mExtraData;
|
||||
@ -419,9 +422,11 @@ private:
|
||||
// read as required by some data decoders.
|
||||
// Returns false if memory couldn't be allocated.
|
||||
bool EnsureCapacity(size_t aSize);
|
||||
nsRefPtr<MediaByteBuffer> mBuffer;
|
||||
uint8_t* mData;
|
||||
size_t mSize;
|
||||
nsAutoArrayPtr<uint8_t> mBuffer;
|
||||
uint32_t mCapacity;
|
||||
CryptoSample mCryptoInternal;
|
||||
uint32_t mPadding;
|
||||
MediaRawData(const MediaRawData&); // Not implemented
|
||||
};
|
||||
|
||||
|
@ -284,17 +284,10 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
|
||||
nsRefPtr<MediaDecoderStateMachine> self = this;
|
||||
|
||||
AudioQueue().AddPopListener(
|
||||
[self] (const MediaData* aSample) {
|
||||
self->OnAudioPopped(aSample->As<AudioData>());
|
||||
}, mTaskQueue);
|
||||
|
||||
VideoQueue().AddPopListener(
|
||||
[self] (const MediaData* aSample) {
|
||||
self->OnVideoPopped(aSample->As<VideoData>());
|
||||
}, mTaskQueue);
|
||||
mAudioQueueListener = AudioQueue().PopEvent().Connect(
|
||||
mTaskQueue, this, &MediaDecoderStateMachine::OnAudioPopped);
|
||||
mVideoQueueListener = VideoQueue().PopEvent().Connect(
|
||||
mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped);
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
||||
@ -640,9 +633,6 @@ MediaDecoderStateMachine::Push(AudioData* aSample)
|
||||
UpdateNextFrameStatus();
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
|
||||
if (mAudioSink) {
|
||||
mAudioSink->NotifyData();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -684,7 +674,7 @@ MediaDecoderStateMachine::PushFront(VideoData* aSample)
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnAudioPopped(const AudioData* aSample)
|
||||
MediaDecoderStateMachine::OnAudioPopped(const MediaData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
@ -694,7 +684,7 @@ MediaDecoderStateMachine::OnAudioPopped(const AudioData* aSample)
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnVideoPopped(const VideoData* aSample)
|
||||
MediaDecoderStateMachine::OnVideoPopped(const MediaData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
@ -786,10 +776,6 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
}
|
||||
CheckIfDecodeComplete();
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
// Tell AudioSink to wake up for audio queue is finished.
|
||||
if (mAudioSink) {
|
||||
mAudioSink->NotifyData();
|
||||
}
|
||||
// Schedule the state machine to notify track ended as soon as possible.
|
||||
if (mAudioCaptured) {
|
||||
ScheduleStateMachine();
|
||||
@ -2216,8 +2202,10 @@ MediaDecoderStateMachine::FinishShutdown()
|
||||
// The reader's listeners hold references to the state machine,
|
||||
// creating a cycle which keeps the state machine and its shared
|
||||
// thread pools alive. So break it here.
|
||||
AudioQueue().ClearListeners();
|
||||
VideoQueue().ClearListeners();
|
||||
|
||||
// Prevent dangling pointers by disconnecting the listeners.
|
||||
mAudioQueueListener.Disconnect();
|
||||
mVideoQueueListener.Disconnect();
|
||||
|
||||
// Disconnect canonicals and mirrors before shutting down our task queue.
|
||||
mBuffered.DisconnectIfConnected();
|
||||
|
@ -91,6 +91,7 @@ hardware (via AudioStream).
|
||||
#include "MediaDecoder.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaDecoderOwner.h"
|
||||
#include "MediaEventSource.h"
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "MediaTimer.h"
|
||||
#include "DecodedStream.h"
|
||||
@ -399,8 +400,8 @@ protected:
|
||||
void PushFront(AudioData* aSample);
|
||||
void PushFront(VideoData* aSample);
|
||||
|
||||
void OnAudioPopped(const AudioData* aSample);
|
||||
void OnVideoPopped(const VideoData* aSample);
|
||||
void OnAudioPopped(const MediaData* aSample);
|
||||
void OnVideoPopped(const MediaData* aSample);
|
||||
|
||||
void VolumeChanged();
|
||||
void LogicalPlaybackRateChanged();
|
||||
@ -1288,6 +1289,9 @@ private:
|
||||
|
||||
MozPromiseRequestHolder<GenericPromise> mAudioSinkPromise;
|
||||
|
||||
MediaEventListener mAudioQueueListener;
|
||||
MediaEventListener mVideoQueueListener;
|
||||
|
||||
private:
|
||||
// The buffered range. Mirrored from the decoder thread.
|
||||
Mirror<media::TimeIntervals> mBuffered;
|
||||
|
@ -8,10 +8,9 @@
|
||||
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "nsDeque.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MediaEventSource.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -26,36 +25,6 @@ class MediaQueueDeallocator : public nsDequeFunctor {
|
||||
|
||||
template <class T>
|
||||
class MediaQueue : private nsDeque {
|
||||
struct Listener {
|
||||
virtual ~Listener() {}
|
||||
virtual void Dispatch(T* aItem) = 0;
|
||||
};
|
||||
|
||||
template<typename Function>
|
||||
class PopListener : public Listener {
|
||||
public:
|
||||
explicit PopListener(const Function& aFunction, TaskQueue* aTarget)
|
||||
: mFunction(aFunction), mTarget(aTarget) {}
|
||||
|
||||
void Dispatch(T* aItem) override {
|
||||
nsRefPtr<T> item = aItem;
|
||||
Function function = mFunction;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
||||
function(item);
|
||||
});
|
||||
mTarget->Dispatch(r.forget());
|
||||
}
|
||||
private:
|
||||
Function mFunction;
|
||||
nsRefPtr<TaskQueue> mTarget;
|
||||
};
|
||||
|
||||
void NotifyPopListeners(T* aItem) {
|
||||
for (auto&& l : mPopListeners) {
|
||||
l->Dispatch(aItem);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
MediaQueue()
|
||||
: nsDeque(new MediaQueueDeallocator<T>()),
|
||||
@ -77,6 +46,7 @@ public:
|
||||
MOZ_ASSERT(aItem);
|
||||
NS_ADDREF(aItem);
|
||||
nsDeque::Push(aItem);
|
||||
mPushEvent.Notify();
|
||||
}
|
||||
|
||||
inline void PushFront(T* aItem) {
|
||||
@ -84,13 +54,14 @@ public:
|
||||
MOZ_ASSERT(aItem);
|
||||
NS_ADDREF(aItem);
|
||||
nsDeque::PushFront(aItem);
|
||||
mPushEvent.Notify();
|
||||
}
|
||||
|
||||
inline already_AddRefed<T> PopFront() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
nsRefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
|
||||
if (rv) {
|
||||
NotifyPopListeners(rv);
|
||||
mPopEvent.Notify(rv);
|
||||
}
|
||||
return rv.forget();
|
||||
}
|
||||
@ -130,6 +101,7 @@ public:
|
||||
void Finish() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mEndOfStream = true;
|
||||
mFinishEvent.Notify();
|
||||
}
|
||||
|
||||
// Returns the approximate number of microseconds of items in the queue.
|
||||
@ -185,21 +157,23 @@ public:
|
||||
return frames;
|
||||
}
|
||||
|
||||
void ClearListeners() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mPopListeners.Clear();
|
||||
MediaEventSource<nsRefPtr<T>>& PopEvent() {
|
||||
return mPopEvent;
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
void AddPopListener(const Function& aFunction, TaskQueue* aTarget) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mPopListeners.AppendElement()->reset(
|
||||
new PopListener<Function>(aFunction, aTarget));
|
||||
MediaEventSource<void>& PushEvent() {
|
||||
return mPushEvent;
|
||||
}
|
||||
|
||||
MediaEventSource<void>& FinishEvent() {
|
||||
return mFinishEvent;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable ReentrantMonitor mReentrantMonitor;
|
||||
nsTArray<UniquePtr<Listener>> mPopListeners;
|
||||
MediaEventProducer<nsRefPtr<T>> mPopEvent;
|
||||
MediaEventProducer<void> mPushEvent;
|
||||
MediaEventProducer<void> mFinishEvent;
|
||||
// True when we've decoded the last frame of data in the
|
||||
// bitstream for which we're queueing frame data.
|
||||
bool mEndOfStream;
|
||||
|
@ -660,7 +660,7 @@ CDMProxy::gmp_Decrypt(nsRefPtr<DecryptJob> aJob)
|
||||
|
||||
aJob->mId = ++mDecryptionJobCount;
|
||||
nsTArray<uint8_t> data;
|
||||
data.AppendElements(aJob->mSample->mData, aJob->mSample->mSize);
|
||||
data.AppendElements(aJob->mSample->Data(), aJob->mSample->Size());
|
||||
mCDM->Decrypt(aJob->mId, aJob->mSample->mCrypto, data);
|
||||
mDecryptionJobs.AppendElement(aJob.forget());
|
||||
}
|
||||
@ -701,14 +701,14 @@ CDMProxy::DecryptJob::PostResult(GMPErr aResult)
|
||||
void
|
||||
CDMProxy::DecryptJob::PostResult(GMPErr aResult, const nsTArray<uint8_t>& aDecryptedData)
|
||||
{
|
||||
if (aDecryptedData.Length() != mSample->mSize) {
|
||||
if (aDecryptedData.Length() != mSample->Size()) {
|
||||
NS_WARNING("CDM returned incorrect number of decrypted bytes");
|
||||
}
|
||||
if (GMP_SUCCEEDED(aResult)) {
|
||||
nsAutoPtr<MediaRawDataWriter> writer(mSample->CreateWriter());
|
||||
PodCopy(writer->mData,
|
||||
PodCopy(writer->Data(),
|
||||
aDecryptedData.Elements(),
|
||||
std::min<size_t>(aDecryptedData.Length(), mSample->mSize));
|
||||
std::min<size_t>(aDecryptedData.Length(), mSample->Size()));
|
||||
} else if (aResult == GMPNoKeyErr) {
|
||||
NS_WARNING("CDM returned GMPNoKeyErr");
|
||||
// We still have the encrypted sample, so we can re-enqueue it to be
|
||||
|
@ -40,7 +40,7 @@ GMPAudioSamplesImpl::GMPAudioSamplesImpl(MediaRawData* aSample,
|
||||
, mChannels(aChannels)
|
||||
, mRate(aRate)
|
||||
{
|
||||
mBuffer.AppendElements(aSample->mData, aSample->mSize);
|
||||
mBuffer.AppendElements(aSample->Data(), aSample->Size());
|
||||
if (aSample->mCrypto.mValid) {
|
||||
mCrypto = new GMPEncryptedBufferDataImpl(aSample->mCrypto);
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ TEST_F(MP3DemuxerTest, FrameParsing) {
|
||||
}
|
||||
|
||||
++numFrames;
|
||||
parsedLength += frameData->mSize;
|
||||
parsedLength += frameData->Size();
|
||||
|
||||
const auto& frame = target.mDemuxer->LastFrame();
|
||||
const auto& header = frame.Header();
|
||||
|
@ -430,7 +430,7 @@ TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime,
|
||||
if (frame->mTime >= lowerLimit.ToMicroseconds()) {
|
||||
break;
|
||||
}
|
||||
partialEvict += sizeof(*frame) + frame->mSize;
|
||||
partialEvict += frame->ComputedSizeOfIncludingThis();
|
||||
}
|
||||
|
||||
int64_t finalSize = mSizeSourceBuffer - aSizeToEvict;
|
||||
@ -468,7 +468,7 @@ TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime,
|
||||
if (frame->mTime <= upperLimit.ToMicroseconds()) {
|
||||
break;
|
||||
}
|
||||
partialEvict += sizeof(*frame) + frame->mSize;
|
||||
partialEvict += frame->ComputedSizeOfIncludingThis();
|
||||
}
|
||||
if (lastKeyFrameIndex < buffer.Length()) {
|
||||
MSE_DEBUG("Step2. Evicting %u bytes from trailing data",
|
||||
@ -1400,7 +1400,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData)
|
||||
}
|
||||
|
||||
samplesRange += sampleInterval;
|
||||
sizeNewSamples += sizeof(*sample) + sample->mSize;
|
||||
sizeNewSamples += sample->ComputedSizeOfIncludingThis();
|
||||
sample->mTime = sampleInterval.mStart.ToMicroseconds();
|
||||
sample->mTimecode = decodeTimestamp.ToMicroseconds();
|
||||
sample->mTrackInfo = trackBuffer.mLastInfo;
|
||||
@ -1606,7 +1606,7 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
||||
if (sample->mDuration > maxSampleDuration) {
|
||||
maxSampleDuration = sample->mDuration;
|
||||
}
|
||||
aTrackData.mSizeBuffer -= sizeof(*sample) + sample->mSize;
|
||||
aTrackData.mSizeBuffer -= sample->ComputedSizeOfIncludingThis();
|
||||
}
|
||||
|
||||
removedIntervals.SetFuzz(TimeUnit::FromMicroseconds(maxSampleDuration));
|
||||
|
@ -149,15 +149,15 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample)
|
||||
}
|
||||
|
||||
// Maximum value is 63*2880, so there's no chance of overflow.
|
||||
int32_t frames_number = opus_packet_get_nb_frames(aSample->mData,
|
||||
aSample->mSize);
|
||||
int32_t frames_number = opus_packet_get_nb_frames(aSample->Data(),
|
||||
aSample->Size());
|
||||
if (frames_number <= 0) {
|
||||
OPUS_DEBUG("Invalid packet header: r=%ld length=%ld",
|
||||
frames_number, aSample->mSize);
|
||||
frames_number, aSample->Size());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t samples = opus_packet_get_samples_per_frame(aSample->mData,
|
||||
int32_t samples = opus_packet_get_samples_per_frame(aSample->Data(),
|
||||
opus_int32(mOpusParser->mRate));
|
||||
|
||||
|
||||
@ -173,11 +173,11 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample)
|
||||
// Decode to the appropriate sample type.
|
||||
#ifdef MOZ_SAMPLE_TYPE_FLOAT32
|
||||
int ret = opus_multistream_decode_float(mOpusDecoder,
|
||||
aSample->mData, aSample->mSize,
|
||||
aSample->Data(), aSample->Size(),
|
||||
buffer, frames, false);
|
||||
#else
|
||||
int ret = opus_multistream_decode(mOpusDecoder,
|
||||
aSample->mData, aSample->mSize,
|
||||
aSample->Data(), aSample->Size(),
|
||||
buffer, frames, false);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
|
@ -87,15 +87,15 @@ VPXDecoder::DoDecodeFrame(MediaRawData* aSample)
|
||||
PodZero(&si);
|
||||
si.sz = sizeof(si);
|
||||
if (mCodec == Codec::VP8) {
|
||||
vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aSample->mData, aSample->mSize, &si);
|
||||
vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aSample->Data(), aSample->Size(), &si);
|
||||
} else if (mCodec == Codec::VP9) {
|
||||
vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aSample->mData, aSample->mSize, &si);
|
||||
vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aSample->Data(), aSample->Size(), &si);
|
||||
}
|
||||
NS_ASSERTION(bool(si.is_kf) == aSample->mKeyframe,
|
||||
"VPX Decode Keyframe error sample->mKeyframe and si.si_kf out of sync");
|
||||
#endif
|
||||
|
||||
if (vpx_codec_err_t r = vpx_codec_decode(&mVPX, aSample->mData, aSample->mSize, nullptr, 0)) {
|
||||
if (vpx_codec_err_t r = vpx_codec_decode(&mVPX, aSample->Data(), aSample->Size(), nullptr, 0)) {
|
||||
LOG("VPX Decode error: %s", vpx_codec_err_to_string(r));
|
||||
return -1;
|
||||
}
|
||||
|
@ -152,8 +152,8 @@ VorbisDataDecoder::Decode(MediaRawData* aSample)
|
||||
int
|
||||
VorbisDataDecoder::DoDecode(MediaRawData* aSample)
|
||||
{
|
||||
const unsigned char* aData = aSample->mData;
|
||||
size_t aLength = aSample->mSize;
|
||||
const unsigned char* aData = aSample->Data();
|
||||
size_t aLength = aSample->Size();
|
||||
int64_t aOffset = aSample->mOffset;
|
||||
uint64_t aTstampUsecs = aSample->mTime;
|
||||
int64_t aTotalFrames = 0;
|
||||
|
@ -126,13 +126,13 @@ GMPVideoDecoder::CreateFrame(MediaRawData* aSample)
|
||||
}
|
||||
|
||||
GMPUniquePtr<GMPVideoEncodedFrame> frame(static_cast<GMPVideoEncodedFrame*>(ftmp));
|
||||
err = frame->CreateEmptyFrame(aSample->mSize);
|
||||
err = frame->CreateEmptyFrame(aSample->Size());
|
||||
if (GMP_FAILED(err)) {
|
||||
mCallback->Error();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memcpy(frame->Buffer(), aSample->mData, frame->Size());
|
||||
memcpy(frame->Buffer(), aSample->Data(), frame->Size());
|
||||
|
||||
// Convert 4-byte NAL unit lengths to host-endian 4-byte buffer lengths to
|
||||
// suit the GMP API.
|
||||
|
@ -473,7 +473,7 @@ void MediaCodecDataDecoder::DecoderLoop()
|
||||
|
||||
void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
|
||||
|
||||
MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->mSize,
|
||||
MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->Size(),
|
||||
"Decoder buffer is not large enough for sample");
|
||||
|
||||
{
|
||||
@ -482,9 +482,9 @@ void MediaCodecDataDecoder::DecoderLoop()
|
||||
mQueue.pop();
|
||||
}
|
||||
|
||||
PodCopy((uint8_t*)directBuffer, sample->mData, sample->mSize);
|
||||
PodCopy((uint8_t*)directBuffer, sample->Data(), sample->Size());
|
||||
|
||||
res = mDecoder->QueueInputBuffer(inputIndex, 0, sample->mSize,
|
||||
res = mDecoder->QueueInputBuffer(inputIndex, 0, sample->Size(),
|
||||
sample->mTime, 0);
|
||||
HANDLE_DECODER_ERROR();
|
||||
|
||||
|
@ -68,7 +68,7 @@ AppleATDecoder::Input(MediaRawData* aSample)
|
||||
aSample->mDuration,
|
||||
aSample->mTime,
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
(unsigned long long)aSample->mSize);
|
||||
(unsigned long long)aSample->Size());
|
||||
|
||||
// Queue a task to perform the actual decoding on a separate thread.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
@ -216,7 +216,7 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample)
|
||||
// This API insists on having packets spoon-fed to it from a callback.
|
||||
// This structure exists only to pass our state.
|
||||
PassthroughUserData userData =
|
||||
{ channels, (UInt32)aSample->mSize, aSample->mData };
|
||||
{ channels, (UInt32)aSample->Size(), aSample->Data() };
|
||||
|
||||
// Decompressed audio buffer
|
||||
nsAutoArrayPtr<AudioDataValue> decoded(new AudioDataValue[maxDecodedSamples]);
|
||||
@ -488,8 +488,8 @@ AppleATDecoder::GetImplicitAACMagicCookie(const MediaRawData* aSample)
|
||||
}
|
||||
|
||||
OSStatus status = AudioFileStreamParseBytes(mStream,
|
||||
adtssample->mSize,
|
||||
adtssample->mData,
|
||||
adtssample->Size(),
|
||||
adtssample->Data(),
|
||||
0 /* discontinuity */);
|
||||
if (status) {
|
||||
NS_WARNING("Couldn't parse sample");
|
||||
|
@ -106,7 +106,7 @@ AppleVDADecoder::Input(MediaRawData* aSample)
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
aSample->mSize);
|
||||
aSample->Size());
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
@ -307,7 +307,7 @@ nsresult
|
||||
AppleVDADecoder::SubmitFrame(MediaRawData* aSample)
|
||||
{
|
||||
AutoCFRelease<CFDataRef> block =
|
||||
CFDataCreate(kCFAllocatorDefault, aSample->mData, aSample->mSize);
|
||||
CFDataCreate(kCFAllocatorDefault, aSample->Data(), aSample->Size());
|
||||
if (!block) {
|
||||
NS_ERROR("Couldn't create CFData");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -84,7 +84,7 @@ AppleVTDecoder::Input(MediaRawData* aSample)
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
aSample->mSize);
|
||||
aSample->Size());
|
||||
|
||||
#ifdef LOG_MEDIA_SHA1
|
||||
SHA1Sum hash;
|
||||
@ -215,12 +215,12 @@ AppleVTDecoder::SubmitFrame(MediaRawData* aSample)
|
||||
// But note that there may be a problem keeping the samples
|
||||
// alive over multiple frames.
|
||||
rv = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, // Struct allocator.
|
||||
const_cast<uint8_t*>(aSample->mData),
|
||||
aSample->mSize,
|
||||
const_cast<uint8_t*>(aSample->Data()),
|
||||
aSample->Size(),
|
||||
kCFAllocatorNull, // Block allocator.
|
||||
NULL, // Block source.
|
||||
0, // Data offset.
|
||||
aSample->mSize,
|
||||
aSample->Size(),
|
||||
false,
|
||||
block.receive());
|
||||
if (rv != noErr) {
|
||||
|
@ -88,8 +88,8 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
packet.data = const_cast<uint8_t*>(aSample->mData);
|
||||
packet.size = aSample->mSize;
|
||||
packet.data = const_cast<uint8_t*>(aSample->Data());
|
||||
packet.size = aSample->Size();
|
||||
|
||||
if (!PrepareFrame()) {
|
||||
NS_WARNING("FFmpeg audio decoder failed to allocate frame.");
|
||||
|
@ -71,8 +71,8 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
packet.data = const_cast<uint8_t*>(aSample->mData);
|
||||
packet.size = aSample->mSize;
|
||||
packet.data = const_cast<uint8_t*>(aSample->Data());
|
||||
packet.size = aSample->Size();
|
||||
packet.dts = aSample->mTimecode;
|
||||
packet.pts = aSample->mTime;
|
||||
packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0;
|
||||
|
@ -127,8 +127,8 @@ GonkAudioDecoderManager::Input(MediaRawData* aSample)
|
||||
nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
|
||||
{
|
||||
MonitorAutoUnlock mon_exit(mMonitor);
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->mData),
|
||||
data->mSize,
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0);
|
||||
}
|
||||
|
@ -132,8 +132,8 @@ GonkVideoDecoderManager::Input(MediaRawData* aSample)
|
||||
nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
|
||||
{
|
||||
MonitorAutoUnlock mon_unlock(mMonitor);
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->mData),
|
||||
data->mSize,
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0);
|
||||
}
|
||||
|
@ -175,8 +175,8 @@ WMFAudioMFTManager::Init()
|
||||
HRESULT
|
||||
WMFAudioMFTManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
return mDecoder->Input(aSample->mData,
|
||||
uint32_t(aSample->mSize),
|
||||
return mDecoder->Input(aSample->Data(),
|
||||
uint32_t(aSample->Size()),
|
||||
aSample->mTime);
|
||||
}
|
||||
|
||||
|
@ -272,8 +272,8 @@ WMFVideoMFTManager::Input(MediaRawData* aSample)
|
||||
return E_FAIL;
|
||||
}
|
||||
// Forward sample data to the decoder.
|
||||
return mDecoder->Input(aSample->mData,
|
||||
uint32_t(aSample->mSize),
|
||||
return mDecoder->Input(aSample->Data(),
|
||||
uint32_t(aSample->Size()),
|
||||
aSample->mTime);
|
||||
}
|
||||
|
||||
|
@ -6,40 +6,43 @@
|
||||
|
||||
#include "AudioContext.h"
|
||||
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "blink/PeriodicWave.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/AnalyserNode.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/AudioContextBinding.h"
|
||||
#include "mozilla/dom/OfflineAudioContextBinding.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
|
||||
#include "mozilla/dom/AnalyserNode.h"
|
||||
#include "mozilla/dom/AudioContextBinding.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/OfflineAudioContextBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
#include "AudioBuffer.h"
|
||||
#include "AudioBufferSourceNode.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "AudioDestinationNode.h"
|
||||
#include "AudioBufferSourceNode.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "GainNode.h"
|
||||
#include "MediaElementAudioSourceNode.h"
|
||||
#include "MediaStreamAudioSourceNode.h"
|
||||
#include "DelayNode.h"
|
||||
#include "PannerNode.h"
|
||||
#include "AudioListener.h"
|
||||
#include "DynamicsCompressorNode.h"
|
||||
#include "AudioStream.h"
|
||||
#include "BiquadFilterNode.h"
|
||||
#include "ScriptProcessorNode.h"
|
||||
#include "StereoPannerNode.h"
|
||||
#include "ChannelMergerNode.h"
|
||||
#include "ChannelSplitterNode.h"
|
||||
#include "MediaStreamAudioDestinationNode.h"
|
||||
#include "WaveShaperNode.h"
|
||||
#include "PeriodicWave.h"
|
||||
#include "ConvolverNode.h"
|
||||
#include "OscillatorNode.h"
|
||||
#include "DelayNode.h"
|
||||
#include "DynamicsCompressorNode.h"
|
||||
#include "GainNode.h"
|
||||
#include "MediaElementAudioSourceNode.h"
|
||||
#include "MediaStreamAudioDestinationNode.h"
|
||||
#include "MediaStreamAudioSourceNode.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "blink/PeriodicWave.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "AudioStream.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "OscillatorNode.h"
|
||||
#include "PannerNode.h"
|
||||
#include "PeriodicWave.h"
|
||||
#include "ScriptProcessorNode.h"
|
||||
#include "StereoPannerNode.h"
|
||||
#include "WaveShaperNode.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -371,7 +371,7 @@ void
|
||||
AudioDestinationNode::DestroyAudioChannelAgent()
|
||||
{
|
||||
if (mAudioChannelAgent && !Context()->IsOffline()) {
|
||||
mAudioChannelAgent->NotifyStoppedPlaying();
|
||||
mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
|
||||
mAudioChannelAgent = nullptr;
|
||||
}
|
||||
}
|
||||
@ -605,7 +605,7 @@ AudioDestinationNode::CreateAudioChannelAgent()
|
||||
}
|
||||
|
||||
if (mAudioChannelAgent) {
|
||||
mAudioChannelAgent->NotifyStoppedPlaying();
|
||||
mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
|
||||
}
|
||||
|
||||
mAudioChannelAgent = new AudioChannelAgent();
|
||||
@ -698,13 +698,14 @@ AudioDestinationNode::InputMuted(bool aMuted)
|
||||
}
|
||||
|
||||
if (aMuted) {
|
||||
mAudioChannelAgent->NotifyStoppedPlaying();
|
||||
mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
|
||||
return;
|
||||
}
|
||||
|
||||
float volume = 0.0;
|
||||
bool muted = true;
|
||||
nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
|
||||
nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY,
|
||||
&volume, &muted);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ IntelWebMVideoDecoder::Demux(nsRefPtr<VP8Sample>& aSample, bool* aEOS)
|
||||
data,
|
||||
length,
|
||||
si.is_kf);
|
||||
if (!aSample->mData) {
|
||||
if (!aSample->Data()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5,47 +5,50 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/Notification.h"
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/dom/NotificationEvent.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
|
||||
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsINotificationStorage.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStructuredCloneContainer.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/NotificationEvent.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsILoadContext.h"
|
||||
#ifdef MOZ_B2G
|
||||
#include "nsIDOMDesktopNotification.h"
|
||||
#endif
|
||||
|
||||
#include "ServiceWorkerManager.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerScope.h"
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
#include "nsIDOMDesktopNotification.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -2423,14 +2423,15 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
|
||||
MOZ_ASSERT(agent);
|
||||
|
||||
if (isMuted) {
|
||||
rv = agent->NotifyStoppedPlaying();
|
||||
rv = agent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
} else {
|
||||
float volume = 0.0;
|
||||
bool muted = true;
|
||||
rv = agent->NotifyStartedPlaying(&volume, &muted);
|
||||
rv = agent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY,
|
||||
&volume, &muted);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
@ -6,32 +6,35 @@
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/Debug.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/dom/MediaStreamError.h"
|
||||
#include "mozilla/dom/PromiseBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/MediaStreamError.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "PromiseCallback.h"
|
||||
#include "PromiseDebugging.h"
|
||||
#include "PromiseNativeHandler.h"
|
||||
#include "PromiseWorkerProxy.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -286,7 +286,6 @@ public:
|
||||
|
||||
explicit WorkerUnsubscribeResultCallback(PromiseWorkerProxy* aProxy)
|
||||
: mProxy(aProxy)
|
||||
, mCallbackCalled(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
@ -295,7 +294,6 @@ public:
|
||||
OnUnsubscribe(nsresult aStatus, bool aSuccess) override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
mCallbackCalled = true;
|
||||
if (!mProxy) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -314,19 +312,27 @@ public:
|
||||
ReleasePromiseWorkerProxy(mProxy.forget());
|
||||
}
|
||||
|
||||
mProxy = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~WorkerUnsubscribeResultCallback()
|
||||
{
|
||||
// Enforces that UnsubscribeRunnable uses the callback for error
|
||||
// reporting once it creates the callback.
|
||||
MOZ_ASSERT(mCallbackCalled);
|
||||
AssertIsOnMainThread();
|
||||
if (mProxy) {
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (!mProxy->IsClean()) {
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> cr =
|
||||
new PromiseWorkerProxyControlRunnable(mProxy->GetWorkerPrivate(), mProxy);
|
||||
cr->Dispatch(jsapi.cx());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> mProxy;
|
||||
DebugOnly<bool> mCallbackCalled;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerUnsubscribeResultCallback, nsIUnsubscribeResultCallback)
|
||||
@ -444,13 +450,9 @@ public:
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
nsRefPtr<Promise> promise = proxy->GetWorkerPromise();
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
if (mEndpoint.IsEmpty()) {
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
} else {
|
||||
nsRefPtr<WorkerPushSubscription> sub =
|
||||
new WorkerPushSubscription(mEndpoint, mScope);
|
||||
promise->MaybeResolve(sub);
|
||||
}
|
||||
nsRefPtr<WorkerPushSubscription> sub =
|
||||
new WorkerPushSubscription(mEndpoint, mScope);
|
||||
promise->MaybeResolve(sub);
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
@ -477,14 +479,12 @@ public:
|
||||
const nsAString& aScope)
|
||||
: mProxy(aProxy)
|
||||
, mScope(aScope)
|
||||
, mCallbackCalled(false)
|
||||
{}
|
||||
|
||||
NS_IMETHOD
|
||||
OnPushEndpoint(nsresult aStatus, const nsAString& aEndpoint) override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
mCallbackCalled = true;
|
||||
|
||||
if (!mProxy) {
|
||||
return NS_OK;
|
||||
@ -503,21 +503,30 @@ public:
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
ReleasePromiseWorkerProxy(mProxy.forget());
|
||||
}
|
||||
|
||||
mProxy = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
~GetSubscriptionCallback()
|
||||
{
|
||||
// Enforces that GetSubscriptionRunnable uses the callback for error
|
||||
// reporting once it creates the callback.
|
||||
MOZ_ASSERT(mCallbackCalled);
|
||||
AssertIsOnMainThread();
|
||||
if (mProxy) {
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (!mProxy->IsClean()) {
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> cr =
|
||||
new PromiseWorkerProxyControlRunnable(mProxy->GetWorkerPrivate(), mProxy);
|
||||
cr->Dispatch(jsapi.cx());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<PromiseWorkerProxy> mProxy;
|
||||
nsString mScope;
|
||||
DebugOnly<bool> mCallbackCalled;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GetSubscriptionCallback, nsIPushEndpointCallback)
|
||||
|
@ -21,5 +21,3 @@ skip-if = os == "android" || toolkit == "gonk"
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
[test_try_registering_offline_disabled.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
[test_push_manager_worker.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
|
@ -1,101 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1184574: Expose PushManager to workers.
|
||||
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1184574</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184574">Mozilla Bug 1184574</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var registration;
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||
.then(swr => { registration = swr; return swr; });
|
||||
}
|
||||
|
||||
function unregisterSW() {
|
||||
return registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
}, function(e) {
|
||||
dump("Unregistering the SW failed with " + e + "\n");
|
||||
});
|
||||
}
|
||||
|
||||
function setupPushNotification(swr) {
|
||||
return swr.pushManager.subscribe().then(
|
||||
pushSubscription => {
|
||||
ok(true, "successful registered for push notification");
|
||||
return pushSubscription;
|
||||
}, error => {
|
||||
ok(false, "could not register for push notification");
|
||||
});
|
||||
}
|
||||
|
||||
function getNewEndpointFromWorker(pushSubscription) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var channel = new MessageChannel();
|
||||
channel.port1.onmessage = e => {
|
||||
(e.data.error ? reject : resolve)(e.data);
|
||||
};
|
||||
registration.active.postMessage({
|
||||
endpoint: pushSubscription.endpoint,
|
||||
}, [channel.port2]);
|
||||
}).then(data => {
|
||||
return registration.pushManager.getSubscription().then(
|
||||
pushSubscription => {
|
||||
is(data.endpoint, pushSubscription.endpoint,
|
||||
"Wrong push endpoint in parent");
|
||||
return pushSubscription;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function unregisterPushNotification(pushSubscription) {
|
||||
return pushSubscription.unsubscribe().then(
|
||||
result => {
|
||||
ok(result, "unsubscribe() on existing subscription should return true.");
|
||||
return pushSubscription;
|
||||
}, error => {
|
||||
ok(false, "unsubscribe() should never fail.");
|
||||
});
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(setupPushNotification)
|
||||
.then(getNewEndpointFromWorker)
|
||||
.then(unregisterPushNotification)
|
||||
.then(unregisterSW)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
SpecialPowers.addPermission('push', true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,14 +1,7 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// This worker is used for two types of tests. `handlePush` sends messages to
|
||||
// `frame.html`, which verifies that the worker can receive push messages.
|
||||
|
||||
// `handleMessage` receives a message from `test_push_manager_worker.html`, and
|
||||
// verifies that `PushManager` can be used from the worker.
|
||||
|
||||
this.onpush = handlePush;
|
||||
this.onmessage = handleMessage;
|
||||
|
||||
function handlePush(event) {
|
||||
|
||||
@ -21,26 +14,3 @@ function handlePush(event) {
|
||||
result[0].postMessage({type: "finished", okay: "no"});
|
||||
});
|
||||
}
|
||||
|
||||
function handleMessage(event) {
|
||||
self.registration.pushManager.getSubscription().then(subscription => {
|
||||
if (subscription.endpoint != event.data.endpoint) {
|
||||
throw new Error("Wrong push endpoint in worker");
|
||||
}
|
||||
return subscription.unsubscribe();
|
||||
}).then(result => {
|
||||
if (!result) {
|
||||
throw new Error("Error dropping subscription in worker");
|
||||
}
|
||||
return self.registration.pushManager.getSubscription();
|
||||
}).then(subscription => {
|
||||
if (subscription) {
|
||||
throw new Error("Subscription not dropped in worker");
|
||||
}
|
||||
return self.registration.pushManager.subscribe();
|
||||
}).then(subscription => {
|
||||
event.ports[0].postMessage({endpoint: subscription.endpoint});
|
||||
}).catch(error => {
|
||||
event.ports[0].postMessage({error: error});
|
||||
});
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ dictionary CaretStateChangedEventInit : EventInit {
|
||||
CaretChangedReason reason = "visibilitychange";
|
||||
boolean caretVisible = false;
|
||||
boolean selectionVisible = false;
|
||||
boolean selectionEditable = false;
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional CaretStateChangedEventInit eventInit),
|
||||
@ -29,4 +30,5 @@ interface CaretStateChangedEvent : Event {
|
||||
readonly attribute CaretChangedReason reason;
|
||||
readonly attribute boolean caretVisible;
|
||||
readonly attribute boolean selectionVisible;
|
||||
readonly attribute boolean selectionEditable;
|
||||
};
|
||||
|
@ -131,15 +131,25 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL,
|
||||
|
||||
// Step 4. If none passed, parse against script's URL
|
||||
if (!aOptions.mScope.WasPassed()) {
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), NS_LITERAL_CSTRING("./"),
|
||||
nullptr, scriptURI);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
|
||||
NS_NAMED_LITERAL_STRING(defaultScope, "./");
|
||||
rv = NS_NewURI(getter_AddRefs(scopeURI), defaultScope,
|
||||
nullptr, scriptURI);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsAutoCString spec;
|
||||
scriptURI->GetSpec(spec);
|
||||
aRv.ThrowTypeError(MSG_INVALID_SCOPE, &defaultScope, &spec);
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// Step 5. Parse against entry settings object's base URL.
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aOptions.mScope.Value(),
|
||||
nullptr, window->GetDocBaseURI());
|
||||
rv = NS_NewURI(getter_AddRefs(scopeURI), aOptions.mScope.Value(),
|
||||
nullptr, window->GetDocBaseURI());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.ThrowTypeError(MSG_INVALID_URL, &aOptions.mScope.Value());
|
||||
nsAutoCString spec;
|
||||
if (window->GetDocBaseURI()) {
|
||||
window->GetDocBaseURI()->GetSpec(spec);
|
||||
}
|
||||
aRv.ThrowTypeError(MSG_INVALID_SCOPE, &aOptions.mScope.Value(), &spec);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user