mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to b2g-i
This commit is contained in:
commit
579eba5ed8
@ -350,9 +350,6 @@ AccessibleWrap::get_accValue(
|
||||
if (IsProxy())
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (xpAccessible->NativeRole() == roles::PASSWORD_TEXT)
|
||||
return E_ACCESSDENIED;
|
||||
|
||||
nsAutoString value;
|
||||
xpAccessible->Value(value);
|
||||
|
||||
|
@ -126,6 +126,15 @@ function URL(url, base) {
|
||||
}
|
||||
}
|
||||
|
||||
let fileName = "/";
|
||||
try {
|
||||
fileName = uri.QueryInterface(Ci.nsIURL).fileName;
|
||||
} catch (e) {
|
||||
if (e.result != Cr.NS_NOINTERFACE) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
let uriData = [uri.path, uri.path.length, {}, {}, {}, {}, {}, {}];
|
||||
URLParser.parsePath.apply(URLParser, uriData);
|
||||
let [{ value: filepathPos }, { value: filepathLen },
|
||||
@ -137,6 +146,7 @@ function URL(url, base) {
|
||||
let search = uri.path.substr(queryPos, queryLen);
|
||||
search = search ? "?" + search : "";
|
||||
|
||||
this.__defineGetter__("fileName", () => fileName);
|
||||
this.__defineGetter__("scheme", () => uri.scheme);
|
||||
this.__defineGetter__("userPass", () => userPass);
|
||||
this.__defineGetter__("host", () => host);
|
||||
|
@ -20,8 +20,6 @@ const { decode } = require('sdk/base64');
|
||||
const httpd = require('./lib/httpd');
|
||||
const port = 8099;
|
||||
|
||||
const defaultLocation = '{\'scheme\':\'about\',\'userPass\':null,\'host\':null,\'hostname\':null,\'port\':null,\'path\':\'addons\',\'pathname\':\'addons\',\'hash\':\'\',\'href\':\'about:addons\',\'origin\':\'about:\',\'protocol\':\'about:\',\'search\':\'\'}'.replace(/'/g, '"');
|
||||
|
||||
exports.testResolve = function(assert) {
|
||||
assert.equal(URL('bar', 'http://www.foo.com/').toString(),
|
||||
'http://www.foo.com/bar');
|
||||
@ -65,6 +63,7 @@ exports.testParseHttp = function(assert) {
|
||||
assert.equal(info.href, aUrl);
|
||||
assert.equal(info.hash, '#myhash');
|
||||
assert.equal(info.search, '?locale=en-US&otherArg=%20x%20');
|
||||
assert.equal(info.fileName, 'bar');
|
||||
};
|
||||
|
||||
exports.testParseHttpSearchAndHash = function (assert) {
|
||||
@ -109,6 +108,7 @@ exports.testParseChrome = function(assert) {
|
||||
assert.equal(info.port, null);
|
||||
assert.equal(info.userPass, null);
|
||||
assert.equal(info.path, '/content/blah');
|
||||
assert.equal(info.fileName, 'blah');
|
||||
};
|
||||
|
||||
exports.testParseAbout = function(assert) {
|
||||
@ -127,6 +127,7 @@ exports.testParseFTP = function(assert) {
|
||||
assert.equal(info.port, null);
|
||||
assert.equal(info.userPass, null);
|
||||
assert.equal(info.path, '/foo');
|
||||
assert.equal(info.fileName, 'foo');
|
||||
};
|
||||
|
||||
exports.testParseFTPWithUserPass = function(assert) {
|
||||
@ -216,7 +217,7 @@ exports.testStringInterface = function(assert) {
|
||||
|
||||
// make sure the standard URL properties are enumerable and not the String interface bits
|
||||
assert.equal(Object.keys(a),
|
||||
'scheme,userPass,host,hostname,port,path,pathname,hash,href,origin,protocol,search',
|
||||
'fileName,scheme,userPass,host,hostname,port,path,pathname,hash,href,origin,protocol,search',
|
||||
'enumerable key list check for URL.');
|
||||
assert.equal(
|
||||
JSON.stringify(a),
|
||||
@ -392,6 +393,20 @@ exports.testLocalURLwithInvalidURL = function(assert) {
|
||||
});
|
||||
}
|
||||
|
||||
exports.testFileName = function(assert) {
|
||||
let urls = [
|
||||
['https://foo/bar.js', 'bar.js'],
|
||||
['app://myfxosapp/file.js', 'file.js'],
|
||||
['http://localhost:8888/file.js', 'file.js'],
|
||||
['http://foo/bar.js#hash', 'bar.js'],
|
||||
['http://foo/bar.js?q=go&query=yeah', 'bar.js'],
|
||||
['chrome://browser/content/content.js', 'content.js'],
|
||||
['resource://gre/foo.js', 'foo.js'],
|
||||
];
|
||||
|
||||
urls.forEach(([url, fileName]) => assert.equal(URL(url).fileName, fileName, 'file names are equal'));
|
||||
};
|
||||
|
||||
function validURIs() {
|
||||
return [
|
||||
'http://foo.com/blah_blah',
|
||||
|
@ -7,6 +7,14 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
|
@ -734,9 +734,6 @@
|
||||
; [Browser Chrome Files]
|
||||
@RESPATH@/chrome/browser@JAREXT@
|
||||
@RESPATH@/chrome/browser.manifest
|
||||
@RESPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf
|
||||
@RESPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/icon.png
|
||||
@RESPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/preview.png
|
||||
@RESPATH@/chrome/toolkit@JAREXT@
|
||||
@RESPATH@/chrome/toolkit.manifest
|
||||
#ifdef XP_UNIX
|
||||
|
@ -186,12 +186,11 @@ body {
|
||||
}
|
||||
|
||||
.rooms > h1 {
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
font-size: 1rem;
|
||||
padding: .5rem 0;
|
||||
height: 3rem;
|
||||
line-height: 3rem;
|
||||
font-size: 1.1rem;
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
@ -205,7 +204,7 @@ body {
|
||||
border-radius: 5px;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
margin: 1rem;
|
||||
margin: 1.5rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
@ -252,8 +251,8 @@ body {
|
||||
line-height: 2.4rem;
|
||||
color: #000;
|
||||
/* See .room-entry-context-item for the margin/size reductions.
|
||||
* An extra 40px to make space for the call button and chevron. */
|
||||
width: calc(100% - 1rem - 56px);
|
||||
* An extra 16px to make space for the edit button. */
|
||||
width: calc(100% - 1rem - 32px);
|
||||
}
|
||||
|
||||
.room-list > .room-entry.room-active:not(.room-opened) > h2 {
|
||||
@ -331,27 +330,9 @@ body {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.room-list > .room-entry > h2:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
background-image: url("../shared/img/icons-14x14.svg#hello");
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
-moz-margin-end: 1rem;
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
||||
.room-list > .room-entry.room-active > h2:before {
|
||||
background-image: url("../shared/img/icons-14x14.svg#hello-active");
|
||||
}
|
||||
|
||||
/* Room entry context button (call button + chevron) */
|
||||
/* Room entry context button (edit button) */
|
||||
.room-entry-context-actions {
|
||||
display: none;
|
||||
border-radius: 30px;
|
||||
background: #56b397;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@ -359,41 +340,17 @@ body {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.room-entry:hover .room-entry-context-actions:hover {
|
||||
background: #50e3c2;
|
||||
}
|
||||
|
||||
/* Room entry call button */
|
||||
.room-entry-call-btn {
|
||||
border-top-left-radius: 30px;
|
||||
border-bottom-left-radius: 30px;
|
||||
background-color: transparent;
|
||||
background-image: url("../shared/img/icons-14x14.svg#video-white");
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .room-entry-call-btn {
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
/* Room entry context menu */
|
||||
.room-entry-context-menu-chevron {
|
||||
display: inline-block;
|
||||
border-top-right-radius: 30px;
|
||||
border-bottom-right-radius: 30px;
|
||||
background-image: url("../shared/img/icons-10x10.svg#dropdown-white");
|
||||
/* Room entry edit button */
|
||||
.room-entry-context-edit-btn {
|
||||
background-image: url("../shared/img/icons-10x10.svg#edit-darkgrey");
|
||||
background-position: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Common styles for chevron and call button. */
|
||||
.room-entry-context-menu-chevron,
|
||||
.room-entry-call-btn {
|
||||
width: 30px;
|
||||
height: 24px;
|
||||
background-size: 12px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 12px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .room-entry-context-actions > .dropdown-menu {
|
||||
@ -410,16 +367,11 @@ html[dir="rtl"] .room-entry-context-actions > .dropdown-menu {
|
||||
/* Keep ".room-list > .room-entry > h2" in sync with these. */
|
||||
.room-entry-context-item {
|
||||
display: inline-block;
|
||||
-moz-margin-end: 1rem;
|
||||
vertical-align: middle;
|
||||
-moz-margin-start: 1rem;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.room-entry:not(.room-opened):hover .room-entry-context-item {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.room-entry-context-item > a > img {
|
||||
.room-entry-context-item > img {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
@ -340,23 +340,39 @@ loop.panel = (function(_, mozL10n) {
|
||||
handleClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.props.mozLoop.openURL(event.currentTarget.href);
|
||||
this.closeWindow();
|
||||
if (event.currentTarget.href) {
|
||||
this.props.mozLoop.openURL(event.currentTarget.href);
|
||||
this.closeWindow();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
|
||||
if (!roomUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
_renderDefaultIcon: function() {
|
||||
return (
|
||||
React.createElement("div", {className: "room-entry-context-item"},
|
||||
React.createElement("a", {href: roomUrl.location, onClick: this.handleClick, title: roomUrl.description},
|
||||
React.createElement("img", {src: "loop/shared/img/icons-16x16.svg#globe"})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
_renderIcon: function(roomUrl) {
|
||||
return (
|
||||
React.createElement("div", {className: "room-entry-context-item"},
|
||||
React.createElement("a", {href: roomUrl.location,
|
||||
onClick: this.handleClick,
|
||||
title: roomUrl.description},
|
||||
React.createElement("img", {src: roomUrl.thumbnail || "loop/shared/img/icons-16x16.svg#globe"})
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
|
||||
if (roomUrl && roomUrl.location) {
|
||||
return this._renderIcon(roomUrl);
|
||||
} else {
|
||||
return this._renderDefaultIcon();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -398,7 +414,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
this.closeWindow();
|
||||
},
|
||||
|
||||
handleContextChevronClick: function(e) {
|
||||
handleClick: function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@ -435,23 +451,19 @@ loop.panel = (function(_, mozL10n) {
|
||||
onClick: this.props.isOpenedRoom ? null : this.handleClickEntry,
|
||||
onMouseLeave: this.props.isOpenedRoom ? null : this._handleMouseOut,
|
||||
ref: "roomEntry"},
|
||||
React.createElement("h2", null,
|
||||
roomTitle
|
||||
),
|
||||
React.createElement(RoomEntryContextItem, {
|
||||
mozLoop: this.props.mozLoop,
|
||||
roomUrls: this.props.room.decryptedContext.urls}),
|
||||
React.createElement("h2", null, roomTitle),
|
||||
this.props.isOpenedRoom ? null :
|
||||
React.createElement(RoomEntryContextButtons, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
eventPosY: this.state.eventPosY,
|
||||
handleClickEntry: this.handleClickEntry,
|
||||
handleContextChevronClick: this.handleContextChevronClick,
|
||||
handleClick: this.handleClick,
|
||||
ref: "contextActions",
|
||||
room: this.props.room,
|
||||
showMenu: this.state.showMenu,
|
||||
toggleDropdownMenu: this.toggleDropdownMenu})
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -459,16 +471,14 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
/**
|
||||
* Buttons corresponding to each conversation entry.
|
||||
* This component renders the video icon call button and chevron button for
|
||||
* displaying contextual dropdown menu for conversation entries.
|
||||
* It also holds the dropdown menu.
|
||||
* This component renders the edit button for displaying contextual dropdown
|
||||
* menu for conversation entries. It also holds the dropdown menu.
|
||||
*/
|
||||
var RoomEntryContextButtons = React.createClass({displayName: "RoomEntryContextButtons",
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.object.isRequired,
|
||||
eventPosY: React.PropTypes.number.isRequired,
|
||||
handleClickEntry: React.PropTypes.func.isRequired,
|
||||
handleContextChevronClick: React.PropTypes.func.isRequired,
|
||||
handleClick: React.PropTypes.func.isRequired,
|
||||
room: React.PropTypes.object.isRequired,
|
||||
showMenu: React.PropTypes.bool.isRequired,
|
||||
toggleDropdownMenu: React.PropTypes.func.isRequired
|
||||
@ -514,13 +524,9 @@ loop.panel = (function(_, mozL10n) {
|
||||
render: function() {
|
||||
return (
|
||||
React.createElement("div", {className: "room-entry-context-actions"},
|
||||
React.createElement("button", {
|
||||
className: "btn room-entry-call-btn",
|
||||
onClick: this.props.handleClickEntry,
|
||||
ref: "callButton"}),
|
||||
React.createElement("div", {
|
||||
className: "room-entry-context-menu-chevron dropdown-menu-button",
|
||||
onClick: this.props.handleContextChevronClick,
|
||||
className: "room-entry-context-edit-btn dropdown-menu-button",
|
||||
onClick: this.props.handleClick,
|
||||
ref: "menu-button"}),
|
||||
this.props.showMenu ?
|
||||
React.createElement(ConversationDropdown, {
|
||||
@ -563,7 +569,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
// Get the parent element and make sure the menu does not overlow its
|
||||
// container.
|
||||
var listNode = loop.shared.utils.findParentNode(this.getDOMNode(),
|
||||
".rooms");
|
||||
"rooms");
|
||||
var listNodeRect = listNode.getBoundingClientRect();
|
||||
|
||||
// Click offset to not display the menu right next to the area clicked.
|
||||
|
@ -340,23 +340,39 @@ loop.panel = (function(_, mozL10n) {
|
||||
handleClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.props.mozLoop.openURL(event.currentTarget.href);
|
||||
this.closeWindow();
|
||||
if (event.currentTarget.href) {
|
||||
this.props.mozLoop.openURL(event.currentTarget.href);
|
||||
this.closeWindow();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
|
||||
if (!roomUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
_renderDefaultIcon: function() {
|
||||
return (
|
||||
<div className="room-entry-context-item">
|
||||
<a href={roomUrl.location} onClick={this.handleClick} title={roomUrl.description}>
|
||||
<img src="loop/shared/img/icons-16x16.svg#globe" />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
_renderIcon: function(roomUrl) {
|
||||
return (
|
||||
<div className="room-entry-context-item">
|
||||
<a href={roomUrl.location}
|
||||
onClick={this.handleClick}
|
||||
title={roomUrl.description}>
|
||||
<img src={roomUrl.thumbnail || "loop/shared/img/icons-16x16.svg#globe"} />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
|
||||
if (roomUrl && roomUrl.location) {
|
||||
return this._renderIcon(roomUrl);
|
||||
} else {
|
||||
return this._renderDefaultIcon();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -398,7 +414,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
this.closeWindow();
|
||||
},
|
||||
|
||||
handleContextChevronClick: function(e) {
|
||||
handleClick: function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@ -435,23 +451,19 @@ loop.panel = (function(_, mozL10n) {
|
||||
onClick={this.props.isOpenedRoom ? null : this.handleClickEntry}
|
||||
onMouseLeave={this.props.isOpenedRoom ? null : this._handleMouseOut}
|
||||
ref="roomEntry">
|
||||
<h2>
|
||||
{roomTitle}
|
||||
</h2>
|
||||
<RoomEntryContextItem
|
||||
mozLoop={this.props.mozLoop}
|
||||
roomUrls={this.props.room.decryptedContext.urls} />
|
||||
<h2>{roomTitle}</h2>
|
||||
{this.props.isOpenedRoom ? null :
|
||||
<RoomEntryContextButtons
|
||||
dispatcher={this.props.dispatcher}
|
||||
eventPosY={this.state.eventPosY}
|
||||
handleClickEntry={this.handleClickEntry}
|
||||
handleContextChevronClick={this.handleContextChevronClick}
|
||||
handleClick={this.handleClick}
|
||||
ref="contextActions"
|
||||
room={this.props.room}
|
||||
showMenu={this.state.showMenu}
|
||||
toggleDropdownMenu={this.toggleDropdownMenu} />
|
||||
}
|
||||
toggleDropdownMenu={this.toggleDropdownMenu} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -459,16 +471,14 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
/**
|
||||
* Buttons corresponding to each conversation entry.
|
||||
* This component renders the video icon call button and chevron button for
|
||||
* displaying contextual dropdown menu for conversation entries.
|
||||
* It also holds the dropdown menu.
|
||||
* This component renders the edit button for displaying contextual dropdown
|
||||
* menu for conversation entries. It also holds the dropdown menu.
|
||||
*/
|
||||
var RoomEntryContextButtons = React.createClass({
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.object.isRequired,
|
||||
eventPosY: React.PropTypes.number.isRequired,
|
||||
handleClickEntry: React.PropTypes.func.isRequired,
|
||||
handleContextChevronClick: React.PropTypes.func.isRequired,
|
||||
handleClick: React.PropTypes.func.isRequired,
|
||||
room: React.PropTypes.object.isRequired,
|
||||
showMenu: React.PropTypes.bool.isRequired,
|
||||
toggleDropdownMenu: React.PropTypes.func.isRequired
|
||||
@ -514,13 +524,9 @@ loop.panel = (function(_, mozL10n) {
|
||||
render: function() {
|
||||
return (
|
||||
<div className="room-entry-context-actions">
|
||||
<button
|
||||
className="btn room-entry-call-btn"
|
||||
onClick={this.props.handleClickEntry}
|
||||
ref="callButton" />
|
||||
<div
|
||||
className="room-entry-context-menu-chevron dropdown-menu-button"
|
||||
onClick={this.props.handleContextChevronClick}
|
||||
className="room-entry-context-edit-btn dropdown-menu-button"
|
||||
onClick={this.props.handleClick}
|
||||
ref="menu-button" />
|
||||
{this.props.showMenu ?
|
||||
<ConversationDropdown
|
||||
@ -563,7 +569,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
// Get the parent element and make sure the menu does not overlow its
|
||||
// container.
|
||||
var listNode = loop.shared.utils.findParentNode(this.getDOMNode(),
|
||||
".rooms");
|
||||
"rooms");
|
||||
var listNodeRect = listNode.getBoundingClientRect();
|
||||
|
||||
// Click offset to not display the menu right next to the area clicked.
|
||||
|
@ -22,6 +22,9 @@
|
||||
use[id$="-disabled"] {
|
||||
fill: rgba(255,255,255,0.4);
|
||||
}
|
||||
use[id$="-darkgrey"] {
|
||||
fill: #565656;
|
||||
}
|
||||
</style>
|
||||
<defs>
|
||||
<polygon id="close-shape" points="10,1.717 8.336,0.049 5.024,3.369 1.663,0 0,1.668 3.36,5.037 0.098,8.307 1.762,9.975 5.025,6.705 8.311,10 9.975,8.332 6.688,5.037"/>
|
||||
@ -43,6 +46,7 @@
|
||||
<use id="edit-active" xlink:href="#edit-shape"/>
|
||||
<use id="edit-disabled" xlink:href="#edit-shape"/>
|
||||
<use id="edit-white" xlink:href="#edit-shape"/>
|
||||
<use id="edit-darkgrey" xlink:href="#edit-shape"/>
|
||||
<use id="expand" xlink:href="#expand-shape"/>
|
||||
<use id="expand-active" xlink:href="#expand-shape"/>
|
||||
<use id="expand-disabled" xlink:href="#expand-shape"/>
|
||||
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.0 KiB |
@ -593,7 +593,7 @@ describe("loop.panel", function() {
|
||||
React.createElement(loop.panel.RoomEntry, props));
|
||||
}
|
||||
|
||||
describe("handleContextChevronClick", function() {
|
||||
describe("handleClick", function() {
|
||||
var view;
|
||||
|
||||
beforeEach(function() {
|
||||
@ -613,15 +613,15 @@ describe("loop.panel", function() {
|
||||
expect(view.refs.contextActions.state.showMenu).to.eql(false);
|
||||
});
|
||||
|
||||
it("should set eventPosY when handleContextChevronClick is called", function() {
|
||||
view.handleContextChevronClick(fakeEvent);
|
||||
it("should set eventPosY when handleClick is called", function() {
|
||||
view.handleClick(fakeEvent);
|
||||
|
||||
expect(view.state.eventPosY).to.eql(fakeEvent.pageY);
|
||||
});
|
||||
|
||||
it("toggle state.showMenu when handleContextChevronClick is called", function() {
|
||||
it("toggle state.showMenu when handleClick is called", function() {
|
||||
var prevState = view.state.showMenu;
|
||||
view.handleContextChevronClick(fakeEvent);
|
||||
view.handleClick(fakeEvent);
|
||||
|
||||
expect(view.state.showMenu).to.eql(!prevState);
|
||||
});
|
||||
@ -702,10 +702,10 @@ describe("loop.panel", function() {
|
||||
});
|
||||
}
|
||||
|
||||
it("should not display a context indicator if the room doesn't have any", function() {
|
||||
it("should display a default context indicator if the room doesn't have any", function() {
|
||||
roomEntry = mountEntryForContext();
|
||||
|
||||
expect(roomEntry.getDOMNode().querySelector(".room-entry-context-item")).eql(null);
|
||||
expect(roomEntry.getDOMNode().querySelector(".room-entry-context-item")).not.eql(null);
|
||||
});
|
||||
|
||||
it("should a context indicator if the room specifies context", function() {
|
||||
@ -1129,11 +1129,10 @@ describe("loop.panel", function() {
|
||||
var props = _.extend({
|
||||
dispatcher: dispatcher,
|
||||
eventPosY: 0,
|
||||
handleClickEntry: sandbox.stub(),
|
||||
showMenu: false,
|
||||
room: roomData,
|
||||
toggleDropdownMenu: sandbox.stub(),
|
||||
handleContextChevronClick: sandbox.stub()
|
||||
handleClick: sandbox.stub()
|
||||
}, extraProps);
|
||||
return TestUtils.renderIntoDocument(
|
||||
React.createElement(loop.panel.RoomEntryContextButtons, props));
|
||||
@ -1192,11 +1191,5 @@ describe("loop.panel", function() {
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.DeleteRoom({ roomToken: roomData.roomToken }));
|
||||
});
|
||||
|
||||
it("should trigger handleClickEntry when button is clicked", function() {
|
||||
TestUtils.Simulate.click(view.refs.callButton.getDOMNode());
|
||||
|
||||
sinon.assert.calledOnce(view.props.handleClickEntry);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -123,7 +123,7 @@ var gContentPane = {
|
||||
let bundlePreferences = document.getElementById("bundlePreferences");
|
||||
let params = { permissionType: "desktop-notification" };
|
||||
params.windowTitle = bundlePreferences.getString("notificationspermissionstitle");
|
||||
params.introText = bundlePreferences.getString("notificationspermissionstext2");
|
||||
params.introText = bundlePreferences.getString("notificationspermissionstext3");
|
||||
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
"resizable=yes", params);
|
||||
|
@ -70,7 +70,7 @@
|
||||
<rows>
|
||||
<row id="notificationsPolicyRow">
|
||||
<vbox align="start">
|
||||
<label id="notificationsPolicy">¬ificationsPolicyDesc.label;</label>
|
||||
<label id="notificationsPolicy">¬ificationsPolicyDesc2.label;</label>
|
||||
</vbox>
|
||||
<hbox pack="end">
|
||||
<button id="notificationsPolicyButton" label="¬ificationsPolicyButton.label;"
|
||||
|
@ -8,7 +8,7 @@
|
||||
<!ENTITY blockPopups.accesskey "B">
|
||||
|
||||
<!ENTITY notificationsPolicy.label "Notifications">
|
||||
<!ENTITY notificationsPolicyDesc.label "Choose which sites are allowed to show notifications">
|
||||
<!ENTITY notificationsPolicyDesc2.label "Choose which sites are allowed to receive notifications">
|
||||
<!ENTITY notificationsPolicyButton.accesskey "h">
|
||||
<!ENTITY notificationsPolicyButton.label "Choose…">
|
||||
<!ENTITY notificationsDoNotDisturb.label "Do not disturb me">
|
||||
|
@ -25,7 +25,7 @@ addonspermissionstext=You can specify which websites are allowed to install add-
|
||||
addons_permissions_title=Allowed Sites - Add-ons Installation
|
||||
popuppermissionstext=You can specify which websites are allowed to open pop-up windows. Type the exact address of the site you want to allow and then click Allow.
|
||||
popuppermissionstitle=Allowed Sites - Pop-ups
|
||||
notificationspermissionstext2=Control which websites are always or never allowed to show notifications. If you remove a site, it will need to request permission again.
|
||||
notificationspermissionstext3=Control which websites are always or never allowed to receive notifications. If you remove a site, it will need to request permission again.
|
||||
notificationspermissionstitle=Notification Permissions
|
||||
invalidURI=Please enter a valid hostname
|
||||
invalidURITitle=Invalid Hostname Entered
|
||||
|
@ -80,7 +80,7 @@ var ContentClick = {
|
||||
// visits across frames should be preserved.
|
||||
try {
|
||||
if (!PrivateBrowsingUtils.isWindowPrivate(window))
|
||||
PlacesUIUtils.markPageAsFollowedLink(href);
|
||||
PlacesUIUtils.markPageAsFollowedLink(json.href);
|
||||
} catch (ex) { /* Skip invalid URIs. */ }
|
||||
}
|
||||
};
|
||||
|
@ -2,8 +2,7 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
mobile-tests := mobile/android/tests/browser/robocop
|
||||
TESTPATH := $(topsrcdir)/$(mobile-tests)
|
||||
TESTPATH := $(topsrcdir)/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests
|
||||
|
||||
ANDROID_EXTRA_JARS += \
|
||||
$(srcdir)/robotium-solo-4.3.1.jar \
|
||||
@ -29,7 +28,7 @@ _JAVA_HARNESS := \
|
||||
StructuredLogger.java \
|
||||
$(NULL)
|
||||
|
||||
java-harness := $(addprefix $(srcdir)/,$(_JAVA_HARNESS))
|
||||
java-harness := $(addprefix $(topsrcdir)/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/,$(_JAVA_HARNESS))
|
||||
java-tests := \
|
||||
$(wildcard $(TESTPATH)/*.java) \
|
||||
$(wildcard $(TESTPATH)/components/*.java) \
|
||||
|
@ -5164,7 +5164,7 @@ fi;
|
||||
dnl ========================================================
|
||||
dnl = Apple platform decoder support
|
||||
dnl ========================================================
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = "cocoa" || test "$MOZ_WIDGET_TOOLKIT" = "uikit"; then
|
||||
MOZ_APPLEMEDIA=1
|
||||
fi
|
||||
|
||||
|
@ -278,21 +278,17 @@ Tools.performance = {
|
||||
Tools.memory = {
|
||||
id: "memory",
|
||||
ordinal: 8,
|
||||
icon: "chrome://devtools/skin/themes/images/tool-styleeditor.svg",
|
||||
icon: "chrome://devtools/skin/themes/images/tool-memory.svg",
|
||||
invertIconForLightTheme: true,
|
||||
highlightedicon: "chrome://devtools/skin/themes/images/tool-memory-active.svg",
|
||||
url: "chrome://devtools/content/memory/memory.xhtml",
|
||||
visibilityswitch: "devtools.memory.enabled",
|
||||
label: "Memory",
|
||||
panelLabel: "Memory Panel",
|
||||
tooltip: "Memory (keyboardshortcut)",
|
||||
hiddenInOptions: true,
|
||||
|
||||
isTargetSupported: function (target) {
|
||||
// TODO 1201907
|
||||
// Once Fx44 lands, we should add a root trait `heapSnapshots`
|
||||
// to indicate that the memory actor can handle this.
|
||||
// Shouldn't make this change until Fx44, however.
|
||||
return true; // target.getTrait("heapSnapshots");
|
||||
return target.getTrait("heapSnapshots");
|
||||
},
|
||||
|
||||
build: function (frame, target) {
|
||||
|
@ -302,6 +302,8 @@ devtools.jar:
|
||||
skin/themes/images/tool-network.svg (themes/images/tool-network.svg)
|
||||
skin/themes/images/tool-scratchpad.svg (themes/images/tool-scratchpad.svg)
|
||||
skin/themes/images/tool-webaudio.svg (themes/images/tool-webaudio.svg)
|
||||
skin/themes/images/tool-memory.svg (themes/images/tool-memory.svg)
|
||||
skin/themes/images/tool-memory-active.svg (themes/images/tool-memory-active.svg)
|
||||
skin/themes/images/close.png (themes/images/close.png)
|
||||
skin/themes/images/close@2x.png (themes/images/close@2x.png)
|
||||
skin/themes/images/vview-delete.png (themes/images/vview-delete.png)
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { breakdowns } = require("./constants");
|
||||
const { toggleRecordingAllocationStacks } = require("./actions/allocations");
|
||||
const { setBreakdownAndRefresh } = require("./actions/breakdown");
|
||||
const { toggleInvertedAndRefresh } = require("./actions/inverted");
|
||||
@ -20,15 +21,24 @@ const App = createClass({
|
||||
|
||||
propTypes: appModel,
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
breakdown: breakdowns.coarseType.breakdown,
|
||||
inverted: false,
|
||||
};
|
||||
},
|
||||
|
||||
childContextTypes: {
|
||||
front: PropTypes.any,
|
||||
heapWorker: PropTypes.any,
|
||||
toolbox: PropTypes.any,
|
||||
},
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
front: this.props.front,
|
||||
heapWorker: this.props.heapWorker,
|
||||
toolbox: this.props.toolbox,
|
||||
}
|
||||
},
|
||||
|
||||
@ -40,13 +50,14 @@ const App = createClass({
|
||||
heapWorker,
|
||||
breakdown,
|
||||
allocations,
|
||||
inverted
|
||||
inverted,
|
||||
toolbox,
|
||||
} = this.props;
|
||||
|
||||
let selectedSnapshot = snapshots.find(s => s.selected);
|
||||
|
||||
return (
|
||||
dom.div({ id: "memory-tool" }, [
|
||||
dom.div({ id: "memory-tool" },
|
||||
|
||||
Toolbar({
|
||||
breakdowns: getBreakdownDisplayData(),
|
||||
@ -61,7 +72,7 @@ const App = createClass({
|
||||
dispatch(toggleInvertedAndRefresh(heapWorker))
|
||||
}),
|
||||
|
||||
dom.div({ id: "memory-tool-container" }, [
|
||||
dom.div({ id: "memory-tool-container" },
|
||||
List({
|
||||
itemComponent: SnapshotListItem,
|
||||
items: snapshots,
|
||||
@ -71,9 +82,10 @@ const App = createClass({
|
||||
HeapView({
|
||||
snapshot: selectedSnapshot,
|
||||
onSnapshotClick: () => dispatch(takeSnapshotAndCensus(front, heapWorker)),
|
||||
}),
|
||||
])
|
||||
])
|
||||
toolbox
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
40
devtools/client/memory/components/frame.js
Normal file
40
devtools/client/memory/components/frame.js
Normal file
@ -0,0 +1,40 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { URL } = require("sdk/url");
|
||||
|
||||
const Frame = module.exports = createClass({
|
||||
displayName: "frame-view",
|
||||
|
||||
propTypes: {
|
||||
frame: PropTypes.object.isRequired,
|
||||
toolbox: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
render() {
|
||||
let { toolbox, frame } = this.props;
|
||||
|
||||
let url = new URL(frame.source);
|
||||
let spec = url.toString();
|
||||
let func = frame.functionDisplayFrame || "";
|
||||
let tooltip = `${func} (${spec}:${frame.line}:${frame.column})`;
|
||||
let onClick = () => toolbox.viewSourceInDebugger(spec, frame.line);
|
||||
|
||||
let fields = [
|
||||
dom.span({ className: "frame-link-function-display-name" }, func),
|
||||
dom.a({ className: "frame-link-filename", onClick }, url.fileName),
|
||||
dom.span({ className: "frame-link-colon" }, ":"),
|
||||
dom.span({ className: "frame-link-line" }, frame.line),
|
||||
dom.span({ className: "frame-link-colon" }, ":"),
|
||||
dom.span({ className: "frame-link-column" }, frame.column)
|
||||
];
|
||||
|
||||
if (url.scheme === "http" || url.scheme === "https" || url.scheme === "ftp") {
|
||||
fields.push(dom.span({ className: "frame-link-host" }, url.host));
|
||||
}
|
||||
|
||||
return dom.span({ className: "frame-link", title: tooltip }, ...fields);
|
||||
}
|
||||
});
|
@ -37,13 +37,13 @@ function createParentMap (node, aggregator=Object.create(null)) {
|
||||
* @param {CensusTreeNode} census
|
||||
* @return {Object}
|
||||
*/
|
||||
function createTreeProperties (census) {
|
||||
function createTreeProperties (census, toolbox) {
|
||||
let map = createParentMap(census);
|
||||
|
||||
return {
|
||||
getParent: node => map(node.id),
|
||||
getParent: node => map[node.id],
|
||||
getChildren: node => node.children || [],
|
||||
renderItem: (item, depth, focused, arrow) => new TreeItem({ item, depth, focused, arrow }),
|
||||
renderItem: (item, depth, focused, arrow) => new TreeItem({ toolbox, item, depth, focused, arrow }),
|
||||
getRoots: () => census.children,
|
||||
getKey: node => node.id,
|
||||
itemHeight: HEAP_TREE_ROW_HEIGHT,
|
||||
@ -68,7 +68,7 @@ const Heap = module.exports = createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
let { snapshot, onSnapshotClick } = this.props;
|
||||
let { snapshot, onSnapshotClick, toolbox } = this.props;
|
||||
let census = snapshot ? snapshot.census : null;
|
||||
let state = snapshot ? snapshot.state : "initial";
|
||||
let statusText = snapshot ? getSnapshotStatusTextFull(snapshot) : "";
|
||||
@ -76,14 +76,14 @@ const Heap = module.exports = createClass({
|
||||
|
||||
switch (state) {
|
||||
case "initial":
|
||||
content = dom.button({
|
||||
content = [dom.button({
|
||||
className: "devtools-toolbarbutton take-snapshot",
|
||||
onClick: onSnapshotClick,
|
||||
// Want to use the [standalone] tag to leverage our styles,
|
||||
// but React hates that evidently
|
||||
"data-standalone": true,
|
||||
"data-text-only": true,
|
||||
}, TAKE_SNAPSHOT_TEXT)
|
||||
}, TAKE_SNAPSHOT_TEXT)];
|
||||
break;
|
||||
case states.ERROR:
|
||||
content = [
|
||||
@ -96,7 +96,7 @@ const Heap = module.exports = createClass({
|
||||
case states.READING:
|
||||
case states.READ:
|
||||
case states.SAVING_CENSUS:
|
||||
content = dom.span({ className: "snapshot-status devtools-throbber" }, statusText)
|
||||
content = [dom.span({ className: "snapshot-status devtools-throbber" }, statusText)];
|
||||
break;
|
||||
case states.SAVED_CENSUS:
|
||||
content = [
|
||||
@ -107,11 +107,11 @@ const Heap = module.exports = createClass({
|
||||
dom.span({ className: "heap-tree-item-total-count" }, "Total Count"),
|
||||
dom.span({ className: "heap-tree-item-name" }, "Name")
|
||||
),
|
||||
Tree(createTreeProperties(snapshot.census))
|
||||
Tree(createTreeProperties(snapshot.census, toolbox))
|
||||
];
|
||||
break;
|
||||
}
|
||||
let pane = dom.div({ className: "heap-view-panel", "data-state": state }, content);
|
||||
let pane = dom.div({ className: "heap-view-panel", "data-state": state }, ...content);
|
||||
|
||||
return (
|
||||
dom.div({ id: "heap-view", "data-state": state }, pane)
|
||||
|
@ -22,9 +22,9 @@ const List = module.exports = createClass({
|
||||
let { items, onClick, itemComponent: Item } = this.props;
|
||||
|
||||
return (
|
||||
dom.ul({ className: "list" }, items.map((item, index) => {
|
||||
dom.ul({ className: "list" }, ...items.map((item, index) => {
|
||||
return Item({
|
||||
item, index, onClick: () => onClick(item),
|
||||
key: index, item, index, onClick: () => onClick(item),
|
||||
});
|
||||
}))
|
||||
);
|
||||
|
@ -4,6 +4,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'frame.js',
|
||||
'heap.js',
|
||||
'list.js',
|
||||
'snapshot-list-item.js',
|
||||
|
@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { DOM, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const models = require("../models");
|
||||
|
||||
@ -33,29 +33,29 @@ const Toolbar = module.exports = createClass({
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
DOM.div({ className: "devtools-toolbar" }, [
|
||||
DOM.button({ className: `take-snapshot devtools-button`, onClick: onTakeSnapshotClick }),
|
||||
dom.div({ className: "devtools-toolbar" },
|
||||
dom.button({ className: `take-snapshot devtools-button`, onClick: onTakeSnapshotClick }),
|
||||
|
||||
DOM.label({},
|
||||
dom.label({},
|
||||
"Breakdown by ",
|
||||
DOM.select({
|
||||
dom.select({
|
||||
className: `select-breakdown`,
|
||||
onChange: e => onBreakdownChange(e.target.value),
|
||||
}, breakdowns.map(({ name, displayName }) => DOM.option({ value: name }, displayName)))
|
||||
}, ...breakdowns.map(({ name, displayName }) => dom.option({ key: name, value: name }, displayName)))
|
||||
),
|
||||
|
||||
DOM.label({}, [
|
||||
DOM.input({
|
||||
dom.label({},
|
||||
dom.input({
|
||||
type: "checkbox",
|
||||
checked: inverted,
|
||||
onChange: onToggleInverted,
|
||||
}),
|
||||
// TODO bug 1214799
|
||||
"Invert tree"
|
||||
]),
|
||||
),
|
||||
|
||||
DOM.label({}, [
|
||||
DOM.input({
|
||||
dom.label({},
|
||||
dom.input({
|
||||
type: "checkbox",
|
||||
checked: allocations.recording,
|
||||
disabled: allocations.togglingInProgress,
|
||||
@ -63,8 +63,8 @@ const Toolbar = module.exports = createClass({
|
||||
}),
|
||||
// TODO bug 1214799
|
||||
"Record allocation stacks"
|
||||
])
|
||||
])
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -3,7 +3,8 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { isSavedFrame } = require("devtools/shared/DevToolsUtils");
|
||||
const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const FrameView = createFactory(require("./frame"));
|
||||
|
||||
const INDENT = 10;
|
||||
const MAX_SOURCE_LENGTH = 200;
|
||||
@ -17,36 +18,23 @@ const TreeItem = module.exports = createClass({
|
||||
displayName: "tree-item",
|
||||
|
||||
render() {
|
||||
let { item, depth, arrow, focused } = this.props;
|
||||
let { item, depth, arrow, focused, toolbox } = this.props;
|
||||
|
||||
return dom.div({ className: `heap-tree-item ${focused ? "focused" :""}` },
|
||||
dom.span({ className: "heap-tree-item-bytes" }, item.bytes),
|
||||
dom.span({ className: "heap-tree-item-count" }, item.count),
|
||||
dom.span({ className: "heap-tree-item-total-bytes" }, item.totalBytes),
|
||||
dom.span({ className: "heap-tree-item-total-count" }, item.totalCount),
|
||||
dom.span({ className: "heap-tree-item-name", style: { marginLeft: depth * INDENT }},
|
||||
dom.span({ className: "heap-tree-item-field heap-tree-item-bytes" }, item.bytes),
|
||||
dom.span({ className: "heap-tree-item-field heap-tree-item-count" }, item.count),
|
||||
dom.span({ className: "heap-tree-item-field heap-tree-item-total-bytes" }, item.totalBytes),
|
||||
dom.span({ className: "heap-tree-item-field heap-tree-item-total-count" }, item.totalCount),
|
||||
dom.span({ className: "heap-tree-item-field heap-tree-item-name", style: { marginLeft: depth * INDENT }},
|
||||
arrow,
|
||||
this.toLabel(item.name)
|
||||
this.toLabel(item.name, toolbox)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
toLabel(name) {
|
||||
toLabel(name, toolbox) {
|
||||
return isSavedFrame(name)
|
||||
? this.savedFrameToLabel(name)
|
||||
? FrameView({ frame: name, toolbox })
|
||||
: String(name);
|
||||
},
|
||||
|
||||
savedFrameToLabel(frame) {
|
||||
return [
|
||||
dom.span({ className: "heap-tree-item-function-display-name" },
|
||||
frame.functionDisplayFrame || ""),
|
||||
dom.span({ className: "heap-tree-item-at" }, "@"),
|
||||
dom.span({ className: "heap-tree-item-source" }, frame.source.slice(0, MAX_SOURCE_LENGTH)),
|
||||
dom.span({ className: "heap-tree-item-colon" }, ":"),
|
||||
dom.span({ className: "heap-tree-item-line" }, frame.line),
|
||||
dom.span({ className: "heap-tree-item-colon" }, ":"),
|
||||
dom.span({ className: "heap-tree-item-column" }, frame.column)
|
||||
];
|
||||
}
|
||||
});
|
||||
|
@ -45,7 +45,7 @@ const ArrowExpander = createFactory(createClass({
|
||||
const TreeNode = createFactory(createClass({
|
||||
componentDidUpdate() {
|
||||
if (this.props.focused) {
|
||||
this.refs.button.getDOMNode().focus();
|
||||
this.refs.button.focus();
|
||||
}
|
||||
},
|
||||
|
||||
@ -244,7 +244,7 @@ const Tree = module.exports = createClass({
|
||||
*/
|
||||
_updateHeight() {
|
||||
this.setState({
|
||||
height: this.refs.tree.getDOMNode().clientHeight
|
||||
height: this.refs.tree.clientHeight
|
||||
});
|
||||
},
|
||||
|
||||
@ -361,8 +361,8 @@ const Tree = module.exports = createClass({
|
||||
*/
|
||||
_onScroll(e) {
|
||||
this.setState({
|
||||
scroll: Math.max(this.refs.tree.getDOMNode().scrollTop, 0),
|
||||
height: this.refs.tree.getDOMNode().clientHeight
|
||||
scroll: Math.max(this.refs.tree.scrollTop, 0),
|
||||
height: this.refs.tree.clientHeight
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -29,6 +29,9 @@ actions.SELECT_SNAPSHOT = "select-snapshot";
|
||||
// Fired to toggle tree inversion on or off.
|
||||
actions.TOGGLE_INVERTED = "toggle-inverted";
|
||||
|
||||
// Fired to set a new breakdown.
|
||||
actions.SET_BREAKDOWN = "set-breakdown";
|
||||
|
||||
// Fired when there is an error processing a snapshot or taking a census.
|
||||
actions.SNAPSHOT_ERROR = "snapshot-error";
|
||||
|
||||
|
@ -9,26 +9,55 @@ const BrowserLoaderModule = {};
|
||||
Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
|
||||
const { require } = BrowserLoaderModule.BrowserLoader("resource://devtools/client/memory/", this);
|
||||
const { Task } = require("resource://gre/modules/Task.jsm");
|
||||
const { createFactory, createElement, render } = require("devtools/client/shared/vendor/react");
|
||||
const { createFactory, createElement, render, unmountComponentAtNode } = require("devtools/client/shared/vendor/react");
|
||||
const { Provider } = require("devtools/client/shared/vendor/react-redux");
|
||||
const App = createFactory(require("devtools/client/memory/app"));
|
||||
const Store = require("devtools/client/memory/store");
|
||||
const { assert } = require("devtools/shared/DevToolsUtils");
|
||||
|
||||
/**
|
||||
* The current target, toolbox, MemoryFront, and HeapAnalysesClient, set by this tool's host.
|
||||
*/
|
||||
var gToolbox, gTarget, gFront, gHeapAnalysesClient;
|
||||
|
||||
function initialize () {
|
||||
return Task.spawn(function*() {
|
||||
let root = document.querySelector("#app");
|
||||
let store = Store();
|
||||
let app = createElement(App, { front: gFront, heapWorker: gHeapAnalysesClient });
|
||||
let provider = createElement(Provider, { store }, app);
|
||||
render(provider, root);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Variables set by `initialize()`
|
||||
*/
|
||||
var gStore, gRoot, gApp, gProvider, unsubscribe, isHighlighted;
|
||||
|
||||
function destroy () {
|
||||
return Task.spawn(function*(){});
|
||||
var initialize = Task.async(function*() {
|
||||
gRoot = document.querySelector("#app");
|
||||
gStore = Store();
|
||||
gApp = createElement(App, { toolbox: gToolbox, front: gFront, heapWorker: gHeapAnalysesClient });
|
||||
gProvider = createElement(Provider, { store: gStore }, gApp);
|
||||
render(gProvider, gRoot);
|
||||
unsubscribe = gStore.subscribe(onStateChange);
|
||||
});
|
||||
|
||||
var destroy = Task.async(function*() {
|
||||
const ok = unmountComponentAtNode(gRoot);
|
||||
assert(ok, "Should successfully unmount the memory tool's top level React component");
|
||||
|
||||
unsubscribe();
|
||||
|
||||
gStore, gRoot, gApp, gProvider, unsubscribe, isHighlighted = null;
|
||||
});
|
||||
|
||||
/**
|
||||
* Fired on any state change, currently only handles toggling
|
||||
* the highlighting of the tool when recording allocations.
|
||||
*/
|
||||
function onStateChange () {
|
||||
let isRecording = gStore.getState().allocations.recording;
|
||||
if (isRecording === isHighlighted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRecording) {
|
||||
gToolbox.highlightTool("memory");
|
||||
} else {
|
||||
gToolbox.unhighlightTool("memory");
|
||||
}
|
||||
|
||||
isHighlighted = isRecording;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ let breakdownModel = exports.breakdown = PropTypes.shape({
|
||||
/**
|
||||
* Snapshot model.
|
||||
*/
|
||||
let stateKeys = Object.keys(states).map(state => states[state]);
|
||||
let snapshotModel = exports.snapshot = PropTypes.shape({
|
||||
// Unique ID for a snapshot
|
||||
id: PropTypes.number.isRequired,
|
||||
@ -37,19 +38,18 @@ let snapshotModel = exports.snapshot = PropTypes.shape({
|
||||
error: PropTypes.object,
|
||||
// State the snapshot is in
|
||||
// @see ./constants.js
|
||||
state: function (props, propName) {
|
||||
let stateNames = Object.keys(states);
|
||||
let current = props.state;
|
||||
state: function (snapshot, propName) {
|
||||
let current = snapshot.state;
|
||||
let shouldHavePath = [states.SAVED, states.READ, states.SAVING_CENSUS, states.SAVED_CENSUS];
|
||||
let shouldHaveCensus = [states.SAVED_CENSUS];
|
||||
|
||||
if (!stateNames.includes(current)) {
|
||||
throw new Error(`Snapshot state must be one of ${stateNames}.`);
|
||||
if (!stateKeys.includes(current)) {
|
||||
throw new Error(`Snapshot state must be one of ${stateKeys}.`);
|
||||
}
|
||||
if (shouldHavePath.includes(current) && !path) {
|
||||
if (shouldHavePath.includes(current) && !snapshot.path) {
|
||||
throw new Error(`Snapshots in state ${current} must have a snapshot path.`);
|
||||
}
|
||||
if (shouldHaveCensus.includes(current) && (!props.census || !props.breakdown)) {
|
||||
if (shouldHaveCensus.includes(current) && (!snapshot.census || !snapshot.breakdown)) {
|
||||
throw new Error(`Snapshots in state ${current} must have a census and breakdown.`);
|
||||
}
|
||||
},
|
||||
|
@ -3,5 +3,11 @@ tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
head.js
|
||||
doc_steady_allocation.html
|
||||
|
||||
[browser_memory_allocationStackBreakdown_01.js]
|
||||
[browser_memory-breakdowns-01.js]
|
||||
skip-if = debug # bug 1219554
|
||||
[browser_memory-simple-01.js]
|
||||
skip-if = debug # bug 1219554
|
||||
[browser_memory_transferHeapSnapshot_e10s_01.js]
|
||||
|
@ -0,0 +1,33 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the heap tree renders rows based on the breakdown
|
||||
*/
|
||||
|
||||
const TEST_URL = "http://example.com/browser/devtools/client/memory/test/browser/doc_steady_allocation.html";
|
||||
|
||||
this.test = makeMemoryTest(TEST_URL, function* ({ tab, panel }) {
|
||||
const { gStore, document } = panel.panelWin;
|
||||
const $$ = document.querySelectorAll.bind(document);
|
||||
|
||||
yield takeSnapshot(panel.panelWin);
|
||||
|
||||
yield waitUntilSnapshotState(gStore, [states.SAVED_CENSUS]);
|
||||
|
||||
info("Check coarse type heap view");
|
||||
["objects", "other", "scripts", "strings"].forEach(findNameCell);
|
||||
|
||||
yield setBreakdown(panel.panelWin, "objectClass");
|
||||
info("Check object class heap view");
|
||||
["Function", "Object"].forEach(findNameCell);
|
||||
|
||||
yield setBreakdown(panel.panelWin, "internalType");
|
||||
info("Check internal type heap view");
|
||||
["JSObject"].forEach(findNameCell);
|
||||
|
||||
function findNameCell (name) {
|
||||
let el = Array.prototype.find.call($$(".tree .heap-tree-item-name span"), el => el.textContent === name);
|
||||
ok(el, `Found heap tree item cell for ${name}.`);
|
||||
}
|
||||
});
|
@ -0,0 +1,35 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests taking snapshots and default states.
|
||||
*/
|
||||
|
||||
const TEST_URL = "http://example.com/browser/devtools/client/memory/test/browser/doc_steady_allocation.html";
|
||||
|
||||
this.test = makeMemoryTest(TEST_URL, function* ({ tab, panel }) {
|
||||
const { gStore, document } = panel.panelWin;
|
||||
const { getState, dispatch } = gStore;
|
||||
|
||||
let snapshotEls = document.querySelectorAll("#memory-tool-container .list li");
|
||||
is(getState().snapshots.length, 0, "Starts with no snapshots in store");
|
||||
is(snapshotEls.length, 0, "No snapshots rendered");
|
||||
|
||||
yield takeSnapshot(panel.panelWin);
|
||||
snapshotEls = document.querySelectorAll("#memory-tool-container .list li");
|
||||
is(getState().snapshots.length, 1, "One snapshot was created in store");
|
||||
is(snapshotEls.length, 1, "One snapshot was rendered");
|
||||
ok(snapshotEls[0].classList.contains("selected"), "Only snapshot has `selected` class");
|
||||
|
||||
yield takeSnapshot(panel.panelWin);
|
||||
snapshotEls = document.querySelectorAll("#memory-tool-container .list li");
|
||||
is(getState().snapshots.length, 2, "Two snapshots created in store");
|
||||
is(snapshotEls.length, 2, "Two snapshots rendered");
|
||||
ok(!snapshotEls[0].classList.contains("selected"), "First snapshot no longer has `selected` class");
|
||||
ok(snapshotEls[1].classList.contains("selected"), "Second snapshot has `selected` class");
|
||||
|
||||
yield waitUntilSnapshotState(gStore, [states.SAVED_CENSUS, states.SAVED_CENSUS]);
|
||||
|
||||
ok(document.querySelector(".heap-tree-item-name"),
|
||||
"Should have rendered some tree items");
|
||||
});
|
@ -0,0 +1,39 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Sanity test that we can show allocation stack breakdowns in the tree.
|
||||
|
||||
"use strict";
|
||||
|
||||
const { waitForTime } = require("devtools/shared/DevToolsUtils");
|
||||
const { breakdowns } = require("devtools/client/memory/constants");
|
||||
const { toggleRecordingAllocationStacks } = require("devtools/client/memory/actions/allocations");
|
||||
const { takeSnapshotAndCensus } = require("devtools/client/memory/actions/snapshot");
|
||||
const breakdownActions = require("devtools/client/memory/actions/breakdown");
|
||||
const { toggleInverted } = require("devtools/client/memory/actions/inverted");
|
||||
|
||||
const TEST_URL = "http://example.com/browser/devtools/client/memory/test/browser/doc_steady_allocation.html";
|
||||
|
||||
this.test = makeMemoryTest(TEST_URL, function* ({ tab, panel }) {
|
||||
const heapWorker = panel.panelWin.gHeapAnalysesClient;
|
||||
const front = panel.panelWin.gFront;
|
||||
const { getState, dispatch } = panel.panelWin.gStore;
|
||||
|
||||
dispatch(toggleInverted());
|
||||
ok(getState().inverted, true);
|
||||
|
||||
dispatch(breakdownActions.setBreakdown(breakdowns.allocationStack.breakdown));
|
||||
is(getState().breakdown.by, "allocationStack");
|
||||
|
||||
yield dispatch(toggleRecordingAllocationStacks(front));
|
||||
ok(getState().allocations.recording);
|
||||
|
||||
// Let some allocations build up.
|
||||
yield waitForTime(500);
|
||||
|
||||
yield dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
|
||||
const doc = panel.panelWin.document;
|
||||
ok(doc.querySelector(".frame-link-function-display-name"),
|
||||
"Should have rendered some allocation stack tree items");
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
var objects = window.objects = [];
|
||||
|
||||
var allocate = this.allocate = function allocate() {
|
||||
for (var i = 0; i < 100; i++)
|
||||
objects.push({});
|
||||
setTimeout(allocate, 10);
|
||||
}
|
||||
|
||||
allocate();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -8,6 +8,9 @@ Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
|
||||
this);
|
||||
|
||||
var { snapshotState: states } = require("devtools/client/memory/constants");
|
||||
var { breakdownEquals, breakdownNameToSpec } = require("devtools/client/memory/utils");
|
||||
|
||||
Services.prefs.setBoolPref("devtools.memory.enabled", true);
|
||||
|
||||
/**
|
||||
@ -63,3 +66,60 @@ function makeMemoryTest(url, generator) {
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function waitUntilState (store, predicate) {
|
||||
let deferred = promise.defer();
|
||||
let unsubscribe = store.subscribe(check);
|
||||
|
||||
function check () {
|
||||
if (predicate(store.getState())) {
|
||||
unsubscribe();
|
||||
deferred.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
// Fire the check immediately incase the action has already occurred
|
||||
check();
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitUntilSnapshotState (store, expected) {
|
||||
let predicate = () => {
|
||||
let snapshots = store.getState().snapshots;
|
||||
info(snapshots.map(x => x.state));
|
||||
return snapshots.length === expected.length &&
|
||||
expected.every((state, i) => state === "*" || snapshots[i].state === state);
|
||||
};
|
||||
info(`Waiting for snapshots to be of state: ${expected}`);
|
||||
return waitUntilState(store, predicate);
|
||||
}
|
||||
|
||||
function takeSnapshot (window) {
|
||||
let { gStore, document } = window;
|
||||
let snapshotCount = gStore.getState().snapshots.length;
|
||||
info(`Taking snapshot...`);
|
||||
document.querySelector(".devtools-toolbar .take-snapshot").click();
|
||||
return waitUntilState(gStore, () => gStore.getState().snapshots.length === snapshotCount + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets breakdown and waits for currently selected breakdown to use it
|
||||
* and be completed the census.
|
||||
*/
|
||||
function setBreakdown (window, type) {
|
||||
info(`Setting breakdown to ${type}...`);
|
||||
let { gStore, gHeapAnalysesClient } = window;
|
||||
// XXX: Should handle this via clicking the DOM, but React doesn't
|
||||
// fire the onChange event, so just change it in the store.
|
||||
// window.document.querySelector(`.select-breakdown`).value = type;
|
||||
gStore.dispatch(require("devtools/client/memory/actions/breakdown")
|
||||
.setBreakdownAndRefresh(gHeapAnalysesClient, breakdownNameToSpec(type)));
|
||||
|
||||
return waitUntilState(window.gStore, () => {
|
||||
let selected = window.gStore.getState().snapshots.find(s => s.selected);
|
||||
return selected.state === states.SAVED_CENSUS &&
|
||||
breakdownEquals(breakdownNameToSpec(type), selected.breakdown);
|
||||
});
|
||||
}
|
||||
|
7
devtools/client/themes/images/tool-memory-active.svg
Normal file
7
devtools/client/themes/images/tool-memory-active.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#71c054">
|
||||
<path opacity="0.2" d="M5.8 3.9l4.9.1v8.3H5.8z"/>
|
||||
<path d="M12.8 8L14 9.2c.1.1.3.2.5.2s.4-.1.5-.2c.3-.3.3-.8 0-1.1l-1.6-1.6c-.2-.2-.5-.3-.8-.2l-.6.4V5.3l.8-.3L14 6.2c.1.1.3.2.5.2s.4-.1.5-.2c.3-.3.3-.8 0-1.1l-1.6-1.6c-.2-.2-.5-.3-.8-.2l-.6.4V2.3c0-.2-.1-.3-.3-.3H4.3c-.2 0-.3.1-.3.3v1.5l-.8-.4c-.3-.1-.6-.1-.9.1L.8 5.1c-.3.3-.3.8 0 1.1.1.1.3.2.5.2s.4-.1.5-.2L3 5l1 .4v1.4l-.8-.4c-.3-.1-.6-.1-.9.1L.8 8.1c-.3.3-.3.8 0 1.1.1.1.3.2.5.2s.4-.1.5-.2L3 8l1 .4v1.4l-.8-.4c-.3-.1-.6-.1-.9.1L.7 11.1c-.3.3-.3.8 0 1.1.1.1.3.2.5.2s.4-.1.5-.2L3 11l1 .4v2.4c0 .1.1.2.3.2h7.5c.1 0 .3-.1.3-.3v-2.4l.8-.3 1.2 1.2c.1.1.3.2.5.2s.4-.1.5-.2c.3-.3.3-.8 0-1.1l-1.6-1.6c-.2-.2-.5-.3-.8-.2l-.7.4V8.3l.8-.3zM10 12H6V4h4v8z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1021 B |
7
devtools/client/themes/images/tool-memory.svg
Normal file
7
devtools/client/themes/images/tool-memory.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="whitesmoke">
|
||||
<path opacity="0.2" d="M5.8 3.9l4.9.1v8.3H5.8z"/>
|
||||
<path d="M12.8 8L14 9.2c.1.1.3.2.5.2s.4-.1.5-.2c.3-.3.3-.8 0-1.1l-1.6-1.6c-.2-.2-.5-.3-.8-.2l-.6.4V5.3l.8-.3L14 6.2c.1.1.3.2.5.2s.4-.1.5-.2c.3-.3.3-.8 0-1.1l-1.6-1.6c-.2-.2-.5-.3-.8-.2l-.6.4V2.3c0-.2-.1-.3-.3-.3H4.3c-.2 0-.3.1-.3.3v1.5l-.8-.4c-.3-.1-.6-.1-.9.1L.8 5.1c-.3.3-.3.8 0 1.1.1.1.3.2.5.2s.4-.1.5-.2L3 5l1 .4v1.4l-.8-.4c-.3-.1-.6-.1-.9.1L.8 8.1c-.3.3-.3.8 0 1.1.1.1.3.2.5.2s.4-.1.5-.2L3 8l1 .4v1.4l-.8-.4c-.3-.1-.6-.1-.9.1L.7 11.1c-.3.3-.3.8 0 1.1.1.1.3.2.5.2s.4-.1.5-.2L3 11l1 .4v2.4c0 .1.1.2.3.2h7.5c.1 0 .3-.1.3-.3v-2.4l.8-.3 1.2 1.2c.1.1.3.2.5.2s.4-.1.5-.2c.3-.3.3-.8 0-1.1l-1.6-1.6c-.2-.2-.5-.3-.8-.2l-.7.4V8.3l.8-.3zM10 12H6V4h4v8z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
@ -122,7 +122,6 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
border-bottom: 1px solid rgba(128,128,128,0.15);
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.list > li.selected {
|
||||
@ -219,7 +218,7 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
height: var(--heap-tree-row-height);
|
||||
}
|
||||
|
||||
.heap-tree-item span, .header span {
|
||||
.heap-tree-item-field, .header span {
|
||||
float: left;
|
||||
}
|
||||
|
||||
@ -268,7 +267,7 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
}
|
||||
|
||||
.heap-tree-item-name {
|
||||
padding-left: 10px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.error::before {
|
||||
@ -287,3 +286,34 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
.theme-light .error::before {
|
||||
background-image: url(chrome://devtools/skin/themes/images/webconsole.svg#light-icons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frame View components
|
||||
*/
|
||||
|
||||
.focused .frame-link-filename,
|
||||
.focused .frame-link-column,
|
||||
.focused .frame-link-line,
|
||||
.focused .frame-link-host,
|
||||
.focused .frame-link-colon {
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.frame-link-filename {
|
||||
color: var(--theme-highlight-blue);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.frame-link-filename:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.frame-link-column, .frame-link-line, .frame-link-colon {
|
||||
color: var(--theme-highlight-orange);
|
||||
}
|
||||
|
||||
.frame-link-host {
|
||||
font-size: 90%;
|
||||
margin-left: 5px;
|
||||
color: var(--theme-content-color2);
|
||||
}
|
||||
|
@ -173,6 +173,9 @@ RootActor.prototype = {
|
||||
// Whether or not `getProfile()` supports specifying a `startTime`
|
||||
// and `endTime` to filter out samples. Fx40+
|
||||
profilerDataFilterable: true,
|
||||
// Whether or not the MemoryActor's heap snapshot abilities are
|
||||
// fully equipped to handle heap snapshots for the memory tool. Fx44+
|
||||
heapSnapshots: true,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -38,7 +38,7 @@ function test_executable_lines() {
|
||||
do_check_true(!error);
|
||||
let source = gThreadClient.source(sources[0]);
|
||||
source.getExecutableLines(function(lines){
|
||||
do_check_true(arrays_equal([2, 3, 5, 6, 7, 8, 12, 14, 16], lines));
|
||||
do_check_true(arrays_equal([2, 5, 7, 8, 12, 14, 16], lines));
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
@ -55,9 +55,11 @@ using JS::ubi::AtomOrTwoByteChars;
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HeapSnapshot)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HeapSnapshot)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HeapSnapshot)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "mozilla/dom/CloseEvent.h"
|
||||
#include "mozilla/net/WebSocketEventService.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsIScriptError.h"
|
||||
@ -240,6 +241,8 @@ public:
|
||||
mozilla::Mutex mMutex;
|
||||
bool mWorkerShuttingDown;
|
||||
|
||||
RefPtr<WebSocketEventService> mService;
|
||||
|
||||
private:
|
||||
~WebSocketImpl()
|
||||
{
|
||||
@ -630,11 +633,8 @@ WebSocketImpl::Disconnect()
|
||||
// until the end of the method.
|
||||
RefPtr<WebSocketImpl> kungfuDeathGrip = this;
|
||||
|
||||
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!");
|
||||
}
|
||||
NS_ReleaseOnMainThread(mChannel);
|
||||
NS_ReleaseOnMainThread(static_cast<nsIWebSocketEventService*>(mService.forget().take()));
|
||||
|
||||
mWebSocket->DontKeepAliveAnyMore();
|
||||
mWebSocket->mImpl = nullptr;
|
||||
@ -769,6 +769,11 @@ WebSocketImpl::OnStart(nsISupports* aContext)
|
||||
|
||||
mWebSocket->SetReadyState(WebSocket::OPEN);
|
||||
|
||||
mService->WebSocketOpened(mChannel->Serial(),mInnerWindowID,
|
||||
mWebSocket->mEffectiveURL,
|
||||
mWebSocket->mEstablishedProtocol,
|
||||
mWebSocket->mEstablishedExtensions);
|
||||
|
||||
// Let's keep the object alive because the webSocket can be CCed in the
|
||||
// onopen callback.
|
||||
RefPtr<WebSocket> webSocket = mWebSocket;
|
||||
@ -1359,6 +1364,12 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Let's inform devtools about this new active WebSocket.
|
||||
webSocket->mImpl->mService->WebSocketCreated(webSocket->mImpl->mChannel->Serial(),
|
||||
webSocket->mImpl->mInnerWindowID,
|
||||
webSocket->mURI,
|
||||
webSocket->mImpl->mRequestedProtocolList);
|
||||
|
||||
cws.Done();
|
||||
return webSocket.forget();
|
||||
}
|
||||
@ -1444,6 +1455,8 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
|
||||
mService = WebSocketEventService::GetOrCreate();
|
||||
|
||||
// We need to keep the implementation alive in case the init disconnects it
|
||||
// because of some error.
|
||||
RefPtr<WebSocketImpl> kungfuDeathGrip = this;
|
||||
@ -1658,6 +1671,8 @@ WebSocketImpl::AsyncOpen(nsIPrincipal* aPrincipal, uint64_t aInnerWindowID,
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInnerWindowID = aInnerWindowID;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1837,14 +1852,20 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint16_t messageType = nsIWebSocketEventListener::TYPE_STRING;
|
||||
|
||||
// Create appropriate JS object for message
|
||||
JS::Rooted<JS::Value> jsData(aCx);
|
||||
if (aIsBinary) {
|
||||
if (mBinaryType == dom::BinaryType::Blob) {
|
||||
messageType = nsIWebSocketEventListener::TYPE_BLOB;
|
||||
|
||||
nsresult rv = nsContentUtils::CreateBlobBuffer(aCx, GetOwner(), aData,
|
||||
&jsData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (mBinaryType == dom::BinaryType::Arraybuffer) {
|
||||
messageType = nsIWebSocketEventListener::TYPE_ARRAYBUFFER;
|
||||
|
||||
JS::Rooted<JSObject*> arrayBuf(aCx);
|
||||
nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, aData,
|
||||
arrayBuf.address());
|
||||
@ -1864,6 +1885,10 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
|
||||
jsData.setString(jsString);
|
||||
}
|
||||
|
||||
mImpl->mService->WebSocketMessageAvailable(mImpl->mChannel->Serial(),
|
||||
mImpl->mInnerWindowID,
|
||||
aData, messageType);
|
||||
|
||||
// create an event that uses the MessageEvent interface,
|
||||
// which does not bubble, is not cancelable, and has no default action
|
||||
|
||||
@ -1883,11 +1908,15 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
|
||||
nsresult
|
||||
WebSocket::CreateAndDispatchCloseEvent(bool aWasClean,
|
||||
uint16_t aCode,
|
||||
const nsAString &aReason)
|
||||
const nsAString& aReason)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
mImpl->mService->WebSocketClosed(mImpl->mChannel->Serial(),
|
||||
mImpl->mInnerWindowID,
|
||||
aWasClean, aCode, aReason);
|
||||
|
||||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK;
|
||||
|
@ -557,13 +557,6 @@ nsDOMAttributeMap::Count() const
|
||||
return mAttributeCache.Count();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDOMAttributeMap::Enumerate(AttrCache::EnumReadFunction aFunc,
|
||||
void *aUserArg) const
|
||||
{
|
||||
return mAttributeCache.EnumerateRead(aFunc, aUserArg);
|
||||
}
|
||||
|
||||
size_t
|
||||
nsDOMAttributeMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
|
@ -128,13 +128,7 @@ public:
|
||||
|
||||
typedef nsRefPtrHashtable<nsAttrHashKey, Attr> AttrCache;
|
||||
|
||||
/**
|
||||
* Enumerates over the attribute nodess in the map and calls aFunc for each
|
||||
* one. If aFunc returns PL_DHASH_STOP we'll stop enumerating at that point.
|
||||
*
|
||||
* @return The number of attribute nodes that aFunc was called for.
|
||||
*/
|
||||
uint32_t Enumerate(AttrCache::EnumReadFunction aFunc, void *aUserArg) const;
|
||||
static void BlastSubtreeToPieces(nsINode *aNode);
|
||||
|
||||
Element* GetParentObject() const
|
||||
{
|
||||
|
@ -7633,42 +7633,36 @@ nsIDocument::GetCompatMode(nsString& aCompatMode) const
|
||||
}
|
||||
}
|
||||
|
||||
static void BlastSubtreeToPieces(nsINode *aNode);
|
||||
|
||||
PLDHashOperator
|
||||
BlastFunc(nsAttrHashKey::KeyType aKey, Attr *aData, void* aUserArg)
|
||||
{
|
||||
nsCOMPtr<nsIAttribute> *attr =
|
||||
static_cast<nsCOMPtr<nsIAttribute>*>(aUserArg);
|
||||
|
||||
*attr = aData;
|
||||
|
||||
NS_ASSERTION(attr->get(),
|
||||
"non-nsIAttribute somehow made it into the hashmap?!");
|
||||
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
static void
|
||||
BlastSubtreeToPieces(nsINode *aNode)
|
||||
void
|
||||
nsDOMAttributeMap::BlastSubtreeToPieces(nsINode *aNode)
|
||||
{
|
||||
if (aNode->IsElement()) {
|
||||
Element *element = aNode->AsElement();
|
||||
const nsDOMAttributeMap *map = element->GetAttributeMap();
|
||||
if (map) {
|
||||
nsCOMPtr<nsIAttribute> attr;
|
||||
while (map->Enumerate(BlastFunc, &attr) > 0) {
|
||||
|
||||
// This non-standard style of iteration is presumably used because some
|
||||
// of the code in the loop body can trigger element removal, which
|
||||
// invalidates the iterator.
|
||||
while (true) {
|
||||
auto iter = map->mAttributeCache.ConstIter();
|
||||
if (iter.Done()) {
|
||||
break;
|
||||
}
|
||||
nsCOMPtr<nsIAttribute> attr = iter.UserData();
|
||||
NS_ASSERTION(attr.get(),
|
||||
"non-nsIAttribute somehow made it into the hashmap?!");
|
||||
|
||||
BlastSubtreeToPieces(attr);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
DebugOnly<nsresult> rv =
|
||||
element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
|
||||
attr->NodeInfo()->NameAtom(),
|
||||
false);
|
||||
|
||||
// XXX Should we abort here?
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, UnsetAttr shouldn't fail!");
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7835,7 +7829,7 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
|
||||
if (rv.Failed()) {
|
||||
// Disconnect all nodes from their parents, since some have the old document
|
||||
// as their ownerDocument and some have this as their ownerDocument.
|
||||
BlastSubtreeToPieces(adoptedNode);
|
||||
nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
|
||||
|
||||
if (!sameDocument && oldDocument) {
|
||||
uint32_t count = nodesWithProperties.Count();
|
||||
@ -7864,7 +7858,7 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
|
||||
|
||||
if (rv.Failed()) {
|
||||
// Disconnect all nodes from their parents.
|
||||
BlastSubtreeToPieces(adoptedNode);
|
||||
nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -5507,7 +5507,8 @@ nsGlobalWindow::GetScrollBoundaryOuter(Side aSide)
|
||||
|
||||
FlushPendingNotifications(Flush_Layout);
|
||||
if (nsIScrollableFrame *sf = GetScrollFrame()) {
|
||||
return sf->GetScrollRange().Edge(aSide);
|
||||
return nsPresContext::
|
||||
AppUnitsToIntCSSPixels(sf->GetScrollRange().Edge(aSide));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -12869,18 +12870,6 @@ nsGlobalWindow::RemoveGamepad(uint32_t aIndex)
|
||||
mGamepads.Remove(aIndex);
|
||||
}
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey, Gamepad* aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
nsTArray<RefPtr<Gamepad> >* array =
|
||||
static_cast<nsTArray<RefPtr<Gamepad> >*>(aUserArg);
|
||||
array->EnsureLengthAtLeast(aData->Index() + 1);
|
||||
(*array)[aData->Index()] = aData;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads)
|
||||
{
|
||||
@ -12888,7 +12877,11 @@ nsGlobalWindow::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads)
|
||||
aGamepads.Clear();
|
||||
// mGamepads.Count() may not be sufficient, but it's not harmful.
|
||||
aGamepads.SetCapacity(mGamepads.Count());
|
||||
mGamepads.EnumerateRead(EnumGamepadsForGet, &aGamepads);
|
||||
for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
|
||||
Gamepad* gamepad = iter.UserData();
|
||||
aGamepads.EnsureLengthAtLeast(gamepad->Index() + 1);
|
||||
aGamepads[gamepad->Index()] = gamepad;
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Gamepad>
|
||||
@ -12918,22 +12911,15 @@ nsGlobalWindow::HasSeenGamepadInput()
|
||||
return mHasSeenGamepadInput;
|
||||
}
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
nsGlobalWindow::EnumGamepadsForSync(const uint32_t& aKey, Gamepad* aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
RefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
|
||||
gamepadsvc->SyncGamepadState(aKey, aData);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::SyncGamepadState()
|
||||
{
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
if (mHasSeenGamepadInput) {
|
||||
mGamepads.EnumerateRead(EnumGamepadsForSync, nullptr);
|
||||
RefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
|
||||
for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
|
||||
gamepadsvc->SyncGamepadState(iter.Key(), iter.UserData());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // MOZ_GAMEPAD
|
||||
@ -12976,9 +12962,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
|
||||
tmp->mMessageManager.get())->Disconnect();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
|
||||
}
|
||||
|
||||
tmp->mGroupMessageManagers.EnumerateRead(DisconnectGroupMessageManager, nullptr);
|
||||
tmp->mGroupMessageManagers.Clear();
|
||||
tmp->DisconnectAndClearGroupMessageManagers();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroupMessageManagers)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
@ -763,12 +763,6 @@ public:
|
||||
void SetHasSeenGamepadInput(bool aHasSeen);
|
||||
bool HasSeenGamepadInput();
|
||||
void SyncGamepadState();
|
||||
static PLDHashOperator EnumGamepadsForSync(const uint32_t& aKey,
|
||||
mozilla::dom::Gamepad* aData,
|
||||
void* aUserArg);
|
||||
static PLDHashOperator EnumGamepadsForGet(const uint32_t& aKey,
|
||||
mozilla::dom::Gamepad* aData,
|
||||
void* aUserArg);
|
||||
#endif
|
||||
|
||||
// Inner windows only.
|
||||
@ -1906,15 +1900,15 @@ public:
|
||||
|
||||
static already_AddRefed<nsGlobalChromeWindow> Create(nsGlobalWindow *aOuterWindow);
|
||||
|
||||
static PLDHashOperator
|
||||
DisconnectGroupMessageManager(const nsAString& aKey,
|
||||
nsIMessageBroadcaster* aMM,
|
||||
void* aUserArg)
|
||||
void DisconnectAndClearGroupMessageManagers()
|
||||
{
|
||||
if (aMM) {
|
||||
static_cast<nsFrameMessageManager*>(aMM)->Disconnect();
|
||||
for (auto iter = mGroupMessageManagers.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsIMessageBroadcaster* mm = iter.UserData();
|
||||
if (mm) {
|
||||
static_cast<nsFrameMessageManager*>(mm)->Disconnect();
|
||||
}
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
mGroupMessageManagers.Clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -1931,8 +1925,7 @@ protected:
|
||||
MOZ_ASSERT(mCleanMessageManager,
|
||||
"chrome windows may always disconnect the msg manager");
|
||||
|
||||
mGroupMessageManagers.EnumerateRead(DisconnectGroupMessageManager, nullptr);
|
||||
mGroupMessageManagers.Clear();
|
||||
DisconnectAndClearGroupMessageManagers();
|
||||
|
||||
if (mMessageManager) {
|
||||
static_cast<nsFrameMessageManager *>(
|
||||
|
@ -66,15 +66,125 @@ class BlobURLsReporter final : public nsIMemoryReporter
|
||||
NS_IMETHOD CollectReports(nsIHandleReportCallback* aCallback,
|
||||
nsISupports* aData, bool aAnonymize) override
|
||||
{
|
||||
EnumArg env;
|
||||
env.mCallback = aCallback;
|
||||
env.mData = aData;
|
||||
env.mAnonymize = aAnonymize;
|
||||
|
||||
if (gDataTable) {
|
||||
gDataTable->EnumerateRead(CountCallback, &env);
|
||||
gDataTable->EnumerateRead(ReportCallback, &env);
|
||||
if (!gDataTable) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDataHashtable<nsPtrHashKey<nsIDOMBlob>, uint32_t> refCounts;
|
||||
|
||||
// Determine number of URLs per blob, to handle the case where it's > 1.
|
||||
for (auto iter = gDataTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsCOMPtr<nsIDOMBlob> blob =
|
||||
do_QueryInterface(iter.UserData()->mObject);
|
||||
if (blob) {
|
||||
refCounts.Put(blob, refCounts.Get(blob) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = gDataTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsCStringHashKey::KeyType key = iter.Key();
|
||||
DataInfo* info = iter.UserData();
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> tmp = do_QueryInterface(info->mObject);
|
||||
RefPtr<mozilla::dom::Blob> blob =
|
||||
static_cast<mozilla::dom::Blob*>(tmp.get());
|
||||
|
||||
if (blob) {
|
||||
NS_NAMED_LITERAL_CSTRING(desc,
|
||||
"A blob URL allocated with URL.createObjectURL; the referenced "
|
||||
"blob cannot be freed until all URLs for it have been explicitly "
|
||||
"invalidated with URL.revokeObjectURL.");
|
||||
nsAutoCString path, url, owner, specialDesc;
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
uint64_t size = 0;
|
||||
uint32_t refCount = 1;
|
||||
DebugOnly<bool> blobWasCounted;
|
||||
|
||||
blobWasCounted = refCounts.Get(blob, &refCount);
|
||||
MOZ_ASSERT(blobWasCounted);
|
||||
MOZ_ASSERT(refCount > 0);
|
||||
|
||||
bool isMemoryFile = blob->IsMemoryFile();
|
||||
|
||||
if (isMemoryFile) {
|
||||
ErrorResult rv;
|
||||
size = blob->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
path = isMemoryFile ? "memory-blob-urls/" : "file-blob-urls/";
|
||||
BuildPath(path, key, info, aAnonymize);
|
||||
|
||||
if (refCount > 1) {
|
||||
nsAutoCString addrStr;
|
||||
|
||||
addrStr = "0x";
|
||||
addrStr.AppendInt((uint64_t)(nsIDOMBlob*)blob, 16);
|
||||
|
||||
path += " ";
|
||||
path.AppendInt(refCount);
|
||||
path += "@";
|
||||
path += addrStr;
|
||||
|
||||
specialDesc = desc;
|
||||
specialDesc += "\n\nNOTE: This blob (address ";
|
||||
specialDesc += addrStr;
|
||||
specialDesc += ") has ";
|
||||
specialDesc.AppendInt(refCount);
|
||||
specialDesc += " URLs.";
|
||||
if (isMemoryFile) {
|
||||
specialDesc += " Its size is divided ";
|
||||
specialDesc += refCount > 2 ? "among" : "between";
|
||||
specialDesc += " them in this report.";
|
||||
}
|
||||
}
|
||||
|
||||
const nsACString& descString = specialDesc.IsEmpty()
|
||||
? static_cast<const nsACString&>(desc)
|
||||
: static_cast<const nsACString&>(specialDesc);
|
||||
if (isMemoryFile) {
|
||||
aCallback->Callback(EmptyCString(),
|
||||
path,
|
||||
KIND_OTHER,
|
||||
UNITS_BYTES,
|
||||
size / refCount,
|
||||
descString,
|
||||
aData);
|
||||
} else {
|
||||
aCallback->Callback(EmptyCString(),
|
||||
path,
|
||||
KIND_OTHER,
|
||||
UNITS_COUNT,
|
||||
1,
|
||||
descString,
|
||||
aData);
|
||||
}
|
||||
} else {
|
||||
// Just report the path for the DOMMediaStream or MediaSource.
|
||||
nsCOMPtr<mozilla::dom::MediaSource>
|
||||
ms(do_QueryInterface(info->mObject));
|
||||
nsAutoCString path;
|
||||
path = ms ? "media-source-urls/" : "dom-media-stream-urls/";
|
||||
BuildPath(path, key, info, aAnonymize);
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(desc,
|
||||
"An object URL allocated with URL.createObjectURL; the referenced "
|
||||
"data cannot be freed until all URLs for it have been explicitly "
|
||||
"invalidated with URL.revokeObjectURL.");
|
||||
|
||||
aCallback->Callback(EmptyCString(),
|
||||
path,
|
||||
KIND_OTHER,
|
||||
UNITS_COUNT,
|
||||
1,
|
||||
desc,
|
||||
aData);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -143,28 +253,6 @@ class BlobURLsReporter final : public nsIMemoryReporter
|
||||
private:
|
||||
~BlobURLsReporter() {}
|
||||
|
||||
struct EnumArg {
|
||||
nsIHandleReportCallback* mCallback;
|
||||
nsISupports* mData;
|
||||
bool mAnonymize;
|
||||
nsDataHashtable<nsPtrHashKey<nsIDOMBlob>, uint32_t> mRefCounts;
|
||||
};
|
||||
|
||||
// Determine number of URLs per blob, to handle the case where it's > 1.
|
||||
static PLDHashOperator CountCallback(nsCStringHashKey::KeyType aKey,
|
||||
DataInfo* aInfo,
|
||||
void* aUserArg)
|
||||
{
|
||||
EnumArg* envp = static_cast<EnumArg*>(aUserArg);
|
||||
nsCOMPtr<nsIDOMBlob> blob;
|
||||
|
||||
blob = do_QueryInterface(aInfo->mObject);
|
||||
if (blob) {
|
||||
envp->mRefCounts.Put(blob, envp->mRefCounts.Get(blob) + 1);
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static void BuildPath(nsAutoCString& path,
|
||||
nsCStringHashKey::KeyType aKey,
|
||||
DataInfo* aInfo,
|
||||
@ -201,112 +289,6 @@ class BlobURLsReporter final : public nsIMemoryReporter
|
||||
path += url;
|
||||
}
|
||||
}
|
||||
|
||||
static PLDHashOperator ReportCallback(nsCStringHashKey::KeyType aKey,
|
||||
DataInfo* aInfo,
|
||||
void* aUserArg)
|
||||
{
|
||||
EnumArg* envp = static_cast<EnumArg*>(aUserArg);
|
||||
nsCOMPtr<nsIDOMBlob> tmp = do_QueryInterface(aInfo->mObject);
|
||||
RefPtr<mozilla::dom::Blob> blob = static_cast<mozilla::dom::Blob*>(tmp.get());
|
||||
|
||||
if (blob) {
|
||||
NS_NAMED_LITERAL_CSTRING
|
||||
(desc, "A blob URL allocated with URL.createObjectURL; the referenced "
|
||||
"blob cannot be freed until all URLs for it have been explicitly "
|
||||
"invalidated with URL.revokeObjectURL.");
|
||||
nsAutoCString path, url, owner, specialDesc;
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
uint64_t size = 0;
|
||||
uint32_t refCount = 1;
|
||||
DebugOnly<bool> blobWasCounted;
|
||||
|
||||
blobWasCounted = envp->mRefCounts.Get(blob, &refCount);
|
||||
MOZ_ASSERT(blobWasCounted);
|
||||
MOZ_ASSERT(refCount > 0);
|
||||
|
||||
bool isMemoryFile = blob->IsMemoryFile();
|
||||
|
||||
if (isMemoryFile) {
|
||||
ErrorResult rv;
|
||||
size = blob->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
path = isMemoryFile ? "memory-blob-urls/" : "file-blob-urls/";
|
||||
BuildPath(path, aKey, aInfo, envp->mAnonymize);
|
||||
|
||||
if (refCount > 1) {
|
||||
nsAutoCString addrStr;
|
||||
|
||||
addrStr = "0x";
|
||||
addrStr.AppendInt((uint64_t)(nsIDOMBlob*)blob, 16);
|
||||
|
||||
path += " ";
|
||||
path.AppendInt(refCount);
|
||||
path += "@";
|
||||
path += addrStr;
|
||||
|
||||
specialDesc = desc;
|
||||
specialDesc += "\n\nNOTE: This blob (address ";
|
||||
specialDesc += addrStr;
|
||||
specialDesc += ") has ";
|
||||
specialDesc.AppendInt(refCount);
|
||||
specialDesc += " URLs.";
|
||||
if (isMemoryFile) {
|
||||
specialDesc += " Its size is divided ";
|
||||
specialDesc += refCount > 2 ? "among" : "between";
|
||||
specialDesc += " them in this report.";
|
||||
}
|
||||
}
|
||||
|
||||
const nsACString& descString = specialDesc.IsEmpty()
|
||||
? static_cast<const nsACString&>(desc)
|
||||
: static_cast<const nsACString&>(specialDesc);
|
||||
if (isMemoryFile) {
|
||||
envp->mCallback->Callback(EmptyCString(),
|
||||
path,
|
||||
KIND_OTHER,
|
||||
UNITS_BYTES,
|
||||
size / refCount,
|
||||
descString,
|
||||
envp->mData);
|
||||
}
|
||||
else {
|
||||
envp->mCallback->Callback(EmptyCString(),
|
||||
path,
|
||||
KIND_OTHER,
|
||||
UNITS_COUNT,
|
||||
1,
|
||||
descString,
|
||||
envp->mData);
|
||||
}
|
||||
} else {
|
||||
// Just report the path for the DOMMediaStream or MediaSource.
|
||||
nsCOMPtr<mozilla::dom::MediaSource> ms(do_QueryInterface(aInfo->mObject));
|
||||
nsAutoCString path;
|
||||
path = ms ? "media-source-urls/" : "dom-media-stream-urls/";
|
||||
BuildPath(path, aKey, aInfo, envp->mAnonymize);
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING
|
||||
(desc, "An object URL allocated with URL.createObjectURL; the referenced "
|
||||
"data cannot be freed until all URLs for it have been explicitly "
|
||||
"invalidated with URL.revokeObjectURL.");
|
||||
|
||||
envp->mCallback->Callback(EmptyCString(),
|
||||
path,
|
||||
KIND_OTHER,
|
||||
UNITS_COUNT,
|
||||
1,
|
||||
desc,
|
||||
envp->mData);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(BlobURLsReporter, nsIMemoryReporter)
|
||||
|
@ -789,37 +789,6 @@ CheckForGhostWindowsEnumerator(nsISupports *aKey, TimeStamp& aTimeStamp,
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
struct GetNonDetachedWindowDomainsEnumeratorData
|
||||
{
|
||||
nsTHashtable<nsCStringHashKey> *nonDetachedDomains;
|
||||
nsIEffectiveTLDService *tldService;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
GetNonDetachedWindowDomainsEnumerator(const uint64_t& aId, nsGlobalWindow* aWindow,
|
||||
void* aClosure)
|
||||
{
|
||||
GetNonDetachedWindowDomainsEnumeratorData *data =
|
||||
static_cast<GetNonDetachedWindowDomainsEnumeratorData*>(aClosure);
|
||||
|
||||
// Null outer window implies null top, but calling GetTop() when there's no
|
||||
// outer window causes us to spew debug warnings.
|
||||
if (!aWindow->GetOuterWindow() || !aWindow->GetTopInternal()) {
|
||||
// This window is detached, so we don't care about its domain.
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
|
||||
|
||||
nsAutoCString domain;
|
||||
if (uri) {
|
||||
data->tldService->GetBaseDomain(uri, 0, domain);
|
||||
}
|
||||
|
||||
data->nonDetachedDomains->PutEntry(domain);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over mDetachedWindows and update it to reflect the current state of
|
||||
* the world. In particular:
|
||||
@ -861,10 +830,22 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
||||
nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
|
||||
|
||||
// Populate nonDetachedWindowDomains.
|
||||
GetNonDetachedWindowDomainsEnumeratorData nonDetachedEnumData =
|
||||
{ &nonDetachedWindowDomains, tldService };
|
||||
windowsById->EnumerateRead(GetNonDetachedWindowDomainsEnumerator,
|
||||
&nonDetachedEnumData);
|
||||
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
||||
// Null outer window implies null top, but calling GetTop() when there's no
|
||||
// outer window causes us to spew debug warnings.
|
||||
nsGlobalWindow* window = iter.UserData();
|
||||
if (!window->GetOuterWindow() || !window->GetTopInternal()) {
|
||||
// This window is detached, so we don't care about its domain.
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = GetWindowURI(window);
|
||||
nsAutoCString domain;
|
||||
if (uri) {
|
||||
tldService->GetBaseDomain(uri, 0, domain);
|
||||
}
|
||||
nonDetachedWindowDomains.PutEntry(domain);
|
||||
}
|
||||
|
||||
// Update mDetachedWindows and write the ghost window IDs into aOutGhostIDs,
|
||||
// if it's not null.
|
||||
|
@ -12,15 +12,20 @@
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
const URI = "ws://mochi.test:8888/tests/dom/base/test/file_websocket_basic";
|
||||
|
||||
var frameReceivedCounter = 0;
|
||||
var frameSentCounter = 0;
|
||||
var webSocketCreatedCounter = 0;
|
||||
var webSocketOpenedCounter = 0;
|
||||
var webSocketMessageAvailableCounter = 0;
|
||||
var webSocketClosedCounter = 0;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var tests = [
|
||||
{ payload: "Hello world!" },
|
||||
{ payload: (function() { var buffer = ""; for (var i = 0; i < 120; ++i) buffer += i; return buffer; }()) },
|
||||
{ payload: "end" },
|
||||
]
|
||||
|
||||
var innerId =
|
||||
@ -28,12 +33,61 @@ var innerId =
|
||||
.getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
|
||||
ok(innerId, "We have a valid innerWindowID: " + innerId);
|
||||
|
||||
var service = Cc["@mozilla.org/websocketframe/service;1"]
|
||||
.getService(Ci.nsIWebSocketFrameService);
|
||||
ok(!!service, "We have the nsIWebSocketFrameService");
|
||||
var service = Cc["@mozilla.org/websocketevent/service;1"]
|
||||
.getService(Ci.nsIWebSocketEventService);
|
||||
ok(!!service, "We have the nsIWebSocketEventService");
|
||||
|
||||
var listener = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebSocketFrameListener]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebSocketEventListener]),
|
||||
|
||||
webSocketCreated: function(aWebSocketSerialID, aURI, aProtocols) {
|
||||
info("WebSocketCreated");
|
||||
|
||||
is(aURI, URI, "URI matches");
|
||||
is(aProtocols, "frame", "Protocol matches");
|
||||
|
||||
webSocketCreatedCounter++;
|
||||
},
|
||||
|
||||
webSocketOpened: function(aWebSocketSerialID, aEffectiveURI, aProtocols, aExtensions) {
|
||||
info("WebSocketOpened");
|
||||
|
||||
is(aEffectiveURI, URI, "EffectiveURI matches");
|
||||
is(aProtocols, "frame", "Protocol matches");
|
||||
is(aExtensions, "permessage-deflate", "No extensions");
|
||||
|
||||
webSocketOpenedCounter++;
|
||||
},
|
||||
|
||||
webSocketMessageAvailable: function(aWebSocketSerialID, aData, aMessageType) {
|
||||
info("WebSocketMessageAvailable");
|
||||
|
||||
if (tests.length) {
|
||||
is(aData, tests[0].payload, "Message matches!");
|
||||
is(aMessageType, Ci.nsIWebSocketEventListener.TYPE_STRING, "The type is 'string'");
|
||||
|
||||
webSocketMessageAvailableCounter++;
|
||||
|
||||
tests.shift();
|
||||
if (tests.length) {
|
||||
ws.send(tests[0].payload);
|
||||
} else {
|
||||
ws.send("end");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
webSocketClosed: function(aWebSocketSerialID, aWasClean,
|
||||
aCode, aReason) {
|
||||
info("WebSocketClosed");
|
||||
|
||||
ok(aWasClean, "The socket is closed in a clean state");
|
||||
is(aCode, 1000, "Exit code 1000");
|
||||
ok(!aReason.length, "No reason");
|
||||
|
||||
webSocketClosedCounter++;
|
||||
checkListener();
|
||||
},
|
||||
|
||||
frameReceived: function(aWebSocketSerialID, aFrame) {
|
||||
ok(!!aFrame, "We have received a frame");
|
||||
@ -48,15 +102,6 @@ var listener = {
|
||||
is(aFrame.maskBit, false, "Checking maskBit");
|
||||
is(aFrame.mask, 0, "Checking mask");
|
||||
is(aFrame.payload, tests[0].payload, "Checking payload: " + aFrame.payload);
|
||||
} else {
|
||||
ok(aFrame.timeStamp, "Checking timeStamp: " + aFrame.timeStamp);
|
||||
is(aFrame.finBit, true, "Checking finBit");
|
||||
is(aFrame.rsvBit1, false, "Checking rsvBit1");
|
||||
is(aFrame.rsvBit2, false, "Checking rsvBit2");
|
||||
is(aFrame.rsvBit3, false, "Checking rsvBit3");
|
||||
is(aFrame.opCode, aFrame.OPCODE_CLOSE, "Checking opCode");
|
||||
is(aFrame.maskBit, false, "Checking maskBit");
|
||||
is(aFrame.mask, 0, "Checking mask");
|
||||
}
|
||||
|
||||
frameReceivedCounter++;
|
||||
@ -75,15 +120,6 @@ var listener = {
|
||||
is(aFrame.maskBit, true, "Checking maskBit");
|
||||
ok(!!aFrame.mask, "Checking mask: " + aFrame.mask);
|
||||
is(aFrame.payload, tests[0].payload, "Checking payload: " + aFrame.payload);
|
||||
} else {
|
||||
ok(aFrame.timeStamp, "Checking timeStamp: " + aFrame.timeStamp);
|
||||
is(aFrame.finBit, true, "Checking finBit");
|
||||
is(aFrame.rsvBit1, false, "Checking rsvBit1");
|
||||
is(aFrame.rsvBit2, false, "Checking rsvBit2");
|
||||
is(aFrame.rsvBit3, false, "Checking rsvBit3");
|
||||
is(aFrame.opCode, aFrame.OPCODE_CLOSE, "Checking opCode");
|
||||
is(aFrame.maskBit, true, "Checking maskBit");
|
||||
ok(!!aFrame.mask, "Checking mask: " + aFrame.mask);
|
||||
}
|
||||
|
||||
frameSentCounter++;
|
||||
@ -98,10 +134,14 @@ function checkListener() {
|
||||
|
||||
ok(frameReceivedCounter, "We received some frames!");
|
||||
ok(frameSentCounter, "We sent some frames!");
|
||||
ok(webSocketCreatedCounter, "We have a create notification");
|
||||
ok(webSocketOpenedCounter, "We have a open notification");
|
||||
ok(webSocketMessageAvailableCounter, "We have a messageAvailable notification");
|
||||
ok(webSocketClosedCounter, "We have a close notification");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
var ws = new WebSocket("ws://mochi.test:8888/tests/dom/base/test/file_websocket_basic", "frame");
|
||||
var ws = new WebSocket(URI, "frame");
|
||||
ws.onopen = function(e) {
|
||||
info("onopen");
|
||||
|
||||
@ -110,18 +150,12 @@ ws.onopen = function(e) {
|
||||
|
||||
ws.onclose = function(e) {
|
||||
info("onclose");
|
||||
|
||||
ws.close();
|
||||
checkListener();
|
||||
}
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
info("onmessage");
|
||||
|
||||
is(e.data, tests[0].payload, "Wrong data");
|
||||
tests.shift();
|
||||
if (tests.length) {
|
||||
ws.send(tests[0].payload);
|
||||
is(e.data, tests[0].payload, "Wrong data");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4497,7 +4497,7 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
|
||||
if (ok) {
|
||||
NativeSurface texSurf;
|
||||
texSurf.mType = NativeSurfaceType::OPENGL_TEXTURE;
|
||||
texSurf.mFormat = SurfaceFormat::R5G6B5;
|
||||
texSurf.mFormat = SurfaceFormat::R5G6B5_UINT16;
|
||||
texSurf.mSize.width = mCurrentVideoSize.width;
|
||||
texSurf.mSize.height = mCurrentVideoSize.height;
|
||||
texSurf.mSurface = (void*)((uintptr_t)mVideoTexture);
|
||||
|
@ -1943,7 +1943,7 @@ WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromE
|
||||
case SurfaceFormat::A8:
|
||||
*format = WebGLTexelFormat::A8;
|
||||
break;
|
||||
case SurfaceFormat::R5G6B5:
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
*format = WebGLTexelFormat::RGB565;
|
||||
break;
|
||||
default:
|
||||
|
@ -430,9 +430,10 @@ AppleMP3Reader::SetupDecoder()
|
||||
// Set output format
|
||||
#if defined(MOZ_SAMPLE_TYPE_FLOAT32)
|
||||
outputFormat.mBitsPerChannel = 32;
|
||||
outputFormat.mFormatFlags =
|
||||
kLinearPCMFormatFlagIsFloat |
|
||||
0;
|
||||
outputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
|
||||
#elif defined(MOZ_SAMPLE_TYPE_S16)
|
||||
outputFormat.mBitsPerChannel = 32;
|
||||
outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||
#else
|
||||
#error Unknown audio sample type
|
||||
#endif
|
||||
@ -506,23 +507,34 @@ AppleMP3Reader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals = mFilter.NotifyDataArrived(aLength, aOffset);
|
||||
AutoPinned<MediaResource> resource(mResource.GetResource());
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals;
|
||||
for (auto& range : byteRanges) {
|
||||
intervals += mFilter.NotifyDataArrived(range.Length(), range.mStart);
|
||||
}
|
||||
for (const auto& interval : intervals) {
|
||||
RefPtr<MediaByteBuffer> bytes =
|
||||
mResource.MediaReadAt(interval.mStart, interval.Length());
|
||||
resource->MediaReadAt(interval.mStart, interval.Length());
|
||||
NS_ENSURE_TRUE_VOID(bytes);
|
||||
mMP3FrameParser.Parse(bytes->Elements(), interval.Length(), interval.mStart);
|
||||
if (!mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mDuration) {
|
||||
LOGD("Updating media duration to %lluus\n", duration);
|
||||
MOZ_ASSERT(mDecoder);
|
||||
mDuration = duration;
|
||||
mDecoder->DispatchUpdateEstimatedMediaDuration(duration);
|
||||
}
|
||||
uint64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mDuration) {
|
||||
LOGD("Updating media duration to %lluus\n", duration);
|
||||
MOZ_ASSERT(mDecoder);
|
||||
mDuration = duration;
|
||||
mDecoder->DispatchUpdateEstimatedMediaDuration(duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,22 +387,32 @@ DirectShowReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals = mFilter.NotifyDataArrived(aLength, aOffset);
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals;
|
||||
for (auto& range : byteRanges) {
|
||||
intervals += mFilter.NotifyDataArrived(range.Length(), range.mStart);
|
||||
}
|
||||
for (const auto& interval : intervals) {
|
||||
RefPtr<MediaByteBuffer> bytes =
|
||||
mDecoder->GetResource()->MediaReadAt(interval.mStart, interval.Length());
|
||||
resource->MediaReadAt(interval.mStart, interval.Length());
|
||||
NS_ENSURE_TRUE_VOID(bytes);
|
||||
mMP3FrameParser.Parse(bytes->Elements(), interval.Length(), interval.mStart);
|
||||
if (!mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mDuration) {
|
||||
MOZ_ASSERT(mDecoder);
|
||||
mDuration = duration;
|
||||
mDecoder->DispatchUpdateEstimatedMediaDuration(mDuration);
|
||||
}
|
||||
}
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mDuration) {
|
||||
MOZ_ASSERT(mDecoder);
|
||||
mDuration = duration;
|
||||
mDecoder->DispatchUpdateEstimatedMediaDuration(mDuration);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,7 +403,7 @@ nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk)
|
||||
cr, halfWidth,
|
||||
mFrameWidth, mFrameHeight);
|
||||
break;
|
||||
case SurfaceFormat::R5G6B5:
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
rv = libyuv::RGB565ToI420(static_cast<uint8*>(map.GetData()),
|
||||
map.GetStride(),
|
||||
y, mFrameWidth,
|
||||
|
@ -1286,22 +1286,32 @@ void GStreamerReader::NotifyDataArrivedInternal(uint32_t aLength,
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals = mFilter.NotifyDataArrived(aLength, aOffset);
|
||||
AutoPinned<MediaResource> resource(mResource.GetResource());
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals;
|
||||
for (auto& range : byteRanges) {
|
||||
intervals += mFilter.NotifyDataArrived(range.Length(), range.mStart);
|
||||
}
|
||||
for (const auto& interval : intervals) {
|
||||
RefPtr<MediaByteBuffer> bytes =
|
||||
mResource.MediaReadAt(interval.mStart, interval.Length());
|
||||
resource->MediaReadAt(interval.mStart, interval.Length());
|
||||
NS_ENSURE_TRUE_VOID(bytes);
|
||||
mMP3FrameParser.Parse(bytes->Elements(), interval.Length(), interval.mStart);
|
||||
if (!mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mLastParserDuration && mUseParserDuration) {
|
||||
MOZ_ASSERT(mDecoder);
|
||||
mLastParserDuration = duration;
|
||||
mDecoder->DispatchUpdateEstimatedMediaDuration(mLastParserDuration);
|
||||
}
|
||||
}
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mLastParserDuration && mUseParserDuration) {
|
||||
MOZ_ASSERT(mDecoder);
|
||||
mLastParserDuration = duration;
|
||||
mDecoder->DispatchUpdateEstimatedMediaDuration(mLastParserDuration);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
@ -75,13 +76,14 @@ static const char* const gMediaSourceTypes[6] = {
|
||||
// * Windows Vista and Server 2008 without the optional "Platform Update Supplement"
|
||||
// * N/KN editions (Europe and Korea) of Windows 7/8/8.1/10 without the
|
||||
// optional "Windows Media Feature Pack"
|
||||
|
||||
// 2. If H264 hardware acceleration is not available.
|
||||
static bool
|
||||
IsWebMForced()
|
||||
{
|
||||
bool mp4supported =
|
||||
DecoderTraits::IsMP4TypeAndEnabled(NS_LITERAL_CSTRING("video/mp4"));
|
||||
return !mp4supported;
|
||||
bool hwsupported = gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding();
|
||||
return !mp4supported || !hwsupported;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
|
@ -520,10 +520,21 @@ void
|
||||
MediaCodecReader::NotifyDataArrivedInternal(uint32_t aLength,
|
||||
int64_t aOffset)
|
||||
{
|
||||
IntervalSet<int64_t> intervals = mFilter.NotifyDataArrived(aLength, aOffset);
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals;
|
||||
for (auto& range : byteRanges) {
|
||||
intervals += mFilter.NotifyDataArrived(range.Length(), range.mStart);
|
||||
}
|
||||
for (const auto& interval : intervals) {
|
||||
RefPtr<MediaByteBuffer> bytes =
|
||||
mDecoder->GetResource()->MediaReadAt(interval.mStart, interval.Length());
|
||||
resource->MediaReadAt(interval.mStart, interval.Length());
|
||||
MonitorAutoLock monLock(mParserMonitor);
|
||||
if (mNextParserPosition == mParsedDataLength &&
|
||||
mNextParserPosition >= interval.mStart &&
|
||||
|
@ -463,21 +463,31 @@ void MediaOmxReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals = mFilter.NotifyDataArrived(aLength, aOffset);
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
IntervalSet<int64_t> intervals;
|
||||
for (auto& range : byteRanges) {
|
||||
intervals += mFilter.NotifyDataArrived(range.Length(), range.mStart);
|
||||
}
|
||||
for (const auto& interval : intervals) {
|
||||
RefPtr<MediaByteBuffer> bytes =
|
||||
mDecoder->GetResource()->MediaReadAt(interval.mStart, interval.Length());
|
||||
resource->MediaReadAt(interval.mStart, interval.Length());
|
||||
NS_ENSURE_TRUE_VOID(bytes);
|
||||
mMP3FrameParser.Parse(bytes->Elements(), interval.Length(), interval.mStart);
|
||||
if (!mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mLastParserDuration) {
|
||||
mLastParserDuration = duration;
|
||||
decoder->DispatchUpdateEstimatedMediaDuration(mLastParserDuration);
|
||||
}
|
||||
}
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mLastParserDuration) {
|
||||
mLastParserDuration = duration;
|
||||
decoder->DispatchUpdateEstimatedMediaDuration(mLastParserDuration);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,6 +241,15 @@ PDMFactory::CreatePDMs()
|
||||
{
|
||||
RefPtr<PlatformDecoderModule> m;
|
||||
|
||||
if (sUseBlankDecoder) {
|
||||
m = CreateBlankDecoderModule();
|
||||
StartupPDM(m);
|
||||
// The Blank PDM SupportsMimeType reports true for all codecs; the creation
|
||||
// of its decoder is infallible. As such it will be used for all media, we
|
||||
// can stop creating more PDM from this point.
|
||||
return;
|
||||
}
|
||||
|
||||
if (sGMPDecoderEnabled) {
|
||||
m = new GMPDecoderModule();
|
||||
StartupPDM(m);
|
||||
@ -282,11 +291,6 @@ PDMFactory::CreatePDMs()
|
||||
|
||||
m = new AgnosticDecoderModule();
|
||||
StartupPDM(m);
|
||||
|
||||
if (sUseBlankDecoder) {
|
||||
m = CreateBlankDecoderModule();
|
||||
StartupPDM(m);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -397,6 +397,9 @@ AppleATDecoder::SetupDecoder(MediaRawData* aSample)
|
||||
mOutputFormat.mFormatFlags =
|
||||
kLinearPCMFormatFlagIsFloat |
|
||||
0;
|
||||
#elif defined(MOZ_SAMPLE_TYPE_S16)
|
||||
mOutputFormat.mBitsPerChannel = 16;
|
||||
mOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | 0;
|
||||
#else
|
||||
# error Unknown audio sample type
|
||||
#endif
|
||||
|
@ -9,9 +9,12 @@
|
||||
#include "AppleCMLinker.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
#ifndef MOZ_WIDGET_UIKIT
|
||||
#include "nsCocoaFeatures.h"
|
||||
#endif
|
||||
|
||||
extern PRLogModuleInfo* GetPDMLog();
|
||||
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
@ -57,7 +60,11 @@ AppleCMLinker::Link()
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_UIKIT
|
||||
if (true) {
|
||||
#else
|
||||
if (nsCocoaFeatures::OnLionOrLater()) {
|
||||
#endif
|
||||
#define LINK_FUNC2(func) \
|
||||
func = (typeof(func))dlsym(sLink, #func); \
|
||||
if (!func) { \
|
||||
|
@ -14,16 +14,19 @@
|
||||
#include "mp4_demuxer/H264.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "MediaData.h"
|
||||
#include "MacIOSurfaceImage.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "VideoUtils.h"
|
||||
#include <algorithm>
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#ifndef MOZ_WIDGET_UIKIT
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "MacIOSurfaceImage.h"
|
||||
#endif
|
||||
|
||||
extern PRLogModuleInfo* GetPDMLog();
|
||||
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
//#define LOG_MEDIA_SHA1
|
||||
@ -43,8 +46,13 @@ AppleVDADecoder::AppleVDADecoder(const VideoInfo& aConfig,
|
||||
, mDisplayHeight(aConfig.mDisplay.height)
|
||||
, mInputIncoming(0)
|
||||
, mIsShutDown(false)
|
||||
#ifdef MOZ_WIDGET_UIKIT
|
||||
, mUseSoftwareImages(true)
|
||||
, mIs106(false)
|
||||
#else
|
||||
, mUseSoftwareImages(false)
|
||||
, mIs106(!nsCocoaFeatures::OnLionOrLater())
|
||||
#endif
|
||||
, mQueuedSamples(0)
|
||||
, mMonitor("AppleVideoDecoder")
|
||||
, mIsFlushing(false)
|
||||
@ -383,6 +391,7 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
|
||||
// Unlock the returned image data.
|
||||
CVPixelBufferUnlockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly);
|
||||
} else {
|
||||
#ifndef MOZ_WIDGET_UIKIT
|
||||
IOSurfacePtr surface = MacIOSurfaceLib::CVPixelBufferGetIOSurface(aImage);
|
||||
MOZ_ASSERT(surface, "Decoder didn't return an IOSurface backed buffer");
|
||||
|
||||
@ -404,6 +413,9 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
|
||||
aFrameRef.is_sync_point,
|
||||
aFrameRef.decode_timestamp.ToMicroseconds(),
|
||||
visible);
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE("No MacIOSurface on iOS");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
@ -608,6 +620,7 @@ AppleVDADecoder::CreateOutputConfiguration()
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
}
|
||||
|
||||
#ifndef MOZ_WIDGET_UIKIT
|
||||
// Construct IOSurface Properties
|
||||
const void* IOSurfaceKeys[] = { MacIOSurfaceLib::kPropIsGlobal };
|
||||
const void* IOSurfaceValues[] = { kCFBooleanTrue };
|
||||
@ -638,6 +651,9 @@ AppleVDADecoder::CreateOutputConfiguration()
|
||||
ArrayLength(outputKeys),
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE("No MacIOSurface on iOS");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -790,10 +790,20 @@ media::TimeIntervals WebMReader::GetBuffered()
|
||||
void WebMReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
RefPtr<MediaByteBuffer> bytes =
|
||||
mDecoder->GetResource()->MediaReadAt(aOffset, aLength);
|
||||
NS_ENSURE_TRUE_VOID(bytes);
|
||||
mBufferedState->NotifyDataArrived(bytes->Elements(), aLength, aOffset);
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& range : byteRanges) {
|
||||
RefPtr<MediaByteBuffer> bytes =
|
||||
resource->MediaReadAt(range.mStart, range.Length());
|
||||
NS_ENSURE_TRUE_VOID(bytes);
|
||||
mBufferedState->NotifyDataArrived(bytes->Elements(), aLength, aOffset);
|
||||
}
|
||||
}
|
||||
|
||||
int WebMReader::GetVideoCodec()
|
||||
|
@ -341,13 +341,10 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
|
||||
mPluginFrame = nullptr;
|
||||
mWidgetCreationComplete = false;
|
||||
#ifdef XP_MACOSX
|
||||
memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
|
||||
mInCGPaintLevel = 0;
|
||||
mSentInitialTopLevelWindowEvent = false;
|
||||
mLastWindowIsActive = false;
|
||||
mLastContentFocused = false;
|
||||
mLastScaleFactor = 1.0;
|
||||
mColorProfile = nullptr;
|
||||
mShouldBlurOnActivate = false;
|
||||
#endif
|
||||
mContentFocused = false;
|
||||
@ -1208,91 +1205,6 @@ void nsPluginInstanceOwner::RemoveFromCARefreshTimer() {
|
||||
}
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::RenderCoreAnimation(CGContextRef aCGContext,
|
||||
int aWidth, int aHeight)
|
||||
{
|
||||
if (aWidth == 0 || aHeight == 0)
|
||||
return;
|
||||
|
||||
if (!mCARenderer) {
|
||||
mCARenderer = new nsCARenderer();
|
||||
}
|
||||
|
||||
// aWidth and aHeight are in "display pixels". In non-HiDPI modes
|
||||
// "display pixels" are device pixels. But in HiDPI modes each
|
||||
// display pixel corresponds to more than one device pixel.
|
||||
double scaleFactor = 1.0;
|
||||
GetContentsScaleFactor(&scaleFactor);
|
||||
|
||||
if (!mIOSurface ||
|
||||
(mIOSurface->GetWidth() != (size_t)aWidth ||
|
||||
mIOSurface->GetHeight() != (size_t)aHeight ||
|
||||
mIOSurface->GetContentsScaleFactor() != scaleFactor)) {
|
||||
mIOSurface = nullptr;
|
||||
|
||||
// If the renderer is backed by an IOSurface, resize it as required.
|
||||
mIOSurface = MacIOSurface::CreateIOSurface(aWidth, aHeight, scaleFactor);
|
||||
if (mIOSurface) {
|
||||
RefPtr<MacIOSurface> attachSurface = MacIOSurface::LookupSurface(
|
||||
mIOSurface->GetIOSurfaceID(),
|
||||
scaleFactor);
|
||||
if (attachSurface) {
|
||||
mCARenderer->AttachIOSurface(attachSurface);
|
||||
} else {
|
||||
NS_ERROR("IOSurface attachment failed");
|
||||
mIOSurface = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mColorProfile) {
|
||||
mColorProfile = CreateSystemColorSpace();
|
||||
}
|
||||
|
||||
if (mCARenderer->isInit() == false) {
|
||||
void *caLayer = nullptr;
|
||||
nsresult rv = mInstance->GetValueFromPlugin(NPPVpluginCoreAnimationLayer, &caLayer);
|
||||
if (NS_FAILED(rv) || !caLayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't run Flash in-process so we can unconditionally disallow
|
||||
// the offliner renderer.
|
||||
mCARenderer->SetupRenderer(caLayer, aWidth, aHeight, scaleFactor,
|
||||
DISALLOW_OFFLINE_RENDERER);
|
||||
|
||||
// Setting up the CALayer requires resetting the painting otherwise we
|
||||
// get garbage for the first few frames.
|
||||
FixUpPluginWindow(ePluginPaintDisable);
|
||||
FixUpPluginWindow(ePluginPaintEnable);
|
||||
}
|
||||
|
||||
CGImageRef caImage = nullptr;
|
||||
nsresult rt = mCARenderer->Render(aWidth, aHeight, scaleFactor, &caImage);
|
||||
if (rt == NS_OK && mIOSurface && mColorProfile) {
|
||||
nsCARenderer::DrawSurfaceToCGContext(aCGContext, mIOSurface, mColorProfile,
|
||||
0, 0, aWidth, aHeight);
|
||||
} else if (rt == NS_OK && caImage != nullptr) {
|
||||
// Significant speed up by resetting the scaling
|
||||
::CGContextSetInterpolationQuality(aCGContext, kCGInterpolationNone );
|
||||
::CGContextTranslateCTM(aCGContext, 0, (double) aHeight * scaleFactor);
|
||||
::CGContextScaleCTM(aCGContext, scaleFactor, -scaleFactor);
|
||||
|
||||
::CGContextDrawImage(aCGContext, CGRectMake(0,0,aWidth,aHeight), caImage);
|
||||
} else {
|
||||
NS_NOTREACHED("nsCARenderer::Render failure");
|
||||
}
|
||||
}
|
||||
|
||||
void* nsPluginInstanceOwner::GetPluginPortCopy()
|
||||
{
|
||||
if (GetDrawingModel() == NPDrawingModelCoreGraphics ||
|
||||
GetDrawingModel() == NPDrawingModelCoreAnimation ||
|
||||
GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation)
|
||||
return &mCGPluginPortCopy;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::SetPluginPort()
|
||||
{
|
||||
void* pluginPort = GetPluginPort();
|
||||
@ -1300,18 +1212,6 @@ void nsPluginInstanceOwner::SetPluginPort()
|
||||
return;
|
||||
mPluginWindow->window = pluginPort;
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::BeginCGPaint()
|
||||
{
|
||||
++mInCGPaintLevel;
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::EndCGPaint()
|
||||
{
|
||||
--mInCGPaintLevel;
|
||||
NS_ASSERTION(mInCGPaintLevel >= 0, "Mismatched call to nsPluginInstanceOwner::EndCGPaint()!");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// static
|
||||
@ -2544,8 +2444,6 @@ nsPluginInstanceOwner::Destroy()
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
RemoveFromCARefreshTimer();
|
||||
if (mColorProfile)
|
||||
::CGColorSpaceRelease(mColorProfile);
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
|
||||
@ -3136,11 +3034,7 @@ void nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState)
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've already set up a CGContext in nsPluginFrame::PaintPlugin(), we
|
||||
// don't want calls to SetPluginPort() to step on our work.
|
||||
if (mInCGPaintLevel < 1) {
|
||||
SetPluginPort();
|
||||
}
|
||||
SetPluginPort();
|
||||
|
||||
nsIntSize widgetClip = mPluginFrame->GetWidgetlessClipRect().Size();
|
||||
|
||||
|
@ -136,19 +136,9 @@ public:
|
||||
// This calls into the plugin (NPP_SetWindow) and can run script.
|
||||
void FixUpPluginWindow(int32_t inPaintState);
|
||||
void HidePluginWindow();
|
||||
// Return a pointer to the internal nsPluginPort structure that's used to
|
||||
// store a copy of plugin port info and to detect when it's been changed.
|
||||
void* GetPluginPortCopy();
|
||||
// Set plugin port info in the plugin (in the 'window' member of the
|
||||
// NPWindow structure passed to the plugin by SetWindow()).
|
||||
void SetPluginPort();
|
||||
// Flag when we've set up a Thebes (and CoreGraphics) context in
|
||||
// nsPluginFrame::PaintPlugin(). We need to know this in
|
||||
// FixUpPluginWindow() (i.e. we need to know when FixUpPluginWindow() has
|
||||
// been called from nsPluginFrame::PaintPlugin() when we're using the
|
||||
// CoreGraphics drawing model).
|
||||
void BeginCGPaint();
|
||||
void EndCGPaint();
|
||||
#else // XP_MACOSX
|
||||
void UpdateWindowPositionAndClipRect(bool aSetWindow);
|
||||
void UpdateWindowVisibility(bool aVisible);
|
||||
@ -293,11 +283,6 @@ private:
|
||||
RefPtr<nsPluginHost> mPluginHost;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
NP_CGContext mCGPluginPortCopy;
|
||||
int32_t mInCGPaintLevel;
|
||||
RefPtr<MacIOSurface> mIOSurface;
|
||||
RefPtr<nsCARenderer> mCARenderer;
|
||||
CGColorSpaceRef mColorProfile;
|
||||
static nsCOMPtr<nsITimer> *sCATimer;
|
||||
static nsTArray<nsPluginInstanceOwner*> *sCARefreshListeners;
|
||||
bool mSentInitialTopLevelWindowEvent;
|
||||
|
@ -188,9 +188,6 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
|
||||
mWsInfo.display = DefaultXDisplay();
|
||||
#endif
|
||||
#endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
|
||||
#if defined(OS_WIN)
|
||||
memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
|
||||
#endif // OS_WIN
|
||||
#if defined(OS_WIN)
|
||||
InitPopupMenuHook();
|
||||
if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
|
||||
@ -821,21 +818,6 @@ PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
|
||||
if (WM_NULL == evcopy.event)
|
||||
return true;
|
||||
|
||||
// Painting for win32. SharedSurfacePaint handles everything.
|
||||
if (mWindow.type == NPWindowTypeDrawable) {
|
||||
if (evcopy.event == WM_PAINT) {
|
||||
*handled = SharedSurfacePaint(evcopy);
|
||||
return true;
|
||||
}
|
||||
else if (DoublePassRenderingEvent() == evcopy.event) {
|
||||
// We'll render to mSharedSurfaceDib first, then render to a cached bitmap
|
||||
// we store locally. The two passes are for alpha extraction, so the second
|
||||
// pass must be to a flat white surface in order for things to work.
|
||||
mAlphaExtract.doublePass = RENDER_BACK_ONE;
|
||||
*handled = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*handled = WinlessHandleEvent(evcopy);
|
||||
return true;
|
||||
#endif
|
||||
@ -1296,13 +1278,6 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
|
||||
}
|
||||
break;
|
||||
|
||||
case NPWindowTypeDrawable:
|
||||
mWindow.type = aWindow.type;
|
||||
if (GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
|
||||
SetupFlashMsgThrottle();
|
||||
return SharedSurfaceSetWindow(aWindow);
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_NOTREACHED("Bad plugin window type.");
|
||||
return false;
|
||||
@ -2024,187 +1999,6 @@ PluginInstanceChild::WinlessHandleEvent(NPEvent& event)
|
||||
return handled;
|
||||
}
|
||||
|
||||
/* windowless drawing helpers */
|
||||
|
||||
bool
|
||||
PluginInstanceChild::SharedSurfaceSetWindow(const NPRemoteWindow& aWindow)
|
||||
{
|
||||
// If the surfaceHandle is empty, parent is telling us we can reuse our cached
|
||||
// memory surface and hdc. Otherwise, we need to reset, usually due to a
|
||||
// expanding plugin port size.
|
||||
if (!aWindow.surfaceHandle) {
|
||||
if (!mSharedSurfaceDib.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Attach to the new shared surface parent handed us.
|
||||
if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle,
|
||||
aWindow.width, aWindow.height, false)))
|
||||
return false;
|
||||
// Free any alpha extraction resources if needed. This will be reset
|
||||
// the next time it's used.
|
||||
AlphaExtractCacheRelease();
|
||||
}
|
||||
|
||||
// NPRemoteWindow's origin is the origin of our shared dib.
|
||||
mWindow.x = aWindow.x;
|
||||
mWindow.y = aWindow.y;
|
||||
mWindow.width = aWindow.width;
|
||||
mWindow.height = aWindow.height;
|
||||
mWindow.type = aWindow.type;
|
||||
|
||||
mWindow.window = reinterpret_cast<void*>(mSharedSurfaceDib.GetHDC());
|
||||
::SetViewportOrgEx(mSharedSurfaceDib.GetHDC(),
|
||||
-aWindow.x, -aWindow.y, nullptr);
|
||||
|
||||
if (mPluginIface->setwindow)
|
||||
mPluginIface->setwindow(&mData, &mWindow);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceChild::SharedSurfaceRelease()
|
||||
{
|
||||
mSharedSurfaceDib.Close();
|
||||
AlphaExtractCacheRelease();
|
||||
}
|
||||
|
||||
/* double pass cache buffer - (rarely) used in cases where alpha extraction
|
||||
* occurs for windowless plugins. */
|
||||
|
||||
bool
|
||||
PluginInstanceChild::AlphaExtractCacheSetup()
|
||||
{
|
||||
AlphaExtractCacheRelease();
|
||||
|
||||
mAlphaExtract.hdc = ::CreateCompatibleDC(nullptr);
|
||||
|
||||
if (!mAlphaExtract.hdc)
|
||||
return false;
|
||||
|
||||
BITMAPINFOHEADER bmih;
|
||||
memset((void*)&bmih, 0, sizeof(BITMAPINFOHEADER));
|
||||
bmih.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmih.biWidth = mWindow.width;
|
||||
bmih.biHeight = mWindow.height;
|
||||
bmih.biPlanes = 1;
|
||||
bmih.biBitCount = 32;
|
||||
bmih.biCompression = BI_RGB;
|
||||
|
||||
void* ppvBits = nullptr;
|
||||
mAlphaExtract.bmp = ::CreateDIBSection(mAlphaExtract.hdc,
|
||||
(BITMAPINFO*)&bmih,
|
||||
DIB_RGB_COLORS,
|
||||
(void**)&ppvBits,
|
||||
nullptr,
|
||||
(unsigned long)sizeof(BITMAPINFOHEADER));
|
||||
if (!mAlphaExtract.bmp)
|
||||
return false;
|
||||
|
||||
DeleteObject(::SelectObject(mAlphaExtract.hdc, mAlphaExtract.bmp));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceChild::AlphaExtractCacheRelease()
|
||||
{
|
||||
if (mAlphaExtract.bmp)
|
||||
::DeleteObject(mAlphaExtract.bmp);
|
||||
|
||||
if (mAlphaExtract.hdc)
|
||||
::DeleteObject(mAlphaExtract.hdc);
|
||||
|
||||
mAlphaExtract.bmp = nullptr;
|
||||
mAlphaExtract.hdc = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceChild::UpdatePaintClipRect(RECT* aRect)
|
||||
{
|
||||
if (aRect) {
|
||||
// Update the clip rect on our internal hdc
|
||||
HRGN clip = ::CreateRectRgnIndirect(aRect);
|
||||
::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip);
|
||||
::DeleteObject(clip);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t
|
||||
PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
|
||||
{
|
||||
if (!mPluginIface->event)
|
||||
return false;
|
||||
|
||||
RECT* pRect = reinterpret_cast<RECT*>(evcopy.lParam);
|
||||
|
||||
switch(mAlphaExtract.doublePass) {
|
||||
case RENDER_NATIVE:
|
||||
// pass the internal hdc to the plugin
|
||||
UpdatePaintClipRect(pRect);
|
||||
evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
|
||||
return mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
|
||||
break;
|
||||
case RENDER_BACK_ONE:
|
||||
// Handle a double pass render used in alpha extraction for transparent
|
||||
// plugins. (See nsPluginFrame and gfxWindowsNativeDrawing for details.)
|
||||
// We render twice, once to the shared dib, and once to a cache which
|
||||
// we copy back on a second paint. These paints can't be spread across
|
||||
// multiple rpc messages as delays cause animation frame changes.
|
||||
if (!mAlphaExtract.bmp && !AlphaExtractCacheSetup()) {
|
||||
mAlphaExtract.doublePass = RENDER_NATIVE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// See gfxWindowsNativeDrawing, color order doesn't have to match.
|
||||
UpdatePaintClipRect(pRect);
|
||||
::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
|
||||
evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
|
||||
if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
|
||||
mAlphaExtract.doublePass = RENDER_NATIVE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy to cache. We render to shared dib so we don't have to call
|
||||
// setwindow between calls (flash issue).
|
||||
::BitBlt(mAlphaExtract.hdc,
|
||||
pRect->left,
|
||||
pRect->top,
|
||||
pRect->right - pRect->left,
|
||||
pRect->bottom - pRect->top,
|
||||
mSharedSurfaceDib.GetHDC(),
|
||||
pRect->left,
|
||||
pRect->top,
|
||||
SRCCOPY);
|
||||
|
||||
::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
||||
if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
|
||||
mAlphaExtract.doublePass = RENDER_NATIVE;
|
||||
return false;
|
||||
}
|
||||
mAlphaExtract.doublePass = RENDER_BACK_TWO;
|
||||
return true;
|
||||
break;
|
||||
case RENDER_BACK_TWO:
|
||||
// copy our cached surface back
|
||||
UpdatePaintClipRect(pRect);
|
||||
::BitBlt(mSharedSurfaceDib.GetHDC(),
|
||||
pRect->left,
|
||||
pRect->top,
|
||||
pRect->right - pRect->left,
|
||||
pRect->bottom - pRect->top,
|
||||
mAlphaExtract.hdc,
|
||||
pRect->left,
|
||||
pRect->top,
|
||||
SRCCOPY);
|
||||
mAlphaExtract.doublePass = RENDER_NATIVE;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* flash msg throttling helpers */
|
||||
|
||||
// Flash has the unfortunate habit of flooding dispatch loops with custom
|
||||
@ -4049,7 +3843,6 @@ PluginInstanceChild::Destroy()
|
||||
mCachedElementActor = nullptr;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
SharedSurfaceRelease();
|
||||
DestroyWinlessPopupSurrogate();
|
||||
UnhookWinlessFlashThrottle();
|
||||
DestroyPluginWindow();
|
||||
|
@ -427,29 +427,6 @@ private:
|
||||
*/
|
||||
nsAutoPtr< nsTHashtable<DeletingObjectEntry> > mDeletingHash;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
private:
|
||||
// Shared dib rendering management for windowless plugins.
|
||||
bool SharedSurfaceSetWindow(const NPRemoteWindow& aWindow);
|
||||
int16_t SharedSurfacePaint(NPEvent& evcopy);
|
||||
void SharedSurfaceRelease();
|
||||
bool AlphaExtractCacheSetup();
|
||||
void AlphaExtractCacheRelease();
|
||||
void UpdatePaintClipRect(RECT* aRect);
|
||||
|
||||
private:
|
||||
enum {
|
||||
RENDER_NATIVE,
|
||||
RENDER_BACK_ONE,
|
||||
RENDER_BACK_TWO
|
||||
};
|
||||
gfx::SharedDIBWin mSharedSurfaceDib;
|
||||
struct {
|
||||
uint16_t doublePass;
|
||||
HDC hdc;
|
||||
HBITMAP bmp;
|
||||
} mAlphaExtract;
|
||||
#endif // defined(OS_WIN)
|
||||
#if defined(MOZ_WIDGET_COCOA)
|
||||
private:
|
||||
#if defined(__i386__)
|
||||
|
@ -176,7 +176,6 @@ PluginInstanceParent::ActorDestroy(ActorDestroyReason why)
|
||||
if (why == AbnormalShutdown) {
|
||||
// If the plugin process crashes, this is the only
|
||||
// chance we get to destroy resources.
|
||||
SharedSurfaceRelease();
|
||||
UnsubclassPluginWindow();
|
||||
}
|
||||
#endif
|
||||
@ -204,7 +203,6 @@ PluginInstanceParent::Destroy()
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
SharedSurfaceRelease();
|
||||
UnsubclassPluginWindow();
|
||||
#endif
|
||||
|
||||
@ -949,11 +947,6 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
|
||||
#if defined(OS_WIN)
|
||||
// On windowless controls, reset the shared memory surface as needed.
|
||||
if (mWindowType == NPWindowTypeDrawable) {
|
||||
// SharedSurfaceSetWindow will take care of NPRemoteWindow.
|
||||
if (!SharedSurfaceSetWindow(aWindow, window)) {
|
||||
return NPERR_OUT_OF_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
MaybeCreateChildPopupSurrogate();
|
||||
} else {
|
||||
SubclassPluginWindow(reinterpret_cast<HWND>(aWindow->window));
|
||||
@ -1188,23 +1181,7 @@ PluginInstanceParent::NPP_HandleEvent(void* event)
|
||||
|
||||
#if defined(OS_WIN)
|
||||
if (mWindowType == NPWindowTypeDrawable) {
|
||||
if (DoublePassRenderingEvent() == npevent->event) {
|
||||
return CallPaint(npremoteevent, &handled) && handled;
|
||||
}
|
||||
|
||||
switch (npevent->event) {
|
||||
case WM_PAINT:
|
||||
{
|
||||
RECT rect;
|
||||
SharedSurfaceBeforePaint(rect, npremoteevent);
|
||||
if (!CallPaint(npremoteevent, &handled)) {
|
||||
handled = false;
|
||||
}
|
||||
SharedSurfaceAfterPaint(npevent);
|
||||
return handled;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_KILLFOCUS:
|
||||
{
|
||||
// When the user selects fullscreen mode in Flash video players,
|
||||
@ -1936,108 +1913,6 @@ PluginInstanceParent::UnsubclassPluginWindow()
|
||||
* painting: mPluginPort (nsIntRect, saved in SetWindow)
|
||||
*/
|
||||
|
||||
void
|
||||
PluginInstanceParent::SharedSurfaceRelease()
|
||||
{
|
||||
mSharedSurfaceDib.Close();
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::SharedSurfaceSetWindow(const NPWindow* aWindow,
|
||||
NPRemoteWindow& aRemoteWindow)
|
||||
{
|
||||
aRemoteWindow.window = 0;
|
||||
aRemoteWindow.x = aWindow->x;
|
||||
aRemoteWindow.y = aWindow->y;
|
||||
aRemoteWindow.width = aWindow->width;
|
||||
aRemoteWindow.height = aWindow->height;
|
||||
aRemoteWindow.type = aWindow->type;
|
||||
|
||||
nsIntRect newPort(aWindow->x, aWindow->y, aWindow->width, aWindow->height);
|
||||
|
||||
// save the the rect location within the browser window.
|
||||
mPluginPort = newPort;
|
||||
|
||||
// move the port to our shared surface origin
|
||||
newPort.MoveTo(0,0);
|
||||
|
||||
// check to see if we have the room in shared surface
|
||||
if (mSharedSurfaceDib.IsValid() && mSharedSize.Contains(newPort)) {
|
||||
// ok to paint
|
||||
aRemoteWindow.surfaceHandle = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// allocate a new shared surface
|
||||
SharedSurfaceRelease();
|
||||
if (NS_FAILED(mSharedSurfaceDib.Create(reinterpret_cast<HDC>(aWindow->window),
|
||||
newPort.width, newPort.height, false)))
|
||||
return false;
|
||||
|
||||
// save the new shared surface size we just allocated
|
||||
mSharedSize = newPort;
|
||||
|
||||
base::SharedMemoryHandle handle;
|
||||
if (NS_FAILED(mSharedSurfaceDib.ShareToProcess(OtherPid(), &handle))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aRemoteWindow.surfaceHandle = handle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceParent::SharedSurfaceBeforePaint(RECT& rect,
|
||||
NPRemoteEvent& npremoteevent)
|
||||
{
|
||||
RECT* dr = (RECT*)npremoteevent.event.lParam;
|
||||
HDC parentHdc = (HDC)npremoteevent.event.wParam;
|
||||
|
||||
nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top);
|
||||
dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y); // should always be smaller than dirtyRect
|
||||
|
||||
::BitBlt(mSharedSurfaceDib.GetHDC(),
|
||||
dirtyRect.x,
|
||||
dirtyRect.y,
|
||||
dirtyRect.width,
|
||||
dirtyRect.height,
|
||||
parentHdc,
|
||||
dr->left,
|
||||
dr->top,
|
||||
SRCCOPY);
|
||||
|
||||
// setup the translated dirty rect we'll send to the child
|
||||
rect.left = dirtyRect.x;
|
||||
rect.top = dirtyRect.y;
|
||||
rect.right = dirtyRect.x + dirtyRect.width;
|
||||
rect.bottom = dirtyRect.y + dirtyRect.height;
|
||||
|
||||
npremoteevent.event.wParam = WPARAM(0);
|
||||
npremoteevent.event.lParam = LPARAM(&rect);
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceParent::SharedSurfaceAfterPaint(NPEvent* npevent)
|
||||
{
|
||||
RECT* dr = (RECT*)npevent->lParam;
|
||||
HDC parentHdc = (HDC)npevent->wParam;
|
||||
|
||||
nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top);
|
||||
dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y);
|
||||
|
||||
// src copy the shared dib into the parent surface we are handed.
|
||||
::BitBlt(parentHdc,
|
||||
dr->left,
|
||||
dr->top,
|
||||
dirtyRect.width,
|
||||
dirtyRect.height,
|
||||
mSharedSurfaceDib.GetHDC(),
|
||||
dirtyRect.x,
|
||||
dirtyRect.y,
|
||||
SRCCOPY);
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::MaybeCreateAndParentChildPluginWindow()
|
||||
{
|
||||
|
@ -353,11 +353,6 @@ private:
|
||||
|
||||
#if defined(OS_WIN)
|
||||
private:
|
||||
// Used in rendering windowless plugins in other processes.
|
||||
bool SharedSurfaceSetWindow(const NPWindow* aWindow, NPRemoteWindow& aRemoteWindow);
|
||||
void SharedSurfaceBeforePaint(RECT &rect, NPRemoteEvent& npremoteevent);
|
||||
void SharedSurfaceAfterPaint(NPEvent* npevent);
|
||||
void SharedSurfaceRelease();
|
||||
// Used in handling parent/child forwarding of events.
|
||||
static LRESULT CALLBACK PluginWindowHookProc(HWND hWnd, UINT message,
|
||||
WPARAM wParam, LPARAM lParam);
|
||||
@ -368,7 +363,6 @@ private:
|
||||
void MaybeCreateChildPopupSurrogate();
|
||||
|
||||
private:
|
||||
gfx::SharedDIBWin mSharedSurfaceDib;
|
||||
nsIntRect mPluginPort;
|
||||
nsIntRect mSharedSize;
|
||||
HWND mPluginHWND;
|
||||
|
@ -54,9 +54,6 @@ NPRemoteWindow::NPRemoteWindow() :
|
||||
, visualID(0)
|
||||
, colormap(0)
|
||||
#endif /* XP_UNIX */
|
||||
#if defined(XP_WIN)
|
||||
,surfaceHandle(0)
|
||||
#endif
|
||||
#if defined(XP_MACOSX)
|
||||
,contentsScaleFactor(1.0)
|
||||
#endif
|
||||
@ -156,18 +153,5 @@ void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v)
|
||||
VOID_TO_NPVARIANT(*v);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
// The private event used for double-pass widgetless plugin rendering.
|
||||
UINT DoublePassRenderingEvent()
|
||||
{
|
||||
static UINT gEventID = 0;
|
||||
if (!gEventID)
|
||||
gEventID = ::RegisterWindowMessage(L"MozDoublePassMsg");
|
||||
return gEventID;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
@ -93,9 +93,6 @@ struct NPRemoteWindow
|
||||
VisualID visualID;
|
||||
Colormap colormap;
|
||||
#endif /* XP_UNIX */
|
||||
#if defined(XP_WIN)
|
||||
base::SharedMemoryHandle surfaceHandle;
|
||||
#endif
|
||||
#if defined(XP_MACOSX)
|
||||
double contentsScaleFactor;
|
||||
#endif
|
||||
@ -254,11 +251,6 @@ struct DeletingObjectEntry : public nsPtrHashKey<NPObject>
|
||||
bool mDeleted;
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
// The private event used for double-pass widgetless plugin rendering.
|
||||
UINT DoublePassRenderingEvent();
|
||||
#endif
|
||||
|
||||
} /* namespace plugins */
|
||||
|
||||
} /* namespace mozilla */
|
||||
@ -345,9 +337,6 @@ struct ParamTraits<mozilla::plugins::NPRemoteWindow>
|
||||
aMsg->WriteULong(aParam.visualID);
|
||||
aMsg->WriteULong(aParam.colormap);
|
||||
#endif
|
||||
#if defined(XP_WIN)
|
||||
WriteParam(aMsg, aParam.surfaceHandle);
|
||||
#endif
|
||||
#if defined(XP_MACOSX)
|
||||
aMsg->WriteDouble(aParam.contentsScaleFactor);
|
||||
#endif
|
||||
@ -377,12 +366,6 @@ struct ParamTraits<mozilla::plugins::NPRemoteWindow>
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
base::SharedMemoryHandle surfaceHandle;
|
||||
if (!ReadParam(aMsg, aIter, &surfaceHandle))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
double contentsScaleFactor;
|
||||
if (!aMsg->ReadDouble(aIter, &contentsScaleFactor))
|
||||
@ -400,9 +383,6 @@ struct ParamTraits<mozilla::plugins::NPRemoteWindow>
|
||||
aResult->visualID = visualID;
|
||||
aResult->colormap = colormap;
|
||||
#endif
|
||||
#if defined(XP_WIN)
|
||||
aResult->surfaceHandle = surfaceHandle;
|
||||
#endif
|
||||
#if defined(XP_MACOSX)
|
||||
aResult->contentsScaleFactor = contentsScaleFactor;
|
||||
#endif
|
||||
|
@ -43,10 +43,10 @@ support-files =
|
||||
[test_bug1092842.html]
|
||||
skip-if = e10s
|
||||
[test_cocoa_focus.html]
|
||||
skip-if = toolkit != "cocoa"
|
||||
skip-if = toolkit != "cocoa" || e10s # Bug 1194534
|
||||
support-files = cocoa_focus.html
|
||||
[test_cocoa_window_focus.html]
|
||||
skip-if = toolkit != "cocoa"
|
||||
skip-if = toolkit != "cocoa" || e10s # Bug 1194534
|
||||
support-files = cocoa_window_focus.html
|
||||
[test_cookies.html]
|
||||
[test_copyText.html]
|
||||
|
@ -1127,9 +1127,6 @@ this.PushServiceWebSocket = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since we've had a successful connection reset the retry fail count.
|
||||
this._retryFailCount = 0;
|
||||
|
||||
let data = {
|
||||
messageType: "hello",
|
||||
use_webpush: true,
|
||||
@ -1196,12 +1193,10 @@ this.PushServiceWebSocket = {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are not waiting for a hello message, reset the retry fail count
|
||||
if (this._currentState != STATE_WAITING_FOR_HELLO) {
|
||||
debug('Reseting _retryFailCount and _pingIntervalRetryTimes');
|
||||
this._retryFailCount = 0;
|
||||
this._pingIntervalRetryTimes = {};
|
||||
}
|
||||
// If we receive a message, we know the connection succeeded. Reset the
|
||||
// connection attempt and ping interval counters.
|
||||
this._retryFailCount = 0;
|
||||
this._pingIntervalRetryTimes = {};
|
||||
|
||||
let doNotHandle = false;
|
||||
if ((message === '{}') ||
|
||||
|
@ -378,7 +378,11 @@ MockWebSocket.prototype = {
|
||||
() => this._listener.onServerClose(this._context, statusCode, reason),
|
||||
() => this._listener.onStop(this._context, Cr.NS_BASE_STREAM_CLOSED)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
serverInterrupt(result = Cr.NS_ERROR_NET_RESET) {
|
||||
waterfall(() => this._listener.onStop(this._context, result));
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
71
dom/push/test/xpcshell/test_retry_ws.js
Normal file
71
dom/push/test/xpcshell/test_retry_ws.js
Normal file
@ -0,0 +1,71 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
|
||||
|
||||
const userAgentID = '05f7b940-51b6-4b6f-8032-b83ebb577ded';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID: userAgentID,
|
||||
pingInterval: 10000,
|
||||
retryBaseInterval: 25,
|
||||
});
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_ws_retry() {
|
||||
let db = PushServiceWebSocket.newPushDB();
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
yield db.put({
|
||||
channelID: '61770ba9-2d57-4134-b949-d40404630d5b',
|
||||
pushEndpoint: 'https://example.org/push/1',
|
||||
scope: 'https://example.net/push/1',
|
||||
version: 1,
|
||||
originAttributes: '',
|
||||
quota: Infinity,
|
||||
});
|
||||
|
||||
let alarmDelays = [];
|
||||
let setAlarm = PushService.setAlarm;
|
||||
PushService.setAlarm = function(delay) {
|
||||
alarmDelays.push(delay);
|
||||
setAlarm.apply(this, arguments);
|
||||
};
|
||||
|
||||
let handshakeDone;
|
||||
let handshakePromise = new Promise(resolve => handshakeDone = resolve);
|
||||
PushService.init({
|
||||
serverURI: "wss://push.example.org/",
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
if (alarmDelays.length == 10) {
|
||||
PushService.setAlarm = setAlarm;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID,
|
||||
}));
|
||||
handshakeDone();
|
||||
return;
|
||||
}
|
||||
this.serverInterrupt();
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
yield waitForPromise(
|
||||
handshakePromise,
|
||||
45000,
|
||||
'Timed out waiting for successful handshake'
|
||||
);
|
||||
deepEqual(alarmDelays, [25, 50, 100, 200, 400, 800, 1600, 3200, 6400, 10000],
|
||||
'Wrong reconnect alarm delays');
|
||||
});
|
@ -40,6 +40,7 @@ run-sequentially = This will delete all existing push subscriptions.
|
||||
[test_webapps_cleardata.js]
|
||||
[test_updateRecordNoEncryptionKeys_ws.js]
|
||||
[test_reconnect_retry.js]
|
||||
[test_retry_ws.js]
|
||||
#http2 test
|
||||
[test_resubscribe_4xxCode_http2.js]
|
||||
[test_resubscribe_5xxCode_http2.js]
|
||||
|
@ -1249,7 +1249,7 @@ public:
|
||||
|
||||
static bool DoesBackendSupportDataDrawtarget(BackendType aType);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
static already_AddRefed<DrawTarget> CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize);
|
||||
static already_AddRefed<GlyphRenderingOptions>
|
||||
CreateCGGlyphRenderingOptions(const Color &aFontSmoothingBackgroundColor);
|
||||
|
@ -137,7 +137,7 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
/* This is a helper class that let's you borrow a CGContextRef from a
|
||||
* DrawTargetCG. This is used for drawing themed widgets.
|
||||
*
|
||||
|
@ -3,6 +3,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "BorrowedContext.h"
|
||||
#include "DataSurfaceHelpers.h"
|
||||
#include "DrawTargetCG.h"
|
||||
@ -177,6 +178,7 @@ DrawTargetCG::GetType() const
|
||||
BackendType
|
||||
DrawTargetCG::GetBackendType() const
|
||||
{
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
// It may be worth spliting Bitmap and IOSurface DrawTarget
|
||||
// into seperate classes.
|
||||
if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
|
||||
@ -184,15 +186,20 @@ DrawTargetCG::GetBackendType() const
|
||||
} else {
|
||||
return BackendType::COREGRAPHICS;
|
||||
}
|
||||
#else
|
||||
return BackendType::COREGRAPHICS;
|
||||
#endif
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
DrawTargetCG::Snapshot()
|
||||
{
|
||||
if (!mSnapshot) {
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
|
||||
return MakeAndAddRef<SourceSurfaceCGIOSurfaceContext>(this);
|
||||
}
|
||||
#endif
|
||||
Flush();
|
||||
mSnapshot = new SourceSurfaceCGBitmapContext(this);
|
||||
}
|
||||
@ -1717,12 +1724,14 @@ DrawTargetCG::Init(BackendType aType,
|
||||
|
||||
mSize = aSize;
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
if (aType == BackendType::COREGRAPHICS_ACCELERATED) {
|
||||
RefPtr<MacIOSurface> ioSurface = MacIOSurface::CreateIOSurface(aSize.width, aSize.height);
|
||||
mCg = ioSurface->CreateIOSurfaceContext();
|
||||
// If we don't have the symbol for 'CreateIOSurfaceContext' mCg will be null
|
||||
// and we will fallback to software below
|
||||
}
|
||||
#endif
|
||||
|
||||
mFormat = SurfaceFormat::B8G8R8A8;
|
||||
|
||||
@ -1820,6 +1829,7 @@ EnsureValidPremultipliedData(CGContextRef aContext)
|
||||
void
|
||||
DrawTargetCG::Flush()
|
||||
{
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
|
||||
CGContextFlush(mCg);
|
||||
} else if (GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP &&
|
||||
@ -1835,6 +1845,9 @@ DrawTargetCG::Flush()
|
||||
EnsureValidPremultipliedData(mCg);
|
||||
mMayContainInvalidPremultipliedData = false;
|
||||
}
|
||||
#else
|
||||
//TODO
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1874,7 +1887,9 @@ DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize)
|
||||
mOriginalTransform = CGContextGetCTM(mCg);
|
||||
|
||||
mFormat = SurfaceFormat::B8G8R8A8;
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
if (GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP) {
|
||||
#endif
|
||||
CGColorSpaceRef colorspace;
|
||||
CGBitmapInfo bitinfo = CGBitmapContextGetBitmapInfo(mCg);
|
||||
colorspace = CGBitmapContextGetColorSpace (mCg);
|
||||
@ -1883,7 +1898,9 @@ DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize)
|
||||
} else if ((bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst) {
|
||||
mFormat = SurfaceFormat::B8G8R8X8;
|
||||
}
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1906,12 +1923,16 @@ DrawTargetCG::CreatePathBuilder(FillRule aFillRule) const
|
||||
void*
|
||||
DrawTargetCG::GetNativeSurface(NativeSurfaceType aType)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
if ((aType == NativeSurfaceType::CGCONTEXT && GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP) ||
|
||||
(aType == NativeSurfaceType::CGCONTEXT_ACCELERATED && GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE)) {
|
||||
return mCg;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
return mCg;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -6,7 +6,14 @@
|
||||
#ifndef mozilla_gfx_DrawTargetCG_h
|
||||
#define mozilla_gfx_DrawTargetCG_h
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#else
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#endif
|
||||
|
||||
#include "2D.h"
|
||||
#include "Rect.h"
|
||||
|
@ -24,8 +24,10 @@
|
||||
|
||||
#ifdef CAIRO_HAS_QUARTZ_SURFACE
|
||||
#include "cairo-quartz.h"
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CAIRO_HAS_XLIB_SURFACE
|
||||
#include "cairo-xlib.h"
|
||||
@ -669,7 +671,7 @@ GfxFormatForCairoSurface(cairo_surface_t* surface)
|
||||
// xlib is currently the only Cairo backend that creates 16bpp surfaces
|
||||
if (type == CAIRO_SURFACE_TYPE_XLIB &&
|
||||
cairo_xlib_surface_get_depth(surface) == 16) {
|
||||
return SurfaceFormat::R5G6B5;
|
||||
return SurfaceFormat::R5G6B5_UINT16;
|
||||
}
|
||||
#endif
|
||||
return CairoContentToGfxFormat(cairo_surface_get_content(surface));
|
||||
|
@ -23,12 +23,12 @@
|
||||
#include "ScaledFontWin.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
#include "ScaledFontMac.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
#include "DrawTargetCG.h"
|
||||
#endif
|
||||
|
||||
@ -299,7 +299,7 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
|
||||
}
|
||||
break;
|
||||
}
|
||||
#elif defined XP_MACOSX
|
||||
#elif defined XP_DARWIN
|
||||
case BackendType::COREGRAPHICS:
|
||||
case BackendType::COREGRAPHICS_ACCELERATED:
|
||||
{
|
||||
@ -382,7 +382,7 @@ Factory::CreateDrawTargetForData(BackendType aBackend,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
case BackendType::COREGRAPHICS:
|
||||
{
|
||||
RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
|
||||
@ -489,7 +489,7 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
case NativeFontType::MAC_FONT_FACE:
|
||||
{
|
||||
return MakeAndAddRef<ScaledFontMac>(static_cast<CGFontRef>(aNativeFont.mFont), aSize);
|
||||
@ -791,7 +791,7 @@ Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSiz
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
already_AddRefed<DrawTarget>
|
||||
Factory::CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize)
|
||||
{
|
||||
|
@ -153,7 +153,7 @@ GfxFormatToCairoFormat(SurfaceFormat format)
|
||||
return CAIRO_FORMAT_RGB24;
|
||||
case SurfaceFormat::A8:
|
||||
return CAIRO_FORMAT_A8;
|
||||
case SurfaceFormat::R5G6B5:
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
return CAIRO_FORMAT_RGB16_565;
|
||||
default:
|
||||
gfxCriticalError() << "Unknown image format " << (int)format;
|
||||
@ -169,7 +169,7 @@ GfxFormatToCairoContent(SurfaceFormat format)
|
||||
case SurfaceFormat::B8G8R8A8:
|
||||
return CAIRO_CONTENT_COLOR_ALPHA;
|
||||
case SurfaceFormat::B8G8R8X8:
|
||||
case SurfaceFormat::R5G6B5: //fall through
|
||||
case SurfaceFormat::R5G6B5_UINT16: //fall through
|
||||
return CAIRO_CONTENT_COLOR;
|
||||
case SurfaceFormat::A8:
|
||||
return CAIRO_CONTENT_ALPHA;
|
||||
@ -241,7 +241,7 @@ CairoFormatToGfxFormat(cairo_format_t format)
|
||||
case CAIRO_FORMAT_A8:
|
||||
return SurfaceFormat::A8;
|
||||
case CAIRO_FORMAT_RGB16_565:
|
||||
return SurfaceFormat::R5G6B5;
|
||||
return SurfaceFormat::R5G6B5_UINT16;
|
||||
default:
|
||||
gfxCriticalError() << "Unknown cairo format " << format;
|
||||
return SurfaceFormat::UNKNOWN;
|
||||
|
@ -30,7 +30,7 @@ GfxFormatToSkiaColorType(SurfaceFormat format)
|
||||
case SurfaceFormat::B8G8R8X8:
|
||||
// We probably need to do something here.
|
||||
return kBGRA_8888_SkColorType;
|
||||
case SurfaceFormat::R5G6B5:
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
return kRGB_565_SkColorType;
|
||||
case SurfaceFormat::A8:
|
||||
return kAlpha_8_SkColorType;
|
||||
@ -47,7 +47,7 @@ SkiaColorTypeToGfxFormat(SkColorType type)
|
||||
case kBGRA_8888_SkColorType:
|
||||
return SurfaceFormat::B8G8R8A8;
|
||||
case kRGB_565_SkColorType:
|
||||
return SurfaceFormat::R5G6B5;
|
||||
return SurfaceFormat::R5G6B5_UINT16;
|
||||
case kAlpha_8_SkColorType:
|
||||
return SurfaceFormat::A8;
|
||||
default:
|
||||
@ -66,7 +66,7 @@ GfxFormatToGrConfig(SurfaceFormat format)
|
||||
case SurfaceFormat::B8G8R8X8:
|
||||
// We probably need to do something here.
|
||||
return kBGRA_8888_GrPixelConfig;
|
||||
case SurfaceFormat::R5G6B5:
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
return kRGB_565_GrPixelConfig;
|
||||
case SurfaceFormat::A8:
|
||||
return kAlpha_8_GrPixelConfig;
|
||||
|
@ -399,8 +399,8 @@ public:
|
||||
case SurfaceFormat::R8G8B8X8:
|
||||
mMessage << "SurfaceFormat::R8G8B8X8";
|
||||
break;
|
||||
case SurfaceFormat::R5G6B5:
|
||||
mMessage << "SurfaceFormat::R5G6B5";
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
mMessage << "SurfaceFormat::R5G6B5_UINT16";
|
||||
break;
|
||||
case SurfaceFormat::A8:
|
||||
mMessage << "SurfaceFormat::A8";
|
||||
|
@ -6,10 +6,23 @@
|
||||
|
||||
#ifndef MacIOSurface_h__
|
||||
#define MacIOSurface_h__
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef XP_DARWIN
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
struct _CGLContextObject;
|
||||
|
||||
typedef _CGLContextObject* CGLContextObj;
|
||||
typedef struct CGContext* CGContextRef;
|
||||
typedef struct CGImage* CGImageRef;
|
||||
typedef uint32_t IOSurfaceID;
|
||||
|
||||
#ifdef XP_IOS
|
||||
typedef kern_return_t IOReturn;
|
||||
typedef int CGLError;
|
||||
#endif
|
||||
|
||||
typedef CFTypeRef IOSurfacePtr;
|
||||
typedef IOSurfacePtr (*IOSurfaceCreateFunc) (CFDictionaryRef properties);
|
||||
typedef IOSurfacePtr (*IOSurfaceLookupFunc) (uint32_t io_surface_id);
|
||||
@ -42,18 +55,16 @@ typedef IOSurfacePtr (*CVPixelBufferGetIOSurfaceFunc)(
|
||||
|
||||
typedef OSType (*IOSurfacePixelFormatFunc)(IOSurfacePtr io_surface);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#else
|
||||
#import <OpenGLES/ES2/gl.h>
|
||||
#endif
|
||||
|
||||
#include "2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
struct _CGLContextObject;
|
||||
|
||||
typedef _CGLContextObject* CGLContextObj;
|
||||
typedef struct CGContext* CGContextRef;
|
||||
typedef struct CGImage* CGImageRef;
|
||||
typedef uint32_t IOSurfaceID;
|
||||
|
||||
enum CGContextType {
|
||||
CG_CONTEXT_TYPE_UNKNOWN = 0,
|
||||
// These are found by inspection, it's possible they could be changed
|
||||
|
@ -6,7 +6,12 @@
|
||||
#ifndef MOZILLA_GFX_PATHCG_H_
|
||||
#define MOZILLA_GFX_PATHCG_H_
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#else
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#endif
|
||||
|
||||
#include "2D.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -13,11 +13,16 @@
|
||||
#include "DrawTargetCG.h"
|
||||
#include <vector>
|
||||
#include <dlfcn.h>
|
||||
#ifdef MOZ_WIDGET_UIKIT
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
// prototype for private API
|
||||
extern "C" {
|
||||
CGPathRef CGFontGetGlyphPath(CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
@ -81,11 +86,12 @@ ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aT
|
||||
{
|
||||
if (aTarget->GetBackendType() == BackendType::COREGRAPHICS ||
|
||||
aTarget->GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED) {
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
|
||||
for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
|
||||
// XXX: we could probably fold both of these transforms together to avoid extra work
|
||||
CGAffineTransform flip = CGAffineTransformMakeScale(1, -1);
|
||||
|
||||
CGPathRef glyphPath = ::CGFontGetGlyphPath(mFont, &flip, 0, aBuffer.mGlyphs[i].mIndex);
|
||||
|
||||
CGAffineTransform matrix = CGAffineTransformMake(mSize, 0, 0, mSize,
|
||||
@ -97,6 +103,10 @@ ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aT
|
||||
RefPtr<Path> ret = new PathCG(path, FillRule::FILL_WINDING);
|
||||
CGPathRelease(path);
|
||||
return ret.forget();
|
||||
#else
|
||||
//TODO: probably want CTFontCreatePathForGlyph
|
||||
MOZ_CRASH("This needs implemented");
|
||||
#endif
|
||||
}
|
||||
return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
|
||||
}
|
||||
@ -108,7 +118,7 @@ ScaledFontMac::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBui
|
||||
ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aBackendType, aTransformHint);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
PathBuilderCG *pathBuilderCG =
|
||||
static_cast<PathBuilderCG*>(aBuilder);
|
||||
// XXX: check builder type
|
||||
@ -123,6 +133,10 @@ ScaledFontMac::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBui
|
||||
CGPathAddPath(pathBuilderCG->mCGPath, &matrix, glyphPath);
|
||||
CGPathRelease(glyphPath);
|
||||
}
|
||||
#else
|
||||
//TODO: probably want CTFontCreatePathForGlyph
|
||||
MOZ_CRASH("This needs implemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -6,7 +6,13 @@
|
||||
#ifndef MOZILLA_GFX_SCALEDFONTMAC_H_
|
||||
#define MOZILLA_GFX_SCALEDFONTMAC_H_
|
||||
|
||||
#import <ApplicationServices/ApplicationServices.h>
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#else
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <CoreText/CoreText.h>
|
||||
#endif
|
||||
|
||||
#include "2D.h"
|
||||
|
||||
#include "ScaledFontBase.h"
|
||||
|
@ -9,7 +9,9 @@
|
||||
#include "DataSurfaceHelpers.h"
|
||||
#include "mozilla/Types.h" // for decltype
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include "MacIOSurface.h"
|
||||
#endif
|
||||
#include "Tools.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -384,6 +386,7 @@ SourceSurfaceCGBitmapContext::~SourceSurfaceCGBitmapContext()
|
||||
CGImageRelease(mImage);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
SourceSurfaceCGIOSurfaceContext::SourceSurfaceCGIOSurfaceContext(DrawTargetCG *aDrawTarget)
|
||||
{
|
||||
CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT_ACCELERATED);
|
||||
@ -452,6 +455,7 @@ SourceSurfaceCGIOSurfaceContext::GetData()
|
||||
{
|
||||
return (unsigned char*)mData;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
@ -6,11 +6,17 @@
|
||||
#ifndef _MOZILLA_GFX_SOURCESURFACECG_H
|
||||
#define _MOZILLA_GFX_SOURCESURFACECG_H
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#else
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#endif
|
||||
|
||||
#include "2D.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
class MacIOSurface;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
@ -163,6 +169,7 @@ private:
|
||||
IntSize mSize;
|
||||
};
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
class SourceSurfaceCGIOSurfaceContext : public SourceSurfaceCGContext
|
||||
{
|
||||
public:
|
||||
@ -196,6 +203,7 @@ private:
|
||||
|
||||
IntSize mSize;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace gfx
|
||||
|
@ -86,7 +86,7 @@ BytesPerPixel(SurfaceFormat aFormat)
|
||||
switch (aFormat) {
|
||||
case SurfaceFormat::A8:
|
||||
return 1;
|
||||
case SurfaceFormat::R5G6B5:
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
|
@ -30,14 +30,28 @@ enum class SurfaceType : int8_t {
|
||||
};
|
||||
|
||||
enum class SurfaceFormat : int8_t {
|
||||
B8G8R8A8,
|
||||
B8G8R8X8,
|
||||
R8G8B8A8,
|
||||
R8G8B8X8,
|
||||
R5G6B5,
|
||||
// The following values are named to reflect layout of colors in memory, from
|
||||
// lowest byte to highest byte. The 32-bit value layout depends on machine
|
||||
// endianness.
|
||||
// in-memory 32-bit LE value 32-bit BE value
|
||||
B8G8R8A8, // [BB, GG, RR, AA] 0xAARRGGBB 0xBBGGRRAA
|
||||
B8G8R8X8, // [BB, GG, RR, 00] 0x00RRGGBB 0xBBGGRR00
|
||||
R8G8B8A8, // [RR, GG, BB, AA] 0xAABBGGRR 0xRRGGBBAA
|
||||
R8G8B8X8, // [RR, GG, BB, 00] 0x00BBGGRR 0xRRGGBB00
|
||||
|
||||
// The _UINT16 suffix here indicates that the name reflects the layout when
|
||||
// viewed as a uint16_t value. In memory these values are stored using native
|
||||
// endianness.
|
||||
R5G6B5_UINT16, // 0bRRRRRGGGGGGBBBBB
|
||||
|
||||
// This one is a single-byte, so endianness isn't an issue.
|
||||
A8,
|
||||
|
||||
// These ones are their own special cases.
|
||||
YUV,
|
||||
NV12,
|
||||
|
||||
// This represents the unknown format.
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
@ -46,7 +60,7 @@ inline bool IsOpaque(SurfaceFormat aFormat)
|
||||
switch (aFormat) {
|
||||
case SurfaceFormat::B8G8R8X8:
|
||||
case SurfaceFormat::R8G8B8X8:
|
||||
case SurfaceFormat::R5G6B5:
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
case SurfaceFormat::YUV:
|
||||
case SurfaceFormat::NV12:
|
||||
return true;
|
||||
|
@ -48,10 +48,9 @@ EXPORTS.mozilla.gfx += [
|
||||
'UserData.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):
|
||||
EXPORTS.mozilla.gfx += [
|
||||
'MacIOSurface.h',
|
||||
'QuartzSupport.h',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'DrawTargetCG.cpp',
|
||||
@ -160,6 +159,9 @@ SOURCES += [
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
EXPORTS.mozilla.gfx += [
|
||||
'QuartzSupport.h',
|
||||
]
|
||||
SOURCES += [
|
||||
'MacIOSurface.cpp',
|
||||
'QuartzSupport.mm',
|
||||
|
@ -77,6 +77,7 @@ static const char *sExtensionNames[] = {
|
||||
"GL_ANGLE_timer_query",
|
||||
"GL_APPLE_client_storage",
|
||||
"GL_APPLE_framebuffer_multisample",
|
||||
"GL_APPLE_sync",
|
||||
"GL_APPLE_texture_range",
|
||||
"GL_APPLE_vertex_array_object",
|
||||
"GL_ARB_ES2_compatibility",
|
||||
@ -783,7 +784,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
|
||||
if (!IsSupported(GLFeature::framebuffer_object)) {
|
||||
|
||||
// Check for aux symbols based on extensions
|
||||
if (IsSupported(GLFeature::framebuffer_object_EXT_OES))
|
||||
{
|
||||
@ -811,11 +811,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) ||
|
||||
IsExtensionSupported(GLContext::EXT_framebuffer_blit) ||
|
||||
IsExtensionSupported(GLContext::NV_framebuffer_blit))
|
||||
|
||||
{
|
||||
if (IsSupported(GLFeature::framebuffer_blit)) {
|
||||
SymLoadStruct extSymbols[] = {
|
||||
EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV),
|
||||
END_SYMBOLS
|
||||
@ -826,11 +822,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) ||
|
||||
IsExtensionSupported(GLContext::APPLE_framebuffer_multisample) ||
|
||||
IsExtensionSupported(GLContext::EXT_framebuffer_multisample) ||
|
||||
IsExtensionSupported(GLContext::EXT_multisampled_render_to_texture))
|
||||
{
|
||||
if (IsSupported(GLFeature::framebuffer_multisample)) {
|
||||
SymLoadStruct extSymbols[] = {
|
||||
EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT),
|
||||
END_SYMBOLS
|
||||
@ -1546,7 +1538,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
|
||||
if (IsSupported(GLFeature::read_buffer)) {
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
@ -1558,6 +1550,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(APPLE_framebuffer_multisample)) {
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fResolveMultisampleFramebufferAPPLE, { "ResolveMultisampleFramebufferAPPLE", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
|
||||
NS_ERROR("GL supports APPLE_framebuffer_multisample without supplying its functions.");
|
||||
|
||||
MarkExtensionUnsupported(APPLE_framebuffer_multisample);
|
||||
ClearSymbols(extSymbols);
|
||||
}
|
||||
}
|
||||
|
||||
// Load developer symbols, don't fail if we can't find them.
|
||||
SymLoadStruct auxSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
|
||||
@ -2913,7 +2919,7 @@ GLContext::GetReadFB()
|
||||
if (mScreen)
|
||||
return mScreen->GetReadFB();
|
||||
|
||||
GLenum bindEnum = IsSupported(GLFeature::framebuffer_blit)
|
||||
GLenum bindEnum = IsSupported(GLFeature::split_framebuffer)
|
||||
? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
|
||||
: LOCAL_GL_FRAMEBUFFER_BINDING;
|
||||
|
||||
|
@ -124,6 +124,7 @@ enum class GLFeature {
|
||||
sRGB_framebuffer,
|
||||
sRGB_texture,
|
||||
sampler_objects,
|
||||
split_framebuffer,
|
||||
standard_derivatives,
|
||||
sync,
|
||||
texture_3D,
|
||||
@ -390,6 +391,7 @@ public:
|
||||
ANGLE_timer_query,
|
||||
APPLE_client_storage,
|
||||
APPLE_framebuffer_multisample,
|
||||
APPLE_sync,
|
||||
APPLE_texture_range,
|
||||
APPLE_vertex_array_object,
|
||||
ARB_ES2_compatibility,
|
||||
@ -3139,6 +3141,16 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// APPLE_framebuffer_multisample
|
||||
|
||||
void fResolveMultisampleFramebufferAPPLE() {
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fResolveMultisampleFramebufferAPPLE);
|
||||
mSymbols.fResolveMultisampleFramebufferAPPLE();
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
protected:
|
||||
|
79
gfx/gl/GLContextEAGL.h
Normal file
79
gfx/gl/GLContextEAGL.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GLCONTEXTEAGL_H_
|
||||
#define GLCONTEXTEAGL_H_
|
||||
|
||||
#include "GLContext.h"
|
||||
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <OpenGLES/EAGL.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
class GLContextEAGL : public GLContext
|
||||
{
|
||||
friend class GLContextProviderEAGL;
|
||||
|
||||
EAGLContext* const mContext;
|
||||
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEAGL, override)
|
||||
GLContextEAGL(const SurfaceCaps& caps, EAGLContext* context,
|
||||
GLContext* sharedContext,
|
||||
bool isOffscreen, ContextProfile profile);
|
||||
|
||||
~GLContextEAGL();
|
||||
|
||||
virtual GLContextType GetContextType() const override {
|
||||
return GLContextType::EAGL;
|
||||
}
|
||||
|
||||
static GLContextEAGL* Cast(GLContext* gl) {
|
||||
MOZ_ASSERT(gl->GetContextType() == GLContextType::EAGL);
|
||||
return static_cast<GLContextEAGL*>(gl);
|
||||
}
|
||||
|
||||
bool Init() override;
|
||||
|
||||
bool AttachToWindow(nsIWidget* aWidget);
|
||||
|
||||
EAGLContext* GetEAGLContext() const { return mContext; }
|
||||
|
||||
virtual bool MakeCurrentImpl(bool aForce) override;
|
||||
|
||||
virtual bool IsCurrent() override;
|
||||
|
||||
virtual bool SetupLookupFunction() override;
|
||||
|
||||
virtual bool IsDoubleBuffered() const override;
|
||||
|
||||
virtual bool SupportsRobustness() const override;
|
||||
|
||||
virtual bool SwapBuffers() override;
|
||||
|
||||
virtual GLuint GetDefaultFramebuffer() override {
|
||||
return mBackbufferFB;
|
||||
}
|
||||
|
||||
virtual bool RenewSurface() override {
|
||||
return RecreateRB();
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint mBackbufferRB;
|
||||
GLuint mBackbufferFB;
|
||||
|
||||
void* mLayer;
|
||||
|
||||
bool RecreateRB();
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GLCONTEXTEAGL_H_
|
@ -547,6 +547,20 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
// Do we have separate DRAW and READ framebuffer bind points?
|
||||
"split_framebuffer",
|
||||
GLVersion::GL3,
|
||||
GLESVersion::ES3,
|
||||
GLContext::ARB_framebuffer_object,
|
||||
{
|
||||
GLContext::ANGLE_framebuffer_blit,
|
||||
GLContext::APPLE_framebuffer_multisample,
|
||||
GLContext::EXT_framebuffer_blit,
|
||||
GLContext::NV_framebuffer_blit,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"standard_derivatives",
|
||||
GLVersion::GL2,
|
||||
@ -561,8 +575,10 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
||||
"sync",
|
||||
GLVersion::GL3_2,
|
||||
GLESVersion::ES3,
|
||||
GLContext::ARB_sync,
|
||||
GLContext::Extension_None,
|
||||
{
|
||||
GLContext::ARB_sync,
|
||||
GLContext::APPLE_sync,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user