mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound. a=merge
This commit is contained in:
commit
24a826d4bf
@ -9,7 +9,9 @@
|
||||
#include "ARIAMap.h"
|
||||
#include "DocAccessible-inl.h"
|
||||
#include "DocAccessibleChild.h"
|
||||
#include "DocAccessibleParent.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "Platform.h"
|
||||
#include "RootAccessibleWrap.h"
|
||||
#include "xpcAccessibleDocument.h"
|
||||
|
||||
@ -36,6 +38,8 @@ using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
StaticAutoPtr<nsTArray<DocAccessibleParent*>> DocManager::sRemoteDocuments;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DocManager
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -533,3 +537,17 @@ DocManager::SearchIfDocIsRefreshing(const nsIDocument* aKey,
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
DocManager::RemoteDocAdded(DocAccessibleParent* aDoc)
|
||||
{
|
||||
if (!sRemoteDocuments) {
|
||||
sRemoteDocuments = new nsTArray<DocAccessibleParent*>;
|
||||
ClearOnShutdown(&sRemoteDocuments);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!sRemoteDocuments->Contains(aDoc),
|
||||
"How did we already have the doc!");
|
||||
sRemoteDocuments->AppendElement(aDoc);
|
||||
ProxyCreated(aDoc);
|
||||
}
|
||||
|
@ -5,12 +5,14 @@
|
||||
#ifndef mozilla_a11_DocManager_h_
|
||||
#define mozilla_a11_DocManager_h_
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
@ -74,21 +76,16 @@ public:
|
||||
/*
|
||||
* Notification that a top level document in a content process has gone away.
|
||||
*/
|
||||
void RemoteDocShutdown(DocAccessibleParent* aDoc)
|
||||
static void RemoteDocShutdown(DocAccessibleParent* aDoc)
|
||||
{
|
||||
DebugOnly<bool> result = mRemoteDocuments.RemoveElement(aDoc);
|
||||
DebugOnly<bool> result = sRemoteDocuments->RemoveElement(aDoc);
|
||||
MOZ_ASSERT(result, "Why didn't we find the document!");
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify of a new top level document in a content process.
|
||||
*/
|
||||
void RemoteDocAdded(DocAccessibleParent* aDoc)
|
||||
{
|
||||
MOZ_ASSERT(!mRemoteDocuments.Contains(aDoc),
|
||||
"How did we already have the doc!");
|
||||
mRemoteDocuments.AppendElement(aDoc);
|
||||
}
|
||||
static void RemoteDocAdded(DocAccessibleParent* aDoc);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsProcessingRefreshDriverNotification() const;
|
||||
@ -176,7 +173,7 @@ private:
|
||||
/*
|
||||
* The list of remote top level documents.
|
||||
*/
|
||||
nsTArray<DocAccessibleParent*> mRemoteDocuments;
|
||||
static StaticAutoPtr<nsTArray<DocAccessibleParent*>> sRemoteDocuments;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -130,5 +130,30 @@ DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
|
||||
ProxyEvent(e->mProxy, aEventType);
|
||||
return true;
|
||||
}
|
||||
bool
|
||||
DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
|
||||
uint64_t aParentID)
|
||||
{
|
||||
ProxyAccessible* outerDoc = mAccessibles.GetEntry(aParentID)->mProxy;
|
||||
if (!outerDoc)
|
||||
return false;
|
||||
|
||||
aChildDoc->mParent = outerDoc;
|
||||
outerDoc->SetChildDoc(aChildDoc);
|
||||
mChildDocs.AppendElement(aChildDoc);
|
||||
aChildDoc->mParentDoc = this;
|
||||
ProxyCreated(aChildDoc);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
ProxyDestroyed(this);
|
||||
MOZ_ASSERT(mChildDocs.IsEmpty(),
|
||||
"why wheren't the child docs destroyed already?");
|
||||
mParentDoc ? mParentDoc->RemoveChildDoc(this)
|
||||
: GetAccService()->RemoteDocShutdown(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class DocAccessibleParent : public ProxyAccessible,
|
||||
{
|
||||
public:
|
||||
DocAccessibleParent() :
|
||||
mParentDoc(nullptr)
|
||||
ProxyAccessible(this), mParentDoc(nullptr)
|
||||
{ MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
|
||||
~DocAccessibleParent()
|
||||
{
|
||||
@ -45,13 +45,7 @@ public:
|
||||
virtual bool RecvShowEvent(const ShowEventData& aData) MOZ_OVERRIDE;
|
||||
virtual bool RecvHideEvent(const uint64_t& aRootID) MOZ_OVERRIDE;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(mChildDocs.IsEmpty(),
|
||||
"why wheren't the child docs destroyed already?");
|
||||
mParentDoc ? mParentDoc->RemoveChildDoc(this)
|
||||
: GetAccService()->RemoteDocShutdown(this);
|
||||
}
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
/*
|
||||
* Return the main processes representation of the parent document (if any)
|
||||
@ -63,18 +57,7 @@ public:
|
||||
* Called when a document in a content process notifies the main process of a
|
||||
* new child document.
|
||||
*/
|
||||
bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID)
|
||||
{
|
||||
ProxyAccessible* outerDoc = mAccessibles.GetEntry(aParentID)->mProxy;
|
||||
if (!outerDoc)
|
||||
return false;
|
||||
|
||||
aChildDoc->mParent = outerDoc;
|
||||
outerDoc->SetChildDoc(aChildDoc);
|
||||
mChildDocs.AppendElement(aChildDoc);
|
||||
aChildDoc->mParentDoc = this;
|
||||
return true;
|
||||
}
|
||||
bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID);
|
||||
|
||||
/*
|
||||
* Called when the document in the content process this object represents
|
||||
|
@ -86,8 +86,9 @@ public:
|
||||
uint64_t ID() const { return mID; }
|
||||
|
||||
protected:
|
||||
ProxyAccessible() :
|
||||
mParent(nullptr), mDoc(nullptr), mWrapper(0), mID(0)
|
||||
explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc) :
|
||||
mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
|
||||
mRole(roles::DOCUMENT)
|
||||
{ MOZ_COUNT_CTOR(ProxyAccessible); }
|
||||
|
||||
protected:
|
||||
|
@ -790,26 +790,28 @@ loop.panel = (function(_, mozL10n) {
|
||||
showTabButtons: React.PropTypes.bool,
|
||||
selectedTab: React.PropTypes.string,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object,
|
||||
roomStore:
|
||||
React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
userProfile: this.props.userProfile || navigator.mozLoop.userProfile,
|
||||
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
userProfile: this.props.userProfile || this.props.mozLoop.userProfile,
|
||||
gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
};
|
||||
},
|
||||
|
||||
_serviceErrorToShow: function() {
|
||||
if (!navigator.mozLoop.errors || !Object.keys(navigator.mozLoop.errors).length) {
|
||||
if (!this.props.mozLoop.errors ||
|
||||
!Object.keys(this.props.mozLoop.errors).length) {
|
||||
return null;
|
||||
}
|
||||
// Just get the first error for now since more than one should be rare.
|
||||
var firstErrorKey = Object.keys(navigator.mozLoop.errors)[0];
|
||||
var firstErrorKey = Object.keys(this.props.mozLoop.errors)[0];
|
||||
return {
|
||||
type: firstErrorKey,
|
||||
error: navigator.mozLoop.errors[firstErrorKey],
|
||||
error: this.props.mozLoop.errors[firstErrorKey],
|
||||
};
|
||||
},
|
||||
|
||||
@ -830,11 +832,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
_roomsEnabled: function() {
|
||||
return navigator.mozLoop.getLoopPref("rooms.enabled");
|
||||
return this.props.mozLoop.getLoopPref("rooms.enabled");
|
||||
},
|
||||
|
||||
_onStatusChanged: function() {
|
||||
var profile = navigator.mozLoop.userProfile;
|
||||
var profile = this.props.mozLoop.userProfile;
|
||||
var currUid = this.state.userProfile ? this.state.userProfile.uid : null;
|
||||
var newUid = profile ? profile.uid : null;
|
||||
if (currUid != newUid) {
|
||||
@ -847,7 +849,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
_gettingStartedSeen: function() {
|
||||
this.setState({
|
||||
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
});
|
||||
},
|
||||
|
||||
@ -999,6 +1001,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
client: client,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher}
|
||||
), document.querySelector("#main"));
|
||||
|
||||
|
@ -790,26 +790,28 @@ loop.panel = (function(_, mozL10n) {
|
||||
showTabButtons: React.PropTypes.bool,
|
||||
selectedTab: React.PropTypes.string,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object,
|
||||
roomStore:
|
||||
React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
userProfile: this.props.userProfile || navigator.mozLoop.userProfile,
|
||||
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
userProfile: this.props.userProfile || this.props.mozLoop.userProfile,
|
||||
gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
};
|
||||
},
|
||||
|
||||
_serviceErrorToShow: function() {
|
||||
if (!navigator.mozLoop.errors || !Object.keys(navigator.mozLoop.errors).length) {
|
||||
if (!this.props.mozLoop.errors ||
|
||||
!Object.keys(this.props.mozLoop.errors).length) {
|
||||
return null;
|
||||
}
|
||||
// Just get the first error for now since more than one should be rare.
|
||||
var firstErrorKey = Object.keys(navigator.mozLoop.errors)[0];
|
||||
var firstErrorKey = Object.keys(this.props.mozLoop.errors)[0];
|
||||
return {
|
||||
type: firstErrorKey,
|
||||
error: navigator.mozLoop.errors[firstErrorKey],
|
||||
error: this.props.mozLoop.errors[firstErrorKey],
|
||||
};
|
||||
},
|
||||
|
||||
@ -830,11 +832,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
_roomsEnabled: function() {
|
||||
return navigator.mozLoop.getLoopPref("rooms.enabled");
|
||||
return this.props.mozLoop.getLoopPref("rooms.enabled");
|
||||
},
|
||||
|
||||
_onStatusChanged: function() {
|
||||
var profile = navigator.mozLoop.userProfile;
|
||||
var profile = this.props.mozLoop.userProfile;
|
||||
var currUid = this.state.userProfile ? this.state.userProfile.uid : null;
|
||||
var newUid = profile ? profile.uid : null;
|
||||
if (currUid != newUid) {
|
||||
@ -847,7 +849,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
_gettingStartedSeen: function() {
|
||||
this.setState({
|
||||
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen"),
|
||||
});
|
||||
},
|
||||
|
||||
@ -999,6 +1001,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
client={client}
|
||||
notifications={notifications}
|
||||
roomStore={roomStore}
|
||||
mozLoop={navigator.mozLoop}
|
||||
dispatcher={dispatcher}
|
||||
/>, document.querySelector("#main"));
|
||||
|
||||
|
@ -728,11 +728,6 @@ html, .fx-embedded, #main,
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.standalone .room-conversation-wrapper {
|
||||
height: calc(100% - 50px - 60px);
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.room-conversation-wrapper header {
|
||||
background: #000;
|
||||
height: 50px;
|
||||
@ -744,10 +739,10 @@ html, .fx-embedded, #main,
|
||||
font-size: 1.5em;
|
||||
color: #fff;
|
||||
line-height: 50px;
|
||||
text-indent: 50px;
|
||||
text-indent: 60px;
|
||||
background-image: url("../img/firefox-logo.png");
|
||||
background-size: 30px;
|
||||
background-position: 10px;
|
||||
background-position: 20px;
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block;
|
||||
}
|
||||
@ -817,29 +812,36 @@ html, .fx-embedded, #main,
|
||||
|
||||
.standalone .room-conversation-wrapper {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.standalone .room-inner-info-area {
|
||||
.standalone .room-conversation-wrapper .video-layout-wrapper {
|
||||
height: calc(100% - 50px - 60px);
|
||||
}
|
||||
|
||||
.standalone .room-conversation-wrapper .room-inner-info-area {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
top: calc(50% - 1em);
|
||||
left: 0;
|
||||
right: 25%;
|
||||
z-index: 1000;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
width: 50%;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.standalone .room-inner-info-area button {
|
||||
.standalone .room-conversation-wrapper .room-inner-info-area button {
|
||||
border-radius: 3px;
|
||||
font-size: 1.2em;
|
||||
padding: .2em 1.2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.standalone .room-inner-info-area a.btn {
|
||||
.standalone .room-conversation-wrapper .room-inner-info-area a.btn {
|
||||
padding: .5em 3em .3em 3em;
|
||||
border-radius: 3px;
|
||||
font-weight: normal;
|
||||
@ -884,3 +886,49 @@ html, .fx-embedded, #main,
|
||||
position: relative;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width:640px) {
|
||||
/* Rooms specific responsive styling */
|
||||
.standalone .room-conversation {
|
||||
background: #000;
|
||||
}
|
||||
.room-conversation-wrapper header {
|
||||
width: 100%;
|
||||
}
|
||||
.standalone .room-conversation-wrapper .room-inner-info-area {
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.standalone .room-conversation-wrapper .video-layout-wrapper {
|
||||
/* 50px: header's height; 25px: footer's height */
|
||||
height: calc(100% - 50px - 25px);
|
||||
}
|
||||
.standalone .room-conversation .video_wrapper.remote_wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.standalone .room-conversation .local-stream {
|
||||
/* Assumes 4:3 aspect ratio */
|
||||
width: 180px;
|
||||
height: 135px;
|
||||
}
|
||||
.standalone .conversation-toolbar {
|
||||
height: 38px;
|
||||
padding: 8px;
|
||||
}
|
||||
.standalone .media.nested {
|
||||
/* This forces the remote video stream to fit within wrapper's height */
|
||||
min-height: 0px;
|
||||
}
|
||||
.standalone .room-conversation-wrapper footer {
|
||||
font-size: 80%;
|
||||
height: 25px;
|
||||
}
|
||||
.standalone .room-conversation-wrapper footer p {
|
||||
padding-top: 4px;
|
||||
}
|
||||
.standalone .room-conversation-wrapper footer .footer-logo {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ var sharedUtils = loop.shared.utils;
|
||||
describe("loop.panel", function() {
|
||||
"use strict";
|
||||
|
||||
var sandbox, notifications, fakeXHR, fakeWindow, requests = [];
|
||||
var sandbox, notifications;
|
||||
var fakeXHR, fakeWindow, fakeMozLoop;
|
||||
var requests = [];
|
||||
|
||||
beforeEach(function(done) {
|
||||
sandbox = sinon.sandbox.create();
|
||||
@ -22,7 +24,7 @@ describe("loop.panel", function() {
|
||||
// https://github.com/cjohansen/Sinon.JS/issues/393
|
||||
fakeXHR.xhr.onCreate = function (xhr) {
|
||||
requests.push(xhr);
|
||||
}
|
||||
};
|
||||
|
||||
fakeWindow = {
|
||||
close: sandbox.stub(),
|
||||
@ -32,7 +34,7 @@ describe("loop.panel", function() {
|
||||
|
||||
notifications = new loop.shared.models.NotificationCollection();
|
||||
|
||||
navigator.mozLoop = {
|
||||
fakeMozLoop = navigator.mozLoop = {
|
||||
doNotDisturb: true,
|
||||
fxAEnabled: true,
|
||||
getStrings: function() {
|
||||
@ -164,7 +166,7 @@ describe("loop.panel", function() {
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
roomStore = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop
|
||||
mozLoop: fakeMozLoop
|
||||
});
|
||||
});
|
||||
|
||||
@ -173,6 +175,7 @@ describe("loop.panel", function() {
|
||||
notifications: notifications,
|
||||
client: fakeClient,
|
||||
showTabButtons: true,
|
||||
mozLoop: fakeMozLoop,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore
|
||||
}));
|
||||
|
@ -48,12 +48,14 @@ var fakeRooms = [
|
||||
* @type {Object}
|
||||
*/
|
||||
navigator.mozLoop = {
|
||||
roomsEnabled: false,
|
||||
ensureRegistered: function() {},
|
||||
getAudioBlob: function(){},
|
||||
getLoopPref: function(pref) {
|
||||
switch(pref) {
|
||||
// Ensure UI for rooms is displayed in the showcase.
|
||||
case "rooms.enabled":
|
||||
return this.roomsEnabled;
|
||||
// Ensure we skip FTE completely.
|
||||
case "gettingStarted.seen":
|
||||
return true;
|
||||
|
@ -77,6 +77,9 @@
|
||||
|
||||
// Local mocks
|
||||
|
||||
var mockMozLoopRooms = _.extend({}, navigator.mozLoop);
|
||||
mockMozLoopRooms.roomsEnabled = true;
|
||||
|
||||
var mockContact = {
|
||||
name: ["Mr Smith"],
|
||||
email: [{
|
||||
@ -215,6 +218,7 @@
|
||||
Example({summary: "Call URL retrieved", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
callUrl: "http://invalid.example.url/",
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore})
|
||||
),
|
||||
@ -222,34 +226,40 @@
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
callUrl: "http://invalid.example.url/",
|
||||
userProfile: {email: "test@example.com"},
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Pending call url retrieval", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Pending call url retrieval - authenticated", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
userProfile: {email: "test@example.com"},
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Error Notification", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: errNotifications,
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Error Notification - authenticated", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: errNotifications,
|
||||
userProfile: {email: "test@example.com"},
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Room list tab", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
userProfile: {email: "test@example.com"},
|
||||
mozLoop: mockMozLoopRooms,
|
||||
dispatcher: dispatcher,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "rooms"})
|
||||
|
@ -77,6 +77,9 @@
|
||||
|
||||
// Local mocks
|
||||
|
||||
var mockMozLoopRooms = _.extend({}, navigator.mozLoop);
|
||||
mockMozLoopRooms.roomsEnabled = true;
|
||||
|
||||
var mockContact = {
|
||||
name: ["Mr Smith"],
|
||||
email: [{
|
||||
@ -215,6 +218,7 @@
|
||||
<Example summary="Call URL retrieved" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
callUrl="http://invalid.example.url/"
|
||||
mozLoop={navigator.mozLoop}
|
||||
dispatcher={dispatcher}
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
@ -222,34 +226,40 @@
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
callUrl="http://invalid.example.url/"
|
||||
userProfile={{email: "test@example.com"}}
|
||||
mozLoop={navigator.mozLoop}
|
||||
dispatcher={dispatcher}
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Pending call url retrieval" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
mozLoop={navigator.mozLoop}
|
||||
dispatcher={dispatcher}
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Pending call url retrieval - authenticated" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
userProfile={{email: "test@example.com"}}
|
||||
mozLoop={navigator.mozLoop}
|
||||
dispatcher={dispatcher}
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Error Notification" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={errNotifications}
|
||||
mozLoop={navigator.mozLoop}
|
||||
dispatcher={dispatcher}
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Error Notification - authenticated" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={errNotifications}
|
||||
userProfile={{email: "test@example.com"}}
|
||||
mozLoop={navigator.mozLoop}
|
||||
dispatcher={dispatcher}
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Room list tab" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
userProfile={{email: "test@example.com"}}
|
||||
mozLoop={mockMozLoopRooms}
|
||||
dispatcher={dispatcher}
|
||||
roomStore={roomStore}
|
||||
selectedTab="rooms" />
|
||||
|
@ -48,8 +48,14 @@ const LAYOUT_CHANGE_TIMER = 250;
|
||||
* Fired when a property is expanded in the computed rules view
|
||||
* - computed-view-property-collapsed
|
||||
* Fired when a property is collapsed in the computed rules view
|
||||
* - computed-view-sourcelinks-updated
|
||||
* Fired when the stylesheet source links have been updated (when switching
|
||||
* to source-mapped files)
|
||||
* - rule-view-refreshed
|
||||
* Fired when the rule view updates to a new node
|
||||
* - rule-view-sourcelinks-updated
|
||||
* Fired when the stylesheet source links have been updated (when switching
|
||||
* to source-mapped files)
|
||||
*/
|
||||
function InspectorPanel(iframeWindow, toolbox) {
|
||||
this._toolbox = toolbox;
|
||||
|
@ -19,8 +19,6 @@ loader.lazyRequireGetter(this, "DevToolsUtils",
|
||||
loader.lazyImporter(this, "gDevTools",
|
||||
"resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
let showTimelineMemory = () => Services.prefs.getBoolPref("devtools.performance.ui.show-timeline-memory");
|
||||
|
||||
/**
|
||||
* A cache of all PerformanceActorsConnection instances. The keys are Target objects.
|
||||
*/
|
||||
@ -212,10 +210,13 @@ PerformanceFront.prototype = {
|
||||
/**
|
||||
* Manually begins a recording session.
|
||||
*
|
||||
* @param object options
|
||||
* An options object to pass to the timeline front. Supported
|
||||
* properties are `withTicks` and `withMemory`.
|
||||
* @return object
|
||||
* A promise that is resolved once recording has started.
|
||||
*/
|
||||
startRecording: Task.async(function*() {
|
||||
startRecording: Task.async(function*(options = {}) {
|
||||
let { isActive, currentTime } = yield this._request("profiler", "isActive");
|
||||
|
||||
// Start the profiler only if it wasn't already active. The built-in
|
||||
@ -236,12 +237,9 @@ PerformanceFront.prototype = {
|
||||
|
||||
// The timeline actor is target-dependent, so just make sure
|
||||
// it's recording.
|
||||
let withMemory = showTimelineMemory();
|
||||
|
||||
// Return start time from timeline actor
|
||||
let startTime = yield this._request("timeline", "start", { withTicks: true, withMemory: withMemory });
|
||||
this._startTime = startTime;
|
||||
|
||||
let startTime = yield this._request("timeline", "start", options);
|
||||
return { startTime };
|
||||
}),
|
||||
|
||||
@ -259,7 +257,7 @@ PerformanceFront.prototype = {
|
||||
filterSamples(profilerData, this._profilingStartTime);
|
||||
offsetSampleTimes(profilerData, this._profilingStartTime);
|
||||
|
||||
let endTime = this._endTime = yield this._request("timeline", "stop");
|
||||
let endTime = yield this._request("timeline", "stop");
|
||||
|
||||
// Join all the acquired data and return it for outside consumers.
|
||||
return {
|
||||
|
@ -18,6 +18,11 @@ devtools.lazyRequireGetter(this, "DevToolsUtils",
|
||||
"devtools/toolkit/DevToolsUtils");
|
||||
devtools.lazyRequireGetter(this, "L10N",
|
||||
"devtools/profiler/global", true);
|
||||
|
||||
devtools.lazyRequireGetter(this, "MarkersOverview",
|
||||
"devtools/timeline/markers-overview", true);
|
||||
devtools.lazyRequireGetter(this, "MemoryOverview",
|
||||
"devtools/timeline/memory-overview", true);
|
||||
devtools.lazyRequireGetter(this, "Waterfall",
|
||||
"devtools/timeline/waterfall", true);
|
||||
devtools.lazyRequireGetter(this, "MarkerDetails",
|
||||
@ -27,15 +32,18 @@ devtools.lazyRequireGetter(this, "CallView",
|
||||
devtools.lazyRequireGetter(this, "ThreadNode",
|
||||
"devtools/profiler/tree-model", true);
|
||||
|
||||
devtools.lazyImporter(this, "CanvasGraphUtils",
|
||||
"resource:///modules/devtools/Graphs.jsm");
|
||||
devtools.lazyImporter(this, "LineGraphWidget",
|
||||
"resource:///modules/devtools/Graphs.jsm");
|
||||
|
||||
// Events emitted by the `PerformanceController`
|
||||
// Events emitted by various objects in the panel.
|
||||
const EVENTS = {
|
||||
// When a recording is started or stopped via the controller
|
||||
// When a recording is started or stopped via the PerformanceController
|
||||
RECORDING_STARTED: "Performance:RecordingStarted",
|
||||
RECORDING_STOPPED: "Performance:RecordingStopped",
|
||||
// When the PerformanceActor front emits `framerate` data
|
||||
|
||||
// When the PerformanceController has new recording data.
|
||||
TIMELINE_DATA: "Performance:TimelineData",
|
||||
|
||||
// Emitted by the PerformanceView on record button click
|
||||
@ -44,6 +52,10 @@ const EVENTS = {
|
||||
|
||||
// Emitted by the OverviewView when more data has been rendered
|
||||
OVERVIEW_RENDERED: "Performance:UI:OverviewRendered",
|
||||
FRAMERATE_GRAPH_RENDERED: "Performance:UI:OverviewFramerateRendered",
|
||||
MARKERS_GRAPH_RENDERED: "Performance:UI:OverviewMarkersRendered",
|
||||
MEMORY_GRAPH_RENDERED: "Performance:UI:OverviewMemoryRendered",
|
||||
|
||||
// Emitted by the OverviewView when a range has been selected in the graphs
|
||||
OVERVIEW_RANGE_SELECTED: "Performance:UI:OverviewRangeSelected",
|
||||
// Emitted by the OverviewView when a selection range has been removed
|
||||
@ -112,6 +124,16 @@ let PrefObserver = {
|
||||
* UI interaction.
|
||||
*/
|
||||
let PerformanceController = {
|
||||
/**
|
||||
* Permanent storage for the markers and the memory measurements streamed by
|
||||
* the backend, along with the start and end timestamps.
|
||||
*/
|
||||
_startTime: 0,
|
||||
_endTime: 0,
|
||||
_markers: [],
|
||||
_memory: [],
|
||||
_ticks: [],
|
||||
|
||||
/**
|
||||
* Listen for events emitted by the current tab target and
|
||||
* main UI events.
|
||||
@ -123,8 +145,9 @@ let PerformanceController = {
|
||||
|
||||
PerformanceView.on(EVENTS.UI_START_RECORDING, this.startRecording);
|
||||
PerformanceView.on(EVENTS.UI_STOP_RECORDING, this.stopRecording);
|
||||
gFront.on("ticks", this._onTimelineData);
|
||||
gFront.on("markers", this._onTimelineData);
|
||||
gFront.on("ticks", this._onTimelineData); // framerate
|
||||
gFront.on("markers", this._onTimelineData); // timeline markers
|
||||
gFront.on("memory", this._onTimelineData); // timeline memory
|
||||
},
|
||||
|
||||
/**
|
||||
@ -135,41 +158,107 @@ let PerformanceController = {
|
||||
PerformanceView.off(EVENTS.UI_STOP_RECORDING, this.stopRecording);
|
||||
gFront.off("ticks", this._onTimelineData);
|
||||
gFront.off("markers", this._onTimelineData);
|
||||
gFront.off("memory", this._onTimelineData);
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts recording with the PerformanceFront. Emits `EVENTS.RECORDING_STARTED`
|
||||
* when the front is starting to record.
|
||||
* when the front has started to record.
|
||||
*/
|
||||
startRecording: Task.async(function *() {
|
||||
// Save local start time for use with faking the endTime
|
||||
// if not returned from the timeline actor
|
||||
// Times must come from the actor in order to be self-consistent.
|
||||
// However, we also want to update the view with the elapsed time
|
||||
// even when the actor is not generating data. To do this we get
|
||||
// the local time and use it to compute a reasonable elapsed time.
|
||||
this._localStartTime = performance.now();
|
||||
|
||||
let startTime = this._startTime = yield gFront.startRecording();
|
||||
this.emit(EVENTS.RECORDING_STARTED, startTime);
|
||||
let { startTime } = yield gFront.startRecording({
|
||||
withTicks: true,
|
||||
withMemory: true
|
||||
});
|
||||
|
||||
this._startTime = startTime;
|
||||
this._endTime = startTime;
|
||||
this._markers = [];
|
||||
this._memory = [];
|
||||
this._ticks = [];
|
||||
|
||||
this.emit(EVENTS.RECORDING_STARTED, this._startTime);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Stops recording with the PerformanceFront. Emits `EVENTS.RECORDING_STOPPED`
|
||||
* when the front stops recording.
|
||||
* when the front has stopped recording.
|
||||
*/
|
||||
stopRecording: Task.async(function *() {
|
||||
let results = yield gFront.stopRecording();
|
||||
|
||||
// If `endTime` is not yielded from timeline actor (< Fx36), fake an endTime.
|
||||
// If `endTime` is not yielded from timeline actor (< Fx36), fake it.
|
||||
if (!results.endTime) {
|
||||
results.endTime = this._startTime + (performance.now() - this._localStartTime);
|
||||
this._endTime = results.endTime;
|
||||
results.endTime = this._startTime + this.getInterval().localElapsedTime;
|
||||
}
|
||||
|
||||
this._endTime = results.endTime;
|
||||
this._markers = this._markers.sort((a,b) => (a.start > b.start));
|
||||
|
||||
this.emit(EVENTS.RECORDING_STOPPED, results);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Fired whenever the gFront emits a ticks, memory, or markers event.
|
||||
* Gets the time interval for the current recording.
|
||||
* @return object
|
||||
*/
|
||||
getInterval: function() {
|
||||
let localElapsedTime = performance.now() - this._localStartTime;
|
||||
let startTime = this._startTime;
|
||||
let endTime = this._endTime;
|
||||
return { localElapsedTime, startTime, endTime };
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the accumulated markers in the current recording.
|
||||
* @return array
|
||||
*/
|
||||
getMarkers: function() {
|
||||
return this._markers;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the accumulated memory measurements in this recording.
|
||||
* @return array
|
||||
*/
|
||||
getMemory: function() {
|
||||
return this._memory;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the accumulated refresh driver ticks in this recording.
|
||||
* @return array
|
||||
*/
|
||||
getTicks: function() {
|
||||
return this._ticks;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired whenever the PerformanceFront emits markers, memory or ticks.
|
||||
*/
|
||||
_onTimelineData: function (eventName, ...data) {
|
||||
// Accumulate markers into an array.
|
||||
if (eventName == "markers") {
|
||||
let [markers] = data;
|
||||
Array.prototype.push.apply(this._markers, markers);
|
||||
}
|
||||
// Accumulate memory measurements into an array.
|
||||
else if (eventName == "memory") {
|
||||
let [delta, measurement] = data;
|
||||
this._memory.push({ delta, value: measurement.total / 1024 / 1024 });
|
||||
}
|
||||
// Save the accumulated refresh driver ticks.
|
||||
else if (eventName == "ticks") {
|
||||
let [delta, timestamps] = data;
|
||||
this._ticks = timestamps;
|
||||
}
|
||||
|
||||
this.emit(EVENTS.TIMELINE_DATA, eventName, ...data);
|
||||
}
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ let PerformanceView = {
|
||||
this._recordButton = $("#record-button");
|
||||
|
||||
this._onRecordButtonClick = this._onRecordButtonClick.bind(this);
|
||||
this._lockRecordButton = this._lockRecordButton.bind(this);
|
||||
this._unlockRecordButton = this._unlockRecordButton.bind(this);
|
||||
|
||||
this._recordButton.addEventListener("click", this._onRecordButtonClick);
|
||||
@ -42,6 +43,14 @@ let PerformanceView = {
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the `locked` attribute on the record button. This prevents it
|
||||
* from being clicked while recording is started or stopped.
|
||||
*/
|
||||
_lockRecordButton: function () {
|
||||
this._recordButton.setAttribute("locked", "true");
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the `locked` attribute on the record button.
|
||||
*/
|
||||
@ -55,11 +64,11 @@ let PerformanceView = {
|
||||
_onRecordButtonClick: function (e) {
|
||||
if (this._recordButton.hasAttribute("checked")) {
|
||||
this._recordButton.removeAttribute("checked");
|
||||
this._recordButton.setAttribute("locked", "true");
|
||||
this._lockRecordButton();
|
||||
this.emit(EVENTS.UI_STOP_RECORDING);
|
||||
} else {
|
||||
this._recordButton.setAttribute("checked", "true");
|
||||
this._recordButton.setAttribute("locked", "true");
|
||||
this._lockRecordButton();
|
||||
this.emit(EVENTS.UI_START_RECORDING);
|
||||
}
|
||||
}
|
||||
|
@ -38,10 +38,13 @@
|
||||
label="&profilerUI.importButton;"/>
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<box id="overview-pane"
|
||||
class="devtools-responsive-container">
|
||||
<vbox id="time-framerate" flex="1"/>
|
||||
</box>
|
||||
|
||||
<vbox id="overview-pane">
|
||||
<hbox id="time-framerate"/>
|
||||
<hbox id="markers-overview"/>
|
||||
<hbox id="memory-overview"/>
|
||||
</vbox>
|
||||
|
||||
<toolbar id="details-toolbar" class="devtools-toolbar">
|
||||
<hbox class="devtools-toolbarbutton-group">
|
||||
<toolbarbutton id="select-waterfall-view"
|
||||
@ -54,13 +57,15 @@
|
||||
data-view="calltree" />
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<deck id="details-pane"
|
||||
class="devtools-responsive-container"
|
||||
flex="1">
|
||||
<hbox id="waterfall-view" flex="1">
|
||||
|
||||
<deck id="details-pane" flex="1">
|
||||
<hbox id="waterfall-view">
|
||||
<vbox id="waterfall-graph" flex="1" />
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<vbox id="waterfall-details" class="theme-sidebar" width="150" height="150"/>
|
||||
<vbox id="waterfall-details"
|
||||
class="theme-sidebar"
|
||||
width="150"
|
||||
height="150"/>
|
||||
</hbox>
|
||||
|
||||
<vbox id="calltree-view" class="call-tree" flex="1">
|
||||
|
@ -32,7 +32,9 @@ support-files =
|
||||
[browser_perf-ui-recording.js]
|
||||
[browser_perf-overview-render-01.js]
|
||||
[browser_perf-overview-render-02.js]
|
||||
[browser_perf-overview-selection.js]
|
||||
[browser_perf-overview-selection-01.js]
|
||||
[browser_perf-overview-selection-02.js]
|
||||
[browser_perf-overview-selection-03.js]
|
||||
|
||||
[browser_perf-details.js]
|
||||
[browser_perf-jump-to-debugger-01.js]
|
||||
|
@ -8,9 +8,6 @@ function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, CallTreeView } = panel.panelWin;
|
||||
|
||||
let updated = 0;
|
||||
CallTreeView.on(EVENTS.CALL_TREE_RENDERED, () => updated++);
|
||||
|
||||
yield startRecording(panel);
|
||||
yield busyWait(100);
|
||||
|
||||
|
@ -15,6 +15,7 @@ function spawnTest () {
|
||||
|
||||
yield startRecording(panel);
|
||||
yield busyWait(100);
|
||||
|
||||
yield stopRecording(panel);
|
||||
yield rendered;
|
||||
|
||||
|
@ -6,20 +6,16 @@
|
||||
*/
|
||||
function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, WaterfallView } = panel.panelWin;
|
||||
let { EVENTS, PerformanceController, WaterfallView } = panel.panelWin;
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
yield waitUntil(() => WaterfallView._markers.length);
|
||||
yield waitUntil(() => PerformanceController.getMarkers().length);
|
||||
|
||||
let rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
yield rendered;
|
||||
ok(true, "WaterfallView rendered after recording is stopped.");
|
||||
|
||||
ok(WaterfallView._markers.length, "WaterfallView contains markers");
|
||||
ok(true, "WaterfallView rendered after recording is stopped.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
|
@ -11,15 +11,16 @@ function spawnTest () {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL);
|
||||
|
||||
yield front.startRecording();
|
||||
|
||||
yield busyWait(WAIT);
|
||||
let { recordingDuration, profilerData, endTime } = yield front.stopRecording();
|
||||
|
||||
let { recordingDuration, profilerData } = yield front.stopRecording();
|
||||
|
||||
ok(recordingDuration > 500, "recordingDuration exists");
|
||||
ok(profilerData, "profilerData exists");
|
||||
ok(recordingDuration > 500,
|
||||
"A `recordingDuration` property exists in the recording data.");
|
||||
ok(profilerData,
|
||||
"A `profilerData` property exists in the recording data.");
|
||||
ok(endTime,
|
||||
"A `endTime` property exists in the recording data.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,6 @@
|
||||
*/
|
||||
|
||||
function spawnTest () {
|
||||
Services.prefs.setBoolPref("devtools.performance.ui.show-timeline-memory", true);
|
||||
|
||||
let { target, front } = yield initBackend(SIMPLE_URL);
|
||||
|
||||
let lastMemoryDelta = 0;
|
||||
@ -29,7 +27,7 @@ function spawnTest () {
|
||||
front.on("memory", handler);
|
||||
front.on("ticks", handler);
|
||||
|
||||
yield front.startRecording();
|
||||
yield front.startRecording({ withMemory: true, withTicks: true });
|
||||
|
||||
yield Promise.all(Object.keys(deferreds).map(type => deferreds[type].promise));
|
||||
|
||||
@ -43,7 +41,17 @@ function spawnTest () {
|
||||
finish();
|
||||
|
||||
function handler (name, ...args) {
|
||||
if (name === "memory") {
|
||||
if (name === "markers") {
|
||||
let [markers] = args;
|
||||
ok(markers[0].start, "received atleast one marker with `start`");
|
||||
ok(markers[0].end, "received atleast one marker with `end`");
|
||||
ok(markers[0].name, "received atleast one marker with `name`");
|
||||
|
||||
counters.markers.push(markers);
|
||||
front.off(name, handler);
|
||||
deferreds[name].resolve();
|
||||
}
|
||||
else if (name === "memory") {
|
||||
let [delta, measurement] = args;
|
||||
is(typeof delta, "number", "received `delta` in memory event");
|
||||
ok(delta > lastMemoryDelta, "received `delta` in memory event");
|
||||
@ -53,7 +61,8 @@ function spawnTest () {
|
||||
|
||||
counters.memory.push({ delta: delta, measurement: measurement });
|
||||
lastMemoryDelta = delta;
|
||||
} else if (name === "ticks") {
|
||||
}
|
||||
else if (name === "ticks") {
|
||||
let [delta, timestamps] = args;
|
||||
ok(delta > lastTickDelta, "received `delta` in ticks event");
|
||||
|
||||
@ -64,15 +73,8 @@ function spawnTest () {
|
||||
|
||||
counters.ticks.push({ delta: delta, timestamps: timestamps});
|
||||
lastTickDelta = delta;
|
||||
} else if (name === "markers") {
|
||||
let [markers] = args;
|
||||
ok(markers[0].start, "received atleast one marker with `start`");
|
||||
ok(markers[0].end, "received atleast one marker with `end`");
|
||||
ok(markers[0].name, "received atleast one marker with `name`");
|
||||
counters.markers.push(markers);
|
||||
front.off(name, handler);
|
||||
deferreds[name].resolve();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new Error("unknown event");
|
||||
}
|
||||
|
||||
|
@ -2,16 +2,27 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the overview renders content when recording.
|
||||
* Tests that the overview continuously renders content when recording.
|
||||
*/
|
||||
function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, OverviewView } = panel.panelWin;
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
|
||||
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
|
||||
|
||||
yield Promise.all([
|
||||
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
|
||||
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
|
||||
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
|
||||
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
|
||||
]);
|
||||
|
||||
yield Promise.all([
|
||||
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
|
||||
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
|
||||
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
|
||||
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
|
||||
]);
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
|
@ -18,6 +18,20 @@ function spawnTest () {
|
||||
is(OverviewView.framerateGraph.hasSelection(), false,
|
||||
"The framerate overview shouldn't have a selection before recording.");
|
||||
|
||||
ok("selectionEnabled" in OverviewView.markersOverview,
|
||||
"The selection should not be enabled for the markers overview (1).");
|
||||
is(OverviewView.markersOverview.selectionEnabled, false,
|
||||
"The selection should not be enabled for the markers overview (2).");
|
||||
is(OverviewView.markersOverview.hasSelection(), false,
|
||||
"The markers overview shouldn't have a selection before recording.");
|
||||
|
||||
ok("selectionEnabled" in OverviewView.memoryOverview,
|
||||
"The selection should not be enabled for the memory overview (1).");
|
||||
is(OverviewView.memoryOverview.selectionEnabled, false,
|
||||
"The selection should not be enabled for the memory overview (2).");
|
||||
is(OverviewView.memoryOverview.hasSelection(), false,
|
||||
"The memory overview shouldn't have a selection before recording.");
|
||||
|
||||
let updated = 0;
|
||||
OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
|
||||
|
||||
@ -31,11 +45,31 @@ function spawnTest () {
|
||||
is(OverviewView.framerateGraph.hasSelection(), false,
|
||||
"The framerate overview still shouldn't have a selection before recording.");
|
||||
|
||||
ok("selectionEnabled" in OverviewView.markersOverview,
|
||||
"The selection should still not be enabled for the markers overview (1).");
|
||||
is(OverviewView.markersOverview.selectionEnabled, false,
|
||||
"The selection should still not be enabled for the markers overview (2).");
|
||||
is(OverviewView.markersOverview.hasSelection(), false,
|
||||
"The markers overview still shouldn't have a selection before recording.");
|
||||
|
||||
ok("selectionEnabled" in OverviewView.memoryOverview,
|
||||
"The selection should still not be enabled for the memory overview (1).");
|
||||
is(OverviewView.memoryOverview.selectionEnabled, false,
|
||||
"The selection should still not be enabled for the memory overview (2).");
|
||||
is(OverviewView.memoryOverview.hasSelection(), false,
|
||||
"The memory overview still shouldn't have a selection before recording.");
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
is(OverviewView.framerateGraph.selectionEnabled, true,
|
||||
"The selection should now be enabled for the framerate overview.");
|
||||
|
||||
is(OverviewView.markersOverview.selectionEnabled, true,
|
||||
"The selection should now be enabled for the markers overview.");
|
||||
|
||||
is(OverviewView.memoryOverview.selectionEnabled, true,
|
||||
"The selection should now be enabled for the memory overview.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
@ -11,10 +11,14 @@ function spawnTest () {
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
// Wait for the overview graph to be rendered while recording.
|
||||
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
// Wait for the overview graph to be rerendered *after* recording.
|
||||
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
|
||||
|
||||
let graph = OverviewView.framerateGraph;
|
||||
let MAX = graph.width;
|
||||
|
||||
@ -37,8 +41,6 @@ function spawnTest () {
|
||||
is(graph.hasSelection(), false, "selection no longer on graph.");
|
||||
is(params, undefined, "OVERVIEW_RANGE_CLEARED fired with no additional arguments.");
|
||||
|
||||
results = beginAt = endAt = graph = OverviewView = null;
|
||||
|
||||
panel.panelWin.clearNamedTimeout("graph-scroll");
|
||||
yield teardown(panel);
|
||||
finish();
|
@ -0,0 +1,52 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the graphs' selection is correctly disabled or enabled.
|
||||
*/
|
||||
function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, OverviewView } = panel.panelWin;
|
||||
let framerateGraph = OverviewView.framerateGraph;
|
||||
let markersOverview = OverviewView.markersOverview;
|
||||
let memoryOverview = OverviewView.memoryOverview;
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
ok(!framerateGraph.selectionEnabled,
|
||||
"Selection shouldn't be enabled when the first recording started (1).");
|
||||
ok(!markersOverview.selectionEnabled,
|
||||
"Selection shouldn't be enabled when the first recording started (2).");
|
||||
ok(!memoryOverview.selectionEnabled,
|
||||
"Selection shouldn't be enabled when the first recording started (3).");
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
ok(framerateGraph.selectionEnabled,
|
||||
"Selection should be enabled when the first recording finishes (1).");
|
||||
ok(markersOverview.selectionEnabled,
|
||||
"Selection should be enabled when the first recording finishes (2).");
|
||||
ok(memoryOverview.selectionEnabled,
|
||||
"Selection should be enabled when the first recording finishes (3).");
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
ok(!framerateGraph.selectionEnabled,
|
||||
"Selection shouldn't be enabled when the second recording started (1).");
|
||||
ok(!markersOverview.selectionEnabled,
|
||||
"Selection shouldn't be enabled when the second recording started (2).");
|
||||
ok(!memoryOverview.selectionEnabled,
|
||||
"Selection shouldn't be enabled when the second recording started (3).");
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
ok(framerateGraph.selectionEnabled,
|
||||
"Selection should be enabled when the first second finishes (1).");
|
||||
ok(markersOverview.selectionEnabled,
|
||||
"Selection should be enabled when the first second finishes (2).");
|
||||
ok(memoryOverview.selectionEnabled,
|
||||
"Selection should be enabled when the first second finishes (3).");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the graphs' selections are linked.
|
||||
*/
|
||||
function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, OverviewView } = panel.panelWin;
|
||||
let framerateGraph = OverviewView.framerateGraph;
|
||||
let markersOverview = OverviewView.markersOverview;
|
||||
let memoryOverview = OverviewView.memoryOverview;
|
||||
|
||||
let MAX = framerateGraph.width;
|
||||
|
||||
yield startRecording(panel);
|
||||
yield stopRecording(panel);
|
||||
|
||||
// Perform a selection inside the framerate graph.
|
||||
|
||||
let selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
|
||||
dragStart(framerateGraph, 0);
|
||||
dragStop(framerateGraph, MAX / 2);
|
||||
yield selected;
|
||||
|
||||
is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (MAX / 2) + "})",
|
||||
"The framerate graph has a correct selection.");
|
||||
is(markersOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
|
||||
"The markers overview has a correct selection.");
|
||||
is(memoryOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
|
||||
"The memory overview has a correct selection.");
|
||||
|
||||
// Perform a selection inside the markers overview.
|
||||
|
||||
selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
|
||||
markersOverview.dropSelection();
|
||||
dragStart(markersOverview, 0);
|
||||
dragStop(markersOverview, MAX / 4);
|
||||
yield selected;
|
||||
|
||||
is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (MAX / 4) + "})",
|
||||
"The framerate graph has a correct selection.");
|
||||
is(markersOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
|
||||
"The markers overview has a correct selection.");
|
||||
is(memoryOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
|
||||
"The memory overview has a correct selection.");
|
||||
|
||||
// Perform a selection inside the memory overview.
|
||||
|
||||
selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
|
||||
memoryOverview.dropSelection();
|
||||
dragStart(memoryOverview, 0);
|
||||
dragStop(memoryOverview, MAX / 10);
|
||||
yield selected;
|
||||
|
||||
is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (MAX / 10) + "})",
|
||||
"The framerate graph has a correct selection.");
|
||||
is(markersOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
|
||||
"The markers overview has a correct selection.");
|
||||
is(memoryOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
|
||||
"The memory overview has a correct selection.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
@ -11,6 +11,10 @@ let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
||||
Services.prefs.setBoolPref("devtools.debugger.log", false);
|
||||
|
||||
// Enable the new performance panel for all tests. Remove this after
|
||||
// bug 1075567 is resolved.
|
||||
let gToolEnabled = Services.prefs.getBoolPref("devtools.performance_dev.enabled");
|
||||
|
||||
let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
@ -29,9 +33,6 @@ const SIMPLE_URL = EXAMPLE_URL + "doc_simple-test.html";
|
||||
// All tests are asynchronous.
|
||||
waitForExplicitFinish();
|
||||
|
||||
let gToolEnabled = Services.prefs.getBoolPref("devtools.performance_dev.enabled");
|
||||
let gShowTimelineMemory = Services.prefs.getBoolPref("devtools.performance.ui.show-timeline-memory");
|
||||
|
||||
gDevTools.testing = true;
|
||||
|
||||
/**
|
||||
@ -49,9 +50,9 @@ registerCleanupFunction(() => {
|
||||
gDevTools.testing = false;
|
||||
info("finish() was called, cleaning up...");
|
||||
|
||||
Services.prefs.setBoolPref("devtools.performance.ui.show-timeline-memory", gShowTimelineMemory);
|
||||
Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
|
||||
Services.prefs.setBoolPref("devtools.performance_dev.enabled", gToolEnabled);
|
||||
|
||||
// Make sure the profiler module is stopped when the test finishes.
|
||||
nsIProfilerModule.StopProfiler();
|
||||
|
||||
@ -186,6 +187,12 @@ function idleWait(time) {
|
||||
return DevToolsUtils.waitForTime(time);
|
||||
}
|
||||
|
||||
function busyWait(time) {
|
||||
let start = Date.now();
|
||||
let stack;
|
||||
while (Date.now() - start < time) { stack = Components.stack; }
|
||||
}
|
||||
|
||||
function consoleMethod (...args) {
|
||||
if (!mm) {
|
||||
throw new Error("`loadFrameScripts()` must be called before using frame scripts.");
|
||||
@ -205,12 +212,6 @@ function* consoleProfileEnd(connection) {
|
||||
yield notified;
|
||||
}
|
||||
|
||||
function busyWait(time) {
|
||||
let start = Date.now();
|
||||
let stack;
|
||||
while (Date.now() - start < time) { stack = Components.stack; }
|
||||
}
|
||||
|
||||
function command (button) {
|
||||
let ev = button.ownerDocument.createEvent("XULCommandEvent");
|
||||
ev.initCommandEvent("command", true, true, button.ownerDocument.defaultView, 0, false, false, false, false, null);
|
||||
|
@ -11,8 +11,7 @@ let CallTreeView = {
|
||||
* Sets up the view with event binding.
|
||||
*/
|
||||
initialize: function () {
|
||||
this.el = $(".call-tree");
|
||||
this._graphEl = $(".call-tree-cells-container");
|
||||
this._callTree = $(".call-tree-cells-container");
|
||||
this._onRangeChange = this._onRangeChange.bind(this);
|
||||
this._onLink = this._onLink.bind(this);
|
||||
this._stop = this._stop.bind(this);
|
||||
@ -32,8 +31,7 @@ let CallTreeView = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Method for handling all the set up for rendering a new
|
||||
* call tree.
|
||||
* Method for handling all the set up for rendering a new call tree.
|
||||
*/
|
||||
render: function (profilerData, beginAt, endAt, options={}) {
|
||||
let threadNode = this._prepareCallTree(profilerData, beginAt, endAt, options);
|
||||
@ -59,6 +57,9 @@ let CallTreeView = {
|
||||
this.render(this._profilerData, beginAt, endAt);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired on the "link" event for the call tree in this container.
|
||||
*/
|
||||
_onLink: function (_, treeItem) {
|
||||
let { url, line } = treeItem.frame.getInfo();
|
||||
viewSourceInDebugger(url, line).then(
|
||||
@ -96,9 +97,9 @@ let CallTreeView = {
|
||||
// Bind events
|
||||
root.on("link", this._onLink);
|
||||
|
||||
// Clear out other graphs
|
||||
this._graphEl.innerHTML = "";
|
||||
root.attachTo(this._graphEl);
|
||||
// Clear out other call trees.
|
||||
this._callTree.innerHTML = "";
|
||||
root.attachTo(this._callTree);
|
||||
|
||||
let contentOnly = !Prefs.showPlatformData;
|
||||
root.toggleCategories(!contentOnly);
|
||||
@ -130,7 +131,7 @@ let viewSourceInDebugger = Task.async(function *(url, line) {
|
||||
|
||||
let { DebuggerView } = dbg;
|
||||
let item = DebuggerView.Sources.getItemForAttachment(a => a.source.url === url);
|
||||
|
||||
|
||||
if (item) {
|
||||
return DebuggerView.setEditorLocation(item.attachment.source.actor, line, { noDebug: true });
|
||||
}
|
||||
|
@ -7,18 +7,12 @@
|
||||
* Waterfall view containing the timeline markers, controlled by DetailsView.
|
||||
*/
|
||||
let WaterfallView = {
|
||||
_startTime: 0,
|
||||
_endTime: 0,
|
||||
_markers: [],
|
||||
|
||||
/**
|
||||
* Sets up the view with event binding.
|
||||
*/
|
||||
initialize: Task.async(function *() {
|
||||
this.el = $("#waterfall-view");
|
||||
this._stop = this._stop.bind(this);
|
||||
this._start = this._start.bind(this);
|
||||
this._onTimelineData = this._onTimelineData.bind(this);
|
||||
this._stop = this._stop.bind(this);
|
||||
this._onMarkerSelected = this._onMarkerSelected.bind(this);
|
||||
this._onResize = this._onResize.bind(this);
|
||||
|
||||
@ -31,8 +25,8 @@ let WaterfallView = {
|
||||
|
||||
PerformanceController.on(EVENTS.RECORDING_STARTED, this._start);
|
||||
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._stop);
|
||||
PerformanceController.on(EVENTS.TIMELINE_DATA, this._onTimelineData);
|
||||
yield this.graph.recalculateBounds();
|
||||
|
||||
this.graph.recalculateBounds();
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -45,36 +39,32 @@ let WaterfallView = {
|
||||
|
||||
PerformanceController.off(EVENTS.RECORDING_STARTED, this._start);
|
||||
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._stop);
|
||||
PerformanceController.off(EVENTS.TIMELINE_DATA, this._onTimelineData);
|
||||
},
|
||||
|
||||
render: Task.async(function *() {
|
||||
yield this.graph.recalculateBounds();
|
||||
this.graph.setData(this._markers, this._startTime, this._startTime, this._endTime);
|
||||
this.emit(EVENTS.WATERFALL_RENDERED);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Event handlers
|
||||
* Method for handling all the set up for rendering a new waterfall.
|
||||
*/
|
||||
render: function() {
|
||||
let { startTime, endTime } = PerformanceController.getInterval();
|
||||
let markers = PerformanceController.getMarkers();
|
||||
|
||||
this.graph.setData(markers, startTime, startTime, endTime);
|
||||
this.emit(EVENTS.WATERFALL_RENDERED);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when recording starts.
|
||||
*/
|
||||
_start: function (_, { startTime }) {
|
||||
this._startTime = startTime;
|
||||
this._endTime = startTime;
|
||||
this.graph.clearView();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when recording stops.
|
||||
*/
|
||||
_stop: Task.async(function *(_, { endTime }) {
|
||||
this._endTime = endTime;
|
||||
this._markers = this._markers.sort((a,b) => (a.start > b.start));
|
||||
_stop: function (_, { endTime }) {
|
||||
this.render();
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a marker is selected in the waterfall view,
|
||||
@ -93,19 +83,8 @@ let WaterfallView = {
|
||||
* Called when the marker details view is resized.
|
||||
*/
|
||||
_onResize: function () {
|
||||
this.graph.recalculateBounds();
|
||||
this.render();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the TimelineFront has new data for
|
||||
* framerate, markers or memory, and stores the data
|
||||
* to be plotted subsequently.
|
||||
*/
|
||||
_onTimelineData: function (_, eventName, ...data) {
|
||||
if (eventName === "markers") {
|
||||
let [markers, endTime] = data;
|
||||
Array.prototype.push.apply(this._markers, markers);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -19,8 +19,7 @@ let DetailsView = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up the view with event binding, initializes
|
||||
* subviews.
|
||||
* Sets up the view with event binding, initializes subviews.
|
||||
*/
|
||||
initialize: Task.async(function *() {
|
||||
this.el = $("#details-pane");
|
||||
@ -36,6 +35,18 @@ let DetailsView = {
|
||||
this.selectView(DEFAULT_DETAILS_SUBVIEW);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Unbinds events, destroys subviews.
|
||||
*/
|
||||
destroy: Task.async(function *() {
|
||||
for (let button of $$("toolbarbutton[data-view]", $("#details-toolbar"))) {
|
||||
button.removeEventListener("command", this._onViewToggle);
|
||||
}
|
||||
|
||||
yield CallTreeView.destroy();
|
||||
yield WaterfallView.destroy();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Select one of the DetailView's subviews to be rendered,
|
||||
* hiding the others.
|
||||
@ -61,19 +72,7 @@ let DetailsView = {
|
||||
*/
|
||||
_onViewToggle: function (e) {
|
||||
this.selectView(e.target.getAttribute("data-view"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Unbinds events, destroys subviews.
|
||||
*/
|
||||
destroy: Task.async(function *() {
|
||||
for (let button of $$("toolbarbutton[data-view]", $("#details-toolbar"))) {
|
||||
button.removeEventListener("command", this._onViewToggle);
|
||||
}
|
||||
|
||||
yield CallTreeView.destroy();
|
||||
yield WaterfallView.destroy();
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,15 @@
|
||||
// in toolkit/devtools/server/actors/timeline.js
|
||||
const OVERVIEW_UPDATE_INTERVAL = 200; // ms
|
||||
|
||||
const FRAMERATE_GRAPH_HEIGHT = 60; // px
|
||||
const FRAMERATE_GRAPH_LOW_RES_INTERVAL = 100; // ms
|
||||
const FRAMERATE_GRAPH_HIGH_RES_INTERVAL = 16; // ms
|
||||
|
||||
const FRAMERATE_GRAPH_HEIGHT = 45; // px
|
||||
const MARKERS_GRAPH_HEADER_HEIGHT = 12; // px
|
||||
const MARKERS_GRAPH_BODY_HEIGHT = 45; // 9px * 5 groups
|
||||
const MARKERS_GROUP_VERTICAL_PADDING = 3.5; // px
|
||||
const MEMORY_GRAPH_HEIGHT = 30; // px
|
||||
|
||||
const GRAPH_SCROLL_EVENTS_DRAIN = 50; // ms
|
||||
|
||||
/**
|
||||
@ -20,23 +28,25 @@ let OverviewView = {
|
||||
* Sets up the view with event binding.
|
||||
*/
|
||||
initialize: Task.async(function *() {
|
||||
this._framerateEl = $("#time-framerate");
|
||||
this._ticksData = [];
|
||||
|
||||
this._start = this._start.bind(this);
|
||||
this._stop = this._stop.bind(this);
|
||||
this._onTimelineData = this._onTimelineData.bind(this);
|
||||
this._onRecordingTick = this._onRecordingTick.bind(this);
|
||||
this._onGraphMouseUp = this._onGraphMouseUp.bind(this);
|
||||
this._onGraphScroll = this._onGraphScroll.bind(this);
|
||||
|
||||
yield this._initializeFramerateGraph();
|
||||
yield this._showFramerateGraph();
|
||||
yield this._showMarkersGraph();
|
||||
yield this._showMemoryGraph();
|
||||
|
||||
this.framerateGraph.on("mouseup", this._onGraphMouseUp);
|
||||
this.framerateGraph.on("scroll", this._onGraphScroll);
|
||||
this.markersOverview.on("mouseup", this._onGraphMouseUp);
|
||||
this.markersOverview.on("scroll", this._onGraphScroll);
|
||||
this.memoryOverview.on("mouseup", this._onGraphMouseUp);
|
||||
this.memoryOverview.on("scroll", this._onGraphScroll);
|
||||
|
||||
PerformanceController.on(EVENTS.RECORDING_STARTED, this._start);
|
||||
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._stop);
|
||||
PerformanceController.on(EVENTS.TIMELINE_DATA, this._onTimelineData);
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -45,24 +55,89 @@ let OverviewView = {
|
||||
destroy: function () {
|
||||
this.framerateGraph.off("mouseup", this._onGraphMouseUp);
|
||||
this.framerateGraph.off("scroll", this._onGraphScroll);
|
||||
this.markersOverview.off("mouseup", this._onGraphMouseUp);
|
||||
this.markersOverview.off("scroll", this._onGraphScroll);
|
||||
this.memoryOverview.off("mouseup", this._onGraphMouseUp);
|
||||
this.memoryOverview.off("scroll", this._onGraphScroll);
|
||||
|
||||
clearNamedTimeout("graph-scroll");
|
||||
PerformanceController.off(EVENTS.RECORDING_STARTED, this._start);
|
||||
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._stop);
|
||||
PerformanceController.off(EVENTS.TIMELINE_DATA, this._onTimelineData);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up the framerate graph.
|
||||
*/
|
||||
_showFramerateGraph: Task.async(function *() {
|
||||
this.framerateGraph = new LineGraphWidget($("#time-framerate"), L10N.getStr("graphs.fps"));
|
||||
this.framerateGraph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
|
||||
yield this.framerateGraph.ready();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Sets up the markers overivew graph.
|
||||
*/
|
||||
_showMarkersGraph: Task.async(function *() {
|
||||
this.markersOverview = new MarkersOverview($("#markers-overview"));
|
||||
this.markersOverview.headerHeight = MARKERS_GRAPH_HEADER_HEIGHT;
|
||||
this.markersOverview.bodyHeight = MARKERS_GRAPH_BODY_HEIGHT;
|
||||
this.markersOverview.groupPadding = MARKERS_GROUP_VERTICAL_PADDING;
|
||||
yield this.markersOverview.ready();
|
||||
|
||||
CanvasGraphUtils.linkAnimation(this.framerateGraph, this.markersOverview);
|
||||
CanvasGraphUtils.linkSelection(this.framerateGraph, this.markersOverview);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Sets up the memory overview graph.
|
||||
*/
|
||||
_showMemoryGraph: Task.async(function *() {
|
||||
this.memoryOverview = new MemoryOverview($("#memory-overview"));
|
||||
this.memoryOverview.fixedHeight = MEMORY_GRAPH_HEIGHT;
|
||||
yield this.memoryOverview.ready();
|
||||
|
||||
CanvasGraphUtils.linkAnimation(this.framerateGraph, this.memoryOverview);
|
||||
CanvasGraphUtils.linkSelection(this.framerateGraph, this.memoryOverview);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Method for handling all the set up for rendering the overview graphs.
|
||||
*
|
||||
* @param number resolution
|
||||
* The fps graph resolution. @see Graphs.jsm
|
||||
*/
|
||||
render: Task.async(function *(resolution) {
|
||||
let interval = PerformanceController.getInterval();
|
||||
let markers = PerformanceController.getMarkers();
|
||||
let memory = PerformanceController.getMemory();
|
||||
let timestamps = PerformanceController.getTicks();
|
||||
|
||||
// Compute an approximate ending time for the view. This is
|
||||
// needed to ensure that the view updates even when new data is
|
||||
// not being generated.
|
||||
let fakeTime = interval.startTime + interval.localElapsedTime;
|
||||
interval.endTime = fakeTime;
|
||||
|
||||
this.markersOverview.setData({ interval, markers });
|
||||
this.emit(EVENTS.MARKERS_GRAPH_RENDERED);
|
||||
|
||||
this.memoryOverview.setData({ interval, memory });
|
||||
this.emit(EVENTS.MEMORY_GRAPH_RENDERED);
|
||||
|
||||
yield this.framerateGraph.setDataFromTimestamps(timestamps, resolution);
|
||||
this.emit(EVENTS.FRAMERATE_GRAPH_RENDERED);
|
||||
|
||||
// Finished rendering all graphs in this overview.
|
||||
this.emit(EVENTS.OVERVIEW_RENDERED);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called at most every OVERVIEW_UPDATE_INTERVAL milliseconds
|
||||
* and uses data fetched from `_onTimelineData` to render
|
||||
* data into all the corresponding overview graphs.
|
||||
*/
|
||||
_onRecordingTick: Task.async(function *() {
|
||||
// The `ticks` event on the TimelineFront returns all ticks for the
|
||||
// recording session, so just convert to plottable values and draw.
|
||||
let [, timestamps] = this._ticksData;
|
||||
yield this.framerateGraph.setDataFromTimestamps(timestamps);
|
||||
|
||||
this.emit(EVENTS.OVERVIEW_RENDERED);
|
||||
yield this.render(FRAMERATE_GRAPH_LOW_RES_INTERVAL);
|
||||
this._prepareNextTick();
|
||||
}),
|
||||
|
||||
@ -84,7 +159,10 @@ let OverviewView = {
|
||||
* Fires an event to be handled elsewhere.
|
||||
*/
|
||||
_onGraphMouseUp: function () {
|
||||
this._onSelectionChange();
|
||||
// Only fire a selection change event if the selection is actually enabled.
|
||||
if (this.framerateGraph.selectionEnabled) {
|
||||
this._onSelectionChange();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -97,18 +175,6 @@ let OverviewView = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up the framerate graph.
|
||||
*/
|
||||
_initializeFramerateGraph: Task.async(function *() {
|
||||
let graph = new LineGraphWidget(this._framerateEl, L10N.getStr("graphs.fps"));
|
||||
graph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
|
||||
graph.selectionEnabled = false;
|
||||
this.framerateGraph = graph;
|
||||
|
||||
yield graph.ready();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called to refresh the timer to keep firing _onRecordingTick.
|
||||
*/
|
||||
@ -121,28 +187,29 @@ let OverviewView = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handlers
|
||||
* Called when recording starts.
|
||||
*/
|
||||
|
||||
_start: function () {
|
||||
this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
|
||||
this.framerateGraph.dropSelection();
|
||||
},
|
||||
|
||||
_stop: function () {
|
||||
clearTimeout(this._timeoutId);
|
||||
this.framerateGraph.selectionEnabled = true;
|
||||
this.framerateGraph.dropSelection();
|
||||
this.framerateGraph.selectionEnabled = false;
|
||||
this.markersOverview.selectionEnabled = false;
|
||||
this.memoryOverview.selectionEnabled = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the TimelineFront has new data for
|
||||
* framerate, markers or memory, and stores the data
|
||||
* to be plotted subsequently.
|
||||
* Called when recording stops.
|
||||
*/
|
||||
_onTimelineData: function (_, eventName, ...data) {
|
||||
if (eventName === "ticks") {
|
||||
this._ticksData = data;
|
||||
}
|
||||
_stop: function () {
|
||||
clearTimeout(this._timeoutId);
|
||||
this._timeoutId = null;
|
||||
|
||||
this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
|
||||
|
||||
this.framerateGraph.selectionEnabled = true;
|
||||
this.markersOverview.selectionEnabled = true;
|
||||
this.memoryOverview.selectionEnabled = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -28,6 +28,7 @@ support-files =
|
||||
[browser_graphs-09b.js]
|
||||
[browser_graphs-09c.js]
|
||||
[browser_graphs-09d.js]
|
||||
[browser_graphs-09e.js]
|
||||
[browser_graphs-10a.js]
|
||||
[browser_graphs-10b.js]
|
||||
[browser_graphs-11a.js]
|
||||
|
@ -29,8 +29,8 @@ function* performTest() {
|
||||
function* testGraph(graph) {
|
||||
yield graph.setDataWhenReady(TEST_DATA);
|
||||
|
||||
is(graph._gutter.hidden, false,
|
||||
"The gutter should not be hidden.");
|
||||
is(graph._gutter.hidden, true,
|
||||
"The gutter should be hidden, since there's no data available.");
|
||||
is(graph._maxTooltip.hidden, true,
|
||||
"The max tooltip should be hidden.");
|
||||
is(graph._avgTooltip.hidden, true,
|
||||
|
65
browser/devtools/shared/test/browser_graphs-09e.js
Normal file
65
browser/devtools/shared/test/browser_graphs-09e.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that line graphs hide the gutter and tooltips when there's no data,
|
||||
// but show them when there is.
|
||||
|
||||
const NO_DATA = [];
|
||||
const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
|
||||
|
||||
let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
|
||||
let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
|
||||
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
|
||||
let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
|
||||
|
||||
let test = Task.async(function*() {
|
||||
yield promiseTab("about:blank");
|
||||
yield performTest();
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
|
||||
function* performTest() {
|
||||
let [host, win, doc] = yield createHost();
|
||||
let graph = new LineGraphWidget(doc.body, "fps");
|
||||
|
||||
yield testGraph(graph);
|
||||
|
||||
graph.destroy();
|
||||
host.destroy();
|
||||
}
|
||||
|
||||
function* testGraph(graph) {
|
||||
yield graph.setDataWhenReady(NO_DATA);
|
||||
|
||||
is(graph._gutter.hidden, true,
|
||||
"The gutter should be hidden when there's no data available.");
|
||||
is(graph._maxTooltip.hidden, true,
|
||||
"The max tooltip should be hidden when there's no data available.");
|
||||
is(graph._avgTooltip.hidden, true,
|
||||
"The avg tooltip should be hidden when there's no data available.");
|
||||
is(graph._minTooltip.hidden, true,
|
||||
"The min tooltip should be hidden when there's no data available.");
|
||||
|
||||
yield graph.setDataWhenReady(TEST_DATA);
|
||||
|
||||
is(graph._gutter.hidden, false,
|
||||
"The gutter should be visible now.");
|
||||
is(graph._maxTooltip.hidden, false,
|
||||
"The max tooltip should be visible now.");
|
||||
is(graph._avgTooltip.hidden, false,
|
||||
"The avg tooltip should be visible now.");
|
||||
is(graph._minTooltip.hidden, false,
|
||||
"The min tooltip should be visible now.");
|
||||
|
||||
yield graph.setDataWhenReady(NO_DATA);
|
||||
|
||||
is(graph._gutter.hidden, true,
|
||||
"The gutter should be hidden again.");
|
||||
is(graph._maxTooltip.hidden, true,
|
||||
"The max tooltip should be hidden again.");
|
||||
is(graph._avgTooltip.hidden, true,
|
||||
"The avg tooltip should be hidden again.");
|
||||
is(graph._minTooltip.hidden, true,
|
||||
"The min tooltip should be hidden again.");
|
||||
}
|
@ -1429,8 +1429,7 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
this._maxTooltip.hidden = !totalTicks || distanceMinMax < LINE_GRAPH_MIN_MAX_TOOLTIP_DISTANCE;
|
||||
this._avgTooltip.hidden = !totalTicks;
|
||||
this._minTooltip.hidden = !totalTicks;
|
||||
|
||||
this._gutter.hidden = !this.withTooltipArrows;
|
||||
this._gutter.hidden = !totalTicks || !this.withTooltipArrows;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1440,6 +1439,7 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
_createGutter: function() {
|
||||
let gutter = this._document.createElementNS(HTML_NS, "div");
|
||||
gutter.className = "line-graph-widget-gutter";
|
||||
gutter.setAttribute("hidden", true);
|
||||
this._container.appendChild(gutter);
|
||||
|
||||
return gutter;
|
||||
|
@ -555,6 +555,7 @@ CssHtmlTree.prototype = {
|
||||
for (let propView of this.propertyViews) {
|
||||
propView.updateSourceLinks();
|
||||
}
|
||||
this.inspector.emit("computed-view-sourcelinks-updated");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1378,7 +1379,7 @@ SelectorView.prototype = {
|
||||
*/
|
||||
updateSourceLink: function()
|
||||
{
|
||||
this.updateSource().then((oldSource) => {
|
||||
return this.updateSource().then((oldSource) => {
|
||||
if (oldSource != this.source && this.tree.element) {
|
||||
let selector = '[sourcelocation="' + oldSource + '"]';
|
||||
let link = this.tree.element.querySelector(selector);
|
||||
|
@ -1461,12 +1461,13 @@ CssRuleView.prototype = {
|
||||
}
|
||||
|
||||
// update text of source links if the rule-view is populated
|
||||
if (this._elementStyle) {
|
||||
if (this._elementStyle && this._elementStyle.rules) {
|
||||
for (let rule of this._elementStyle.rules) {
|
||||
if (rule.editor) {
|
||||
rule.editor.updateSourceLink();
|
||||
}
|
||||
}
|
||||
this.inspector.emit("rule-view-sourcelinks-updated");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -26,16 +26,26 @@ add_task(function*() {
|
||||
yield expandComputedViewPropertyByIndex(view, 0);
|
||||
|
||||
info("Verifying the link text");
|
||||
yield verifyLinkText(view, SCSS_LOC);
|
||||
// Forcing a call to updateSourceLink on the SelectorView here. The
|
||||
// computed-view already does it, but we have no way of waiting for it to be
|
||||
// done here, so just call it again and wait for the returned promise to
|
||||
// resolve.
|
||||
let propertyView = getComputedViewPropertyView(view, "color");
|
||||
yield propertyView.matchedSelectorViews[0].updateSourceLink();
|
||||
verifyLinkText(view, SCSS_LOC);
|
||||
|
||||
info("Toggling the pref");
|
||||
let onLinksUpdated = inspector.once("computed-view-sourcelinks-updated");
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
yield onLinksUpdated;
|
||||
|
||||
info("Verifying that the link text has changed after the pref change");
|
||||
yield verifyLinkText(view, CSS_LOC);
|
||||
|
||||
info("Toggling the pref again");
|
||||
onLinksUpdated = inspector.once("computed-view-sourcelinks-updated");
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
yield onLinksUpdated;
|
||||
|
||||
info("Testing that clicking on the link works");
|
||||
yield testClickingLink(toolbox, view);
|
||||
@ -60,9 +70,5 @@ function* testClickingLink(toolbox, view) {
|
||||
|
||||
function verifyLinkText(view, text) {
|
||||
let link = getComputedViewLinkByIndex(view, 0);
|
||||
|
||||
return waitForSuccess(
|
||||
() => link.textContent == text,
|
||||
"link text changed to display correct location: " + text
|
||||
);
|
||||
is(link.textContent, text, "Linked text changed to display the correct location");
|
||||
}
|
||||
|
@ -785,6 +785,23 @@ function getComputedViewProperty(view, name) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of PropertyView from the computed-view.
|
||||
* @param {CssHtmlTree} view The instance of the computed view panel
|
||||
* @param {String} name The name of the property to retrieve
|
||||
* @return {PropertyView}
|
||||
*/
|
||||
function getComputedViewPropertyView(view, name) {
|
||||
let propView;
|
||||
for (let propertyView of view.propertyViews) {
|
||||
if (propertyView._propertyInfo.name === name) {
|
||||
propView = propertyView;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return propView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the property-content element for a given property name in
|
||||
* the computed-view.
|
||||
|
@ -34,6 +34,9 @@ function MarkerDetails(parent, splitter) {
|
||||
}
|
||||
|
||||
MarkerDetails.prototype = {
|
||||
/**
|
||||
* Removes any node references from this view.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.empty();
|
||||
this._parent = null;
|
||||
|
@ -63,11 +63,20 @@ function MarkersOverview(parent, ...args) {
|
||||
}
|
||||
|
||||
MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
fixedHeight: OVERVIEW_HEADER_HEIGHT + OVERVIEW_BODY_HEIGHT,
|
||||
clipheadLineColor: OVERVIEW_CLIPHEAD_LINE_COLOR,
|
||||
selectionLineColor: OVERVIEW_SELECTION_LINE_COLOR,
|
||||
selectionBackgroundColor: OVERVIEW_SELECTION_BACKGROUND_COLOR,
|
||||
selectionStripesColor: OVERVIEW_SELECTION_STRIPES_COLOR,
|
||||
headerHeight: OVERVIEW_HEADER_HEIGHT,
|
||||
bodyHeight: OVERVIEW_BODY_HEIGHT,
|
||||
groupPadding: OVERVIEW_GROUP_VERTICAL_PADDING,
|
||||
|
||||
/**
|
||||
* Compute the height of the overview.
|
||||
*/
|
||||
get fixedHeight() {
|
||||
return this.headerHeight + this.bodyHeight;
|
||||
},
|
||||
|
||||
/**
|
||||
* List of names and colors used to paint this overview.
|
||||
@ -100,7 +109,7 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
let { interval, markers } = this._data;
|
||||
let { startTime, endTime } = interval;
|
||||
|
||||
let { canvas, ctx } = this._getNamedCanvas("overview-data");
|
||||
let { canvas, ctx } = this._getNamedCanvas("markers-overview-data");
|
||||
let canvasWidth = this._width;
|
||||
let canvasHeight = this._height;
|
||||
let safeBounds = OVERVIEW_HEADER_SAFE_BOUNDS * this._pixelRatio;
|
||||
@ -116,9 +125,9 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
// Calculate each group's height, and the time-based scaling.
|
||||
|
||||
let totalGroups = this._lastGroup + 1;
|
||||
let headerHeight = OVERVIEW_HEADER_HEIGHT * this._pixelRatio;
|
||||
let groupHeight = OVERVIEW_BODY_HEIGHT * this._pixelRatio / totalGroups;
|
||||
let groupPadding = OVERVIEW_GROUP_VERTICAL_PADDING * this._pixelRatio;
|
||||
let headerHeight = this.headerHeight * this._pixelRatio;
|
||||
let groupHeight = this.bodyHeight * this._pixelRatio / totalGroups;
|
||||
let groupPadding = this.groupPadding * this._pixelRatio;
|
||||
|
||||
let totalTime = (endTime - startTime) || 0;
|
||||
let dataScale = this.dataScaleX = availableWidth / totalTime;
|
||||
|
@ -53,6 +53,7 @@ const WATERFALL_ROWCOUNT_ONPAGEUPDOWN = 10;
|
||||
*/
|
||||
function Waterfall(parent, container) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._parent = parent;
|
||||
this._document = parent.ownerDocument;
|
||||
this._container = container;
|
||||
@ -87,9 +88,13 @@ function Waterfall(parent, container) {
|
||||
}
|
||||
|
||||
Waterfall.prototype = {
|
||||
/**
|
||||
* Removes any node references from this view.
|
||||
*/
|
||||
destroy: function() {
|
||||
this._parent = this._document = this._container = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Populates this view with the provided data source.
|
||||
*
|
||||
|
@ -2,72 +2,87 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the Web Console shows SHA-1 Certificate warnings
|
||||
// Tests that the Web Console shows weak crypto warnings (SHA-1 Certificate, SSLv3, and RC4)
|
||||
|
||||
const TEST_BAD_URI = "https://sha1ee.example.com/browser/browser/devtools/webconsole/test/test-certificate-messages.html";
|
||||
const TEST_GOOD_URI = "https://sha256ee.example.com/browser/browser/devtools/webconsole/test/test-certificate-messages.html";
|
||||
const TEST_URI_PATH = "/browser/browser/devtools/webconsole/test/test-certificate-messages.html";
|
||||
let gWebconsoleTests = [
|
||||
{url: "https://sha1ee.example.com" + TEST_URI_PATH,
|
||||
name: "SHA1 warning displayed successfully",
|
||||
warning: ["SHA-1"], nowarning: ["SSL 3.0", "RC4"]},
|
||||
{url: "https://ssl3.example.com" + TEST_URI_PATH,
|
||||
name: "SSL3 warning displayed successfully",
|
||||
pref: [["security.tls.version.min", 0]],
|
||||
warning: ["SSL 3.0"], nowarning: ["SHA-1", "RC4"]},
|
||||
{url: "https://rc4.example.com" + TEST_URI_PATH,
|
||||
name: "RC4 warning displayed successfully",
|
||||
warning: ["RC4"], nowarning: ["SHA-1", "SSL 3.0"]},
|
||||
{url: "https://ssl3rc4.example.com" + TEST_URI_PATH,
|
||||
name: "SSL3 and RC4 warning displayed successfully",
|
||||
pref: [["security.tls.version.min", 0]],
|
||||
warning: ["SSL 3.0", "RC4"], nowarning: ["SHA-1"]},
|
||||
{url: "https://sha256ee.example.com" + TEST_URI_PATH,
|
||||
name: "SSL warnings appropriately not present",
|
||||
warning: [], nowarning: ["SHA-1", "SSL 3.0", "RC4"]},
|
||||
];
|
||||
const TRIGGER_MSG = "If you haven't seen ssl warnings yet, you won't";
|
||||
|
||||
let gHud = undefined;
|
||||
let gCurrentTest;
|
||||
|
||||
function test() {
|
||||
registerCleanupFunction(function () {
|
||||
gHud = null;
|
||||
});
|
||||
|
||||
addTab("data:text/html;charset=utf8,Web Console SHA-1 warning test");
|
||||
addTab("data:text/html;charset=utf8,Web Console weak crypto warnings test");
|
||||
browser.addEventListener("load", function _onLoad() {
|
||||
browser.removeEventListener("load", _onLoad, true);
|
||||
openConsole(null, loadBadDocument);
|
||||
openConsole(null, runTestLoop);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function loadBadDocument(theHud) {
|
||||
gHud = theHud;
|
||||
browser.addEventListener("load", onBadLoad, true);
|
||||
content.location = TEST_BAD_URI;
|
||||
function runTestLoop(theHud) {
|
||||
gCurrentTest = gWebconsoleTests.shift();
|
||||
if (!gCurrentTest) {
|
||||
finishTest();
|
||||
}
|
||||
if (!gHud) {
|
||||
gHud = theHud;
|
||||
}
|
||||
gHud.jsterm.clearOutput();
|
||||
browser.addEventListener("load", onLoad, true);
|
||||
if (gCurrentTest.pref) {
|
||||
SpecialPowers.pushPrefEnv({"set": gCurrentTest.pref},
|
||||
function() {
|
||||
content.location = gCurrentTest.url;
|
||||
});
|
||||
} else {
|
||||
content.location = gCurrentTest.url;
|
||||
}
|
||||
}
|
||||
|
||||
function onBadLoad(aEvent) {
|
||||
browser.removeEventListener("load", onBadLoad, true);
|
||||
testForWarningMessage();
|
||||
}
|
||||
|
||||
function loadGoodDocument(theHud) {
|
||||
gHud.jsterm.clearOutput()
|
||||
browser.addEventListener("load", onGoodLoad, true);
|
||||
content.location = TEST_GOOD_URI;
|
||||
}
|
||||
|
||||
function onGoodLoad(aEvent) {
|
||||
browser.removeEventListener("load", onGoodLoad, true);
|
||||
testForNoWarning();
|
||||
}
|
||||
|
||||
function testForWarningMessage() {
|
||||
function onLoad(aEvent) {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
let aOutputNode = gHud.outputNode;
|
||||
|
||||
waitForSuccess({
|
||||
name: "SHA1 warning displayed successfully",
|
||||
name: gCurrentTest.name,
|
||||
validatorFn: function() {
|
||||
return gHud.outputNode.textContent.indexOf("SHA-1") > -1;
|
||||
},
|
||||
successFn: loadGoodDocument,
|
||||
failureFn: finishTest,
|
||||
});
|
||||
}
|
||||
|
||||
function testForNoWarning() {
|
||||
let aOutputNode = gHud.outputNode;
|
||||
|
||||
waitForSuccess({
|
||||
name: "SHA1 warning appropriately missed",
|
||||
validatorFn: function() {
|
||||
if (gHud.outputNode.textContent.indexOf(TRIGGER_MSG) > -1) {
|
||||
return gHud.outputNode.textContent.indexOf("SHA-1") == -1;
|
||||
if (gHud.outputNode.textContent.indexOf(TRIGGER_MSG) >= 0) {
|
||||
for (let warning of gCurrentTest.warning) {
|
||||
if (gHud.outputNode.textContent.indexOf(warning) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (let nowarning of gCurrentTest.nowarning) {
|
||||
if (gHud.outputNode.textContent.indexOf(nowarning) >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
successFn: finishTest,
|
||||
successFn: runTestLoop,
|
||||
failureFn: finishTest,
|
||||
});
|
||||
}
|
||||
|
@ -32,8 +32,9 @@ openFile.title=Open File
|
||||
# open fails.
|
||||
openFile.failed=Failed to read the file.
|
||||
|
||||
# LOCALIZATION NOTE (openFile.failed): This is the message displayed when file
|
||||
# open fails.
|
||||
# LOCALIZATION NOTE (importFromFile.convert.failed): This is the message
|
||||
# displayed when file conversion from some charset to Unicode fails.
|
||||
# %1 is the name of the charset from which the conversion failed.
|
||||
importFromFile.convert.failed=Failed to convert file to Unicode from %1$S.
|
||||
|
||||
# LOCALIZATION NOTE (clearRecentMenuItems.label): This is the label for the
|
||||
|
@ -308,6 +308,7 @@
|
||||
transform-origin: left center;
|
||||
}
|
||||
|
||||
.waterfall-marker-container.selected > .waterfall-sidebar,
|
||||
.waterfall-marker-container.selected > .waterfall-marker-item {
|
||||
background-color: var(--theme-selection-background);
|
||||
color: var(--theme-selection-color);
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "clang/Frontend/MultiplexConsumer.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <memory>
|
||||
|
||||
#define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR)
|
||||
@ -54,6 +56,66 @@ private:
|
||||
MatchFinder astMatcher;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
bool isInIgnoredNamespace(const Decl *decl) {
|
||||
const DeclContext *DC = decl->getDeclContext()->getEnclosingNamespaceContext();
|
||||
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
|
||||
if (!ND) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (const DeclContext *ParentDC = ND->getParent()) {
|
||||
if (!isa<NamespaceDecl>(ParentDC)) {
|
||||
break;
|
||||
}
|
||||
ND = cast<NamespaceDecl>(ParentDC);
|
||||
}
|
||||
|
||||
// namespace std and icu are ignored for now
|
||||
return ND->getName() == "std" || // standard C++ lib
|
||||
ND->getName() == "__gnu_cxx" || // gnu C++ lib
|
||||
ND->getName() == "boost" || // boost
|
||||
ND->getName() == "webrtc" || // upstream webrtc
|
||||
ND->getName() == "icu_52" || // icu
|
||||
ND->getName() == "google" || // protobuf
|
||||
ND->getName() == "google_breakpad" || // breakpad
|
||||
ND->getName() == "soundtouch" || // libsoundtouch
|
||||
ND->getName() == "stagefright" || // libstagefright
|
||||
ND->getName() == "MacFileUtilities" || // MacFileUtilities
|
||||
ND->getName() == "dwarf2reader" || // dwarf2reader
|
||||
ND->getName() == "arm_ex_to_module" || // arm_ex_to_module
|
||||
ND->getName() == "testing"; // gtest
|
||||
}
|
||||
|
||||
bool isIgnoredPath(const Decl *decl) {
|
||||
decl = decl->getCanonicalDecl();
|
||||
SourceLocation Loc = decl->getLocation();
|
||||
const SourceManager &SM = decl->getASTContext().getSourceManager();
|
||||
SmallString<1024> FileName = SM.getFilename(Loc);
|
||||
llvm::sys::fs::make_absolute(FileName);
|
||||
llvm::sys::path::reverse_iterator begin = llvm::sys::path::rbegin(FileName),
|
||||
end = llvm::sys::path::rend(FileName);
|
||||
for (; begin != end; ++begin) {
|
||||
if (begin->compare_lower(StringRef("skia")) == 0 ||
|
||||
begin->compare_lower(StringRef("angle")) == 0 ||
|
||||
begin->compare_lower(StringRef("harfbuzz")) == 0 ||
|
||||
begin->compare_lower(StringRef("hunspell")) == 0 ||
|
||||
begin->compare_lower(StringRef("scoped_ptr.h")) == 0 ||
|
||||
begin->compare_lower(StringRef("graphite2")) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isInterestingDecl(const Decl *decl) {
|
||||
return !isInIgnoredNamespace(decl) &&
|
||||
!isIgnoredPath(decl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
|
||||
DiagnosticsEngine &Diag;
|
||||
const CompilerInstance &CI;
|
||||
@ -126,6 +188,32 @@ public:
|
||||
Diag.Report((*it)->getLocation(), overrideNote);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInterestingDecl(d)) {
|
||||
for (CXXRecordDecl::ctor_iterator ctor = d->ctor_begin(),
|
||||
e = d->ctor_end(); ctor != e; ++ctor) {
|
||||
// Ignore non-converting ctors
|
||||
if (!ctor->isConvertingConstructor(false)) {
|
||||
continue;
|
||||
}
|
||||
// Ignore copy or move constructors
|
||||
if (ctor->isCopyOrMoveConstructor()) {
|
||||
continue;
|
||||
}
|
||||
// Ignore deleted constructors
|
||||
if (ctor->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
// Ignore whitelisted constructors
|
||||
if (MozChecker::hasCustomAnnotation(*ctor, "moz_implicit")) {
|
||||
continue;
|
||||
}
|
||||
unsigned ctorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "bad implicit conversion constructor for %0");
|
||||
Diag.Report(ctor->getLocation(), ctorID) << d->getDeclName();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
34
build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp
Normal file
34
build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
|
||||
|
||||
struct Foo {
|
||||
Foo(int); // expected-error {{bad implicit conversion constructor for 'Foo'}}
|
||||
Foo(int, char=0); // expected-error {{bad implicit conversion constructor for 'Foo'}}
|
||||
Foo(...); // expected-error {{bad implicit conversion constructor for 'Foo'}}
|
||||
Foo(int, unsigned);
|
||||
Foo(Foo&);
|
||||
Foo(const Foo&);
|
||||
Foo(volatile Foo&);
|
||||
Foo(const volatile Foo&);
|
||||
Foo(Foo&&);
|
||||
Foo(const Foo&&);
|
||||
Foo(volatile Foo&&);
|
||||
Foo(const volatile Foo&&);
|
||||
};
|
||||
|
||||
struct Bar {
|
||||
explicit Bar(int);
|
||||
explicit Bar(int, char=0);
|
||||
explicit Bar(...);
|
||||
};
|
||||
|
||||
struct Baz {
|
||||
MOZ_IMPLICIT Baz(int);
|
||||
MOZ_IMPLICIT Baz(int, char=0);
|
||||
MOZ_IMPLICIT Baz(...);
|
||||
};
|
||||
|
||||
struct Barn {
|
||||
Barn(int) = delete;
|
||||
Barn(int, char=0) = delete;
|
||||
Barn(...) = delete;
|
||||
};
|
@ -5,6 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
SOURCES += [
|
||||
'TestBadImplicitConversionCtor.cpp',
|
||||
'TestCustomHeap.cpp',
|
||||
'TestMustOverride.cpp',
|
||||
'TestNonHeapClass.cpp',
|
||||
|
Binary file not shown.
Binary file not shown.
@ -233,3 +233,8 @@ https://include-subdomains.pinning.example.com:443 privileged,cer
|
||||
# Hosts for sha1 console warning tests
|
||||
https://sha1ee.example.com:443 privileged,cert=sha1_end_entity
|
||||
https://sha256ee.example.com:443 privileged,cert=sha256_end_entity
|
||||
|
||||
# Hosts for ssl3/rc4 console warning tests
|
||||
https://ssl3.example.com:443 privileged,ssl3
|
||||
https://rc4.example.com:443 privileged,rc4
|
||||
https://ssl3rc4.example.com:443 privileged,ssl3,rc4
|
||||
|
@ -15,9 +15,6 @@ leak:nsComponentManagerImpl
|
||||
leak:mozJSComponentLoader::LoadModule
|
||||
leak:nsNativeModuleLoader::LoadModule
|
||||
|
||||
# Bug 980109 - Freeing this properly on shutdown is hard.
|
||||
leak:profiler_init
|
||||
|
||||
# Bug 981220 - Pixman fails to free TLS memory.
|
||||
leak:pixman_implementation_lookup_composite
|
||||
|
||||
|
@ -80,7 +80,7 @@ public:
|
||||
: mWebSocket(aWebSocket)
|
||||
, mOnCloseScheduled(false)
|
||||
, mFailed(false)
|
||||
, mDisconnected(false)
|
||||
, mDisconnectingOrDisconnected(false)
|
||||
, mCloseEventWasClean(false)
|
||||
, mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL)
|
||||
, mScriptLine(0)
|
||||
@ -89,10 +89,13 @@ public:
|
||||
#ifdef DEBUG
|
||||
, mHasFeatureRegistered(false)
|
||||
#endif
|
||||
, mIsMainThread(true)
|
||||
, mWorkerShuttingDown(false)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mIsMainThread = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +155,7 @@ public:
|
||||
void AddRefObject();
|
||||
void ReleaseObject();
|
||||
|
||||
void RegisterFeature();
|
||||
bool RegisterFeature();
|
||||
void UnregisterFeature();
|
||||
|
||||
nsresult CancelInternal();
|
||||
@ -166,7 +169,7 @@ public:
|
||||
|
||||
bool mOnCloseScheduled;
|
||||
bool mFailed;
|
||||
bool mDisconnected;
|
||||
bool mDisconnectingOrDisconnected;
|
||||
|
||||
// Set attributes of DOM 'onclose' message
|
||||
bool mCloseEventWasClean;
|
||||
@ -218,11 +221,14 @@ public:
|
||||
|
||||
nsWeakPtr mWeakLoadGroup;
|
||||
|
||||
bool mIsMainThread;
|
||||
bool mWorkerShuttingDown;
|
||||
|
||||
private:
|
||||
~WebSocketImpl()
|
||||
{
|
||||
// If we threw during Init we never called disconnect
|
||||
if (!mDisconnected) {
|
||||
if (!mDisconnectingOrDisconnected) {
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
@ -313,6 +319,8 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI,
|
||||
// This method must run on the main thread.
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
|
||||
nsRefPtr<PrintErrorOnConsoleRunnable> runnable =
|
||||
new PrintErrorOnConsoleRunnable(this, aBundleURI, aError, aFormatStrings,
|
||||
aFormatStringsLen);
|
||||
@ -404,6 +412,25 @@ private:
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS MaybeDisconnect
|
||||
{
|
||||
public:
|
||||
explicit MaybeDisconnect(WebSocketImpl* aImpl)
|
||||
: mImpl(aImpl)
|
||||
{
|
||||
}
|
||||
|
||||
~MaybeDisconnect()
|
||||
{
|
||||
if (mImpl->mWorkerShuttingDown) {
|
||||
mImpl->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
WebSocketImpl* mImpl;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
nsresult
|
||||
@ -412,6 +439,15 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If this method is called because the worker is going away, we will not
|
||||
// receive the OnStop() method and we have to disconnect the WebSocket and
|
||||
// release the WorkerFeature.
|
||||
MaybeDisconnect md(this);
|
||||
|
||||
uint16_t readyState = mWebSocket->ReadyState();
|
||||
if (readyState == WebSocket::CLOSING ||
|
||||
readyState == WebSocket::CLOSED) {
|
||||
@ -484,6 +520,10 @@ WebSocketImpl::FailConnection(uint16_t aReasonCode,
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConsoleError();
|
||||
mFailed = true;
|
||||
CloseConnection(aReasonCode, aReasonString);
|
||||
@ -515,12 +555,18 @@ private:
|
||||
nsresult
|
||||
WebSocketImpl::Disconnect()
|
||||
{
|
||||
if (mDisconnected) {
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
// Disconnect can be called from some control event (such as Notify() of
|
||||
// WorkerFeature). This will be schedulated before any other sync/async
|
||||
// runnable. In order to prevent some double Disconnect() calls, we use this
|
||||
// boolean.
|
||||
mDisconnectingOrDisconnected = true;
|
||||
|
||||
// DisconnectInternal touches observers and nsILoadGroup and it must run on
|
||||
// the main thread.
|
||||
|
||||
@ -536,20 +582,19 @@ WebSocketImpl::Disconnect()
|
||||
// until the end of the method.
|
||||
nsRefPtr<WebSocketImpl> kungfuDeathGrip = this;
|
||||
|
||||
if (mWorkerPrivate && mWorkerFeature) {
|
||||
UnregisterFeature();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
if (NS_FAILED(NS_GetMainThread(getter_AddRefs(mainThread))) ||
|
||||
NS_FAILED(NS_ProxyRelease(mainThread, mChannel))) {
|
||||
NS_WARNING("Failed to proxy release of channel, leaking instead!");
|
||||
}
|
||||
|
||||
mDisconnected = true;
|
||||
mWebSocket->DontKeepAliveAnyMore();
|
||||
mWebSocket->mImpl = nullptr;
|
||||
|
||||
if (mWorkerPrivate && mWorkerFeature) {
|
||||
UnregisterFeature();
|
||||
}
|
||||
|
||||
// We want to release the WebSocket in the correct thread.
|
||||
mWebSocket = nullptr;
|
||||
|
||||
@ -585,6 +630,10 @@ WebSocketImpl::DoOnMessageAvailable(const nsACString& aMsg, bool isBinary)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int16_t readyState = mWebSocket->ReadyState();
|
||||
if (readyState == WebSocket::CLOSED) {
|
||||
NS_ERROR("Received message after CLOSED");
|
||||
@ -612,6 +661,11 @@ WebSocketImpl::OnMessageAvailable(nsISupports* aContext,
|
||||
const nsACString& aMsg)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoOnMessageAvailable(aMsg, false);
|
||||
}
|
||||
|
||||
@ -620,6 +674,11 @@ WebSocketImpl::OnBinaryMessageAvailable(nsISupports* aContext,
|
||||
const nsACString& aMsg)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoOnMessageAvailable(aMsg, true);
|
||||
}
|
||||
|
||||
@ -628,6 +687,10 @@ WebSocketImpl::OnStart(nsISupports* aContext)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int16_t readyState = mWebSocket->ReadyState();
|
||||
|
||||
// This is the only function that sets OPEN, and should be called only once
|
||||
@ -671,6 +734,10 @@ WebSocketImpl::OnStop(nsISupports* aContext, nsresult aStatusCode)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We can be CONNECTING here if connection failed.
|
||||
// We can be OPEN if we have encountered a fatal protocol error
|
||||
// We can be CLOSING if close() was called and/or server initiated close.
|
||||
@ -719,6 +786,10 @@ WebSocketImpl::OnAcknowledge(nsISupports *aContext, uint32_t aSize)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aSize > mWebSocket->mOutgoingBufferedAmount) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
@ -733,6 +804,10 @@ WebSocketImpl::OnServerClose(nsISupports *aContext, uint16_t aCode,
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int16_t readyState = mWebSocket->ReadyState();
|
||||
|
||||
MOZ_ASSERT(readyState != WebSocket::CONNECTING,
|
||||
@ -802,7 +877,7 @@ WebSocketImpl::GetInterface(const nsIID& aIID, void** aResult)
|
||||
|
||||
WebSocket::WebSocket(nsPIDOMWindow* aOwnerWindow)
|
||||
: DOMEventTargetHelper(aOwnerWindow)
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mIsMainThread(true)
|
||||
, mKeepingAlive(false)
|
||||
, mCheckMustKeepAlive(true)
|
||||
, mOutgoingBufferedAmount(0)
|
||||
@ -811,7 +886,7 @@ WebSocket::WebSocket(nsPIDOMWindow* aOwnerWindow)
|
||||
, mReadyState(CONNECTING)
|
||||
{
|
||||
mImpl = new WebSocketImpl(this);
|
||||
mWorkerPrivate = mImpl->mWorkerPrivate;
|
||||
mIsMainThread = mImpl->mIsMainThread;
|
||||
}
|
||||
|
||||
WebSocket::~WebSocket()
|
||||
@ -1058,6 +1133,13 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
webSocket->mImpl->Init(aGlobal.Context(), principal, aUrl, protocolArray,
|
||||
EmptyCString(), 0, aRv, &connectionFailed);
|
||||
} else {
|
||||
// In workers we have to keep the worker alive using a feature in order to
|
||||
// dispatch messages correctly.
|
||||
if (!webSocket->mImpl->RegisterFeature()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned lineno;
|
||||
JS::AutoFilename file;
|
||||
if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno)) {
|
||||
@ -1075,6 +1157,13 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It can be that we have been already disconnected because the WebSocket is
|
||||
// gone away while we where initializing the webSocket.
|
||||
if (!webSocket->mImpl) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We don't return an error if the connection just failed. Instead we dispatch
|
||||
// an event.
|
||||
if (connectionFailed) {
|
||||
@ -1087,12 +1176,6 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
return webSocket.forget();
|
||||
}
|
||||
|
||||
if (webSocket->mWorkerPrivate) {
|
||||
// In workers we have to keep the worker alive using a feature in order to
|
||||
// dispatch messages correctly.
|
||||
webSocket->mImpl->RegisterFeature();
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS ClearWebSocket
|
||||
{
|
||||
public:
|
||||
@ -1140,6 +1223,13 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It can be that we have been already disconnected because the WebSocket is
|
||||
// gone away while we where initializing the webSocket.
|
||||
if (!webSocket->mImpl) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cws.Done();
|
||||
return webSocket.forget();
|
||||
}
|
||||
@ -1499,6 +1589,11 @@ void
|
||||
WebSocketImpl::DispatchConnectionCloseEvents()
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWebSocket->SetReadyState(WebSocket::CLOSED);
|
||||
|
||||
// Call 'onerror' if needed
|
||||
@ -1559,8 +1654,9 @@ WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
if (NS_WARN_IF(!jsapi.Init(mWorkerPrivate->GlobalScope()))) {
|
||||
MOZ_ASSERT(!mIsMainThread);
|
||||
MOZ_ASSERT(mImpl->mWorkerPrivate);
|
||||
if (NS_WARN_IF(!jsapi.Init(mImpl->mWorkerPrivate->GlobalScope()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -1796,7 +1892,7 @@ void
|
||||
WebSocket::UpdateMustKeepAlive()
|
||||
{
|
||||
// Here we could not have mImpl.
|
||||
MOZ_ASSERT(NS_IsMainThread() == !mWorkerPrivate);
|
||||
MOZ_ASSERT(NS_IsMainThread() == mIsMainThread);
|
||||
|
||||
if (!mCheckMustKeepAlive || !mImpl) {
|
||||
return;
|
||||
@ -1805,9 +1901,7 @@ WebSocket::UpdateMustKeepAlive()
|
||||
bool shouldKeepAlive = false;
|
||||
uint16_t readyState = ReadyState();
|
||||
|
||||
if (mWorkerPrivate && readyState != CLOSED) {
|
||||
shouldKeepAlive = true;
|
||||
} else if (mListenerManager) {
|
||||
if (mListenerManager) {
|
||||
switch (readyState)
|
||||
{
|
||||
case CONNECTING:
|
||||
@ -1853,7 +1947,7 @@ void
|
||||
WebSocket::DontKeepAliveAnyMore()
|
||||
{
|
||||
// Here we could not have mImpl.
|
||||
MOZ_ASSERT(NS_IsMainThread() == !mWorkerPrivate);
|
||||
MOZ_ASSERT(NS_IsMainThread() == mIsMainThread);
|
||||
|
||||
if (mKeepingAlive) {
|
||||
MOZ_ASSERT(mImpl);
|
||||
@ -1880,6 +1974,7 @@ public:
|
||||
MOZ_ASSERT(aStatus > workers::Running);
|
||||
|
||||
if (aStatus >= Canceling) {
|
||||
mWebSocketImpl->mWorkerShuttingDown = true;
|
||||
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||
}
|
||||
|
||||
@ -1888,6 +1983,7 @@ public:
|
||||
|
||||
bool Suspend(JSContext* aCx)
|
||||
{
|
||||
mWebSocketImpl->mWorkerShuttingDown = true;
|
||||
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||
return true;
|
||||
}
|
||||
@ -1903,25 +1999,16 @@ WebSocketImpl::AddRefObject()
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
AddRef();
|
||||
|
||||
if (mWorkerPrivate && !mWorkerFeature) {
|
||||
RegisterFeature();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketImpl::ReleaseObject()
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mWorkerPrivate && mWorkerFeature) {
|
||||
UnregisterFeature();
|
||||
}
|
||||
|
||||
Release();
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
WebSocketImpl::RegisterFeature()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
@ -1932,17 +2019,20 @@ WebSocketImpl::RegisterFeature()
|
||||
if (!mWorkerPrivate->AddFeature(cx, mWorkerFeature)) {
|
||||
NS_WARNING("Failed to register a feature.");
|
||||
mWorkerFeature = nullptr;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
SetHasFeatureRegistered(true);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketImpl::UnregisterFeature()
|
||||
{
|
||||
MOZ_ASSERT(mDisconnectingOrDisconnected);
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(mWorkerFeature);
|
||||
@ -1950,6 +2040,7 @@ WebSocketImpl::UnregisterFeature()
|
||||
JSContext* cx = GetCurrentThreadJSContext();
|
||||
mWorkerPrivate->RemoveFeature(cx, mWorkerFeature);
|
||||
mWorkerFeature = nullptr;
|
||||
mWorkerPrivate = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
SetHasFeatureRegistered(false);
|
||||
@ -2333,7 +2424,8 @@ WebSocketImpl::Cancel(nsresult aStatus)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
if (!mIsMainThread) {
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
nsRefPtr<CancelRunnable> runnable =
|
||||
new CancelRunnable(mWorkerPrivate, this);
|
||||
if (!runnable->Dispatch(nullptr)) {
|
||||
@ -2353,7 +2445,7 @@ WebSocketImpl::CancelInternal()
|
||||
|
||||
// If CancelInternal is called by a runnable, we may already be disconnected
|
||||
// by the time it runs.
|
||||
if (mDisconnected) {
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2388,7 +2480,7 @@ WebSocketImpl::GetLoadGroup(nsILoadGroup** aLoadGroup)
|
||||
|
||||
*aLoadGroup = nullptr;
|
||||
|
||||
if (!mWorkerPrivate) {
|
||||
if (mIsMainThread) {
|
||||
nsresult rv;
|
||||
nsIScriptContext* sc = mWebSocket->GetContextForEventHandlers(&rv);
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
@ -2401,6 +2493,8 @@ WebSocketImpl::GetLoadGroup(nsILoadGroup** aLoadGroup)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
|
||||
// Walk up to our containing page
|
||||
WorkerPrivate* wp = mWorkerPrivate;
|
||||
while (wp->GetParent()) {
|
||||
@ -2490,10 +2584,22 @@ NS_IMETHODIMP
|
||||
WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
{
|
||||
// If the target is the main-thread we can just dispatch the runnable.
|
||||
if (!mWorkerPrivate) {
|
||||
if (mIsMainThread) {
|
||||
return NS_DispatchToMainThread(aEvent);
|
||||
}
|
||||
|
||||
// No messages when disconnected.
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
NS_WARNING("Dispatching a WebSocket event after the disconnection!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mWorkerShuttingDown) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(HasFeatureRegistered());
|
||||
#endif
|
||||
@ -2519,13 +2625,13 @@ WebSocketImpl::IsOnCurrentThread(bool* aResult)
|
||||
bool
|
||||
WebSocketImpl::IsTargetThread() const
|
||||
{
|
||||
return NS_IsMainThread() == !mWorkerPrivate;
|
||||
return NS_IsMainThread() == mIsMainThread;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::AssertIsOnTargetThread() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() == !mWorkerPrivate);
|
||||
MOZ_ASSERT(NS_IsMainThread() == mIsMainThread);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
|
@ -173,7 +173,7 @@ private:
|
||||
// WebSocket.
|
||||
WebSocketImpl* mImpl;
|
||||
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
bool mIsMainThread;
|
||||
|
||||
bool mKeepingAlive;
|
||||
bool mCheckMustKeepAlive;
|
||||
|
@ -6265,7 +6265,13 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
|
||||
return;
|
||||
}
|
||||
|
||||
aRetval.set(JS_GetFunctionObject(constructor));
|
||||
JS::Rooted<JSObject*> constructorObj(aCx, JS_GetFunctionObject(constructor));
|
||||
if (!JS_LinkConstructorAndPrototype(aCx, constructorObj, protoObject)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
aRetval.set(constructorObj);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -185,6 +185,7 @@ static uint32_t sForgetSkippableBeforeCC = 0;
|
||||
static uint32_t sPreviousSuspectedCount = 0;
|
||||
static uint32_t sCleanupsSinceLastGC = UINT32_MAX;
|
||||
static bool sNeedsFullCC = false;
|
||||
static bool sNeedsFullGC = false;
|
||||
static bool sNeedsGCAfterCC = false;
|
||||
static bool sIncrementalCC = false;
|
||||
static bool sDidPaintAfterPreviousICCSlice = false;
|
||||
@ -1462,7 +1463,13 @@ nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
|
||||
return;
|
||||
}
|
||||
|
||||
JS::PrepareForFullGC(sRuntime);
|
||||
if (sNeedsFullGC || aReason != JS::gcreason::CC_WAITING) {
|
||||
sNeedsFullGC = false;
|
||||
JS::PrepareForFullGC(sRuntime);
|
||||
} else {
|
||||
CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC();
|
||||
}
|
||||
|
||||
if (aIncremental == IncrementalGC) {
|
||||
MOZ_ASSERT(aShrinking == NonShrinkingGC);
|
||||
JS::IncrementalGC(sRuntime, aReason, aSliceMillis);
|
||||
@ -2149,6 +2156,8 @@ nsJSContext::RunNextCollectorTimer()
|
||||
void
|
||||
nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay)
|
||||
{
|
||||
sNeedsFullGC = sNeedsFullGC || aReason != JS::gcreason::CC_WAITING;
|
||||
|
||||
if (sGCTimer || sInterSliceGCTimer || sShuttingDown) {
|
||||
// There's already a timer for GC'ing, just return
|
||||
return;
|
||||
@ -2458,6 +2467,7 @@ mozilla::dom::StartupJSEnvironment()
|
||||
sLikelyShortLivingObjectsNeedingGC = 0;
|
||||
sPostGCEventsToConsole = false;
|
||||
sNeedsFullCC = false;
|
||||
sNeedsFullGC = false;
|
||||
sNeedsGCAfterCC = false;
|
||||
gNameSpaceManager = nullptr;
|
||||
sRuntimeService = nullptr;
|
||||
|
@ -151,7 +151,7 @@ BluetoothService::ToggleBtAck::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class BluetoothService::StartupTask : public nsISettingsServiceCallback
|
||||
class BluetoothService::StartupTask MOZ_FINAL : public nsISettingsServiceCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -71,7 +71,7 @@ IsSupportedChld(const int aChld) {
|
||||
return (aChld >= 0 && aChld <= 3);
|
||||
}
|
||||
|
||||
class BluetoothHfpManager::GetVolumeTask : public nsISettingsServiceCallback
|
||||
class BluetoothHfpManager::GetVolumeTask MOZ_FINAL : public nsISettingsServiceCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -862,7 +862,7 @@ static int
|
||||
FindProperty(const InfallibleTArray<BluetoothNamedValue>& aProperties,
|
||||
const char* aPropertyType)
|
||||
{
|
||||
for (int i = 0; i < aProperties.Length(); ++i) {
|
||||
for (size_t i = 0; i < aProperties.Length(); ++i) {
|
||||
if (aProperties[i].name().EqualsASCII(aPropertyType)) {
|
||||
return i;
|
||||
}
|
||||
@ -4086,7 +4086,7 @@ BluetoothDBusService::SendMetaData(const nsAString& aTitle,
|
||||
a2dp->GetTitle(prevTitle);
|
||||
a2dp->GetAlbum(prevAlbum);
|
||||
|
||||
if (aMediaNumber != a2dp->GetMediaNumber() ||
|
||||
if (aMediaNumber < 0 || (uint64_t)aMediaNumber != a2dp->GetMediaNumber() ||
|
||||
!aTitle.Equals(prevTitle) ||
|
||||
!aAlbum.Equals(prevAlbum)) {
|
||||
UpdateNotification(ControlEventId::EVENT_TRACK_CHANGED, aMediaNumber);
|
||||
|
@ -25,7 +25,7 @@ template<class T>
|
||||
class CameraClosedMessage : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CameraClosedMessage(nsMainThreadPtrHandle<T> aListener)
|
||||
explicit CameraClosedMessage(nsMainThreadPtrHandle<T> aListener)
|
||||
: mListener(aListener)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
@ -56,7 +56,7 @@ template<class T>
|
||||
class CameraClosedListenerProxy : public CameraControlListener
|
||||
{
|
||||
public:
|
||||
CameraClosedListenerProxy(T* aListener)
|
||||
explicit CameraClosedListenerProxy(T* aListener)
|
||||
: mListener(new nsMainThreadPtrHolder<T>(aListener))
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
@ -32,10 +32,9 @@ namespace android {
|
||||
|
||||
class GonkCameraSource;
|
||||
struct MOZ_EXPORT MediaSource;
|
||||
struct MOZ_EXPORT MediaWriter;
|
||||
struct MediaWriter;
|
||||
class MOZ_EXPORT MetaData;
|
||||
struct MOZ_EXPORT AudioSource;
|
||||
class MOZ_EXPORT MediaProfiles;
|
||||
class GonkCameraHardware;
|
||||
|
||||
struct GonkRecorder {
|
||||
|
@ -50,4 +50,10 @@ LOCAL_INCLUDES += [
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Suppress some GCC warnings being treated as errors:
|
||||
# - about attributes on forward declarations for types that are already
|
||||
# defined, which complains about an important MOZ_EXPORT for android::AString
|
||||
if CONFIG['GNU_CC']:
|
||||
CXXFLAGS += ['-Wno-error=attributes']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -18,12 +18,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1096146
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.requestFlakyTimeout("untriaged");
|
||||
|
||||
const kKeydownEvent = 0x1;
|
||||
const kScrollEvent = 0x2;
|
||||
|
||||
var gCurrentTest = 0;
|
||||
var gNumEvents = 0;
|
||||
var kTests = [
|
||||
{
|
||||
description: "no preventDefault at 'mozbrowserbeforekeydown'",
|
||||
@ -48,19 +47,29 @@ function frameScript()
|
||||
addEventListener('scroll', handler);
|
||||
}
|
||||
|
||||
|
||||
function waitAndVerifyResult(count) {
|
||||
if (gNumEvents >= 3 || count > 10) {
|
||||
is(kTests[gCurrentTest].resultEvents,
|
||||
kTests[gCurrentTest].expectedEvents,
|
||||
"verify result");
|
||||
runTests();
|
||||
} else {
|
||||
SimpleTest.requestFlakyTimeout("We must delay to wait for scroll/keydown events.");
|
||||
setTimeout(function () waitAndVerifyResult(count + 1), 100);
|
||||
}
|
||||
}
|
||||
|
||||
function testDefaultAction()
|
||||
{
|
||||
synthesizeKey('VK_END', {}, document.getElementById("embedded").contentWindow);
|
||||
setTimeout(function () {
|
||||
is(kTests[gCurrentTest].expectedEvents,
|
||||
kTests[gCurrentTest].resultEvents,
|
||||
"verify result");
|
||||
runTests();
|
||||
}, 500);
|
||||
waitAndVerifyResult(0);
|
||||
}
|
||||
|
||||
function prepareTest()
|
||||
{
|
||||
gNumEvents = 0;
|
||||
|
||||
var handler;
|
||||
if (kTests[gCurrentTest].doPreventDefault) {
|
||||
handler = preventDefaultHandler;
|
||||
@ -83,9 +92,11 @@ function prepareTest()
|
||||
var value = 0;
|
||||
switch(msg.json.type) {
|
||||
case "scroll":
|
||||
++gNumEvents;
|
||||
value = kScrollEvent;
|
||||
break;
|
||||
case "keydown":
|
||||
++gNumEvents;
|
||||
value = kKeydownEvent;
|
||||
break;
|
||||
default:
|
||||
@ -106,12 +117,14 @@ function prepareTest()
|
||||
function preventDefaultHandler(evt)
|
||||
{
|
||||
ok(true, "receive " + evt.type + " and do preventDefault.");
|
||||
++gNumEvents;
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
function noPreventDefaultHandler(evt)
|
||||
{
|
||||
ok(true, "receive " + evt.type + ".");
|
||||
++gNumEvents;
|
||||
}
|
||||
|
||||
function teardownHandler()
|
||||
@ -123,6 +136,7 @@ function teardownHandler()
|
||||
handler = noPreventDefaultHandler;
|
||||
}
|
||||
window.removeEventListener("mozbrowserbeforekeydown", handler);
|
||||
document.body.removeChild(document.getElementById("embedded"));
|
||||
|
||||
runTests();
|
||||
}
|
||||
|
@ -893,20 +893,12 @@ nsHTMLDocument::GetDomainURI()
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLDocument::GetDomain(nsAString& aDomain)
|
||||
{
|
||||
ErrorResult rv;
|
||||
GetDomain(aDomain, rv);
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLDocument::GetDomain(nsAString& aDomain, ErrorResult& rv)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri = GetDomainURI();
|
||||
|
||||
if (!uri) {
|
||||
SetDOMStringToNull(aDomain);
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString hostName;
|
||||
@ -918,6 +910,7 @@ nsHTMLDocument::GetDomain(nsAString& aDomain, ErrorResult& rv)
|
||||
// etc), just return an null string.
|
||||
SetDOMStringToNull(aDomain);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -168,7 +168,6 @@ public:
|
||||
// WebIDL API
|
||||
virtual JSObject* WrapNode(JSContext* aCx)
|
||||
MOZ_OVERRIDE;
|
||||
void GetDomain(nsAString& aDomain, mozilla::ErrorResult& rv);
|
||||
void SetDomain(const nsAString& aDomain, mozilla::ErrorResult& rv);
|
||||
void GetCookie(nsAString& aCookie, mozilla::ErrorResult& rv);
|
||||
void SetCookie(const nsAString& aCookie, mozilla::ErrorResult& rv);
|
||||
|
@ -578,4 +578,5 @@ skip-if = buildapp == 'b2g' || e10s
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
|
||||
support-files = file_bug871161-1.html file_bug871161-2.html
|
||||
[test_bug1013316.html]
|
||||
[test_bug1081037.html]
|
||||
|
||||
|
142
dom/html/test/test_bug1081037.html
Normal file
142
dom/html/test/test_bug1081037.html
Normal file
@ -0,0 +1,142 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1081037
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1081037</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1081037 **/
|
||||
|
||||
function shouldThrow(fun, msg, ex, todo) {
|
||||
try {
|
||||
fun();
|
||||
ok(todo, msg);
|
||||
} catch (e) {
|
||||
ok(new RegExp(ex).test(e), msg + " (thrown:" + e + ")")
|
||||
}
|
||||
}
|
||||
|
||||
var Foo = document.registerElement('x-foo', {
|
||||
prototype: {bar: 5}
|
||||
});
|
||||
|
||||
Foo.prototype.bar = 6;
|
||||
var foo = new Foo();
|
||||
is(foo.bar, 6, "prototype of the ctor returned from registerElement works");
|
||||
|
||||
var protoDesc = Object.getOwnPropertyDescriptor(Foo, "prototype");
|
||||
is(protoDesc.configurable, false, "proto should be non-configurable");
|
||||
is(protoDesc.enumerable, false, "proto should be non-enumerable");
|
||||
is(protoDesc.writable, false, "proto should be non-writable");
|
||||
|
||||
// TODO: FIXME!
|
||||
shouldThrow(function() {
|
||||
document.registerElement('x-foo2', {
|
||||
prototype: Foo.prototype
|
||||
});
|
||||
},
|
||||
"if proto is an interface prototype object, registerElement should throw",
|
||||
"not supported",
|
||||
/* todo = */ true);
|
||||
|
||||
var nonConfigReadonlyProto = Object.create(HTMLElement.prototype,
|
||||
{ constructor: { configurable: false, writable: false, value: 42 } });
|
||||
|
||||
shouldThrow(function() {
|
||||
document.registerElement('x-nonconfig-readonly', {
|
||||
prototype: nonConfigReadonlyProto
|
||||
});
|
||||
},
|
||||
"non-configurable and not-writable constructor property",
|
||||
"not supported");
|
||||
|
||||
|
||||
// this is not defined in current spec:
|
||||
var readonlyProto = Object.create(HTMLElement.prototype,
|
||||
{ constructor: { configurable: true, writable: false, value: 42 } });
|
||||
|
||||
var Readonly = document.registerElement('x-nonconfig-readonly', {
|
||||
prototype: readonlyProto
|
||||
});
|
||||
|
||||
is(Readonly.prototype, readonlyProto, "configurable readonly constructor property");
|
||||
|
||||
var handler = {
|
||||
getOwnPropertyDescriptor: function(target, name) {
|
||||
return name == "constructor" ? undefined : Object.getOwnPropertyDescriptor(target,name);
|
||||
},
|
||||
defineProperty: function(target, name, propertyDescriptor) {
|
||||
if (name == "constructor") {
|
||||
throw "spec this";
|
||||
}
|
||||
|
||||
return Object.defineProperty(target, name, propertyDescriptor);
|
||||
},
|
||||
has: function(target, name) {
|
||||
if (name == "constructor") {
|
||||
return false;
|
||||
}
|
||||
return name in target;
|
||||
}
|
||||
};
|
||||
var proxy = new Proxy({}, handler);
|
||||
|
||||
shouldThrow(function() {
|
||||
document.registerElement('x-proxymagic', {
|
||||
prototype: proxy
|
||||
});
|
||||
},
|
||||
"proxy magic",
|
||||
"spec this");
|
||||
|
||||
var getOwn = 0;
|
||||
var defineProp = 0;
|
||||
var _has = 0;
|
||||
var handler2 = {
|
||||
getOwnPropertyDescriptor: function(target, name) {
|
||||
if (name == "constructor") {
|
||||
getOwn++;
|
||||
}
|
||||
return Object.getOwnPropertyDescriptor(target,name);
|
||||
},
|
||||
defineProperty: function(target, name, propertyDescriptor) {
|
||||
if (name == "constructor") {
|
||||
defineProp++;
|
||||
}
|
||||
return Object.defineProperty(target, name, propertyDescriptor);
|
||||
},
|
||||
has: function(target, name) {
|
||||
if (name == "constructor") {
|
||||
_has++;
|
||||
}
|
||||
return name in target;
|
||||
}
|
||||
};
|
||||
var proxy2 = new Proxy({}, handler2);
|
||||
|
||||
document.registerElement('x-proxymagic2', {
|
||||
prototype: proxy2
|
||||
});
|
||||
|
||||
is(getOwn, 1, "number of getOwnPropertyDescriptor calls from registerElement: " + getOwn);
|
||||
is(defineProp, 1, "number of defineProperty calls from registerElement: " + defineProp);
|
||||
is(_has, 1, "number of 'has' calls from registerElement: " + _has);
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081037">Mozilla Bug 1081037</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -59,7 +59,7 @@ public:
|
||||
IsDisplaySpnRequired() const;
|
||||
|
||||
protected:
|
||||
~IccInfo() {}
|
||||
virtual ~IccInfo() {}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
@ -125,7 +125,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
ThreadLocal(const nsID& aBackgroundChildLoggingId);
|
||||
explicit ThreadLocal(const nsID& aBackgroundChildLoggingId);
|
||||
~ThreadLocal();
|
||||
|
||||
ThreadLocal() MOZ_DELETE;
|
||||
|
@ -5080,7 +5080,7 @@ class DatabaseLoggingInfo MOZ_FINAL
|
||||
LoggingInfo mLoggingInfo;
|
||||
|
||||
public:
|
||||
DatabaseLoggingInfo(const LoggingInfo& aLoggingInfo)
|
||||
explicit DatabaseLoggingInfo(const LoggingInfo& aLoggingInfo)
|
||||
: mLoggingInfo(aLoggingInfo)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
@ -2321,8 +2321,6 @@ public:
|
||||
static void
|
||||
DoNuwaFork()
|
||||
{
|
||||
NS_ASSERTION(NuwaSpawnPrepare != nullptr,
|
||||
"NuwaSpawnPrepare() is not available!");
|
||||
NuwaSpawnPrepare(); // NuwaSpawn will be blocked.
|
||||
|
||||
{
|
||||
@ -2331,8 +2329,6 @@ DoNuwaFork()
|
||||
}
|
||||
|
||||
// IOThread should be blocked here for waiting NuwaSpawn().
|
||||
NS_ASSERTION(NuwaSpawnWait != nullptr,
|
||||
"NuwaSpawnWait() is not available!");
|
||||
NuwaSpawnWait(); // Now! NuwaSpawn can go.
|
||||
// Here, we can make sure the spawning was finished.
|
||||
}
|
||||
|
@ -75,6 +75,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsAnonymousTemporaryFile.h"
|
||||
#include "nsAppRunner.h"
|
||||
@ -1749,6 +1750,9 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID);
|
||||
|
||||
if (AbnormalShutdown == why) {
|
||||
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
|
||||
NS_LITERAL_CSTRING("content"), 1);
|
||||
|
||||
props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
@ -2588,8 +2592,8 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
size_t numNuwaPrefUpdates = sNuwaPrefUpdates ?
|
||||
sNuwaPrefUpdates->Length() : 0;
|
||||
// Resend pref updates to the forked child.
|
||||
for (int i = 0; i < numNuwaPrefUpdates; i++) {
|
||||
content->SendPreferenceUpdate(sNuwaPrefUpdates->ElementAt(i));
|
||||
for (size_t i = 0; i < numNuwaPrefUpdates; i++) {
|
||||
mozilla::unused << content->SendPreferenceUpdate(sNuwaPrefUpdates->ElementAt(i));
|
||||
}
|
||||
|
||||
// Update offline settings.
|
||||
@ -2598,7 +2602,7 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
ClipboardCapabilities clipboardCaps;
|
||||
RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries,
|
||||
&clipboardCaps);
|
||||
content->SendSetOffline(isOffline);
|
||||
mozilla::unused << content->SendSetOffline(isOffline);
|
||||
MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() &&
|
||||
!clipboardCaps.supportsFindClipboard(),
|
||||
"Unexpected values");
|
||||
@ -2864,7 +2868,7 @@ ContentParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc, PDocAcc
|
||||
return parentDoc->AddChildDoc(doc, aParentID);
|
||||
} else {
|
||||
MOZ_ASSERT(!aParentID);
|
||||
GetAccService()->RemoteDocAdded(doc);
|
||||
a11y::DocManager::RemoteDocAdded(doc);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "nsXULAppAPI.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsICrashService.h"
|
||||
@ -171,21 +173,27 @@ CrashReporterParent::NotifyCrashService()
|
||||
int32_t processType;
|
||||
int32_t crashType = nsICrashService::CRASH_TYPE_CRASH;
|
||||
|
||||
nsCString telemetryKey;
|
||||
|
||||
switch (mProcessType) {
|
||||
case GeckoProcessType_Content:
|
||||
processType = nsICrashService::PROCESS_TYPE_CONTENT;
|
||||
telemetryKey.AssignLiteral("content");
|
||||
break;
|
||||
case GeckoProcessType_Plugin: {
|
||||
processType = nsICrashService::PROCESS_TYPE_PLUGIN;
|
||||
telemetryKey.AssignLiteral("plugin");
|
||||
nsAutoCString val;
|
||||
if (mNotes.Get(NS_LITERAL_CSTRING("PluginHang"), &val) &&
|
||||
val.Equals(NS_LITERAL_CSTRING("1"))) {
|
||||
crashType = nsICrashService::CRASH_TYPE_HANG;
|
||||
telemetryKey.AssignLiteral("pluginhang");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GeckoProcessType_GMPlugin:
|
||||
processType = nsICrashService::PROCESS_TYPE_GMPLUGIN;
|
||||
telemetryKey.AssignLiteral("gmplugin");
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("unknown process type");
|
||||
@ -193,6 +201,7 @@ CrashReporterParent::NotifyCrashService()
|
||||
}
|
||||
|
||||
crashService->AddCrash(processType, crashType, mChildDumpID);
|
||||
Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/PreallocatedProcessManager.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
@ -111,11 +112,13 @@ PreallocatedProcessManagerImpl::Singleton()
|
||||
NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver)
|
||||
|
||||
PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
|
||||
: mEnabled(false)
|
||||
:
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
, mPreallocateAppProcessTask(nullptr)
|
||||
mPreallocateAppProcessTask(nullptr)
|
||||
, mIsNuwaReady(false)
|
||||
,
|
||||
#endif
|
||||
mEnabled(false)
|
||||
, mShutdown(false)
|
||||
{}
|
||||
|
||||
@ -292,7 +295,7 @@ PreallocatedProcessManagerImpl::PublishSpareProcess(ContentParent* aContent)
|
||||
AutoJSContext cx;
|
||||
nsCOMPtr<nsIMessageBroadcaster> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
nsresult rv = ppmm->BroadcastAsyncMessage(
|
||||
mozilla::unused << ppmm->BroadcastAsyncMessage(
|
||||
NS_LITERAL_STRING("TEST-ONLY:nuwa-add-new-process"),
|
||||
JS::NullHandleValue, JS::NullHandleValue, cx, 1);
|
||||
}
|
||||
@ -338,7 +341,7 @@ PreallocatedProcessManagerImpl::OnNuwaReady()
|
||||
AutoJSContext cx;
|
||||
nsCOMPtr<nsIMessageBroadcaster> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
nsresult rv = ppmm->BroadcastAsyncMessage(
|
||||
mozilla::unused << ppmm->BroadcastAsyncMessage(
|
||||
NS_LITERAL_STRING("TEST-ONLY:nuwa-ready"),
|
||||
JS::NullHandleValue, JS::NullHandleValue, cx, 1);
|
||||
}
|
||||
@ -355,7 +358,7 @@ PreallocatedProcessManagerImpl::PreallocatedProcessReady()
|
||||
void
|
||||
PreallocatedProcessManagerImpl::NuwaFork()
|
||||
{
|
||||
mPreallocatedAppProcess->SendNuwaFork();
|
||||
mozilla::unused << mPreallocatedAppProcess->SendNuwaFork();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -19,3 +19,8 @@ LoadingMixedActiveContent=Loading mixed (insecure) active content on a secure pa
|
||||
LoadingMixedDisplayContent=Loading mixed (insecure) display content on a secure page "%1$S"
|
||||
# LOCALIZATION NOTE: Do not translate "allow-scripts", "allow-same-origin", "sandbox" or "iframe"
|
||||
BothAllowScriptsAndSameOriginPresent=An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can remove its sandboxing.
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "SSL 3.0".
|
||||
WeakProtocolVersionWarning=This site uses the protocol SSL 3.0 for encryption, which is deprecated and insecure.
|
||||
# LOCALIZATION NOTE: Do not translate "RC4".
|
||||
WeakCipherSuiteWarning=This site uses the cipher RC4 for encryption, which is deprecated and insecure.
|
||||
|
@ -125,8 +125,7 @@ void MediaDecoder::SetDormantIfNecessary(bool aDormant)
|
||||
|
||||
if (!mDecoderStateMachine ||
|
||||
!mDecoderStateMachine->IsDormantNeeded() ||
|
||||
mPlayState == PLAY_STATE_SHUTDOWN ||
|
||||
mIsDormant == aDormant) {
|
||||
mPlayState == PLAY_STATE_SHUTDOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -140,14 +139,11 @@ void MediaDecoder::SetDormantIfNecessary(bool aDormant)
|
||||
mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
|
||||
|
||||
mNextState = mPlayState;
|
||||
mIsDormant = true;
|
||||
mIsExitingDormant = false;
|
||||
ChangeState(PLAY_STATE_LOADING);
|
||||
} else if (!aDormant && mPlayState == PLAY_STATE_LOADING) {
|
||||
} else {
|
||||
// exit dormant state
|
||||
// trigger to state machine.
|
||||
mDecoderStateMachine->SetDormant(false);
|
||||
mIsExitingDormant = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +151,7 @@ void MediaDecoder::Pause()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if ((mPlayState == PLAY_STATE_LOADING && mIsDormant) ||
|
||||
if (mPlayState == PLAY_STATE_LOADING ||
|
||||
mPlayState == PLAY_STATE_SEEKING ||
|
||||
mPlayState == PLAY_STATE_ENDED) {
|
||||
mNextState = PLAY_STATE_PAUSED;
|
||||
@ -432,8 +428,6 @@ MediaDecoder::MediaDecoder() :
|
||||
mMediaSeekable(true),
|
||||
mSameOriginMedia(false),
|
||||
mReentrantMonitor("media.decoder"),
|
||||
mIsDormant(false),
|
||||
mIsExitingDormant(false),
|
||||
mPlayState(PLAY_STATE_LOADING),
|
||||
mNextState(PLAY_STATE_PAUSED),
|
||||
mIgnoreProgressData(false),
|
||||
@ -600,12 +594,13 @@ nsresult MediaDecoder::Play()
|
||||
}
|
||||
nsresult res = ScheduleStateMachineThread();
|
||||
NS_ENSURE_SUCCESS(res,res);
|
||||
if ((mPlayState == PLAY_STATE_LOADING && mIsDormant) || mPlayState == PLAY_STATE_SEEKING) {
|
||||
if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) {
|
||||
mNextState = PLAY_STATE_PLAYING;
|
||||
return NS_OK;
|
||||
}
|
||||
if (mPlayState == PLAY_STATE_ENDED)
|
||||
if (mPlayState == PLAY_STATE_ENDED) {
|
||||
return Seek(0, SeekTarget::PrevSyncPoint);
|
||||
}
|
||||
|
||||
ChangeState(PLAY_STATE_PLAYING);
|
||||
return NS_OK;
|
||||
@ -628,7 +623,7 @@ nsresult MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
|
||||
// If we are already in the seeking state, then setting mRequestedSeekTarget
|
||||
// above will result in the new seek occurring when the current seek
|
||||
// completes.
|
||||
if ((mPlayState != PLAY_STATE_LOADING || !mIsDormant) && mPlayState != PLAY_STATE_SEEKING) {
|
||||
if (mPlayState != PLAY_STATE_LOADING && mPlayState != PLAY_STATE_SEEKING) {
|
||||
bool paused = false;
|
||||
if (mOwner) {
|
||||
paused = mOwner->GetPaused();
|
||||
@ -703,12 +698,6 @@ void MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if (mPlayState == PLAY_STATE_LOADING && mIsDormant && !mIsExitingDormant) {
|
||||
return;
|
||||
} else if (mPlayState == PLAY_STATE_LOADING && mIsDormant && mIsExitingDormant) {
|
||||
mIsDormant = false;
|
||||
mIsExitingDormant = false;
|
||||
}
|
||||
mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
|
||||
// Duration has changed so we should recompute playback rate
|
||||
UpdatePlaybackRate();
|
||||
@ -741,10 +730,6 @@ void MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo)
|
||||
aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
|
||||
aInfo->HasAudio(), aInfo->HasVideo());
|
||||
|
||||
if (mPlayState == PLAY_STATE_LOADING && mIsDormant && !mIsExitingDormant) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInfo = aInfo.forget();
|
||||
|
||||
if (mOwner) {
|
||||
@ -829,7 +814,8 @@ bool MediaDecoder::IsSameOriginMedia()
|
||||
bool MediaDecoder::IsSeeking() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mPlayState == PLAY_STATE_SEEKING;
|
||||
return mPlayState == PLAY_STATE_SEEKING ||
|
||||
(mPlayState == PLAY_STATE_LOADING && mRequestedSeekTarget.IsValid());
|
||||
}
|
||||
|
||||
bool MediaDecoder::IsEnded() const
|
||||
@ -844,7 +830,7 @@ void MediaDecoder::PlaybackEnded()
|
||||
|
||||
if (mShuttingDown ||
|
||||
mPlayState == PLAY_STATE_SEEKING ||
|
||||
(mPlayState == PLAY_STATE_LOADING && mIsDormant)) {
|
||||
(mPlayState == PLAY_STATE_LOADING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1141,8 +1127,7 @@ void MediaDecoder::ChangeState(PlayState aState)
|
||||
mNextState = PLAY_STATE_PAUSED;
|
||||
}
|
||||
|
||||
if ((mPlayState == PLAY_STATE_LOADING && mIsDormant && aState != PLAY_STATE_SHUTDOWN) ||
|
||||
mPlayState == PLAY_STATE_SHUTDOWN) {
|
||||
if (mPlayState == PLAY_STATE_SHUTDOWN) {
|
||||
GetReentrantMonitor().NotifyAll();
|
||||
return;
|
||||
}
|
||||
@ -1167,11 +1152,6 @@ void MediaDecoder::ChangeState(PlayState aState)
|
||||
|
||||
ApplyStateToStateMachine(mPlayState);
|
||||
|
||||
if (aState!= PLAY_STATE_LOADING) {
|
||||
mIsDormant = false;
|
||||
mIsExitingDormant = false;
|
||||
}
|
||||
|
||||
GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
|
@ -1124,14 +1124,6 @@ protected:
|
||||
// without holding the monitor.
|
||||
nsAutoPtr<DecodedStreamData> mDecodedStream;
|
||||
|
||||
// True if this decoder is in dormant state.
|
||||
// Should be true only when PlayState is PLAY_STATE_LOADING.
|
||||
bool mIsDormant;
|
||||
|
||||
// True if this decoder is exiting from dormant state.
|
||||
// Should be true only when PlayState is PLAY_STATE_LOADING.
|
||||
bool mIsExitingDormant;
|
||||
|
||||
// Set to one of the valid play states.
|
||||
// This can only be changed on the main thread while holding the decoder
|
||||
// monitor. Thus, it can be safely read while holding the decoder monitor
|
||||
|
@ -1570,7 +1570,7 @@ void MediaDecoderStateMachine::Seek(const SeekTarget& aTarget)
|
||||
NS_ASSERTION(mState > DECODER_STATE_DECODING_METADATA,
|
||||
"We should have got duration already");
|
||||
|
||||
if (mState <= DECODER_STATE_DECODING_FIRSTFRAME) {
|
||||
if (mState < DECODER_STATE_DECODING) {
|
||||
DECODER_LOG("Seek() Not Enough Data to continue at this stage, queuing seek");
|
||||
mQueuedSeekTarget = aTarget;
|
||||
return;
|
||||
@ -2491,10 +2491,9 @@ MediaDecoderStateMachine::ShutdownReader()
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::FinishShutdown(bool aSuccess)
|
||||
MediaDecoderStateMachine::FinishShutdown()
|
||||
{
|
||||
MOZ_ASSERT(OnStateMachineThread());
|
||||
MOZ_ASSERT(aSuccess);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
// The reader's listeners hold references to the state machine,
|
||||
|
@ -163,7 +163,7 @@ public:
|
||||
void SetDormant(bool aDormant);
|
||||
void Shutdown();
|
||||
void ShutdownReader();
|
||||
void FinishShutdown(bool aSuccess);
|
||||
void FinishShutdown();
|
||||
|
||||
// Called from the main thread to get the duration. The decoder monitor
|
||||
// must be obtained before calling this. It is in units of microseconds.
|
||||
|
@ -155,6 +155,32 @@ protected:
|
||||
const char* mCallSite;
|
||||
};
|
||||
|
||||
/*
|
||||
* We create two overloads for invoking Resolve/Reject Methods so as to
|
||||
* make the resolve/reject value argument "optional".
|
||||
*/
|
||||
|
||||
// Avoid confusing the compiler when the callback accepts T* but the ValueType
|
||||
// is nsRefPtr<T>. See bug 1109954 comment 6.
|
||||
template <typename T>
|
||||
struct NonDeduced
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename ThisType, typename ValueType>
|
||||
static void InvokeCallbackMethod(ThisType* aThisVal, void(ThisType::*aMethod)(ValueType),
|
||||
typename NonDeduced<ValueType>::type aValue)
|
||||
{
|
||||
((*aThisVal).*aMethod)(aValue);
|
||||
}
|
||||
|
||||
template<typename ThisType, typename ValueType>
|
||||
static void InvokeCallbackMethod(ThisType* aThisVal, void(ThisType::*aMethod)(), ValueType aValue)
|
||||
{
|
||||
((*aThisVal).*aMethod)();
|
||||
}
|
||||
|
||||
template<typename TargetType, typename ThisType,
|
||||
typename ResolveMethodType, typename RejectMethodType>
|
||||
class ThenValue : public ThenValueBase
|
||||
@ -187,12 +213,12 @@ protected:
|
||||
protected:
|
||||
virtual void DoResolve(ResolveValueType aResolveValue)
|
||||
{
|
||||
((*mThisVal).*mResolveMethod)(aResolveValue);
|
||||
InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aResolveValue);
|
||||
}
|
||||
|
||||
virtual void DoReject(RejectValueType aRejectValue)
|
||||
{
|
||||
((*mThisVal).*mRejectMethod)(aRejectValue);
|
||||
InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aRejectValue);
|
||||
}
|
||||
|
||||
virtual ~ThenValue() {}
|
||||
|
@ -1085,21 +1085,6 @@ RTCPeerConnection.prototype = {
|
||||
dict.id != undefined ? dict.id : 0xFFFF
|
||||
);
|
||||
return channel;
|
||||
},
|
||||
|
||||
connectDataConnection: function(localport, remoteport, numstreams) {
|
||||
if (numstreams == undefined || numstreams <= 0) {
|
||||
numstreams = 16;
|
||||
}
|
||||
this._queueOrRun({
|
||||
func: this._connectDataConnection,
|
||||
args: [localport, remoteport, numstreams],
|
||||
wait: false
|
||||
});
|
||||
},
|
||||
|
||||
_connectDataConnection: function(localport, remoteport, numstreams) {
|
||||
this._impl.connectDataConnection(localport, remoteport, numstreams);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -50,3 +50,9 @@ CXXFLAGS += [
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Suppress some GCC warnings being treated as errors:
|
||||
# - about attributes on forward declarations for types that are already
|
||||
# defined, which complains about an important MOZ_EXPORT for android::AString
|
||||
if CONFIG['GNU_CC']:
|
||||
CXXFLAGS += ['-Wno-error=attributes']
|
||||
|
@ -68,7 +68,9 @@ public:
|
||||
aSample);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
} else if (GMP_FAILED(aResult)) {
|
||||
mDecryptor->mCallback->Error();
|
||||
if (mDecryptor->mCallback) {
|
||||
mDecryptor->mCallback->Error();
|
||||
}
|
||||
MOZ_ASSERT(!aSample);
|
||||
} else {
|
||||
RefPtr<nsIRunnable> task;
|
||||
@ -150,6 +152,7 @@ public:
|
||||
mTaskQueue->AwaitShutdownAndIdle();
|
||||
mTaskQueue = nullptr;
|
||||
mProxy = nullptr;
|
||||
mCallback = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,8 @@
|
||||
#include <stagefright/foundation/ALooper.h>
|
||||
#include "media/openmax/OMX_Audio.h"
|
||||
|
||||
#define LOG_TAG "GonkAudioDecoderManager"
|
||||
#include <android/log.h>
|
||||
#define ALOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__)
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* GetDemuxerLog();
|
||||
@ -42,8 +41,8 @@ GonkAudioDecoderManager::GonkAudioDecoderManager(
|
||||
: mAudioChannels(aConfig.channel_count)
|
||||
, mAudioRate(aConfig.samples_per_second)
|
||||
, mAudioProfile(aConfig.aac_profile)
|
||||
, mAudioBuffer(nullptr)
|
||||
, mUseAdts(true)
|
||||
, mAudioBuffer(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkAudioDecoderManager);
|
||||
MOZ_ASSERT(mAudioChannels);
|
||||
@ -77,7 +76,7 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
}
|
||||
sp<AMessage> format = new AMessage;
|
||||
// Fixed values
|
||||
ALOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate);
|
||||
GADM_LOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate);
|
||||
format->setString("mime", "audio/mp4a-latm");
|
||||
format->setInt32("channel-count", mAudioChannels);
|
||||
format->setInt32("sample-rate", mAudioRate);
|
||||
@ -93,7 +92,7 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
if (rv == OK) {
|
||||
return mDecoder;
|
||||
} else {
|
||||
ALOG("Failed to input codec specific data!");
|
||||
GADM_LOG("Failed to input codec specific data!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -101,7 +100,7 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
nsresult
|
||||
GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
||||
if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
|
||||
ALOG("Audio Buffer is not valid!");
|
||||
GADM_LOG("Audio Buffer is not valid!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -167,7 +166,7 @@ GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
case android::INFO_OUTPUT_BUFFERS_CHANGED:
|
||||
{
|
||||
// If the format changed, update our cached info.
|
||||
ALOG("Decoder format changed");
|
||||
GADM_LOG("Decoder format changed");
|
||||
return Output(aStreamOffset, aOutData);
|
||||
}
|
||||
case -EAGAIN:
|
||||
@ -176,14 +175,14 @@ GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
}
|
||||
case android::ERROR_END_OF_STREAM:
|
||||
{
|
||||
ALOG("Got EOS frame!");
|
||||
GADM_LOG("Got EOS frame!");
|
||||
nsRefPtr<AudioData> data;
|
||||
nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data));
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
// For EOS, no need to do any thing.
|
||||
return NS_ERROR_ABORT;
|
||||
} else if (rv != NS_OK || data == nullptr) {
|
||||
ALOG("Failed to create audio data!");
|
||||
GADM_LOG("Failed to create audio data!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
aOutData = data;
|
||||
@ -191,12 +190,12 @@ GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
}
|
||||
case -ETIMEDOUT:
|
||||
{
|
||||
ALOG("Timeout. can try again next time");
|
||||
GADM_LOG("Timeout. can try again next time");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ALOG("Decoder failed, err=%d", err);
|
||||
GADM_LOG("Decoder failed, err=%d", err);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
@ -221,7 +220,7 @@ nsresult
|
||||
GonkAudioDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
ALOG("Decoder is not inited");
|
||||
GADM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (aSample && mUseAdts) {
|
||||
@ -232,7 +231,7 @@ GonkAudioDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
mAudioProfile,
|
||||
aSample);
|
||||
if (!rv) {
|
||||
ALOG("Failed to apply ADTS header");
|
||||
GADM_LOG("Failed to apply ADTS header");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,8 @@
|
||||
#include "MediaCodecProxy.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#define LOG_TAG "GonkMediaDataDecoder(blake)"
|
||||
#include <android/log.h>
|
||||
#define ALOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder(blake)", __VA_ARGS__)
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* GetDemuxerLog();
|
||||
@ -76,7 +75,7 @@ GonkMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
|
||||
nsresult rv = mManager->Input(aSample);
|
||||
if (rv != NS_OK) {
|
||||
NS_WARNING("GonkAudioDecoder failed to input data");
|
||||
ALOG("Failed to input data err: %d",rv);
|
||||
GMDD_LOG("Failed to input data err: %d",rv);
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
@ -111,7 +110,7 @@ GonkMediaDataDecoder::ProcessOutput()
|
||||
}
|
||||
if (rv != NS_OK) {
|
||||
NS_WARNING("GonkMediaDataDecoder failed to output data");
|
||||
ALOG("Failed to output data");
|
||||
GMDD_LOG("Failed to output data");
|
||||
// GonkDecoderManangers report NS_ERROR_ABORT when EOS is reached.
|
||||
if (rv == NS_ERROR_ABORT) {
|
||||
if (output) {
|
||||
|
@ -29,9 +29,8 @@
|
||||
|
||||
#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000
|
||||
|
||||
#define LOG_TAG "GonkVideoDecoderManager"
|
||||
#include <android/log.h>
|
||||
#define ALOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__)
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* GetDemuxerLog();
|
||||
@ -93,7 +92,7 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
// that our video frame creation code doesn't overflow.
|
||||
nsIntSize frameSize(mVideoWidth, mVideoHeight);
|
||||
if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
|
||||
ALOG("It is not a valid region");
|
||||
GVDM_LOG("It is not a valid region");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -175,12 +174,12 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
||||
int32_t keyFrame;
|
||||
|
||||
if (mVideoBuffer == nullptr) {
|
||||
ALOG("Video Buffer is not valid!");
|
||||
GVDM_LOG("Video Buffer is not valid!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
|
||||
ALOG("Decoder did not return frame time");
|
||||
GVDM_LOG("Decoder did not return frame time");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -234,7 +233,7 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
||||
picture);
|
||||
} else {
|
||||
if (!mVideoBuffer->data()) {
|
||||
ALOG("No data in Video Buffer!");
|
||||
GVDM_LOG("No data in Video Buffer!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
uint8_t *yuv420p_buffer = (uint8_t *)mVideoBuffer->data();
|
||||
@ -252,7 +251,7 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
||||
if (mColorConverter.convertDecoderOutputToI420(mVideoBuffer->data(),
|
||||
mFrameInfo.mWidth, mFrameInfo.mHeight, crop, yuv420p_buffer) != OK) {
|
||||
ReleaseVideoBuffer();
|
||||
ALOG("Color conversion failed!");
|
||||
GVDM_LOG("Color conversion failed!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
stride = mFrameInfo.mWidth;
|
||||
@ -330,7 +329,7 @@ GonkVideoDecoderManager::SetVideoFormat()
|
||||
!codecFormat->findInt32("slice-height", &slice_height) ||
|
||||
!codecFormat->findInt32("color-format", &color_format) ||
|
||||
!codecFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
|
||||
ALOG("Failed to find values");
|
||||
GVDM_LOG("Failed to find values");
|
||||
return false;
|
||||
}
|
||||
mFrameInfo.mWidth = width;
|
||||
@ -341,12 +340,12 @@ GonkVideoDecoderManager::SetVideoFormat()
|
||||
|
||||
nsIntSize displaySize(width, height);
|
||||
if (!IsValidVideoRegion(mInitialFrame, mPicture, displaySize)) {
|
||||
ALOG("It is not a valid region");
|
||||
GVDM_LOG("It is not a valid region");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ALOG("Fail to get output format");
|
||||
GVDM_LOG("Fail to get output format");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -358,7 +357,7 @@ GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
aOutData = nullptr;
|
||||
status_t err;
|
||||
if (mDecoder == nullptr) {
|
||||
ALOG("Decoder is not inited");
|
||||
GVDM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
err = mDecoder->Output(&mVideoBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
|
||||
@ -372,7 +371,7 @@ GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
// Decoder outputs a empty video buffer, try again
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
} else if (rv != NS_OK || data == nullptr) {
|
||||
ALOG("Failed to create VideoData");
|
||||
GVDM_LOG("Failed to create VideoData");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
aOutData = data;
|
||||
@ -381,7 +380,7 @@ GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
case android::INFO_FORMAT_CHANGED:
|
||||
{
|
||||
// If the format changed, update our cached info.
|
||||
ALOG("Decoder format changed");
|
||||
GVDM_LOG("Decoder format changed");
|
||||
if (!SetVideoFormat()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
@ -400,7 +399,7 @@ GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
}
|
||||
case android::ERROR_END_OF_STREAM:
|
||||
{
|
||||
ALOG("Got the EOS frame!");
|
||||
GVDM_LOG("Got the EOS frame!");
|
||||
nsRefPtr<VideoData> data;
|
||||
nsresult rv = CreateVideoData(aStreamOffset, getter_AddRefs(data));
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
@ -408,7 +407,7 @@ GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
if (rv != NS_OK || data == nullptr) {
|
||||
ALOG("Failed to create video data");
|
||||
GVDM_LOG("Failed to create video data");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
aOutData = data;
|
||||
@ -416,12 +415,12 @@ GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
}
|
||||
case -ETIMEDOUT:
|
||||
{
|
||||
ALOG("Timeout. can try again next time");
|
||||
GVDM_LOG("Timeout. can try again next time");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ALOG("Decoder failed, err=%d", err);
|
||||
GVDM_LOG("Decoder failed, err=%d", err);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
@ -440,7 +439,7 @@ nsresult
|
||||
GonkVideoDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
ALOG("Decoder is not inited");
|
||||
GVDM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
status_t rv;
|
||||
@ -488,7 +487,7 @@ GonkVideoDecoderManager::codecReserved()
|
||||
if (mNativeWindow != nullptr) {
|
||||
surface = new Surface(mNativeWindow->getBufferQueue());
|
||||
}
|
||||
status_t err = mDecoder->configure(format, surface, nullptr, 0);
|
||||
mDecoder->configure(format, surface, nullptr, 0);
|
||||
mDecoder->Prepare();
|
||||
|
||||
if (mHandler != nullptr) {
|
||||
@ -519,7 +518,7 @@ GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
{
|
||||
// Our decode may have acquired the hardware resource that it needs
|
||||
// to start. Notify the state machine to resume loading metadata.
|
||||
ALOG("CodecReserved!");
|
||||
GVDM_LOG("CodecReserved!");
|
||||
mReaderCallback->NotifyResourcesStatusChanged();
|
||||
break;
|
||||
}
|
||||
@ -650,7 +649,7 @@ void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffers()
|
||||
}
|
||||
|
||||
void GonkVideoDecoderManager::ReleaseMediaResources() {
|
||||
ALOG("ReleseMediaResources");
|
||||
GVDM_LOG("ReleseMediaResources");
|
||||
ReleaseAllPendingVideoBuffers();
|
||||
mDecoder->ReleaseMediaResources();
|
||||
}
|
||||
|
@ -21,8 +21,8 @@
|
||||
using namespace android;
|
||||
|
||||
namespace android {
|
||||
struct MOZ_EXPORT ALooper;
|
||||
class MOZ_EXPORT MediaBuffer;
|
||||
struct ALooper;
|
||||
class MediaBuffer;
|
||||
struct MOZ_EXPORT AString;
|
||||
class GonkNativeWindow;
|
||||
} // namespace android
|
||||
|
@ -22,6 +22,16 @@ LOCAL_INCLUDES += [
|
||||
]
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Suppress some GCC/clang warnings being treated as errors:
|
||||
# - about attributes on forward declarations for types that are already
|
||||
# defined, which complains about an important MOZ_EXPORT for android::AString
|
||||
# - about multi-character constants which are used in codec-related code
|
||||
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-error=attributes',
|
||||
'-Wno-error=multichar'
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -30,6 +30,8 @@ using CrashReporter::AnnotationTable;
|
||||
using CrashReporter::GetIDFromMinidump;
|
||||
#endif
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef LOG
|
||||
@ -653,6 +655,8 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
LOGD(("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int) aWhy));
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
if (AbnormalShutdown == aWhy) {
|
||||
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
|
||||
NS_LITERAL_CSTRING("gmplugin"), 1);
|
||||
nsString dumpID;
|
||||
GetCrashID(dumpID);
|
||||
nsString id;
|
||||
|
@ -299,14 +299,13 @@ MediaSourceReader::Shutdown()
|
||||
MOZ_ASSERT(mMediaSourceShutdownPromise.IsEmpty());
|
||||
nsRefPtr<ShutdownPromise> p = mMediaSourceShutdownPromise.Ensure(__func__);
|
||||
|
||||
ContinueShutdown(true);
|
||||
ContinueShutdown();
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::ContinueShutdown(bool aSuccess)
|
||||
MediaSourceReader::ContinueShutdown()
|
||||
{
|
||||
MOZ_ASSERT(aSuccess);
|
||||
if (mTrackBuffers.Length()) {
|
||||
mTrackBuffers[0]->Shutdown()->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::ContinueShutdown,
|
||||
|
@ -180,7 +180,7 @@ private:
|
||||
|
||||
bool mHasEssentialTrackBuffers;
|
||||
|
||||
void ContinueShutdown(bool aSuccess);
|
||||
void ContinueShutdown();
|
||||
MediaPromiseHolder<ShutdownPromise> mMediaSourceShutdownPromise;
|
||||
#ifdef MOZ_FMP4
|
||||
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
||||
|
@ -112,9 +112,8 @@ TrackBuffer::Shutdown()
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::ContinueShutdown(bool aSuccess)
|
||||
TrackBuffer::ContinueShutdown()
|
||||
{
|
||||
MOZ_ASSERT(aSuccess);
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
if (mDecoders.Length()) {
|
||||
mDecoders[0]->GetReader()->Shutdown()
|
||||
@ -349,6 +348,10 @@ TrackBuffer::NewDecoder()
|
||||
bool
|
||||
TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
|
||||
{
|
||||
if (NS_WARN_IF(!mTaskQueue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
|
||||
&TrackBuffer::InitializeDecoder,
|
||||
|
@ -160,7 +160,7 @@ private:
|
||||
// Protected by mParentDecoder's monitor.
|
||||
MediaInfo mInfo;
|
||||
|
||||
void ContinueShutdown(bool aSuccess);
|
||||
void ContinueShutdown();
|
||||
MediaPromiseHolder<ShutdownPromise> mShutdownPromise;
|
||||
};
|
||||
|
||||
|
@ -225,6 +225,11 @@ SOURCES += [
|
||||
'DecoderTraits.cpp',
|
||||
]
|
||||
|
||||
# Some codec-related code uses multi-character constants, which GCC and clang
|
||||
# warn about. Suppress turning this warning into an error.
|
||||
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
|
||||
SOURCES['DecoderTraits.cpp'].flags += ['-Wno-error=multichar']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'PeerConnection.js',
|
||||
'PeerConnection.manifest',
|
||||
@ -273,4 +278,10 @@ CXXFLAGS += CONFIG['GSTREAMER_CFLAGS']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Suppress some GCC warnings being treated as errors:
|
||||
# - about attributes on forward declarations for types that are already
|
||||
# defined, which complains about an important MOZ_EXPORT for android::AString
|
||||
if CONFIG['GNU_CC']:
|
||||
CXXFLAGS += ['-Wno-error=attributes']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -24,7 +24,7 @@ MediaCodecDecoder::CreateReader()
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine*
|
||||
MediaCodecDecoder::CreateStateMachine(MediaOmxCommonReader* aReader)
|
||||
MediaCodecDecoder::CreateStateMachineFromReader(MediaOmxCommonReader* aReader)
|
||||
{
|
||||
return new MediaDecoderStateMachine(this, aReader);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
|
||||
virtual MediaOmxCommonReader* CreateReader();
|
||||
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader);
|
||||
virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -265,7 +265,7 @@ MediaOmxCommonDecoder::CreateStateMachine()
|
||||
if (mReader != nullptr) {
|
||||
mReader->SetAudioChannel(GetAudioChannel());
|
||||
}
|
||||
return CreateStateMachine(mReader);
|
||||
return CreateStateMachineFromReader(mReader);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine();
|
||||
|
||||
virtual MediaOmxCommonReader* CreateReader() = 0;
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader) = 0;
|
||||
virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~MediaOmxCommonDecoder();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user