Merge m-c to b2ginbound, a=merge CLOSED TREE

This commit is contained in:
Wes Kocher 2015-10-20 15:29:33 -07:00
Родитель ebc505b603 9630ce26b8
Коммит 81aaf29f3d
182 изменённых файлов: 4478 добавлений и 1683 удалений

Просмотреть файл

@ -953,7 +953,7 @@ pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket");
// falling back to Skia/software for smaller canvases
#ifdef MOZ_WIDGET_GONK
pref("gfx.canvas.azure.backends", "skia");
pref("gfx.canvas.azure.accelerated", false);
pref("gfx.canvas.azure.accelerated", true);
#endif
// Turn on dynamic cache size for Skia

Просмотреть файл

@ -676,7 +676,7 @@
<hbox id="nav-bar-customization-target" flex="1">
<toolbaritem id="urlbar-container" flex="400" persist="width"
title="&locationItem.title;" removable="false"
removable="false"
class="chromeclass-location" overflows="false">
<toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&backCmd.label;"
@ -799,16 +799,13 @@
<toolbarbutton id="urlbar-go-button"
class="chromeclass-toolbar-additional"
onclick="gURLBar.handleCommand(event);"
aria-label="&goEndCap.tooltip;"
tooltiptext="&goEndCap.tooltip;"/>
<toolbarbutton id="urlbar-reload-button"
class="chromeclass-toolbar-additional"
command="Browser:ReloadOrDuplicate"
onclick="checkForMiddleClick(this, event);"
aria-label="&reloadButton.tooltip;"
tooltiptext="&reloadButton.tooltip;"/>
<toolbarbutton id="urlbar-stop-button"
aria-label="&stopButton.tooltip;"
class="chromeclass-toolbar-additional"
command="Browser:Stop"
tooltiptext="&stopButton.tooltip;"/>

Просмотреть файл

@ -3,5 +3,7 @@ support-files =
file_dom_notifications.html
[browser_notification_open_settings.js]
[browser_notification_remove_permission.js]
skip-if = e10s
[browser_notification_tab_switching.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1100662 - content access causing uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32 (or in RemoteAddonsChild.jsm)

Просмотреть файл

@ -0,0 +1,79 @@
"use strict";
var tab;
var notification;
var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
var alertWindowClosed = false;
var permRemoved = false;
function test () {
waitForExplicitFinish();
let pm = Services.perms;
registerCleanupFunction(function() {
pm.remove(makeURI(notificationURL), "desktop-notification");
gBrowser.removeTab(tab);
window.restore();
});
pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
tab = gBrowser.addTab(notificationURL);
gBrowser.selectedTab = tab;
tab.linkedBrowser.addEventListener("load", onLoad, true);
}
function onLoad() {
tab.linkedBrowser.removeEventListener("load", onLoad, true);
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
notification = win.showNotification2();
notification.addEventListener("show", onAlertShowing);
}
function onAlertShowing() {
info("Notification alert showing");
notification.removeEventListener("show", onAlertShowing);
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
if (!alertWindow) {
ok(true, "Notifications don't use XUL windows on all platforms.");
notification.close();
finish();
return;
}
ok(Services.perms.testExactPermission(makeURI(notificationURL), "desktop-notification"),
"Permission should exist prior to removal");
let disableForOriginMenuItem = alertWindow.document.getElementById("disableForOriginMenuItem");
is(disableForOriginMenuItem.localName, "menuitem", "menuitem found");
Services.obs.addObserver(permObserver, "perm-changed", false);
alertWindow.addEventListener("beforeunload", onAlertClosing);
disableForOriginMenuItem.click();
info("Clicked on disable-for-origin menuitem")
}
function permObserver(subject, topic, data) {
if (topic != "perm-changed") {
return;
}
let permission = subject.QueryInterface(Ci.nsIPermission);
is(permission.type, "desktop-notification", "desktop-notification permission changed");
is(data, "deleted", "desktop-notification permission deleted");
Services.obs.removeObserver(permObserver, "perm-changed");
permRemoved = true;
if (alertWindowClosed) {
finish();
}
}
function onAlertClosing(event) {
event.target.removeEventListener("beforeunload", onAlertClosing);
alertWindowClosed = true;
if (permRemoved) {
finish();
}
}

Просмотреть файл

@ -60,7 +60,7 @@ function onAlertShowing() {
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
if (!alertWindow) {
todo(false, "Notifications don't use XUL windows on all platforms.");
ok(true, "Notifications don't use XUL windows on all platforms.");
notification.close();
newWindowOpenedFromTab.close();
finish();

Просмотреть файл

@ -218,8 +218,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY urlbar.toggleAutocomplete.label "Toggle the autocomplete popup">
<!ENTITY locationItem.title "Location">
<!ENTITY searchItem.title "Search">
<!-- Toolbar items -->

Просмотреть файл

@ -125,3 +125,8 @@
shown in the inspector contextual-menu for the item that lets users take
a screenshot of the currently selected node. -->
<!ENTITY inspectorScreenshotNode.label "Screenshot Node">
<!-- LOCALIZATION NOTE (inspectorDuplicateNode.label): This is the label
shown in the inspector contextual-menu for the item that lets users
duplicate the currently selected node. -->
<!ENTITY inspectorDuplicateNode.label "Duplicate Node">

Просмотреть файл

@ -893,7 +893,7 @@ toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarb
transition: opacity 0.15s ease;
}
#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}

Просмотреть файл

@ -4,7 +4,7 @@
%filter substitution
%define toolbarHighlight rgba(255,255,255,.3)
%define toolbarHighlight rgba(255,255,255,.4)
%define fgTabTexture linear-gradient(transparent 2px, @toolbarHighlight@ 2px, @toolbarHighlight@)
%define fgTabTextureLWT @fgTabTexture@
%define fgTabBackgroundColor -moz-dialog

Просмотреть файл

@ -1697,7 +1697,7 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
transition: opacity 0.15s ease;
}
#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}

Просмотреть файл

@ -1410,7 +1410,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
transition: opacity 0.15s ease;
}
#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}

Просмотреть файл

@ -4,7 +4,7 @@
%filter substitution
%define toolbarHighlight rgba(255,255,255,.3)
%define toolbarHighlight rgba(255,255,255,.4)
%define fgTabTexture linear-gradient(transparent 2px, @toolbarHighlight@ 2px, @toolbarHighlight@)
%define fgTabBackgroundColor -moz-dialog
%define fgTabTextureLWT @fgTabTexture@

4
config/external/icu/Makefile.in поставляемый
Просмотреть файл

@ -47,9 +47,9 @@ buildicu::
# Msys screws up GENRBOPTS when it contains spaces, so all genrb flags need
# to be stuck together. See https://bugzilla.mozilla.org/show_bug.cgi?id=1034594#c34
ifdef CROSS_COMPILE
+$(MAKE) -j1 -C $(DEPTH)/intl/icu/host STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kRC'
+ASAN_OPTIONS=detect_leaks=0 $(MAKE) -j1 -C $(DEPTH)/intl/icu/host STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kRC'
endif
+$(MAKE) -j1 -C $(DEPTH)/intl/icu/target STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kR'
+ASAN_OPTIONS=detect_leaks=0 $(MAKE) -j1 -C $(DEPTH)/intl/icu/target STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kR'
$(ICU_LIB_RENAME)
distclean clean::

4
config/external/nss/nss.def поставляемый
Просмотреть файл

@ -403,9 +403,6 @@ PK11_NeedLogin
PK11_NeedUserInit
PK11_ParamFromIV
PK11_PBEKeyGen
PK11_PQG_DestroyParams
PK11_PQG_DestroyVerify
PK11_PQG_ParamGen
PK11_PrivDecrypt
PK11_PrivDecryptPKCS1
PK11_ProtectedAuthenticationPath
@ -685,4 +682,3 @@ VFY_VerifyData
VFY_VerifyDataWithAlgorithmID
VFY_VerifyDigestDirect
_SGN_VerifyPKCS1DigestInfo
PK11_PQG_ParamGenV2

Просмотреть файл

