Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-12-15 14:04:03 -05:00
commit 24a826d4bf
388 changed files with 7703 additions and 3304 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@ function spawnTest () {
yield startRecording(panel);
yield busyWait(100);
yield stopRecording(panel);
yield rendered;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -34,6 +34,9 @@ function MarkerDetails(parent, splitter) {
}
MarkerDetails.prototype = {
/**
* Removes any node references from this view.
*/
destroy: function() {
this.empty();
this._parent = null;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -173,7 +173,7 @@ private:
// WebSocket.
WebSocketImpl* mImpl;
workers::WorkerPrivate* mWorkerPrivate;
bool mIsMainThread;
bool mKeepingAlive;
bool mCheckMustKeepAlive;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -59,7 +59,7 @@ public:
IsDisplaySpnRequired() const;
protected:
~IccInfo() {}
virtual ~IccInfo() {}
protected:
nsCOMPtr<nsPIDOMWindow> mWindow;

View File

@ -125,7 +125,7 @@ public:
}
private:
ThreadLocal(const nsID& aBackgroundChildLoggingId);
explicit ThreadLocal(const nsID& aBackgroundChildLoggingId);
~ThreadLocal();
ThreadLocal() MOZ_DELETE;

View File

@ -5080,7 +5080,7 @@ class DatabaseLoggingInfo MOZ_FINAL
LoggingInfo mLoggingInfo;
public:
DatabaseLoggingInfo(const LoggingInfo& aLoggingInfo)
explicit DatabaseLoggingInfo(const LoggingInfo& aLoggingInfo)
: mLoggingInfo(aLoggingInfo)
{
AssertIsOnBackgroundThread();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -180,7 +180,7 @@ private:
bool mHasEssentialTrackBuffers;
void ContinueShutdown(bool aSuccess);
void ContinueShutdown();
MediaPromiseHolder<ShutdownPromise> mMediaSourceShutdownPromise;
#ifdef MOZ_FMP4
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;

View File

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

View File

@ -160,7 +160,7 @@ private:
// Protected by mParentDecoder's monitor.
MediaInfo mInfo;
void ContinueShutdown(bool aSuccess);
void ContinueShutdown();
MediaPromiseHolder<ShutdownPromise> mShutdownPromise;
};

View File

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

View File

@ -24,7 +24,7 @@ MediaCodecDecoder::CreateReader()
}
MediaDecoderStateMachine*
MediaCodecDecoder::CreateStateMachine(MediaOmxCommonReader* aReader)
MediaCodecDecoder::CreateStateMachineFromReader(MediaOmxCommonReader* aReader)
{
return new MediaDecoderStateMachine(this, aReader);
}

View File

@ -20,7 +20,7 @@ public:
virtual MediaOmxCommonReader* CreateReader();
virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader);
virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader);
};
} // namespace mozilla

View File

@ -265,7 +265,7 @@ MediaOmxCommonDecoder::CreateStateMachine()
if (mReader != nullptr) {
mReader->SetAudioChannel(GetAudioChannel());
}
return CreateStateMachine(mReader);
return CreateStateMachineFromReader(mReader);
}
} // namespace mozilla

View File

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