Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-08-06 15:22:37 -04:00
commit bac91f37d2
302 changed files with 8883 additions and 3960 deletions

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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)
{

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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);"/>

View File

@ -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);

View File

@ -1670,7 +1670,7 @@ nsContextMenu.prototype = {
},
savePageAs: function CM_savePageAs() {
saveDocument(this.browser.contentDocumentAsCPOW);
saveBrowser(this.browser);
},
saveLinkToPocket: function CM_saveLinkToPocket() {

View File

@ -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>

View File

@ -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);
}
}
}, {

View File

@ -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]

View File

@ -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);
}

View File

@ -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,
},
],
});
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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>

View File

@ -1 +0,0 @@
Strict-Transport-Security: max-age444

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)

View File

@ -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 =

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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>*

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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()) {

View File

@ -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
};
/**

View File

@ -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

Binary file not shown.

View 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>

View File

@ -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 {

View File

@ -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}.")

View File

@ -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);

View File

@ -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();

View File

@ -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.

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)
{

View File

@ -18,6 +18,7 @@ public:
private:
WebGL1Context();
virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const override;
public:
virtual ~WebGL1Context();

View File

@ -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()
{

View File

@ -356,6 +356,7 @@ public:
private:
WebGL2Context();
virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const override;
virtual bool IsTexParamValid(GLenum pname) const override;

View File

@ -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;

View File

@ -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"

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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();

View File

@ -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)
{

View File

@ -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,

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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
};

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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();

View File

@ -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));

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;

View File

@ -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.

View File

@ -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();

View File

@ -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");

View File

@ -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;

View File

@ -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) {

View File

@ -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.");

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -215,7 +215,7 @@ IntelWebMVideoDecoder::Demux(nsRefPtr<VP8Sample>& aSample, bool* aEOS)
data,
length,
si.is_kf);
if (!aSample->mData) {
if (!aSample->Data()) {
return false;
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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)

View File

@ -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"

View File

@ -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>

View File

@ -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});
});
}

View File

@ -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;
};

View File

@ -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