@ -53,7 +53,7 @@ dnl ========================================================
MOZJPEG=62
MOZPNG=10617
NSPR_VERSION=4
NSPR_MINVER=4.10.8
NSPR_MINVER=4.10.10
NSS_VERSION=3
dnl Set the minimum version of toolkit libs used by mozilla
@ -3427,7 +3427,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
_USE_SYSTEM_NSS=1 )
if test -n "$_USE_SYSTEM_NSS"; then
AM_PATH_NSS(3.19.2, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
AM_PATH_NSS(3.20.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSS"; then

Просмотреть файл

@ -654,6 +654,9 @@ InspectorPanel.prototype = {
!this.selection.isPseudoElementNode();
let isEditableElement = isSelectionElement &&
!this.selection.isAnonymousNode();
let isDuplicatableElement = isSelectionElement &&
!this.selection.isAnonymousNode() &&
!this.selection.isRoot();
let isScreenshotable = isSelectionElement &&
this.canGetUniqueSelector &&
this.selection.nodeFront.isTreeDisplayed;
@ -683,6 +686,7 @@ InspectorPanel.prototype = {
// "Copy outer HTML", "Scroll Into View" & "Screenshot Node" as appropriate
let unique = this.panelDoc.getElementById("node-menu-copyuniqueselector");
let screenshot = this.panelDoc.getElementById("node-menu-screenshotnode");
let duplicateNode = this.panelDoc.getElementById("node-menu-duplicatenode");
let copyInnerHTML = this.panelDoc.getElementById("node-menu-copyinner");
let copyOuterHTML = this.panelDoc.getElementById("node-menu-copyouter");
let scrollIntoView = this.panelDoc.getElementById("node-menu-scrollnodeintoview");
@ -700,10 +704,20 @@ InspectorPanel.prototype = {
expandAll.removeAttribute("disabled");
}
this._target.actorHasMethod("domwalker", "duplicateNode").then(value => {
duplicateNode.hidden = !value;
});
this._target.actorHasMethod("domnode", "scrollIntoView").then(value => {
scrollIntoView.hidden = !value;
});
if (isDuplicatableElement) {
duplicateNode.removeAttribute("disabled");
}
else {
duplicateNode.setAttribute("disabled", "true");
}
if (isSelectionElement) {
unique.removeAttribute("disabled");
copyInnerHTML.removeAttribute("disabled");
@ -1177,6 +1191,20 @@ InspectorPanel.prototype = {
this.selection.nodeFront.scrollIntoView();
},
/**
* Duplicate the selected node
*/
duplicateNode: function() {
let selection = this.selection;
if (!selection.isElementNode() ||
selection.isRoot() ||
selection.isAnonymousNode() ||
selection.isPseudoElementNode()) {
return;
}
this.walker.duplicateNode(selection.nodeFront).catch(e => console.error(e));
},
/**
* Delete the selected node.
*/

Просмотреть файл

@ -103,6 +103,9 @@
<menuitem id="node-menu-screenshotnode"
label="&inspectorScreenshotNode.label;"
oncommand="inspector.screenshotNode()" />
<menuitem id="node-menu-duplicatenode"
label="&inspectorDuplicateNode.label;"
oncommand="inspector.duplicateNode()"/>
<menuitem id="node-menu-delete"
label="&inspectorHTMLDelete.label;"
accesskey="&inspectorHTMLDelete.accesskey;"

Просмотреть файл

@ -4,17 +4,14 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for menuitem functionality that doesn't fit into any specific category
const TEST_URL = TEST_URL_ROOT + "doc_inspector_menu.html";
add_task(function* () {
let { inspector, toolbox, testActor } = yield openInspectorForURL(TEST_URL);
yield testShowDOMProperties();
yield testDuplicateNode();
yield testDeleteNode();
yield testDeleteRootNode();
yield testScrollIntoView();
function* testShowDOMProperties() {
info("Testing 'Show DOM Properties' menu item.");
let showDOMPropertiesNode = inspector.panelDoc.getElementById("node-menu-showdomproperties");
@ -29,20 +26,38 @@ add_task(function* () {
let webconsoleUI = toolbox.getPanel("webconsole").hud.ui;
let messagesAdded = webconsoleUI.once("new-messages");
yield messagesAdded;
info("Checking if 'inspect($0)' was evaluated");
ok(webconsoleUI.jsterm.history[0] === 'inspect($0)');
yield toolbox.toggleSplitConsole();
}
function* testDuplicateNode() {
info("Testing 'Duplicate Node' menu item for normal elements.");
yield selectNode(".duplicate", inspector);
is((yield testActor.getNumberOfElementMatches(".duplicate")), 1,
"There should initially be 1 .duplicate node");
let menuItem = inspector.panelDoc.getElementById("node-menu-duplicatenode");
ok(menuItem, "'Duplicate node' menu item should exist");
info("Triggering 'Duplicate Node' and waiting for inspector to update");
let updated = inspector.once("markupmutation");
dispatchCommandEvent(menuItem);
yield updated;
is((yield testActor.getNumberOfElementMatches(".duplicate")), 2,
"The duplicated node should be in the markup.");
let container = yield getContainerForSelector(".duplicate + .duplicate",
inspector);
ok(container, "A MarkupContainer should be created for the new node");
}
function* testDeleteNode() {
info("Testing 'Delete Node' menu item for normal elements.");
yield selectNode("#delete", inspector);
let deleteNode = inspector.panelDoc.getElementById("node-menu-delete");
ok(deleteNode, "the popup menu has a delete menu item");
let updated = inspector.once("inspector-updated");
info("Triggering 'Delete Node' and waiting for inspector to update");

Просмотреть файл

@ -15,6 +15,7 @@
</div>
<p data-id="copy">Paragraph for testing copy</p>
<p id="sensitivity">Paragraph for sensitivity</p>
<p class="duplicate">This will be duplicated</p>
<p id="delete">This has to be deleted</p>
<img id="copyimage" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==" />
<div id="hiddenElement" style="display: none;">

Просмотреть файл

@ -224,14 +224,14 @@ devtools.jar:
skin/themes/images/breadcrumbs-scrollbutton@2x.png (themes/images/breadcrumbs-scrollbutton@2x.png)
skin/themes/animationinspector.css (themes/animationinspector.css)
skin/themes/eyedropper.css (themes/eyedropper.css)
* skin/themes/canvasdebugger.css (themes/canvasdebugger.css)
skin/themes/canvasdebugger.css (themes/canvasdebugger.css)
skin/themes/debugger.css (themes/debugger.css)
* skin/themes/netmonitor.css (themes/netmonitor.css)
skin/themes/performance.css (themes/performance.css)
skin/themes/memory.css (themes/memory.css)
skin/themes/promisedebugger.css (themes/promisedebugger.css)
skin/themes/images/timeline-filter.svg (themes/images/timeline-filter.svg)
* skin/themes/scratchpad.css (themes/scratchpad.css)
skin/themes/scratchpad.css (themes/scratchpad.css)
skin/themes/shadereditor.css (themes/shadereditor.css)
skin/themes/storage.css (themes/storage.css)
* skin/themes/splitview.css (themes/splitview.css)

Просмотреть файл

@ -82,6 +82,21 @@ var TestActor = exports.TestActor = protocol.ActorClass({
}
return node;
},
/**
* Helper to get the number of elements matching a selector
* @param {string} CSS selector.
*/
getNumberOfElementMatches: protocol.method(function (selector,
root=this.content.document) {
return root.querySelectorAll(selector).length;
}, {
request: {
selector: Arg(0, "string"),
},
response: {
value: RetVal("number")
}
}),
/**
* Get a value for a given attribute name, on one of the elements of the box

Просмотреть файл

@ -2,14 +2,12 @@
* 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/. */
%filter substitution
%define darkCheckerboardBackground #000
%define lightCheckerboardBackground #fff
%define checkerboardCell rgba(128,128,128,0.2)
%define checkerboardPattern linear-gradient(45deg, @checkerboardCell@ 25%, transparent 25%, transparent 75%, @checkerboardCell@ 75%, @checkerboardCell@), linear-gradient(45deg, @checkerboardCell@ 25%, transparent 25%, transparent 75%, @checkerboardCell@ 75%, @checkerboardCell@)
%define gutterWidth 3em
%define gutterPaddingStart 22px
:root {
--gutter-width: 3em;
--gutter-padding-start: 22px;
--checkerboard-pattern: linear-gradient(45deg, rgba(128,128,128,0.2) 25%, transparent 25%, transparent 75%, rgba(128,128,128,0.2) 75%, rgba(128,128,128,0.2)),
linear-gradient(45deg, rgba(128,128,128,0.2) 25%, transparent 25%, transparent 75%, rgba(128,128,128,0.2) 75%, rgba(128,128,128,0.2));
}
/* Reload and waiting notices */
.notice-container {
@ -35,22 +33,9 @@
/* Snapshots pane */
#snapshots-pane > tabs {
-moz-border-end: 1px solid;
}
#snapshots-pane > tabs,
#snapshots-pane .devtools-toolbar {
-moz-border-end: 1px solid;
}
.theme-dark #snapshots-pane > tabs,
.theme-dark #snapshots-pane .devtools-toolbar {
-moz-border-end-color: black; /* Match the splitter color. */
}
.theme-light #snapshots-pane > tabs,
.theme-light #snapshots-pane .devtools-toolbar {
-moz-border-end-color: #aaa; /* Match the splitter color. */
-moz-border-end: 1px solid var(--theme-splitter-color);
}
#record-snapshot {
@ -65,7 +50,7 @@
.snapshot-item-thumbnail {
image-rendering: -moz-crisp-edges;
background-image: @checkerboardPattern@;
background-image: var(--checkerboard-pattern);
background-size: 12px 12px, 12px 12px;
background-position: 0px 0px, 6px 6px;
background-repeat: repeat, repeat;
@ -75,12 +60,8 @@
transform: scaleY(-1);
}
.theme-dark .snapshot-item-thumbnail {
background-color: @darkCheckerboardBackground@;
}
.theme-light .snapshot-item-thumbnail {
background-color: @lightCheckerboardBackground@;
.snapshot-item-thumbnail {
background-color: var(--theme-body-background);
}
.snapshot-item-details {
@ -234,9 +215,9 @@
}
.call-item-gutter {
width: calc(@gutterWidth@ + @gutterPaddingStart@);
-moz-padding-start: @gutterPaddingStart@;
-moz-padding-end: 4px;
width: calc(var(--gutter-width) + var(--gutter-padding-start));
padding-inline-start: var(--gutter-padding-start);
padding-inline-end: 4px;
padding-top: 2px;
padding-bottom: 2px;
-moz-border-end: 1px solid;
@ -300,7 +281,7 @@
}
.call-item-stack {
-moz-padding-start: calc(@gutterWidth@ + @gutterPaddingStart@);
-moz-padding-start: calc(var(--gutter-width) + var(--gutter-padding-start));
padding-bottom: 10px;
}
@ -345,20 +326,13 @@
/* Rendering preview */
#screenshot-container {
background-image: @checkerboardPattern@;
background-color: var(--theme-body-background);
background-image: var(--checkerboard-pattern);
background-size: 30px 30px, 30px 30px;
background-position: 0px 0px, 15px 15px;
background-repeat: repeat, repeat;
}
.theme-dark #screenshot-container {
background-color: @darkCheckerboardBackground@;
}
.theme-light #screenshot-container {
background-color: @lightCheckerboardBackground@;
}
@media (min-width: 701px) {
#screenshot-container {
width: 30vw;
@ -403,22 +377,22 @@
/* Snapshot filmstrip */
#snapshot-filmstrip {
border-top: 1px solid var(--theme-splitter-color);
overflow: hidden;
}
.theme-dark #snapshot-filmstrip {
border-top: 1px solid #000;
color: var(--theme-selection-color);
}
.theme-light #snapshot-filmstrip {
border-top: 1px solid #aaa;
color: var(--theme-body-color-alt);
}
.filmstrip-thumbnail {
image-rendering: -moz-crisp-edges;
background-image: @checkerboardPattern@;
background-color: var(--theme-body-background);
background-image: var(--checkerboard-pattern);
background-size: 12px 12px, 12px 12px;
background-position: 0px -1px, 6px 5px;
background-repeat: repeat, repeat;
@ -426,6 +400,7 @@
cursor: pointer;
padding-top: 1px;
padding-bottom: 1px;
border-inline-end: 1px solid var(--theme-splitter-color);
transition: opacity 0.1s ease-in-out;
}
@ -433,18 +408,6 @@
transform: scaleY(-1);
}
.theme-dark .filmstrip-thumbnail {
background-color: @darkCheckerboardBackground@;
}
.theme-light .filmstrip-thumbnail {
background-color: @lightCheckerboardBackground@;
}
.filmstrip-thumbnail {
-moz-border-end: 1px solid var(--theme-splitter-color)
}
#snapshot-filmstrip > .filmstrip-thumbnail:hover,
#snapshot-filmstrip:not(:hover) > .filmstrip-thumbnail[highlighted] {
border: 1px solid var(--theme-highlight-blue);

Просмотреть файл

@ -1,8 +1,6 @@
%if 0
/* 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/. */
%endif
#scratchpad-sidebar > tabs {
height: 0;

Просмотреть файл

@ -67,14 +67,7 @@
.stylesheet-sidebar {
max-width: 400px;
min-width: 100px;
}
.theme-light .stylesheet-sidebar {
border-color: #aaa; /* Splitters */
}
.theme-dark .stylesheet-sidebar {
border-color: #000; /* Splitters */
border-color: var(--theme-splitter-color);
}
.theme-light .media-rule-label {

Просмотреть файл

@ -563,47 +563,21 @@
}
.devtools-sidebar-tabs tabs > tab:first-child {
-moz-border-start-width: 0;
border-inline-start-width: 0;
}
.theme-dark .devtools-sidebar-tabs tabs > tab:hover {
background: hsla(206,37%,4%,.2);
.devtools-sidebar-tabs tabs > tab:hover {
background: rgba(0, 0, 0, 0.12);
}
.theme-dark .devtools-sidebar-tabs tabs > tab:hover:active {
background: hsla(206,37%,4%,.4);
.devtools-sidebar-tabs tabs > tab:hover:active {
background: rgba(0, 0, 0, 0.2);
}
.theme-dark .devtools-sidebar-tabs tabs > tab[selected] + tab:hover {
background: hsla(206,37%,4%,.2);
}
.theme-dark .devtools-sidebar-tabs tabs > tab[selected] + tab:hover:active {
background: hsla(206,37%,4%,.4);
}
.theme-dark .devtools-sidebar-tabs tabs > tab[selected],
.theme-dark .devtools-sidebar-tabs tabs > tab[selected]:hover:active {
.devtools-sidebar-tabs tabs > tab[selected],
.devtools-sidebar-tabs tabs > tab[selected]:hover:active {
color: var(--theme-selection-color);
background: #1d4f73;
}
.theme-light .devtools-sidebar-tabs tabs > tab:hover {
background: #ddd;
}
.theme-light .devtools-sidebar-tabs tabs > tab:hover:active {
background: #ddd;
}
.theme-light .devtools-sidebar-tabs tabs > tab[selected] + tab:hover {
background: #ddd;
}
.theme-light .devtools-sidebar-tabs tabs > tab[selected],
.theme-light .devtools-sidebar-tabs tabs > tab[selected]:hover:active {
color: var(--theme-selection-color);
background: #4c9ed9;
background: var(--theme-selection-background);
}
/* Toolbox - moved from toolbox.css.

Просмотреть файл

@ -30,10 +30,10 @@ svg {
}
.theme-dark .edgePath path {
stroke: #b6babf; /* Grey foreground text */
stroke: var(--theme-body-color-alt);
}
.theme-light .edgePath path {
stroke: #aaaaaa; /* Splitters */
stroke: var(--theme-splitter-color);
}
/* AudioParam connection edges */
@ -42,27 +42,21 @@ g.edgePath.param-connection {
}
.theme-dark .edgePath.param-connection path {
stroke: #b6babf; /* Grey foreground text */
stroke: var(--theme-body-color-alt);
}
.theme-light .edgePath.param-connection path {
stroke: #aaaaaa; /* Splitters */
stroke: var(--theme-splitter-color);
}
/* Labels in AudioParam connection should have background that match
* the main background so there's whitespace around the label, on top of the
* dotted lines. */
.theme-dark g.edgeLabel rect {
fill: #14171a;
g.edgeLabel rect {
fill: var(--theme-body-background);
}
.theme-light g.edgeLabel rect {
fill: #fcfcfc; /* Background - Editor */
}
.theme-dark g.edgeLabel tspan {
g.edgeLabel tspan {
fill: var(--theme-body-color-alt);
}
.theme-light g.edgeLabel tspan {
fill: #585959; /* Grey foreground text */
}
/* Audio Nodes */
.nodes rect {
@ -219,11 +213,8 @@ text {
background-color: transparent;
}
.theme-dark #audio-node-toolbar toolbarbutton[checked] {
background-color: #1d4f73; /* Select Highlight Blue */
}
.theme-light #audio-node-toolbar toolbarbutton[checked] {
background-color: #4c9ed9; /* Select Highlight Blue */
#audio-node-toolbar toolbarbutton[checked] {
background-color: var(--theme-selection-background);
}
/* don't invert checked buttons so we can have white icons on light theme */

Просмотреть файл

@ -26,7 +26,7 @@ a {
.message > .prefix,
.message > .timestamp {
flex: none;
color: GrayText;
color: var(--theme-comment);
margin: 3px 6px 0 0;
}
@ -131,11 +131,6 @@ a {
margin-top: 0;
}
.jsterm-input-container {
border-top-width: 1px;
border-top-style: solid;
}
#output-wrapper {
direction: ltr;
overflow: auto;
@ -253,11 +248,11 @@ a {
}
.message[category=network].mixed-content .url {
color: #FF0000;
color: var(--theme-highlight-red);
}
.message .learn-more-link {
color: -moz-nativehyperlinktext;
color: var(--theme-highlight-blue);
margin: 0 6px;
}
@ -360,6 +355,18 @@ a {
}
/* JSTerm Styles */
.jsterm-input-container {
background-color: var(--theme-tab-toolbar-background);
border-top: 1px solid var(--theme-splitter-color);
}
.theme-light .jsterm-input-container {
/* For light theme use a white background for the input - it looks better
than off-white */
background-color: #fff;
border-top-color: #e0e0e0;
}
.jsterm-input-node,
.jsterm-complete-node {
border: none;
@ -368,10 +375,15 @@ a {
background-color: transparent;
}
.jsterm-complete-node {
color: var(--theme-comment);
}
.jsterm-input-node {
background-image: -moz-image-rect(url("chrome://devtools/skin/themes/images/commandline-icon.png"), 0, 32, 16, 16);
background-repeat: no-repeat;
background-size: 16px 16px;
color: var(--theme-content-color1);
}
@media (min-resolution: 1.1dppx) {
@ -398,7 +410,7 @@ a {
margin-top: 5px;
margin-bottom: 15px;
-moz-margin-end: 15px;
border: 1px solid rgba(128, 128, 128, .5);
border: 1px solid var(--theme-splitter-color);
border-radius: 3px;
}
@ -442,6 +454,11 @@ a {
.navigation-marker .url {
-moz-padding-end: 9px;
text-decoration: none;
background: var(--theme-body-background);
}
.theme-light .navigation-marker .url {
background: #fff;
}
.stacktrace {
@ -451,7 +468,7 @@ a {
margin: 5px 0 0 0;
max-height: 10em;
overflow-y: auto;
border: 1px solid rgb(200,200,200);
border: 1px solid var(--theme-splitter-color);
border-radius: 3px;
}
@ -514,49 +531,6 @@ a {
background-position: -16px 0;
}
.jsterm-input-container {
background-color: var(--theme-tab-toolbar-background);
border-color: var(--theme-body-background);
}
.jsterm-input-node {
color: var(--theme-content-color1);
}
.jsterm-complete-node {
color: var(--theme-comment);
}
.navigation-marker .url {
background: var(--theme-body-background);
}
.theme-dark .inlined-variables-view iframe {
border-color: #333;
}
.theme-dark .stacktrace {
border-color: #333;
}
.theme-light .jsterm-input-container {
/* For light theme use a white background for the input - it looks better
than off-white */
background-color: #fff;
border-color: ThreeDShadow;
}
.theme-light .navigation-marker .url {
background: #fff;
}
.theme-light .inlined-variables-view iframe {
border-color: #ccc;
}
.theme-light .stacktrace {
border-color: #ccc;
}
@media (max-width: 500px) {
.message > .timestamp {
display: none;

Просмотреть файл

@ -2592,6 +2592,21 @@ var WalkerActor = protocol.ActorClass({
response: RetVal("disconnectedNodeArray")
}),
/**
* Duplicate a specified node
*
* @param {NodeActor} node The node to duplicate.
*/
duplicateNode: method(function({rawNode}) {
let clonedNode = rawNode.cloneNode(true);
rawNode.parentNode.insertBefore(clonedNode, rawNode.nextSibling);
}, {
request: {
node: Arg(0, "domnode")
},
response: {}
}),
/**
* Test whether a node is a document or a document element.
*

Просмотреть файл

@ -57,6 +57,7 @@ skip-if = buildapp == 'mulet'
[test_inspector-changeattrs.html]
[test_inspector-changevalue.html]
[test_inspector-dead-nodes.html]
[test_inspector-duplicate-node.html]
[test_inspector_getImageData.html]
skip-if = buildapp == 'mulet'
[test_inspector_getImageDataFromURL.html]

Просмотреть файл

@ -80,12 +80,11 @@
<select multiple><option>one</option><option>two</option></select>
<div id="pseudo"><span>middle</span></div>
<div id="pseudo-empty"></div>
<div id="shadow">light dom</div>
<object>
<div id="1"></div>
</object>
<div class="node-to-duplicate"></div>
<div id="scroll-into-view" style="margin-top: 1000px;">scroll</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1208864
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1208864</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
<script type="application/javascript;version=1.8">
const inspector = require("devtools/server/actors/inspector");
window.onload = function() {
SimpleTest.waitForExplicitFinish();
runNextTest();
}
var gInspectee = null;
var gClient = null;
var gWalker = null;
function assertOwnership() {
assertOwnershipTrees(gWalker);
}
addTest(function setup() {
let url = document.getElementById("inspectorContent").href;
attachURL(url, function(err, client, tab, doc) {
gInspectee = doc;
let {InspectorFront} = require("devtools/server/actors/inspector");
let inspector = InspectorFront(client, tab);
promiseDone(inspector.getWalker().then(walker => {
ok(walker, "getWalker() should return an actor.");
gClient = client;
gWalker = walker;
}).then(runNextTest));
});
});
addTest(Task.async(function* testDuplicateNode() {
let className = ".node-to-duplicate";
let matches = yield gWalker.querySelectorAll(gWalker.rootNode, className);
is(matches.length, 1, "There should initially be one node to duplicate.");
let nodeFront = yield gWalker.querySelector(gWalker.rootNode, className);
yield gWalker.duplicateNode(nodeFront);
matches = yield gWalker.querySelectorAll(gWalker.rootNode, className);
is(matches.length, 2, "The node should now be duplicated.");
runNextTest();
}));
addTest(function cleanup() {
delete gWalker;
delete gInspectee;
delete gClient;
runNextTest();
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208864">Mozilla Bug 1208864</a>
<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -458,6 +458,25 @@ exports.dbg_assert = function dbg_assert(cond, e) {
}
};
exports.defineLazyGetter(this, "AppConstants", () => {
const scope = {};
Cu.import("resource://gre/modules/AppConstants.jsm", scope);
return scope.AppConstants;
});
/**
* No operation. The empty function.
*/
exports.noop = function () { };
function reallyAssert(condition, message) {
if (!condition) {
const err = new Error("Assertion failure: " + message);
exports.reportException("DevToolsUtils.assert", err);
throw err;
}
}
/**
* DevToolsUtils.assert(condition, message)
*
@ -477,23 +496,11 @@ exports.dbg_assert = function dbg_assert(cond, e) {
* This is an improvement over `dbg_assert`, which doesn't actually cause any
* fatal behavior, and is therefore much easier to accidentally ignore.
*/
exports.defineLazyGetter(exports, "assert", () => {
function noop(condition, msg) { }
function assert(condition, message) {
if (!condition) {
const err = new Error("Assertion failure: " + message);
exports.reportException("DevToolsUtils.assert", err);
throw err;
}
}
const scope = {};
Cu.import("resource://gre/modules/AppConstants.jsm", scope);
const { DEBUG, DEBUG_JS_MODULES } = scope.AppConstants;
return (DEBUG || DEBUG_JS_MODULES || exports.testing) ? assert : noop;
});
Object.defineProperty(exports, "assert", {
get: () => (AppConstants.DEBUG || AppConstants.DEBUG_JS_MODULES || this.testing)
? reallyAssert
: exports.noop,
})
/**
* Defines a getter on a specified object for a module. The module will not

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/devtools/DeserializedNode.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefCounted.h"
@ -139,6 +140,15 @@ public:
void TakeCensus(JSContext* cx, JS::HandleObject options,
JS::MutableHandleValue rval, ErrorResult& rv);
dom::Nullable<uint64_t> GetCreationTime() {
static const uint64_t maxTime = uint64_t(1) << 53;
if (timestamp.isSome() && timestamp.ref() <= maxTime) {
return dom::Nullable<uint64_t>(timestamp.ref());
}
return dom::Nullable<uint64_t>();
}
};
// A `CoreDumpWriter` is given the data we wish to save in a core dump and

Просмотреть файл

@ -0,0 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// HeapSnapshot.prototype.creationTime returns the expected time.
function waitForTenMilliseconds() {
const start = Date.now();
while (Date.now() - start < 10) ;
}
function run_test() {
const start = Date.now() * 1000;
do_print("start = " + start);
// Because Date.now() is less precise than the snapshot's time stamp, give it
// a little bit of head room.
waitForTenMilliseconds();
const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
waitForTenMilliseconds();
const end = Date.now() * 1000;
do_print("end = " + end);
const snapshot = ChromeUtils.readHeapSnapshot(path);
do_print("snapshot.creationTime = " + snapshot.creationTime);
ok(snapshot.creationTime >= start);
ok(snapshot.creationTime <= end);
}

Просмотреть файл

@ -25,6 +25,7 @@ support-files =
[test_HeapAnalyses_takeCensus_03.js]
[test_HeapAnalyses_takeCensus_04.js]
[test_HeapAnalyses_takeCensus_05.js]
[test_HeapSnapshot_creationTime_01.js]
[test_HeapSnapshot_takeCensus_01.js]
[test_HeapSnapshot_takeCensus_02.js]
[test_HeapSnapshot_takeCensus_03.js]

Просмотреть файл

@ -9,6 +9,11 @@ const DevToolsUtils = require("devtools/shared/DevToolsUtils");
// Register a console listener, so console messages don't just disappear
// into the ether.
// If for whatever reason the test needs to post console errors that aren't
// failures, set this to true.
var ALLOW_CONSOLE_ERRORS = false;
var errorCount = 0;
var listener = {
observe: function (aMessage) {
@ -35,7 +40,10 @@ var listener = {
while (DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
DebuggerServer.xpcInspector.exitNestedEventLoop();
}
do_throw("head_dbg.js got console message: " + string + "\n");
if (!ALLOW_CONSOLE_ERRORS) {
do_throw("head_devtools.js got console message: " + string + "\n");
}
}
};

Просмотреть файл

@ -0,0 +1,36 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test DevToolsUtils.assert
ALLOW_CONSOLE_ERRORS = true;
function run_test() {
// Enable assertions.
DevToolsUtils.testing = true;
const { assert } = DevToolsUtils;
equal(typeof assert, "function");
try {
assert(true, "this assertion should not fail");
} catch (e) {
// If you catch assertion failures in practice, I will hunt you down. I get
// email notifications every time it happens.
ok(false, "Should not get an error for an assertion that should not fail. Got "
+ DevToolsUtils.safeErrorString(e));
}
let assertionFailed = false;
try {
assert(false, "this assertion should fail");
} catch (e) {
ok(e.message.startsWith("Assertion failure:"),
"Should be an assertion failure error");
assertionFailed = true;
}
ok(assertionFailed,
"The assertion should have failed, which should throw an error when assertions are enabled.");
}

Просмотреть файл

@ -6,6 +6,7 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
exposeLoader.js
[test_assert.js]
[test_fetch-chrome.js]
[test_fetch-file.js]
[test_fetch-http.js]

Просмотреть файл

@ -862,16 +862,16 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
{ }
static bool
Write(const nsString& aName, bool isFile, const nsString& aValue,
File* aFile, void* aClosure)
Write(const nsString& aName, const OwningFileOrUSVString& aValue,
void* aClosure)
{
Closure* closure = static_cast<Closure*>(aClosure);
if (!WriteString(closure->mWriter, aName)) {
return false;
}
if (isFile) {
BlobImpl* blobImpl = aFile->Impl();
if (aValue.IsFile()) {
BlobImpl* blobImpl = aValue.GetAsFile()->Impl();
if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
closure->mHolder->BlobImpls().Length())) {
return false;
@ -882,9 +882,10 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
}
size_t charSize = sizeof(nsString::char_type);
if (!JS_WriteUint32Pair(closure->mWriter, 0, aValue.Length()) ||
!JS_WriteBytes(closure->mWriter, aValue.get(),
aValue.Length() * charSize)) {
if (!JS_WriteUint32Pair(closure->mWriter, 0,
aValue.GetAsUSVString().Length()) ||
!JS_WriteBytes(closure->mWriter, aValue.GetAsUSVString().get(),
aValue.GetAsUSVString().Length() * charSize)) {
return false;
}

Просмотреть файл

@ -61,7 +61,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
ImplCycleCollectionUnlink(tmp->mFormData[i].fileValue);
ImplCycleCollectionUnlink(tmp->mFormData[i].value);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@ -71,8 +71,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
ImplCycleCollectionTraverse(cb,tmp->mFormData[i].fileValue,
"mFormData[i].fileValue", 0);
ImplCycleCollectionTraverse(cb, tmp->mFormData[i].value,
"mFormData[i].GetAsFile()", 0);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
@ -126,24 +126,13 @@ nsFormData::Delete(const nsAString& aName)
}
}
void
nsFormData::ExtractValue(const FormDataTuple& aTuple,
OwningFileOrUSVString* aOutValue)
{
if (aTuple.valueIsFile) {
aOutValue->SetAsFile() = aTuple.fileValue;
} else {
aOutValue->SetAsUSVString() = aTuple.stringValue;
}
}
void
nsFormData::Get(const nsAString& aName,
Nullable<OwningFileOrUSVString>& aOutValue)
{
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
if (aName.Equals(mFormData[i].name)) {
ExtractValue(mFormData[i], &aOutValue.SetValue());
aOutValue.SetValue() = mFormData[i].value;
return;
}
}
@ -158,7 +147,7 @@ nsFormData::GetAll(const nsAString& aName,
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
if (aName.Equals(mFormData[i].name)) {
OwningFileOrUSVString* element = aValues.AppendElement();
ExtractValue(mFormData[i], element);
*element = mFormData[i].value;
}
}
}
@ -229,6 +218,26 @@ nsFormData::Set(const nsAString& aName, const nsAString& aValue)
}
}
uint32_t
nsFormData::GetIterableLength() const
{
return mFormData.Length();
}
const nsAString&
nsFormData::GetKeyAtIndex(uint32_t aIndex) const
{
MOZ_ASSERT(aIndex < mFormData.Length());
return mFormData[aIndex].name;
}
const OwningFileOrUSVString&
nsFormData::GetValueAtIndex(uint32_t aIndex) const
{
MOZ_ASSERT(aIndex < mFormData.Length());
return mFormData[aIndex].value;
}
// -------------------------------------------------------------------------
// nsIDOMFormData
@ -297,11 +306,13 @@ nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
if (mFormData[i].valueIsFile) {
fs.AddNameFilePair(mFormData[i].name, mFormData[i].fileValue);
}
else {
fs.AddNameValuePair(mFormData[i].name, mFormData[i].stringValue);
if (mFormData[i].value.IsFile()) {
fs.AddNameFilePair(mFormData[i].name, mFormData[i].value.GetAsFile());
} else if (mFormData[i].value.IsUSVString()) {
fs.AddNameValuePair(mFormData[i].name,
mFormData[i].value.GetAsUSVString());
} else {
fs.AddNameFilePair(mFormData[i].name, nullptr);
}
}

Просмотреть файл

@ -37,13 +37,12 @@ private:
typedef mozilla::dom::Blob Blob;
typedef mozilla::dom::File File;
typedef mozilla::dom::OwningFileOrUSVString OwningFileOrUSVString;
struct FormDataTuple
{
nsString name;
nsString stringValue;
RefPtr<File> fileValue;
bool valueIsFile;
OwningFileOrUSVString value;
};
// Returns the FormDataTuple to modify. This may be null, in which case
@ -57,8 +56,7 @@ private:
{
MOZ_ASSERT(aData);
aData->name = aName;
aData->stringValue = aValue;
aData->valueIsFile = false;
aData->value.SetAsUSVString() = aValue;
}
void SetNameFilePair(FormDataTuple* aData,
@ -67,12 +65,11 @@ private:
{
MOZ_ASSERT(aData);
aData->name = aName;
aData->fileValue = aFile;
aData->valueIsFile = true;
if (aFile) {
aData->value.SetAsFile() = aFile;
}
}
void ExtractValue(const FormDataTuple& aTuple,
mozilla::dom::OwningFileOrUSVString* aOutValue);
public:
explicit nsFormData(nsISupports* aOwner = nullptr);
@ -100,13 +97,17 @@ public:
void Append(const nsAString& aName, Blob& aBlob,
const mozilla::dom::Optional<nsAString>& aFilename);
void Delete(const nsAString& aName);
void Get(const nsAString& aName, mozilla::dom::Nullable<mozilla::dom::OwningFileOrUSVString>& aOutValue);
void GetAll(const nsAString& aName, nsTArray<mozilla::dom::OwningFileOrUSVString>& aValues);
void Get(const nsAString& aName, mozilla::dom::Nullable<OwningFileOrUSVString>& aOutValue);
void GetAll(const nsAString& aName, nsTArray<OwningFileOrUSVString>& aValues);
bool Has(const nsAString& aName);
void Set(const nsAString& aName, Blob& aBlob,
const mozilla::dom::Optional<nsAString>& aFilename);
void Set(const nsAString& aName, const nsAString& aValue);
uint32_t GetIterableLength() const;
const nsAString& GetKeyAtIndex(uint32_t aIndex) const;
const OwningFileOrUSVString& GetValueAtIndex(uint32_t aIndex) const;
// nsFormSubmission
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
nsIInputStream** aPostDataStream) override;
@ -120,9 +121,9 @@ public:
virtual nsresult AddNameFilePair(const nsAString& aName,
File* aFile) override;
typedef bool (*FormDataEntryCallback)(const nsString& aName, bool aIsFile,
const nsString& aValue,
File* aFile, void* aClosure);
typedef bool (*FormDataEntryCallback)(const nsString& aName,
const OwningFileOrUSVString& aValue,
void* aClosure);
uint32_t
Length() const
@ -137,8 +138,7 @@ public:
{
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
FormDataTuple& tuple = mFormData[i];
if (!aFunc(tuple.name, tuple.valueIsFile, tuple.stringValue,
tuple.fileValue, aClosure)) {
if (!aFunc(tuple.name, tuple.value, aClosure)) {
return false;
}
}

Просмотреть файл

@ -5598,6 +5598,8 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
PersistentBufferProvider *provider = GetBufferProvider(aManager);
data.mBufferProvider = provider;
} else {
PersistentBufferProvider *provider = GetBufferProvider(aManager);
data.mBufferProvider = provider;
@ -5648,6 +5650,8 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
PersistentBufferProvider *provider = GetBufferProvider(aManager);
data.mBufferProvider = provider;
} else {
PersistentBufferProvider *provider = GetBufferProvider(aManager);
data.mBufferProvider = provider;

Просмотреть файл

@ -102,6 +102,19 @@ public:
mInternalHeaders->Set(aName, aValue, aRv);
}
uint32_t GetIterableLength() const
{
return mInternalHeaders->GetIterableLength();
}
const nsString GetKeyAtIndex(unsigned aIndex) const
{
return mInternalHeaders->GetKeyAtIndex(aIndex);
}
const nsString GetValueAtIndex(unsigned aIndex) const
{
return mInternalHeaders->GetValueAtIndex(aIndex);
}
// ChromeOnly
HeadersGuardEnum Guard() const
{

Просмотреть файл

@ -51,11 +51,14 @@ public:
}
explicit InternalHeaders(const InternalHeaders& aOther)
: mGuard(aOther.mGuard)
: mGuard(HeadersGuardEnum::None)
{
ErrorResult result;
Fill(aOther, result);
MOZ_ASSERT(!result.Failed());
// Note that it's important to set the guard after Fill(), to make sure
// that Fill() doesn't fail if aOther is immutable.
mGuard = aOther.mGuard;
}
explicit InternalHeaders(const nsTArray<Entry>&& aHeaders,
@ -70,6 +73,21 @@ public:
bool Has(const nsACString& aName, ErrorResult& aRv) const;
void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
uint32_t GetIterableLength() const
{
return mList.Length();
}
const NS_ConvertASCIItoUTF16 GetKeyAtIndex(unsigned aIndex) const
{
MOZ_ASSERT(aIndex < mList.Length());
return NS_ConvertASCIItoUTF16(mList[aIndex].mName);
}
const NS_ConvertASCIItoUTF16 GetValueAtIndex(unsigned aIndex) const
{
MOZ_ASSERT(aIndex < mList.Length());
return NS_ConvertASCIItoUTF16(mList[aIndex].mValue);
}
void Clear();
HeadersGuardEnum Guard() const { return mGuard; }

Просмотреть файл

@ -105,6 +105,56 @@ function testFilename() {
is(f.get("file3").name, "", "File's filename is returned even if empty.");
}
function testIterable() {
var fd = new FormData();
fd.set('1','2');
fd.set('2','4');
fd.set('3','6');
fd.set('4','8');
fd.set('5','10');
var key_iter = fd.keys();
var value_iter = fd.values();
var entries_iter = fd.entries();
for (var i = 0; i < 5; ++i) {
var v = i + 1;
var key = key_iter.next();
var value = value_iter.next();
var entry = entries_iter.next();
is(key.value, v.toString(), "Correct Key iterator: " + v.toString());
ok(!key.done, "key.done is false");
is(value.value, (v * 2).toString(), "Correct Value iterator: " + (v * 2).toString());
ok(!value.done, "value.done is false");
is(entry.value[0], v.toString(), "Correct Entry 0 iterator: " + v.toString());
is(entry.value[1], (v * 2).toString(), "Correct Entry 1 iterator: " + (v * 2).toString());
ok(!entry.done, "entry.done is false");
}
var last = key_iter.next();
ok(last.done, "Nothing more to read.");
is(last.value, undefined, "Undefined is the last key");
last = value_iter.next();
ok(last.done, "Nothing more to read.");
is(last.value, undefined, "Undefined is the last value");
last = entries_iter.next();
ok(last.done, "Nothing more to read.");
key_iter = fd.keys();
key_iter.next();
key_iter.next();
fd.delete('1');
fd.delete('2');
fd.delete('3');
fd.delete('4');
fd.delete('5');
last = key_iter.next();
ok(last.done, "Nothing more to read.");
is(last.value, undefined, "Undefined is the last key");
}
function testSend(doneCb) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "form_submit_server.sjs");
@ -161,6 +211,7 @@ function runTest(doneCb) {
testSet();
testIterate();
testFilename();
testIterable();
// Finally, send an XHR and verify the response matches.
testSend(doneCb);
}

Просмотреть файл

@ -2112,6 +2112,7 @@ SourceMediaStream::AddTrackInternal(TrackID aID, TrackRate aRate, StreamTime aSt
TrackData* data = track_data->AppendElement();
data->mID = aID;
data->mInputRate = aRate;
data->mResamplerChannelCount = 0;
data->mStart = aStart;
data->mEndOfFlushedData = aStart;
data->mCommands = TRACK_CREATE;

Просмотреть файл

@ -37,6 +37,8 @@ public:
, mDetune(0.f)
, mType(OscillatorType::Sine)
, mPhase(0.)
, mFinalFrequency(0.)
, mPhaseIncrement(0.)
, mRecomputeParameters(true)
, mCustomLength(0)
{

Просмотреть файл

@ -21,7 +21,6 @@ namespace dom {
NS_IMPL_ISUPPORTS(PresentationDeviceManager,
nsIPresentationDeviceManager,
nsIPresentationDeviceListener,
nsIPresentationDeviceEventListener,
nsIObserver,
nsISupportsWeakReference)
@ -180,7 +179,6 @@ PresentationDeviceManager::AddDevice(nsIPresentationDevice* aDevice)
}
mDevices.AppendElement(aDevice);
aDevice->SetListener(this);
NotifyDeviceChange(aDevice, MOZ_UTF16("add"));
@ -198,7 +196,6 @@ PresentationDeviceManager::RemoveDevice(nsIPresentationDevice* aDevice)
return NS_ERROR_FAILURE;
}
mDevices[index]->SetListener(nullptr);
mDevices.RemoveElementAt(index);
NotifyDeviceChange(aDevice, MOZ_UTF16("remove"));
@ -221,7 +218,6 @@ PresentationDeviceManager::UpdateDevice(nsIPresentationDevice* aDevice)
return NS_OK;
}
// nsIPresentationDeviceListener
NS_IMETHODIMP
PresentationDeviceManager::OnSessionRequest(nsIPresentationDevice* aDevice,
const nsAString& aUrl,

Просмотреть файл

@ -19,7 +19,6 @@ namespace dom {
class PresentationDeviceManager final : public nsIPresentationDeviceManager
, public nsIPresentationDeviceListener
, public nsIPresentationDeviceEventListener
, public nsIObserver
, public nsSupportsWeakReference
{
@ -27,7 +26,6 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPRESENTATIONDEVICEMANAGER
NS_DECL_NSIPRESENTATIONDEVICELISTENER
NS_DECL_NSIPRESENTATIONDEVICEEVENTLISTENER
NS_DECL_NSIOBSERVER
PresentationDeviceManager();

Просмотреть файл

@ -5,30 +5,11 @@
#include "nsISupports.idl"
interface nsIPresentationControlChannel;
interface nsIPresentationDevice;
/*
* Event callbacks from remote presentation device.
*/
[scriptable, uuid(81984458-b9d1-4731-a26a-ba62ab339aac)]
interface nsIPresentationDeviceEventListener : nsISupports
{
/*
* Callback while the remote device is requesting to start a presentation session.
* @param url The URL requested to open by remote device.
* @param presentationId The Id for representing this session.
* @param controlChannel The control channel for this session.
*/
void onSessionRequest(in nsIPresentationDevice device,
in DOMString url,
in DOMString presentationId,
in nsIPresentationControlChannel controlChannel);
};
/*
* Remote device.
*/
[scriptable, uuid(7fac99d4-9b19-4b8d-b5cd-5da8adbe58f1)]
[scriptable, uuid(b1e0a7af-5936-4066-8f2e-f789fb9a7e8f)]
interface nsIPresentationDevice : nsISupports
{
// The unique Id for the device. UUID is recommanded.
@ -41,9 +22,6 @@ interface nsIPresentationDevice : nsISupports
// The category of this device, could be "wifi", "bluetooth", "hdmi", etc.
readonly attribute AUTF8String type;
// The listener for handling remote session request.
attribute nsIPresentationDeviceEventListener listener;
/*
* Establish a control channel to this device.
* @param url The URL requested to open by remote device.

Просмотреть файл

@ -5,20 +5,33 @@
#include "nsISupports.idl"
interface nsIPresentationDevice;
interface nsIPresentationControlChannel;
%{C++
#define PRESENTATION_DEVICE_PROVIDER_CATEGORY "presentation-device-provider"
%}
/*
* The callbacks for any device updates.
* The callbacks for any device updates and session request.
*/
[scriptable, uuid(7f9f0514-d957-485a-90e8-57cc3acbf15b)]
[scriptable, uuid(46fd372b-2e40-4179-9b36-0478d141e440)]
interface nsIPresentationDeviceListener: nsISupports
{
void addDevice(in nsIPresentationDevice device);
void removeDevice(in nsIPresentationDevice device);
void updateDevice(in nsIPresentationDevice device);
/*
* Callback while the remote device is requesting to start a presentation session.
* @param device The remote device that sent session request.
* @param url The URL requested to open by remote device.
* @param presentationId The Id for representing this session.
* @param controlChannel The control channel for this session.
*/
void onSessionRequest(in nsIPresentationDevice device,
in DOMString url,
in DOMString presentationId,
in nsIPresentationControlChannel controlChannel);
};
/*

Просмотреть файл

@ -4,9 +4,25 @@
#include "nsISupports.idl"
interface nsIPresentationDevice;
interface nsIPresentationControlChannel;
[scriptable, uuid(b0dc6b1f-5f6f-455d-a917-90d0ad37186b)]
%{C++
#define TCP_PRESENTATION_SERVER_CONTACT_ID \
"@mozilla.org/presentation-device/tcp-presentation-server;1"
%}
/*
* The device information required for establishing TCP control channel.
*/
[scriptable, uuid(7fce55c0-2470-4a41-a3b9-c35fbe55f206)]
interface nsITCPDeviceInfo: nsISupports
{
readonly attribute AUTF8String id;
readonly attribute AUTF8String host;
readonly attribute uint16_t port;
};
[scriptable, uuid(fbb890a9-9e95-47d1-a425-86fd95881d81)]
interface nsITCPPresentationServerListener: nsISupports
{
/**
@ -16,12 +32,24 @@ interface nsITCPPresentationServerListener: nsISupports
* <other-error> on failure.
*/
void onClose(in nsresult aReason);
/**
* Callback while the remote host is requesting to start a presentation session.
* @param aDeviceInfo The device information related to the remote host.
* @param aUrl The URL requested to open by remote device.
* @param aPresentationId The Id for representing this session.
* @param aControlChannel The control channel for this session.
*/
void onSessionRequest(in nsITCPDeviceInfo aDeviceInfo,
in DOMString aUrl,
in DOMString aPresentationId,
in nsIPresentationControlChannel aControlChannel);
};
/**
* TCP presentation server which can be used by discovery services.
*/
[scriptable, uuid(fcadc9fe-f1e9-4f74-b9d3-9cd6b74afc9e)]
[scriptable, uuid(494237ec-c567-41ab-afc9-82d26c4fe1dc)]
interface nsITCPPresentationServer: nsISupports
{
/**
@ -38,70 +66,27 @@ interface nsITCPPresentationServer: nsISupports
*/
void init([optional] in AUTF8String aId, [optional] in uint16_t aPort);
/**
* Request session to designated remote TCP device.
* @param aDeviceInfo
* The remtoe device info for establish connection.
* @param aUrl
* The URL requested to open by remote device.
* @param aPresentationId
* The Id for representing this session.
* @returns The control channel for this session.
* @throws NS_ERROR_FAILURE if the server socket has been inited or the
* server socket can not be inited.
*/
nsIPresentationControlChannel requestSession(in nsITCPDeviceInfo aDeviceInfo,
in DOMString aUrl,
in DOMString aPresentationId);
/**
* Close server socket and call |listener.onClose(NS_OK)|
*/
void close();
/**
* Create TCPDevice for this server.
* @param aId
* The unique Id for the discovered device
* @param aName
* The human-readable name of the discovered device
* @param aType
* The category of the discovered device
* @param aHost
* The host of the provided control channel of the discovered device
* @param aPort
* The port of the provided control channel of the discovered device
* @returns The created device
* @throws NS_ERROR_INVALID_ARG if a TCPDevice with |aId| have existed.
*/
nsIPresentationDevice createTCPDevice(in AUTF8String aId,
in AUTF8String aName,
in AUTF8String aType,
in AUTF8String aHost,
in uint16_t aPort);
/**
* Update TCPDevice for this server.
* @param aId
* The unique Id for the discovered device
* @param aName
* The human-readable name of the discovered device
* @param aType
* The category of the discovered device
* @param aHost
* The host of the provided control channel of the discovered device
* @param aPort
* The port of the provided control channel of the discovered device
* @returns The updated device
* @throws NS_ERROR_INVALID_ARG if a TCPDevice with |aId| does not existed.
*/
nsIPresentationDevice updateTCPDevice(in AUTF8String aId,
in AUTF8String aName,
in AUTF8String aType,
in AUTF8String aHost,
in uint16_t aPort);
/**
* Get TCPDevice with |aID|.
* @param aId
* The unique Id for the query device
* @returns The queried device; return |undefined|
* @throws NS_ERROR_INVALID_ARG if a TCPDevice with |aId| does not exist.
*/
nsIPresentationDevice getTCPDevice(in AUTF8String aId);
/**
* Remove TCPDevice with |aID|.
* @param aId
* The unique Id for the device which needs to be removed
* @throws NS_ERROR_INVALID_ARG if a TCPDevice with |aId| does not exist.
*/
void removeTCPDevice(in AUTF8String aId);
/**
* Get the listen port of the TCP socket, valid after |init|. 0 indicates
* the server socket is not inited or closed.

Просмотреть файл

@ -12,7 +12,6 @@
#include "nsAutoPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsIObserverService.h"
#include "nsIPresentationDevice.h"
#include "nsServiceManagerUtils.h"
#define PREF_PRESENTATION_DISCOVERY "dom.presentation.discovery.enabled"
@ -20,9 +19,6 @@
#define PREF_PRESENTATION_DISCOVERABLE "dom.presentation.discoverable"
#define PREF_PRESENTATION_DEVICE_NAME "dom.presentation.device.name"
#define TCP_PRESENTATION_SERVER_CONTACT_ID \
"@mozilla.org/presentation-device/tcp-presentation-server;1"
#define SERVICE_TYPE "_mozilla_papi._tcp."
inline static PRLogModuleInfo*
@ -48,6 +44,58 @@ static const char* kObservedPrefs[] = {
nullptr
};
namespace {
class TCPDeviceInfo final : public nsITCPDeviceInfo
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSITCPDEVICEINFO
explicit TCPDeviceInfo(const nsACString& aId,
const nsACString& aHost,
const uint16_t aPort)
: mId(aId)
, mHost(aHost)
, mPort(aPort)
{
}
private:
virtual ~TCPDeviceInfo() {}
nsCString mId;
nsCString mHost;
uint16_t mPort;
};
NS_IMPL_ISUPPORTS(TCPDeviceInfo,
nsITCPDeviceInfo)
// nsITCPDeviceInfo
NS_IMETHODIMP
TCPDeviceInfo::GetId(nsACString& aId)
{
aId = mId;
return NS_OK;
}
NS_IMETHODIMP
TCPDeviceInfo::GetHost(nsACString& aHost)
{
aHost = mHost;
return NS_OK;
}
NS_IMETHODIMP
TCPDeviceInfo::GetPort(uint16_t* aPort)
{
*aPort = mPort;
return NS_OK;
}
} //anonymous namespace
/**
* This wrapper is used to break circular-reference problem.
*/
@ -261,6 +309,22 @@ MulticastDNSDeviceProvider::StopDiscovery(nsresult aReason)
return NS_OK;
}
nsresult
MulticastDNSDeviceProvider::RequestSession(Device* aDevice,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel** aRetVal)
{
MOZ_ASSERT(aDevice);
MOZ_ASSERT(mPresentationServer);
RefPtr<TCPDeviceInfo> deviceInfo = new TCPDeviceInfo(aDevice->Id(),
aDevice->Host(),
aDevice->Port());
return mPresentationServer->RequestSession(deviceInfo, aUrl, aPresentationId, aRetVal);
}
nsresult
MulticastDNSDeviceProvider::AddDevice(const nsACString& aServiceName,
const nsACString& aServiceType,
@ -270,25 +334,20 @@ MulticastDNSDeviceProvider::AddDevice(const nsACString& aServiceName,
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mPresentationServer);
nsresult rv;
nsCOMPtr<nsIPresentationDevice> device;
if (NS_WARN_IF(NS_FAILED(rv =
mPresentationServer->CreateTCPDevice(aHost, /* ID */
aServiceName,
aServiceType,
aHost,
aPort,
getter_AddRefs(device))))) {
return rv;
}
RefPtr<Device> device = new Device(aHost, /* ID */
aServiceName,
aServiceType,
aHost,
aPort,
DeviceState::eActive,
this);
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
unused << listener->AddDevice(device);
}
mDevices.AppendElement(Device(aHost, DeviceState::eActive));
mDevices.AppendElement(device);
return NS_OK;
}
@ -307,26 +366,15 @@ MulticastDNSDeviceProvider::UpdateDevice(const uint32_t aIndex,
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsCOMPtr<nsIPresentationDevice> device;
if (NS_WARN_IF(NS_FAILED(rv =
mPresentationServer->UpdateTCPDevice(aHost, /* ID */
aServiceName,
aServiceType,
aHost,
aPort,
getter_AddRefs(device))))) {
return rv;
}
RefPtr<Device> device = mDevices[aIndex];
device->Update(aServiceName, aServiceType, aHost, aPort);
device->ChangeState(DeviceState::eActive);
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
unused << listener->UpdateDevice(device);
}
mDevices[aIndex].state = DeviceState::eActive;
return NS_OK;
}
@ -340,39 +388,56 @@ MulticastDNSDeviceProvider::RemoveDevice(const uint32_t aIndex)
return NS_ERROR_INVALID_ARG;
}
nsCString deviceId = mDevices[aIndex].id;
LOG_I("RemoveDevice: %s", deviceId.get());
RefPtr<Device> device = mDevices[aIndex];
nsCOMPtr<nsIPresentationDevice> device;
if (NS_FAILED(mPresentationServer->GetTCPDevice(deviceId,
getter_AddRefs(device)))) {
LOG_I("ignore non-existing device: %s", deviceId.get());
return NS_OK;
}
nsresult rv;
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->RemoveTCPDevice(deviceId)))) {
return rv;
}
LOG_I("RemoveDevice: %s", device->Id().get());
mDevices.RemoveElementAt(aIndex);
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
unused << listener->RemoveDevice(device);
}
mDevices.RemoveElementAt(aIndex);
return NS_OK;
}
bool
MulticastDNSDeviceProvider::FindDevice(const nsACString& aId,
uint32_t& aIndex)
MulticastDNSDeviceProvider::FindDeviceById(const nsACString& aId,
uint32_t& aIndex)
{
MOZ_ASSERT(NS_IsMainThread());
size_t index = mDevices.IndexOf(Device(aId, DeviceState::eUnknown),
0,
DeviceIdComparator());
RefPtr<Device> device = new Device(aId,
/* aName = */ EmptyCString(),
/* aType = */ EmptyCString(),
/* aHost = */ EmptyCString(),
/* aPort = */ 0,
/* aState = */ DeviceState::eUnknown,
/* aProvider = */ nullptr);
size_t index = mDevices.IndexOf(device, 0, DeviceIdComparator());
if (index == mDevices.NoIndex) {
return false;
}
aIndex = index;
return true;
}
bool
MulticastDNSDeviceProvider::FindDeviceByHost(const nsACString& aHost,
uint32_t& aIndex)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<Device> device = new Device(/* aId = */ EmptyCString(),
/* aName = */ EmptyCString(),
/* aType = */ EmptyCString(),
aHost,
/* aPort = */ 0,
/* aState = */ DeviceState::eUnknown,
/* aProvider = */ nullptr);
size_t index = mDevices.IndexOf(device, 0, DeviceHostComparator());
if (index == mDevices.NoIndex) {
return false;
@ -388,7 +453,7 @@ MulticastDNSDeviceProvider::MarkAllDevicesUnknown()
MOZ_ASSERT(NS_IsMainThread());
for (auto& device : mDevices) {
device.state = DeviceState::eUnknown;
device->ChangeState(DeviceState::eUnknown);
}
}
@ -400,7 +465,7 @@ MulticastDNSDeviceProvider::ClearUnknownDevices()
size_t i = mDevices.Length();
while (i > 0) {
--i;
if (mDevices[i].state == DeviceState::eUnknown) {
if (mDevices[i]->State() == DeviceState::eUnknown) {
NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
}
}
@ -589,7 +654,7 @@ MulticastDNSDeviceProvider::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
}
uint32_t index;
if (!FindDevice(host, index)) {
if (!FindDeviceById(host, index)) {
// given device was not found
return NS_OK;
}
@ -721,7 +786,7 @@ MulticastDNSDeviceProvider::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
}
uint32_t index;
if (FindDevice(host, index)) {
if (FindDeviceById(host, index)) {
return UpdateDevice(index,
serviceName,
serviceType,
@ -758,12 +823,52 @@ MulticastDNSDeviceProvider::OnClose(nsresult aReason)
nsresult rv;
if (mDiscoveryEnabled && NS_WARN_IF(NS_FAILED(rv = ForceDiscovery()))) {
if (mDiscoverable && NS_WARN_IF(NS_FAILED(rv = RegisterService()))) {
return rv;
}
if (mDiscoverable && NS_WARN_IF(NS_FAILED(rv = RegisterService()))) {
return rv;
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel* aControlChannel)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoCString host;
unused << aDeviceInfo->GetHost(host);
LOG_I("OnSessionRequest: %s", host.get());
RefPtr<Device> device;
uint32_t index;
if (FindDeviceByHost(host, index)) {
device = mDevices[index];
} else {
// create a one-time device object for non-discoverable controller
// this device will not be listed in available device list and cannot
// be used for requesting session.
nsAutoCString id;
unused << aDeviceInfo->GetId(id);
uint16_t port;
unused << aDeviceInfo->GetPort(&port);
device = new Device(id,
/* aName = */ id,
/* aType = */ EmptyCString(),
host,
port,
DeviceState::eActive,
/* aProvider = */ nullptr);
}
nsCOMPtr<nsIPresentationDeviceListener> listener;
if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
unused << listener->OnSessionRequest(device, aUrl, aPresentationId,
aControlChannel);
}
return NS_OK;
@ -858,6 +963,47 @@ MulticastDNSDeviceProvider::OnServiceNameChanged(const nsACString& aServiceName)
return NS_OK;
}
// MulticastDNSDeviceProvider::Device
NS_IMPL_ISUPPORTS(MulticastDNSDeviceProvider::Device,
nsIPresentationDevice)
// nsIPresentationDevice
NS_IMETHODIMP
MulticastDNSDeviceProvider::Device::GetId(nsACString& aId)
{
aId = mId;
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::Device::GetName(nsACString& aName)
{
aName = mName;
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::Device::GetType(nsACString& aType)
{
aType = mType;
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::Device::EstablishControlChannel(const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel** aRetVal)
{
if (!mProvider) {
return NS_ERROR_FAILURE;
}
return mProvider->RequestSession(this, aUrl, aPresentationId, aRetVal);
}
} // namespace presentation
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -11,6 +11,7 @@
#include "nsICancelable.h"
#include "nsIDNSServiceDiscovery.h"
#include "nsIObserver.h"
#include "nsIPresentationDevice.h"
#include "nsIPresentationDeviceProvider.h"
#include "nsITCPPresentationServer.h"
#include "nsITimer.h"
@ -52,19 +53,86 @@ private:
eActive
};
struct Device final {
explicit Device(const nsACString& aId, DeviceState aState)
: id(aId), state(aState)
class Device final : public nsIPresentationDevice
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPRESENTATIONDEVICE
explicit Device(const nsACString& aId,
const nsACString& aName,
const nsACString& aType,
const nsACString& aHost,
const uint16_t aPort,
DeviceState aState,
MulticastDNSDeviceProvider* aProvider)
: mId(aId)
, mName(aName)
, mType(aType)
, mHost(aHost)
, mPort(aPort)
, mState(aState)
, mProvider(aProvider)
{
}
nsCString id;
DeviceState state;
const nsCString& Id() const
{
return mId;
}
const nsCString& Host() const
{
return mHost;
}
const uint16_t Port() const
{
return mPort;
}
const DeviceState State() const
{
return mState;
}
void ChangeState(DeviceState aState)
{
mState = aState;
}
void Update(const nsACString& aName,
const nsACString& aType,
const nsACString& aHost,
const uint16_t aPort)
{
mName = aName;
mType = aType;
mHost = aHost;
mPort = aPort;
}
private:
virtual ~Device() = default;
nsCString mId;
nsCString mName;
nsCString mType;
nsCString mHost;
uint16_t mPort;
DeviceState mState;
MulticastDNSDeviceProvider* mProvider;
};
struct DeviceIdComparator {
bool Equals(const Device& aA, const Device& aB) const {
return aA.id == aB.id;
bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
return aA->Id() == aB->Id();
}
};
struct DeviceHostComparator {
bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
return aA->Host() == aB->Host();
}
};
@ -72,6 +140,10 @@ private:
nsresult RegisterService();
nsresult UnregisterService(nsresult aReason);
nsresult StopDiscovery(nsresult aReason);
nsresult RequestSession(Device* aDevice,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel** aRetVal);
// device manipulation
nsresult AddDevice(const nsACString& aServiceName,
@ -84,9 +156,12 @@ private:
const nsACString& aHost,
const uint16_t aPort);
nsresult RemoveDevice(const uint32_t aIndex);
bool FindDevice(const nsACString& aId,
bool FindDeviceById(const nsACString& aId,
uint32_t& aIndex);
bool FindDeviceByHost(const nsACString& aHost,
uint32_t& aIndex);
void MarkAllDevicesUnknown();
void ClearUnknownDevices();
void ClearDevices();
@ -106,7 +181,7 @@ private:
nsCOMPtr<nsICancelable> mDiscoveryRequest;
nsCOMPtr<nsICancelable> mRegisterRequest;
nsTArray<Device> mDevices;
nsTArray<RefPtr<Device>> mDevices;
bool mDiscoveryEnabled = false;
bool mIsDiscovering = false;

Просмотреть файл

@ -14,19 +14,16 @@ function log(aMsg) {
dump("-*- TCPPresentationServer.js: " + aMsg + "\n");
}
function TCPDeviceInfo(aHost, aPort, aId, aName, aType) {
function TCPDeviceInfo(aHost, aPort, aId) {
this.host = aHost;
this.port = aPort;
this.id = aId;
this.name = aName;
this.type = aType;
}
function TCPPresentationServer() {
this._id = null;
this._port = 0;
this._serverSocket = null;
this._devices = new Map(); // id -> device
}
TCPPresentationServer.prototype = {
@ -113,57 +110,12 @@ TCPPresentationServer.prototype = {
return this._id !== null && this._serverSocket !== null;
},
createTCPDevice: function(aId, aName, aType, aHost, aPort) {
DEBUG && log("TCPPresentationServer - createTCPDevice with id: " + aId);
if (this._devices.has(aId)) {
throw Cr.NS_ERROR_INVALID_ARG;
}
this._devices.set(aId, new TCPDevice(this, {id: aId,
name: aName,
type: aType,
host: aHost,
port: aPort}));
return this._devices.get(aId);
},
updateTCPDevice: function(aId, aName, aType, aHost, aPort) {
DEBUG && log("TCPPresentationServer - updateTCPDevice with id: " + aId);
if (!this._devices.has(aId)) {
throw Cr.NS_ERROR_INVALID_ARG;
}
let device = this._devices.get(aId);
device.name = aName;
device.type = aType;
device.host = aHost;
device.port = aPort;
return device;
},
getTCPDevice: function(aId) {
DEBUG && log("TCPPresentationServer - getTCPDevice with id: " + aId);
if (!this._devices.has(aId)) {
throw Cr.NS_ERROR_INVALID_ARG;
}
return this._devices.get(aId);
},
removeTCPDevice: function(aId) {
DEBUG && log("TCPPresentationServer - removeTCPDevice with id: " + aId);
if (!this._devices.has(aId)) {
throw Cr.NS_ERROR_INVALID_ARG;
}
this._devices.delete(aId);
},
requestSession: function(aDevice, aUrl, aPresentationId) {
requestSession: function(aDeviceInfo, aUrl, aPresentationId) {
if (!this._isInit()) {
DEBUG && log("TCPPresentationServer - has not initialized; requestSession fails");
return null;
}
DEBUG && log("TCPPresentationServer - requestSession to " + aDevice.name
DEBUG && log("TCPPresentationServer - requestSession to " + aDeviceInfo.id
+ ": " + aUrl + ", " + aPresentationId);
let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
@ -173,8 +125,8 @@ TCPPresentationServer.prototype = {
try {
socketTransport = sts.createTransport(null,
0,
aDevice.host,
aDevice.port,
aDeviceInfo.host,
aDeviceInfo.port,
null);
} catch (e) {
DEBUG && log("TCPPresentationServer - createTransport throws: " + e);
@ -183,22 +135,22 @@ TCPPresentationServer.prototype = {
}
return new TCPControlChannel(this,
socketTransport,
aDevice,
aDeviceInfo,
aPresentationId,
"sender",
aUrl);
},
responseSession: function(aDevice, aSocketTransport) {
responseSession: function(aDeviceInfo, aSocketTransport) {
if (!this._isInit()) {
DEBUG && log("TCPPresentationServer - has not initialized; responseSession fails");
return null;
}
DEBUG && log("TCPPresentationServer - responseSession to "
+ JSON.stringify(aDevice));
+ JSON.stringify(aDeviceInfo));
return new TCPControlChannel(this,
aSocketTransport,
aDevice,
aDeviceInfo,
null, // presentation ID
"receiver",
null // url
@ -206,18 +158,13 @@ TCPPresentationServer.prototype = {
},
// Triggered by TCPControlChannel
onSessionRequest: function(aId, aUrl, aPresentationId, aControlChannel) {
let device = this._devices.get(aId);
if (!device) {
//XXX Bug 1136565 - should have a way to recovery
DEBUG && log("TCPPresentationServer - onSessionRequest not found device for id: "
+ aId );
return;
}
device.listener.onSessionRequest(device,
aUrl,
aPresentationId,
aControlChannel);
onSessionRequest: function(aDeviceInfo, aUrl, aPresentationId, aControlChannel) {
DEBUG && log("TCPPresentationServer - onSessionRequest: "
+ aDeviceInfo.host + ":" + aDeviceInfo.port);
this.listener.onSessionRequest(aDeviceInfo,
aUrl,
aPresentationId,
aControlChannel);
this.releaseControlChannel(aControlChannel);
},
@ -225,8 +172,8 @@ TCPPresentationServer.prototype = {
onSocketAccepted: function(aServerSocket, aClientSocket) {
DEBUG && log("TCPPresentationServer - onSocketAccepted: "
+ aClientSocket.host + ":" + aClientSocket.port);
let device = new TCPDeviceInfo(aClientSocket.host, aClientSocket.port);
this.holdControlChannel(this.responseSession(device, aClientSocket));
let deviceInfo = new TCPDeviceInfo(aClientSocket.host, aClientSocket.port);
this.holdControlChannel(this.responseSession(deviceInfo, aClientSocket));
},
holdControlChannel: function(aControlChannel) {
@ -264,7 +211,6 @@ TCPPresentationServer.prototype = {
}
this._id = null;
this._port = 0;
this._devices && this._devices.clear();
},
classID: Components.ID("{f4079b8b-ede5-4b90-a112-5b415a931deb}"),
@ -342,13 +288,13 @@ function discriptionAsJson(aDescription) {
function TCPControlChannel(presentationServer,
transport,
device,
deviceInfo,
presentationId,
direction,
url) {
DEBUG && log("create TCPControlChannel: " + presentationId + " with role: "
+ direction);
this._device = device;
this._deviceInfo = deviceInfo;
this._presentationId = presentationId;
this._direction = direction;
this._transport = transport;
@ -542,13 +488,13 @@ TCPControlChannel.prototype = {
// Handle command from remote side
_handleMessage: function(aMsg) {
DEBUG && log("TCPControlChannel - handleMessage from "
+ JSON.stringify(this._device) + ": " + JSON.stringify(aMsg));
+ JSON.stringify(this._deviceInfo) + ": " + JSON.stringify(aMsg));
switch (aMsg.type) {
case "requestSession:Init": {
this._device.id = aMsg.id;
this._deviceInfo.id = aMsg.id;
this._url = aMsg.url;
this._presentationId = aMsg.presentationId;
this._presentationServer.onSessionRequest(aMsg.id,
this._presentationServer.onSessionRequest(this._deviceInfo,
aMsg.url,
aMsg.presentationId,
this);
@ -688,43 +634,4 @@ TCPControlChannel.prototype = {
Ci.nsIStreamListener]),
};
function TCPDevice(aPresentationServer, aInfo) {
DEBUG && log("create TCPDevice");
this.id = aInfo.id;
this.name = aInfo.name;
this.type = aInfo.type
this.host = aInfo.host;
this.port = aInfo.port;
this._presentationServer = aPresentationServer;
this._listener = null;
}
TCPDevice.prototype = {
establishControlChannel: function(aUrl, aPresentationId) {
DEBUG && log("TCPDevice - establishControlChannel: " + aUrl + ", "
+ aPresentationId);
return this._presentationServer
.requestSession(this._getDeviceInfo(), aUrl, aPresentationId);
},
get listener() {
return this._listener;
},
set listener(aListener) {
DEBUG && log("TCPDevice - set listener");
this._listener = aListener;
},
_getDeviceInfo: function() {
return new TCPDeviceInfo(this.host,
this.port,
this.id,
this.name,
this.type);
},
classID: Components.ID("{d6492549-a4f2-4a0c-9a93-00f0e9918b0a}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TCPPresentationServer]);

Просмотреть файл

@ -167,15 +167,6 @@ const mockedDevice = {
sendAsyncMessage('control-channel-established');
return mockedControlChannel;
},
set listener(listener) {
this._listener = listener;
},
get listener() {
return this._listener;
},
simulateSessionRequest: function(url, presentationId, controlChannel) {
this._listener.onSessionRequest(this, url, presentationId, controlChannel);
},
};
const mockedDevicePrompt = {
@ -358,7 +349,10 @@ addMessageListener('trigger-device-prompt-cancel', function() {
});
addMessageListener('trigger-incoming-session-request', function(url) {
mockedDevice.simulateSessionRequest(url, sessionId, mockedControlChannel);
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
.onSessionRequest(mockedDevice, url, sessionId, mockedControlChannel);
});
addMessageListener('trigger-incoming-offer', function() {

Просмотреть файл

@ -14,6 +14,7 @@ const INFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info
const PROVIDER_CONTRACT_ID = "@mozilla.org/presentation-device/multicastdns-provider;1";
const SD_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
const UUID_CONTRACT_ID = "@mozilla.org/uuid-generator;1";
const SERVER_CONTRACT_ID = "@mozilla.org/presentation-device/tcp-presentation-server;1";
const PREF_DISCOVERY = "dom.presentation.discovery.enabled";
const PREF_DISCOVERABLE = "dom.presentation.discoverable";
@ -169,6 +170,7 @@ TestPresentationDeviceListener.prototype = {
addDevice: function(device) { this.devices[device.id] = device; },
removeDevice: function(device) { delete this.devices[device.id]; },
updateDevice: function(device) { this.devices[device.id] = device; },
onSessionRequest: function(device, url, presentationId, controlChannel) {},
count: function() {
var size = 0, key;
@ -368,6 +370,231 @@ function addDevice() {
run_next_test();
}
function handleSessionRequest() {
Services.prefs.setBoolPref(PREF_DISCOVERY, true);
const testUrl = "http://example.com";
const testPresentationId = "test-presentation-id";
let mockDevice = createDevice("device.local",
12345,
"service.name",
"_mozilla_papi._tcp");
let mockSDObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
startDiscovery: function(serviceType, listener) {
listener.onDiscoveryStarted(serviceType);
listener.onServiceFound(createDevice("",
0,
mockDevice.serviceName,
mockDevice.serviceType));
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
cancel: function() {}
};
},
registerService: function(serviceInfo, listener) {},
resolveService: function(serviceInfo, listener) {
listener.onServiceResolved(createDevice(mockDevice.host,
mockDevice.port,
mockDevice.serviceName,
mockDevice.serviceType));
}
};
let mockServerObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]),
requestSession: function(deviceInfo, url, presentationId) {
this.request = {
deviceInfo: deviceInfo,
url: url,
presentationId: presentationId,
};
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
};
},
};
let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
Ci.nsISupportsWeakReference]),
addDevice: function(device) {
this.device = device;
},
};
provider.listener = listener;
let controlChannel = listener.device.establishControlChannel(testUrl, testPresentationId);
Assert.equal(mockServerObj.request.deviceInfo.id, mockDevice.host);
Assert.equal(mockServerObj.request.deviceInfo.host, mockDevice.host);
Assert.equal(mockServerObj.request.deviceInfo.port, mockDevice.port);
Assert.equal(mockServerObj.request.url, testUrl);
Assert.equal(mockServerObj.request.presentationId, testPresentationId);
provider.listener = null;
run_next_test();
}
function handleOnSessionRequest() {
Services.prefs.setBoolPref(PREF_DISCOVERY, true);
let mockDevice = createDevice("device.local",
12345,
"service.name",
"_mozilla_papi._tcp");
let mockSDObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
startDiscovery: function(serviceType, listener) {
listener.onDiscoveryStarted(serviceType);
listener.onServiceFound(createDevice("",
0,
mockDevice.serviceName,
mockDevice.serviceType));
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
cancel: function() {}
};
},
registerService: function(serviceInfo, listener) {},
resolveService: function(serviceInfo, listener) {
listener.onServiceResolved(createDevice(mockDevice.host,
mockDevice.port,
mockDevice.serviceName,
mockDevice.serviceType));
}
};
let mockServerObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]),
init: function() {},
sessionRequest: function() {},
close: function() {},
id: '',
port: 0,
listener: null,
};
let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
Ci.nsISupportsWeakReference]),
addDevice: function(device) {},
removeDevice: function(device) {},
updateDevice: function(device) {},
onSessionRequest: function(device, url, presentationId, controlChannel) {
Assert.ok(true, "recieve onSessionRequest event");
this.request = {
deviceId: device.id,
url: url,
presentationId: presentationId,
};
}
};
provider.listener = listener;
const deviceInfo = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
id: mockDevice.host,
host: mockDevice.host,
port: 54321,
};
const testUrl = "http://example.com";
const testPresentationId = "test-presentation-id";
const testControlChannel = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
};
provider.QueryInterface(Ci.nsITCPPresentationServerListener)
.onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
Assert.equal(listener.request.deviceId, deviceInfo.id);
Assert.equal(listener.request.url, testUrl);
Assert.equal(listener.request.presentationId, testPresentationId);
provider.listener = null;
run_next_test();
}
function handleOnSessionRequestFromUnknownDevice() {
let mockSDObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
startDiscovery: function(serviceType, listener) {},
registerService: function(serviceInfo, listener) {},
resolveService: function(serviceInfo, listener) {}
};
let mockServerObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]),
init: function() {},
sessionRequest: function() {},
close: function() {},
id: '',
port: 0,
listener: null,
};
let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
Ci.nsISupportsWeakReference]),
addDevice: function(device) {
Assert.ok(false, "shouldn't create any new device");
},
removeDevice: function(device) {
Assert.ok(false, "shouldn't remote any device");
},
updateDevice: function(device) {
Assert.ok(false, "shouldn't update any device");
},
onSessionRequest: function(device, url, presentationId, controlChannel) {
Assert.ok(true, "recieve onSessionRequest event");
this.request = {
deviceId: device.id,
url: url,
presentationId: presentationId,
};
}
};
provider.listener = listener;
const deviceInfo = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
id: "unknown-device.local",
host: "unknown-device.local",
port: 12345,
};
const testUrl = "http://example.com";
const testPresentationId = "test-presentation-id";
const testControlChannel = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
};
provider.QueryInterface(Ci.nsITCPPresentationServerListener)
.onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
Assert.equal(listener.request.deviceId, deviceInfo.id);
Assert.equal(listener.request.url, testUrl);
Assert.equal(listener.request.presentationId, testPresentationId);
provider.listener = null;
run_next_test();
}
function noAddDevice() {
Services.prefs.setBoolPref(PREF_DISCOVERY, false);
@ -714,6 +941,9 @@ function run_test() {
add_test(noRegisterService);
add_test(registerServiceDynamically);
add_test(addDevice);
add_test(handleSessionRequest);
add_test(handleOnSessionRequest);
add_test(handleOnSessionRequestFromUnknownDevice);
add_test(noAddDevice);
add_test(addDeviceDynamically);
add_test(updateDevice);

Просмотреть файл

@ -45,16 +45,6 @@ var testDevice = {
establishControlChannel: function(url, presentationId) {
return null;
},
set listener(listener) {
this._listener = listener;
},
get listener() {
return this._listener;
},
simulateSessionRequest: function(url, presentationId, controlChannel) {
this._listener.onSessionRequest(this, url, presentationId, controlChannel);
},
};
function addProvider() {
@ -144,7 +134,8 @@ function sessionRequest() {
run_next_test();
}, 'presentation-session-request', false);
testDevice.simulateSessionRequest(testUrl, testPresentationId, testControlChannel);
manager.QueryInterface(Ci.nsIPresentationDeviceListener)
.onSessionRequest(testDevice, testUrl, testPresentationId, testControlChannel);
}
function removeDevice() {

Просмотреть файл

@ -65,22 +65,14 @@ function loopOfferAnser() {
function testPresentationServer() {
let yayFuncs = makeJointSuccess(['controllerControlChannelClose',
'presenterControlChannelClose']);
let controllerDevice, controllerControlChannel;
let presenterDevice, presenterControlChannel;
let controllerControlChannel;
tps.listener = {
controllerDevice = tps.createTCPDevice('controllerID',
'controllerName',
'testType',
'127.0.0.1',
CONTROLLER_CONTROL_CHANNEL_PORT)
.QueryInterface(Ci.nsIPresentationDevice);
controllerDevice.listener = {
onSessionRequest: function(device, url, presentationId, controlChannel) {
onSessionRequest: function(deviceInfo, url, presentationId, controlChannel) {
controllerControlChannel = controlChannel;
Assert.strictEqual(device, controllerDevice, 'expected device object');
Assert.equal(deviceInfo.id, tps.id, 'expected device id');
Assert.equal(deviceInfo.host, '127.0.0.1', 'expected device host');
Assert.equal(url, 'http://example.com', 'expected url');
Assert.equal(presentationId, 'testPresentationId', 'expected presentation id');
@ -116,28 +108,23 @@ function testPresentationServer() {
this.status = 'closed';
yayFuncs.controllerControlChannelClose();
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceEventListener]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
};
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServerListener]),
};
presenterDevice = tps.createTCPDevice('presentatorID',
'presentatorName',
'testType',
'127.0.0.1',
PRESENTER_CONTROL_CHANNEL_PORT)
.QueryInterface(Ci.nsIPresentationDevice);
let presenterDeviceInfo = {
id: 'presentatorID',
host: '127.0.0.1',
port: PRESENTER_CONTROL_CHANNEL_PORT,
QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
};
presenterDevice.listener = {
onSessionRequest: function(device, url, presentationId, controlChannel) {
Assert.ok(false, 'presenterDevice.listener.onSessionRequest should not be called');
},
}
presenterControlChannel =
presenterDevice.establishControlChannel('http://example.com', 'testPresentationId');
let presenterControlChannel = tps.requestSession(presenterDeviceInfo,
'http://example.com',
'testPresentationId');
presenterControlChannel.listener = {
status: 'created',
@ -211,23 +198,17 @@ function shutdown()
tps.close();
}
function setPref() {
Services.prefs.setBoolPref("dom.presentation.tcp_server.debug", true);
run_next_test();
}
function clearPref() {
Services.prefs.clearUserPref("dom.presentation.tcp_server.debug");
run_next_test();
}
add_test(setPref);
add_test(loopOfferAnser);
add_test(setOffline);
add_test(oneMoreLoop);
add_test(shutdown);
add_test(clearPref);
function run_test() {
Services.prefs.setBoolPref("dom.presentation.tcp_server.debug", true);
do_register_cleanup(() => {
Services.prefs.clearUserPref("dom.presentation.tcp_server.debug");
});
run_next_test();
}

Просмотреть файл

@ -101,7 +101,9 @@ this.RequestSyncService = {
aStore.openCursor().onsuccess = event => {
let cursor = event.target.result;
if (cursor) {
this.addRegistration(cursor.value, cursor.continue);
this.addRegistration(cursor.value, function() {
cursor.continue();
});
}
}
}.bind(this),

Просмотреть файл

@ -13,16 +13,27 @@ function shouldThrow(func, expected, msg) {
}
}
function recursiveArrayCompare(actual, expected) {
is(Array.isArray(actual), Array.isArray(expected), "Both should either be arrays, or not");
if (Array.isArray(actual) && Array.isArray(expected)) {
var diff = actual.length !== expected.length;
for (var i = 0, n = actual.length; !diff && i < n; ++i) {
diff = recursiveArrayCompare(actual[i], expected[i]);
}
return diff;
} else {
return actual !== expected;
}
}
function arrayEquals(actual, expected, msg) {
if (actual === expected) {
return;
}
var diff = actual.length !== expected.length;
for (var i = 0, n = actual.length; !diff && i < n; ++i) {
diff = actual[i] !== expected[i];
}
var diff = recursiveArrayCompare(actual, expected);
ok(!diff, msg);
if (diff) {
@ -169,8 +180,60 @@ function TestFilledHeaders() {
}, TypeError, "Fill with non-tuple sequence should throw TypeError.");
}
function iterate(iter) {
var result = [];
for (var val = iter.next(); !val.done;) {
result.push(val.value);
val = iter.next();
}
return result;
}
function iterateForOf(iter) {
var result = [];
for (var value of iter) {
result.push(value);
}
return result;
}
function byteInflate(str) {
var encoder = new TextEncoder("utf-8");
var encoded = encoder.encode(str);
var result = "";
for (var i = 0; i < encoded.length; ++i) {
result += String.fromCharCode(encoded[i]);
}
return result
}
function TestHeadersIterator() {
var ehsanInflated = byteInflate("احسان");
var headers = new Headers();
headers.set("foo0", "bar0");
headers.append("foo", "bar");
headers.append("foo", ehsanInflated);
headers.append("Foo2", "bar2");
headers.set("Foo2", "baz2");
headers.set("foo3", "bar3");
headers.delete("foo0");
headers.delete("foo3");
var key_iter = headers.keys();
var value_iter = headers.values();
var entries_iter = headers.entries();
arrayEquals(iterate(key_iter), ["foo", "foo", "foo2"], "Correct key iterator");
arrayEquals(iterate(value_iter), ["bar", ehsanInflated, "baz2"], "Correct value iterator");
arrayEquals(iterate(entries_iter), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
arrayEquals(iterateForOf(headers), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
arrayEquals(iterateForOf(new Headers(headers)), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
}
function runTest() {
TestEmptyHeaders();
TestFilledHeaders();
TestHeadersIterator();
return Promise.resolve();
}

Просмотреть файл

@ -20,5 +20,5 @@ interface FormData {
boolean has(USVString name);
void set(USVString name, Blob value, optional USVString filename);
void set(USVString name, USVString value);
// iterable<USVString, FormDataEntryValue>; - Bug 1127703
iterable<USVString, FormDataEntryValue>;
};

Просмотреть файл

@ -27,6 +27,7 @@ interface Headers {
[Throws] sequence<ByteString> getAll(ByteString name);
[Throws] boolean has(ByteString name);
[Throws] void set(ByteString name, ByteString value);
iterable<ByteString, ByteString>;
// Used to test different guard states from mochitest.
// Note: Must be set prior to populating headers or will throw.

Просмотреть файл

@ -9,6 +9,12 @@
*/
[ChromeOnly, Exposed=(Window,System,Worker)]
interface HeapSnapshot {
/**
* A time stamp of when the heap snapshot was taken, if available. Units are
* microseconds since midnight (00:00:00) 1 January 1970 UTC.
*/
readonly attribute unsigned long long? creationTime;
/**
* Take a census of the heap snapshot.
*

Просмотреть файл

@ -1037,6 +1037,12 @@ private:
request->SetContentPolicyType(mContentPolicyType);
request->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, result);
if (NS_WARN_IF(result.Failed())) {
result.SuppressException();
return false;
}
// TODO: remove conditional on http here once app protocol support is
// removed from service worker interception
MOZ_ASSERT_IF(mIsHttpChannel && internalReq->IsNavigationRequest(),

Просмотреть файл

@ -61,6 +61,7 @@ CopyableCanvasLayer::Initialize(const Data& aData)
gfx::IntSize size(aData.mSize.width, aData.mSize.height);
mGLFrontbuffer = SharedSurface_Basic::Wrap(aData.mGLContext, size, aData.mHasAlpha,
aData.mFrontbufferGLTex);
mBufferProvider = aData.mBufferProvider;
}
} else if (aData.mBufferProvider) {
mBufferProvider = aData.mBufferProvider;
@ -85,7 +86,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
{
if (mAsyncRenderer) {
mSurface = mAsyncRenderer->GetSurface();
} else if (mBufferProvider) {
} else if (!mGLFrontbuffer && mBufferProvider) {
mSurface = mBufferProvider->GetSnapshot();
}
@ -100,7 +101,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
return;
}
if (mBufferProvider || mAsyncRenderer) {
if ((!mGLFrontbuffer && mBufferProvider) || mAsyncRenderer) {
return;
}

Просмотреть файл

@ -366,6 +366,38 @@ private:
LayerScopeManager gLayerScopeManager;
/*
* The static helper functions that set data into the packet
* 1. DumpRect
* 2. DumpFilter
*/
template<typename T>
static void DumpRect(T* aPacketRect, const Rect& aRect)
{
aPacketRect->set_x(aRect.x);
aPacketRect->set_y(aRect.y);
aPacketRect->set_w(aRect.width);
aPacketRect->set_h(aRect.height);
}
static void DumpFilter(TexturePacket* aTexturePacket, const Filter& aFilter)
{
switch (aFilter) {
case Filter::GOOD:
aTexturePacket->set_mfilter(TexturePacket::GOOD);
break;
case Filter::LINEAR:
aTexturePacket->set_mfilter(TexturePacket::LINEAR);
break;
case Filter::POINT:
aTexturePacket->set_mfilter(TexturePacket::POINT);
break;
default:
MOZ_ASSERT(false, "Can't dump unexpected mFilter to texture packet!");
break;
}
}
/*
* DebugGLData is the base class of
* 1. DebugGLFrameStatusData (Frame start/end packet)
@ -436,26 +468,28 @@ public:
GLenum target,
GLuint name,
const LayerRenderState &aState,
bool aIsMask)
bool aIsMask,
UniquePtr<Packet> aPacket)
: DebugGLData(Packet::TEXTURE),
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
mTarget(target),
mName(name),
mState(aState),
mIsMask(aIsMask)
mIsMask(aIsMask),
mPacket(Move(aPacket))
{
}
virtual bool Write() override {
return WriteToStream(mPacket);
return WriteToStream(*mPacket);
}
bool TryPack(bool packData) {
android::sp<android::GraphicBuffer> buffer = mState.mSurface;
MOZ_ASSERT(buffer.get());
mPacket.set_type(mDataType);
TexturePacket* tp = mPacket.mutable_texture();
mPacket->set_type(mDataType);
TexturePacket* tp = mPacket->mutable_texture();
tp->set_layerref(mLayerRef);
tp->set_name(mName);
tp->set_target(mTarget);
@ -517,7 +551,7 @@ private:
GLuint mName;
const LayerRenderState &mState;
bool mIsMask;
Packet mPacket;
UniquePtr<Packet> mPacket;
};
#endif
@ -528,14 +562,16 @@ public:
GLenum target,
GLuint name,
DataSourceSurface* img,
bool aIsMask)
bool aIsMask,
UniquePtr<Packet> aPacket)
: DebugGLData(Packet::TEXTURE),
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
mTarget(target),
mName(name),
mContextAddress(reinterpret_cast<intptr_t>(cx)),
mDatasize(0),
mIsMask(aIsMask)
mIsMask(aIsMask),
mPacket(Move(aPacket))
{
// pre-packing
// DataSourceSurface may have locked buffer,
@ -545,14 +581,14 @@ public:
}
virtual bool Write() override {
return WriteToStream(mPacket);
return WriteToStream(*mPacket);
}
private:
void pack(DataSourceSurface* aImage) {
mPacket.set_type(mDataType);
mPacket->set_type(mDataType);
TexturePacket* tp = mPacket.mutable_texture();
TexturePacket* tp = mPacket->mutable_texture();
tp->set_layerref(mLayerRef);
tp->set_name(mName);
tp->set_target(mTarget);
@ -600,7 +636,7 @@ protected:
bool mIsMask;
// Packet data
Packet mPacket;
UniquePtr<Packet> mPacket;
};
class DebugGLColorData final: public DebugGLData {
@ -721,18 +757,9 @@ public:
MOZ_ASSERT(mRects > 0 && mRects < 4);
for (size_t i = 0; i < mRects; i++) {
// Vertex
layerscope::DrawPacket::Rect* pRect = dp->add_layerrect();
pRect->set_x(mLayerRects[i].x);
pRect->set_y(mLayerRects[i].y);
pRect->set_w(mLayerRects[i].width);
pRect->set_h(mLayerRects[i].height);
DumpRect(dp->add_layerrect(), mLayerRects[i]);
// UV
pRect = dp->add_texturerect();
pRect->set_x(mTextureRects[i].x);
pRect->set_y(mTextureRects[i].y);
pRect->set_w(mTextureRects[i].width);
pRect->set_h(mTextureRects[i].height);
DumpRect(dp->add_texturerect(), mTextureRects[i]);
}
for (GLuint texId: mTexIDs) {
@ -907,7 +934,6 @@ public:
static void ClearSentTextureIds();
// Sender private functions
private:
static void SendColor(void* aLayerRef,
@ -918,7 +944,8 @@ private:
void* aLayerRef,
TextureSourceOGL* aSource,
bool aFlipY,
bool aIsMask);
bool aIsMask,
UniquePtr<Packet> aPacket);
#ifdef MOZ_WIDGET_GONK
static bool SendGraphicBuffer(GLContext* aGLContext,
void* aLayerRef,
@ -926,6 +953,10 @@ private:
const TexturedEffect* aEffect,
bool aIsMask);
#endif
static void SetAndSendTexture(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
const TexturedEffect* aEffect);
static void SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect);
@ -1044,7 +1075,8 @@ SenderHelper::SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
bool aFlipY,
bool aIsMask)
bool aIsMask,
UniquePtr<Packet> aPacket)
{
MOZ_ASSERT(aGLContext);
if (!aGLContext) {
@ -1070,7 +1102,7 @@ SenderHelper::SendTextureSource(GLContext* aGLContext,
shaderConfig, aFlipY);
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
texID, img, aIsMask));
texID, img, aIsMask, Move(aPacket)));
sSentTextureIds.push_back(texID);
gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
@ -1092,9 +1124,16 @@ SenderHelper::SendGraphicBuffer(GLContext* aGLContext,
return false;
}
// Expose packet creation here, so we could dump primary texture effect attributes.
auto packet = MakeUnique<layerscope::Packet>();
layerscope::TexturePacket* texturePacket = packet->mutable_texture();
texturePacket->set_mpremultiplied(aEffect->mPremultiplied);
DumpFilter(texturePacket, aEffect->mFilter);
DumpRect(texturePacket->mutable_mtexturecoords(), aEffect->mTextureCoords);
GLenum target = aSource->GetTextureTarget();
mozilla::UniquePtr<DebugGLGraphicBuffer> package =
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, texID, aEffect->mState, aIsMask);
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, texID, aEffect->mState, aIsMask, Move(packet));
// The texure content in this TexureHost is not altered,
// we don't need to send it again.
@ -1115,6 +1154,21 @@ SenderHelper::SendGraphicBuffer(GLContext* aGLContext,
}
#endif
void
SenderHelper::SetAndSendTexture(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
const TexturedEffect* aEffect)
{
// Expose packet creation here, so we could dump primary texture effect attributes.
auto packet = MakeUnique<layerscope::Packet>();
layerscope::TexturePacket* texturePacket = packet->mutable_texture();
texturePacket->set_mpremultiplied(aEffect->mPremultiplied);
DumpFilter(texturePacket, aEffect->mFilter);
DumpRect(texturePacket->mutable_mtexturecoords(), aEffect->mTextureCoords);
SendTextureSource(aGLContext, aLayerRef, aSource, false, false, Move(packet));
}
void
SenderHelper::SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
@ -1130,9 +1184,9 @@ SenderHelper::SendTexturedEffect(GLContext* aGLContext,
return;
}
#endif
// Fallback texture sending path.
// Render to texture and read pixels back.
SendTextureSource(aGLContext, aLayerRef, source, false, false);
SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
}
void
@ -1145,7 +1199,18 @@ SenderHelper::SendMaskEffect(GLContext* aGLContext,
return;
}
SendTextureSource(aGLContext, aLayerRef, source, false, true);
// Expose packet creation here, so we could dump secondary mask effect attributes.
auto packet = MakeUnique<layerscope::Packet>();
TexturePacket::EffectMask* mask = packet->mutable_texture()->mutable_mask();
mask->set_mis3d(aEffect->mIs3D);
mask->mutable_msize()->set_w(aEffect->mSize.width);
mask->mutable_msize()->set_h(aEffect->mSize.height);
auto element = reinterpret_cast<const Float *>(&(aEffect->mMaskTransform));
for (int i = 0; i < 16; i++) {
mask->mutable_mmasktransform()->add_m(*element++);
}
SendTextureSource(aGLContext, aLayerRef, source, false, true, Move(packet));
}
void
@ -1158,13 +1223,15 @@ SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
return;
const int Y = 0, Cb = 1, Cr = 2;
TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
TextureSourceOGL *sources[] = {
sourceYCbCr->GetSubSource(Y)->AsSourceOGL(),
sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(),
sourceYCbCr->GetSubSource(Cr)->AsSourceOGL()
};
SendTextureSource(aGLContext, aLayerRef, sourceY, false, false);
SendTextureSource(aGLContext, aLayerRef, sourceCb, false, false);
SendTextureSource(aGLContext, aLayerRef, sourceCr, false, false);
for (auto source: sources) {
SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
}
}
void

Просмотреть файл

@ -6,9 +6,7 @@
#include "TaskThrottler.h"
#include "mozilla/layers/APZThreadUtils.h" // for NewTimerCallback
#include "nsComponentManagerUtils.h" // for do_CreateInstance
#include "nsITimer.h"
#include "base/message_loop.h"
#define TASK_LOG(...)
// #define TASK_LOG(...) printf_stderr("TASK: " __VA_ARGS__)
@ -23,17 +21,14 @@ TaskThrottler::TaskThrottler(const TimeStamp& aTimeStamp, const TimeDuration& aM
, mStartTime(aTimeStamp)
, mMaxWait(aMaxWait)
, mMean(1)
, mTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
, mTimeoutTask(nullptr)
{
// The TaskThrottler must be created on the main thread (or some nsITimer-
// compatible thread) for the nsITimer to work properly. In particular,
// creating it on the Compositor thread doesn't work.
MOZ_ASSERT(NS_IsMainThread());
}
TaskThrottler::~TaskThrottler()
{
mTimer->Cancel();
// The timeout task holds a strong reference to the TaskThrottler, so if the
// TaskThrottler is being destroyed, there's no need to cancel the task.
}
void
@ -53,17 +48,9 @@ TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
// Make sure the queued task is sent after mMaxWait time elapses,
// even if we don't get a TaskComplete() until then.
TimeDuration timeout = mMaxWait - TimeSinceLastRequest(aTimeStamp, lock);
TimeStamp timeoutTime = mStartTime + mMaxWait;
RefPtr<TaskThrottler> refPtrThis = this;
mTimer->InitWithCallback(NewTimerCallback(
[refPtrThis, timeoutTime]()
{
MonitorAutoLock lock(refPtrThis->mMonitor);
if (refPtrThis->mQueuedTask) {
refPtrThis->RunQueuedTask(timeoutTime, lock);
}
}),
timeout.ToMilliseconds(), nsITimer::TYPE_ONE_SHOT);
mTimeoutTask = NewRunnableMethod(this, &TaskThrottler::OnTimeout);
MessageLoop::current()->PostDelayedTask(FROM_HERE, mTimeoutTask,
timeout.ToMilliseconds());
return;
}
// we've been waiting for more than the max-wait limit, so just fall through
@ -75,6 +62,18 @@ TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
mOutstanding = true;
}
void
TaskThrottler::OnTimeout()
{
MonitorAutoLock lock(mMonitor);
if (mQueuedTask) {
RunQueuedTask(TimeStamp::Now(), lock);
}
// The message loop will delete the posted timeout task. Make sure we don't
// keep a dangling pointer to it.
mTimeoutTask = nullptr;
}
void
TaskThrottler::TaskComplete(const TimeStamp& aTimeStamp)
{
@ -88,7 +87,7 @@ TaskThrottler::TaskComplete(const TimeStamp& aTimeStamp)
if (mQueuedTask) {
RunQueuedTask(aTimeStamp, lock);
mTimer->Cancel();
CancelTimeoutTask(lock);
} else {
mOutstanding = false;
}
@ -126,7 +125,16 @@ TaskThrottler::CancelPendingTask(const MonitorAutoLock& aProofOfLock)
TASK_LOG("%p cancelling task %p\n", this, mQueuedTask.get());
mQueuedTask->Cancel();
mQueuedTask = nullptr;
mTimer->Cancel();
CancelTimeoutTask(aProofOfLock);
}
}
void
TaskThrottler::CancelTimeoutTask(const MonitorAutoLock& aProofOfLock)
{
if (mTimeoutTask) {
mTimeoutTask->Cancel();
mTimeoutTask = nullptr; // the MessageLoop will destroy it
}
}

Просмотреть файл

@ -18,8 +18,6 @@
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_THREADSAFE_REFCOUNTING
#include "nsTArray.h" // for nsTArray
class nsITimer;
namespace tracked_objects {
class Location;
} // namespace tracked_objects
@ -102,7 +100,8 @@ private:
TimeStamp mStartTime;
TimeDuration mMaxWait;
RollingMean<TimeDuration, TimeDuration> mMean;
nsCOMPtr<nsITimer> mTimer;
CancelableTask* mTimeoutTask; // not owned because it's posted to a MessageLoop
// which deletes it
~TaskThrottler();
void RunQueuedTask(const TimeStamp& aTimeStamp,
@ -110,6 +109,8 @@ private:
void CancelPendingTask(const MonitorAutoLock& aProofOfLock);
TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp,
const MonitorAutoLock& aProofOfLock);
void OnTimeout();
void CancelTimeoutTask(const MonitorAutoLock& aProofOfLock);
};
} // namespace layers

Просмотреть файл

@ -29,3 +29,5 @@ skip-if = toolkit != 'gonk'
skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
[test_scroll_inactive_bug1190112.html]
skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
[test_scroll_subframe_scrollbar.html]
skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet

Просмотреть файл

@ -0,0 +1,119 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test scrolling subframe scrollbars</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style>
p {
width:200px;
height:200px;
border:solid 1px black;
}
</style>
</head>
<body>
<p id="subframe">
1 <br>
2 <br>
3 <br>
4 <br>
5 <br>
6 <br>
7 <br>
8 <br>
9 <br>
10 <br>
11 <br>
12 <br>
13 <br>
14 <br>
15 <br>
16 <br>
17 <br>
18 <br>
19 <br>
20 <br>
21 <br>
22 <br>
23 <br>
24 <br>
25 <br>
26 <br>
27 <br>
28 <br>
29 <br>
30 <br>
31 <br>
32 <br>
33 <br>
34 <br>
35 <br>
36 <br>
37 <br>
38 <br>
39 <br>
40 <br>
</p>
<script clss="testbody" type="text/javascript;version=1.7">
var DefaultEvent = {
deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 0, deltaY: 1,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 1,
};
var ScrollbarWidth = 0;
function test() {
var subframe = document.getElementById('subframe');
var oldClientWidth = subframe.clientWidth;
subframe.style.overflow = 'auto';
subframe.getBoundingClientRect();
waitForAllPaintsFlushed(function () {
ScrollbarWidth = oldClientWidth - subframe.clientWidth;
if (!ScrollbarWidth) {
// Probably we have overlay scrollbars - abort the test.
ok(true, "overlay scrollbars - skipping test");
SimpleTest.finish();
return;
}
ok(subframe.scrollHeight > subframe.clientHeight, "subframe should have scrollable content");
testScrolling(subframe);
});
}
function testScrolling(subframe) {
// Send a wheel event roughly to where we think the trackbar is. We pick a
// point at the bottom, in the middle of the trackbar, where the slider is
// unlikely to be (since it starts at the top).
var posX = subframe.clientWidth + (ScrollbarWidth / 2);
var posY = subframe.clientHeight - 20;
var oldScrollTop = subframe.scrollTop;
sendWheelAndPaint(subframe, posX, posY, DefaultEvent, function () {
ok(subframe.scrollTop > oldScrollTop, "subframe should have scrolled");
SimpleTest.finish();
});
}
window.onload = function() {
SpecialPowers.pushPrefEnv({
'set': [['general.smoothScroll', false],
['mousewheel.transaction.timeout', 0],
['mousewheel.transaction.ignoremovedelay', 0]]
}, function () {
SimpleTest.waitForFocus(test);
});
}
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

Просмотреть файл

@ -817,6 +817,10 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
mPaintSyncId = 0;
}
}
#else
// Non-Android platforms still care about this flag being cleared after
// the first call to TransformShadowTree().
mIsFirstPaint = false;
#endif
// Transform the current local clip by this APZC's async transform. If we're

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -20,6 +20,32 @@ message ColorPacket {
}
message TexturePacket {
enum Filter {
GOOD = 0;
LINEAR = 1;
POINT = 2;
}
message Rect {
optional float x = 1;
optional float y = 2;
optional float w = 3;
optional float h = 4;
}
message Size {
optional int32 w = 1;
optional int32 h = 2;
}
message Matrix {
optional bool is2D = 1;
optional bool isId = 2;
repeated float m = 3;
}
message EffectMask {
optional bool mIs3D = 1;
optional Size mSize = 2;
optional Matrix mMaskTransform = 3;
}
// Basic info
required uint64 layerref = 1;
optional uint32 width = 2;
@ -31,12 +57,14 @@ message TexturePacket {
optional uint64 glcontext = 8;
optional bytes data = 9;
// Texture effect attributes (10 to 19)
// TODO: reserved for primary textured effect attributes, see Bug 1205521
// TextureEffect attributes
optional Rect mTextureCoords = 10;
optional bool mPremultiplied = 11;
optional Filter mFilter = 12;
// Mask effect attributes (20 to 29)
// Mask attributes
optional bool isMask = 20;
// TODO: reserved for secondary mask effect attributes, see Bug 1205521
optional EffectMask mask = 21;
}
message LayersPacket {
@ -57,13 +85,15 @@ message LayersPacket {
HORIZONTAL = 2;
}
enum Filter {
FILTER_FAST = 0;
FILTER_FAST = 0; // deprecated
FILTER_GOOD = 1;
FILTER_BEST = 2;
FILTER_NEAREST = 3;
FILTER_BILINEAR = 4;
FILTER_GAUSSIAN = 5;
FILTER_SENTINEL = 6;
FILTER_BEST = 2; // deprecated
FILTER_NEAREST = 3; //deprecated
FILTER_BILINEAR = 4; //deprecated
FILTER_GAUSSIAN = 5; //deprecated
FILTER_SENTINEL = 6; //deprecated
FILTER_LINEAR = 7;
FILTER_POINT = 8;
}
message Size {
optional int32 w = 1;

Просмотреть файл

@ -103,7 +103,7 @@ load 783041-2.html
load 783041-3.html
load 783041-4.html
asserts-if(gtkWidget,0-1) load 798853.html # bug 868792
asserts-if(winWidget,0-1) skip-if(B2G) load 815489.html
asserts-if(winWidget,0-1) skip-if(B2G||Android) load 815489.html # bug 871763, 1216304
load 836225-1.html
load 839745-1.html
load 856784-1.html

Просмотреть файл

@ -0,0 +1,4 @@
if (!('oomTest' in this))
quit();
oomTest(() => parseModule(10));

Просмотреть файл

@ -0,0 +1,7 @@
if (!('oomTest' in this))
quit();
var lfcode = new Array();
oomTest((function(x) {
assertEq(...Object);
}));

Просмотреть файл

@ -0,0 +1,5 @@
if (!('oomTest' in this))
quit();
var lfcode = new Array();
oomTest(() => getBacktrace({}));

Просмотреть файл

@ -0,0 +1,15 @@
if (!('oomTest' in this) || helperThreadCount() === 0)
quit();
oomTest(() => {
offThreadCompileScript(
`
function f(x) {
if (x == 0)
return "foobar";
return 1 + f(x - 1);
}
f(5);
`);
runOffThreadScript();
});

Просмотреть файл

@ -8008,7 +8008,11 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
// will trickle to jit::Compile() and return Method_Skipped.
uint32_t warmUpCount = script->getWarmUpCount();
RecompileInfo recompileInfo;
if (!FinishCompilation(cx, script, constraints, &recompileInfo))
bool isValid;
if (!FinishCompilation(cx, script, constraints, &recompileInfo, &isValid))
return false;
if (!isValid)
return true;
// IonMonkey could have inferred better type information during

Просмотреть файл

@ -125,7 +125,8 @@ class CompactBufferWriter
}
void writeByteAt(uint32_t pos, uint32_t byte) {
MOZ_ASSERT(byte <= 0xFF);
buffer_[pos] = byte;
if (!oom())
buffer_[pos] = byte;
}
void writeUnsigned(uint32_t value) {
do {
@ -178,9 +179,11 @@ class CompactBufferWriter
return buffer_.length();
}
uint8_t* buffer() {
MOZ_ASSERT(!oom());
return &buffer_[0];
}
const uint8_t* buffer() const {
MOZ_ASSERT(!oom());
return &buffer_[0];
}
bool oom() const {

Просмотреть файл

@ -338,6 +338,9 @@ class RInstructionResults
bool init(JSContext* cx, uint32_t numResults);
bool isInitialized() const;
#ifdef DEBUG
size_t length() const;
#endif
JitFrameLayout* frame() const;

Просмотреть файл

@ -1750,6 +1750,14 @@ RInstructionResults::isInitialized() const
return initialized_;
}
#ifdef DEBUG
size_t
RInstructionResults::length() const
{
return results_->length();
}
#endif
JitFrameLayout*
RInstructionResults::frame() const
{
@ -2216,6 +2224,7 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback)
}
MOZ_ASSERT(results->isInitialized());
MOZ_ASSERT(results->length() == recover_.numInstructions() - 1);
instructionResults_ = results;
return true;
}

Просмотреть файл

@ -323,8 +323,7 @@ RValueAllocation::read(CompactBufferReader& reader)
}
void
RValueAllocation::writePayload(CompactBufferWriter& writer, PayloadType type,
Payload p)
RValueAllocation::writePayload(CompactBufferWriter& writer, PayloadType type, Payload p)
{
switch (type) {
case PAYLOAD_NONE:
@ -348,10 +347,12 @@ RValueAllocation::writePayload(CompactBufferWriter& writer, PayloadType type,
case PAYLOAD_PACKED_TAG: {
// This code assumes that the PACKED_TAG payload is following the
// writeByte of the mode.
MOZ_ASSERT(writer.length());
uint8_t* mode = writer.buffer() + (writer.length() - 1);
MOZ_ASSERT((*mode & PACKED_TAG_MASK) == 0 && (p.type & ~PACKED_TAG_MASK) == 0);
*mode = *mode | p.type;
if (!writer.oom()) {
MOZ_ASSERT(writer.length());
uint8_t* mode = writer.buffer() + (writer.length() - 1);
MOZ_ASSERT((*mode & PACKED_TAG_MASK) == 0 && (p.type & ~PACKED_TAG_MASK) == 0);
*mode = *mode | p.type;
}
break;
}
}

Просмотреть файл

@ -160,8 +160,8 @@ CodeGeneratorARM::bailoutFrom(Label* label, LSnapshot* snapshot)
if (masm.bailed())
return;
MOZ_ASSERT(label->used());
MOZ_ASSERT(!label->bound());
MOZ_ASSERT_IF(!masm.oom(), label->used());
MOZ_ASSERT_IF(!masm.oom(), !label->bound());
encode(snapshot);

Просмотреть файл

@ -171,8 +171,8 @@ CodeGeneratorMIPSShared::bailoutFrom(Label* label, LSnapshot* snapshot)
if (masm.bailed())
return;
MOZ_ASSERT(label->used());
MOZ_ASSERT(!label->bound());
MOZ_ASSERT_IF(!masm.oom(), label->used());
MOZ_ASSERT_IF(!masm.oom(), !label->bound());
encode(snapshot);

Просмотреть файл

@ -518,7 +518,7 @@ struct AssemblerBufferWithConstantPools : public AssemblerBuffer<SliceSize, Inst
size_t size() const {
// Return the current actual size of the buffer. This is only accurate
// if there are no pending pool entries to dump, check.
MOZ_ASSERT(pool_.numEntries() == 0);
MOZ_ASSERT_IF(!this->oom(), pool_.numEntries() == 0);
return sizeExcludingCurrentPool();
}
@ -771,7 +771,7 @@ struct AssemblerBufferWithConstantPools : public AssemblerBuffer<SliceSize, Inst
// state into the BufferSlice.
Pool** tmp = &perforatedSlice->pool;
*tmp = static_cast<Pool*>(this->lifoAlloc_.alloc(sizeof(Pool)));
if (tmp == nullptr) {
if (!*tmp) {
this->fail_oom();
return;
}

Просмотреть файл

@ -432,8 +432,10 @@ js::ReportErrorVA(JSContext* cx, unsigned flags, const char* format, va_list ap)
return true;
message = JS_vsmprintf(format, ap);
if (!message)
if (!message) {
ReportOutOfMemory(cx);
return false;
}
messagelen = strlen(message);
report.flags = flags;

Просмотреть файл

@ -3511,8 +3511,15 @@ js::DumpBacktrace(JSContext* cx)
const char* filename = JS_GetScriptFilename(i.script());
unsigned line = PCToLineNumber(i.script(), i.pc());
JSScript* script = i.script();
sprinter.printf("#%d %14p %s:%d (%p @ %d)\n",
depth, (i.isJit() ? 0 : i.interpFrame()), filename, line,
char frameType =
i.isInterp() ? 'i' :
i.isBaseline() ? 'b' :
i.isIon() ? 'I' :
i.isAsmJS() ? 'A' :
'?';
sprinter.printf("#%d %14p %c %s:%d (%p @ %d)\n",
depth, i.rawFramePtr(), frameType, filename, line,
script, script->pcToOffset(i.pc()));
}
fprintf(stdout, "%s", sprinter.string());

Просмотреть файл

@ -375,11 +375,11 @@ BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas)
if (c > '9' || c < '0') {
if (c == '$') { // numbered argument case
if (i > 0)
return false;
MOZ_CRASH("Bad format string");
number++;
} else { // non-numbered argument case
if (number > 0)
return false;
MOZ_CRASH("Bad format string");
i = 1;
}
break;
@ -417,7 +417,7 @@ BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas)
}
if (!c || cn < 1 || cn > number)
return false;
MOZ_CRASH("Bad format string");
// nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
cn--;
@ -429,7 +429,7 @@ BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas)
// width
if (c == '*') {
// not supported feature, for the argument is not numbered
return false;
MOZ_CRASH("Bad format string");
}
while ((c >= '0') && (c <= '9')) {
@ -441,7 +441,7 @@ BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas)
c = *p++;
if (c == '*') {
// not supported feature, for the argument is not numbered
return false;
MOZ_CRASH("Bad format string");
}
while ((c >= '0') && (c <= '9')) {
@ -527,7 +527,7 @@ BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas)
// get a legal para.
if (nas[cn].type == TYPE_UNKNOWN)
return false;
MOZ_CRASH("Bad format string");
}
@ -557,7 +557,7 @@ BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas)
case TYPE_INTSTR: (void) va_arg(ap, int*); break;
case TYPE_DOUBLE: (void) va_arg(ap, double); break;
default: return false;
default: MOZ_CRASH();
}
cn++;
@ -599,8 +599,7 @@ dosprintf(SprintfState* ss, const char* fmt, va_list ap)
NumArgStateVector nas;
if (!BuildArgArray(fmt, ap, nas)) {
// the fmt contains error Numbered Argument format, jliu@netscape.com
MOZ_ASSERT(0);
return false;
MOZ_CRASH("Bad format string");
}
while ((c = *fmt++) != 0) {
@ -633,7 +632,7 @@ dosprintf(SprintfState* ss, const char* fmt, va_list ap)
}
if (nas[i - 1].type == TYPE_UNKNOWN)
return false;
MOZ_CRASH("Bad format string");
ap = nas[i - 1].ap;
dolPt = fmt;

Просмотреть файл

@ -404,16 +404,18 @@ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& optio
if (OffThreadParsingMustWaitForGC(cx->runtime())) {
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWaitingOnGC().append(task.get()))
if (!HelperThreadState().parseWaitingOnGC().append(task.get())) {
ReportOutOfMemory(cx);
return false;
}
} else {
task->activate(cx->runtime());
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWorklist().append(task.get()))
if (!HelperThreadState().parseWorklist().append(task.get())) {
ReportOutOfMemory(cx);
return false;
}
task->activate(cx->runtime());
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
}
@ -1066,16 +1068,21 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void
if (cx->isExceptionPending())
return nullptr;
if (script) {
// The Debugger only needs to be told about the topmost script that was compiled.
Debugger::onNewScript(cx, script);
// Update the compressed source table with the result. This is normally
// called by setCompressedSource when compilation occurs on the main thread.
if (script->scriptSource()->hasCompressedSource())
script->scriptSource()->updateCompressedSourceSet(rt);
if (!script) {
// No error was reported, but no script produced. Assume we hit out of
// memory.
ReportOutOfMemory(cx);
return nullptr;
}
// The Debugger only needs to be told about the topmost script that was compiled.
Debugger::onNewScript(cx, script);
// Update the compressed source table with the result. This is normally
// called by setCompressedSource when compilation occurs on the main thread.
if (script->scriptSource()->hasCompressedSource())
script->scriptSource()->updateCompressedSourceSet(rt);
return script;
}

Просмотреть файл

@ -1447,8 +1447,10 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc
cx->recoverFromOutOfMemory();
}
if (!table->add(p, key, res))
if (!table->add(p, key, res)) {
ReportOutOfMemory(cx);
return nullptr;
}
return res;
}

Просмотреть файл

@ -853,6 +853,21 @@ FrameIter::copyDataAsAbstractFramePtr() const
return frame;
}
void*
FrameIter::rawFramePtr() const
{
switch (data_.state_) {
case DONE:
case ASMJS:
return nullptr;
case JIT:
return data_.jitFrames_.fp();
case INTERP:
return interpFrame();
}
MOZ_CRASH("Unexpected state");
}
JSCompartment*
FrameIter::compartment() const
{

Просмотреть файл

@ -2040,6 +2040,9 @@ class FrameIter
// This can only be called when isPhysicalIonFrame():
inline jit::CommonFrameLayout* physicalIonFrame() const;
// This is used to provide a raw interface for debugging.
void* rawFramePtr() const;
private:
Data data_;
jit::InlineFrameIterator ionInlineFrames_;

Просмотреть файл

@ -1368,7 +1368,7 @@ class TypeConstraintFreezeStack : public TypeConstraint
bool
js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
RecompileInfo* precompileInfo)
RecompileInfo* precompileInfo, bool* isValidOut)
{
if (constraints->failed())
return false;
@ -1452,9 +1452,11 @@ js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList
if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
types.compilerOutputs->back().invalidate();
script->resetWarmUpCounter();
return false;
*isValidOut = false;
return true;
}
*isValidOut = true;
return true;
}

Просмотреть файл

@ -1064,11 +1064,11 @@ FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap);
class RecompileInfo;
// Allocate a CompilerOutput for a finished compilation and generate the type
// constraints for the compilation. Returns whether the type constraints
// still hold.
// constraints for the compilation. Sets |isValidOut| based on whether the type
// constraints still hold.
bool
FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
RecompileInfo* precompileInfo);
RecompileInfo* precompileInfo, bool* isValidOut);
// Reset any CompilerOutput present for a script.
void

Просмотреть файл

@ -624,6 +624,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
mCurrentScrollbarFlags(0),
mCurrentScrollbarWillHaveLayer(false),
mBuildCaret(aBuildCaret),
mIgnoreSuppression(false),
mHadToIgnoreSuppression(false),
@ -3214,7 +3215,15 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
} else {
mHitRegion.Or(mHitRegion, borderBox);
}
if (aBuilder->GetAncestorHasApzAwareEventHandler()) {
if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
aBuilder->GetAncestorHasApzAwareEventHandler())
{
// Scrollbars may be painted into a layer below the actual layer they will
// scroll, and therefore wheel events may be dispatched to the outer frame
// instead of the intended scrollframe. To address this, we force a d-t-c
// region on scrollbar frames that won't be placed in their own layer. See
// bug 1213324 for details.
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
} else if (aFrame->GetType() == nsGkAtoms::objectFrame) {
// If the frame is a plugin frame and wants to handle wheel events as

Просмотреть файл

@ -312,6 +312,14 @@ public:
*aOutScrollbarTarget = mCurrentScrollbarTarget;
*aOutScrollbarFlags = mCurrentScrollbarFlags;
}
/**
* Returns true if building a scrollbar, and the scrollbar will not be
* layerized.
*/
bool IsBuildingNonLayerizedScrollbar() const {
return mCurrentScrollbarTarget != FrameMetrics::NULL_SCROLL_ID &&
!mCurrentScrollbarWillHaveLayer;
}
/**
* Calling this setter makes us include all out-of-flow descendant
* frames in the display list, wherever they may be positioned (even
@ -753,15 +761,17 @@ public:
class AutoCurrentScrollbarInfoSetter {
public:
AutoCurrentScrollbarInfoSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollTargetID,
uint32_t aScrollbarFlags)
uint32_t aScrollbarFlags, bool aWillHaveLayer)
: mBuilder(aBuilder) {
aBuilder->mCurrentScrollbarTarget = aScrollTargetID;
aBuilder->mCurrentScrollbarFlags = aScrollbarFlags;
aBuilder->mCurrentScrollbarWillHaveLayer = aWillHaveLayer;
}
~AutoCurrentScrollbarInfoSetter() {
// No need to restore old values because scrollbars cannot be nested.
mBuilder->mCurrentScrollbarTarget = FrameMetrics::NULL_SCROLL_ID;
mBuilder->mCurrentScrollbarFlags = 0;
mBuilder->mCurrentScrollbarWillHaveLayer = false;
}
private:
nsDisplayListBuilder* mBuilder;
@ -1156,6 +1166,7 @@ private:
uint32_t mCurrentScrollbarFlags;
BlendModeSet mContainedBlendModes;
Preserves3DContext mPreserves3DCtx;
bool mCurrentScrollbarWillHaveLayer;
bool mBuildCaret;
bool mIgnoreSuppression;
bool mHadToIgnoreSuppression;

Просмотреть файл

@ -698,7 +698,7 @@ nsPresContext::GetDocumentColorPreferences()
// 0 = default: always, except in high contrast mode
// 1 = always
// 2 = never
if (sDocumentColorsSetting == 1) {
if (sDocumentColorsSetting == 1 || mDocument->IsBeingUsedAsImage()) {
mUseDocumentColors = true;
} else if (sDocumentColorsSetting == 2) {
mUseDocumentColors = isChromeDocShell || mIsChromeOriginImage;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше