Merge mozilla-central to b2g-i

This commit is contained in:
Carsten "Tomcat" Book 2015-10-29 12:16:17 +01:00
commit 579eba5ed8
384 changed files with 5026 additions and 3399 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -70,7 +70,7 @@
<rows>
<row id="notificationsPolicyRow">
<vbox align="start">
<label id="notificationsPolicy">&notificationsPolicyDesc.label;</label>
<label id="notificationsPolicy">&notificationsPolicyDesc2.label;</label>
</vbox>
<hbox pack="end">
<button id="notificationsPolicyButton" label="&notificationsPolicyButton.label;"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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