Merge branch 'mozilla-central'

This commit is contained in:
Jacek Caban 2016-02-16 10:38:25 +01:00
commit 33db3dfa02
348 changed files with 4182 additions and 7569 deletions

10
.gitignore vendored
View File

@ -54,6 +54,16 @@ parser/html/java/javaparser/
.cproject
.settings/
# Ignore the files and directory that JetBrains IDEs create.
/.idea/
*.iml
# Gradle cache.
/.gradle/
# Local Gradle configuration properties.
/local.properties
# Python virtualenv artifacts.
python/psutil/**/*.so
python/psutil/**/*.pyd

View File

@ -821,9 +821,17 @@ Accessible::XULElmName(DocAccessible* aDocument,
nsIContent *bindingParent = aElm->GetBindingParent();
nsIContent* parent =
bindingParent? bindingParent->GetParent() : aElm->GetParent();
nsAutoString ancestorTitle;
while (parent) {
if (parent->IsXULElement(nsGkAtoms::toolbaritem) &&
parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, ancestorTitle)) {
// Before returning this, check if the element itself has a tooltip:
if (aElm->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) {
aName.CompressWhitespace();
return;
}
aName.Assign(ancestorTitle);
aName.CompressWhitespace();
return;
}

View File

@ -13,4 +13,5 @@ support-files =
[test_list.html]
[test_markup.html]
[test_svg.html]
[test_toolbaritem.xul]
[test_tree.xul]

View File

@ -0,0 +1,84 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<?xml-stylesheet href="general.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Accessibility Name Calculating Test.">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../name.js"></script>
<script type="application/javascript">
<![CDATA[
var gQueue = null;
function doTest() {
let ids = [];
for (let item of ["button", "textbox"]) {
ids.push(item + "withtooltip");
ids.push(item + "withouttooltip");
ids.push("nested" + item + "withtooltip");
ids.push("nested" + item + "withouttooltip");
}
for (let id of ids) {
if (id.endsWith("withtooltip")) {
testName(id, id, id + " should have individual name from its tooltip - ");
} else {
testName(id, "Toolbaritem title", id + " should have toolbaritem's title for a name - ");
}
}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1216478"
title="Items with tooltips inside items with a label should use their own tooltip as an accessible name, not the ancestor's label">
Mozilla Bug 1216478
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1">
<toolbox>
<toolbar>
<toolbaritem title="Toolbaritem title">
<toolbarbutton id="buttonwithtooltip" tooltiptext="buttonwithtooltip"/>
<toolbarbutton id="buttonwithouttooltip"/>
<textbox id="textboxwithtooltip" tooltiptext="textboxwithtooltip"/>
<textbox id="textboxwithouttooltip"/>
<vbox>
<toolbarbutton id="nestedbuttonwithtooltip" tooltiptext="nestedbuttonwithtooltip"/>
<toolbarbutton id="nestedbuttonwithouttooltip"/>
<textbox id="nestedtextboxwithtooltip" tooltiptext="nestedtextboxwithtooltip"/>
<textbox id="nestedtextboxwithouttooltip"/>
</vbox>
</toolbaritem>
</toolbar>
</toolbox>
</vbox> <!-- close tests area -->
</hbox> <!-- close main area -->
</window>

View File

@ -57,7 +57,29 @@
<menuitem id="context-openlinkintab"
label="&openLinkCmdInTab.label;"
accesskey="&openLinkCmdInTab.accesskey;"
oncommand="gContextMenu.openLinkInTab();"/>
usercontextid="0"
oncommand="gContextMenu.openLinkInTab(event);"/>
<menu id="context-openlinkinusercontext-menu"
label="&openLinkCmdInContainerTab.label;"
accesskey="&openLinkCmdInContainerTab.accesskey;"
hidden="true">
<menupopup oncommand="gContextMenu.openLinkInTab(event);">
<menuitem label="&userContextPersonal.label;"
usercontextid="1"
accesskey="&userContextPersonal.accesskey;"/>
<menuitem label="&userContextWork.label;"
usercontextid="2"
accesskey="&userContextWork.accesskey;"/>
<menuitem label="&userContextBanking.label;"
usercontextid="3"
accesskey="&userContextBanking.accesskey;"/>
<menuitem label="&userContextShopping.label;"
usercontextid="4"
accesskey="&userContextShopping.accesskey;"/>
</menupopup>
</menu>
<menuitem id="context-openlink"
label="&openLinkCmd.label;"
accesskey="&openLinkCmd.accesskey;"

View File

@ -451,6 +451,10 @@
class="show-only-for-keyboard"
command="Browser:BookmarkAllTabs"
key="bookmarkAllTabsKb"/>
<menuseparator/>
<menuitem label="&recentBookmarks.label;"
disabled="true"/>
<vbox id="menu_recentBookmarks"/>
<menuseparator id="bookmarksToolbarSeparator"/>
<menu id="bookmarksToolbarFolderMenu"
class="menu-iconic bookmark-item"

View File

@ -1305,6 +1305,9 @@ var BookmarkingUI = {
return;
}
this._updateRecentBookmarks(document.getElementById("BMB_recentBookmarks"),
"subviewbutton");
if (!this._popupNeedsUpdate)
return;
this._popupNeedsUpdate = false;
@ -1338,6 +1341,60 @@ var BookmarkingUI = {
});
},
_updateRecentBookmarks: function(container, extraCSSClass = "") {
const kMaxResults = 5;
let options = PlacesUtils.history.getNewQueryOptions();
options.excludeQueries = true;
options.queryType = options.QUERY_TYPE_BOOKMARKS;
options.sortingMode = options.SORT_BY_DATE_DESCENDING;
options.maxResults = kMaxResults;
let query = PlacesUtils.history.getNewQuery();
while (container.firstChild) {
container.firstChild.remove();
}
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.asyncExecuteLegacyQueries([query], 1, options, {
handleResult: function (aResultSet) {
let onItemClick = function (aEvent) {
let item = aEvent.target;
openUILink(item.getAttribute("targetURI"), aEvent);
CustomizableUI.hidePanelForNode(item);
};
let fragment = document.createDocumentFragment();
let row;
while ((row = aResultSet.getNextRow())) {
let uri = row.getResultByIndex(1);
let title = row.getResultByIndex(2);
let icon = row.getResultByIndex(6);
let item =
document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"menuitem");
item.setAttribute("label", title || uri);
item.setAttribute("targetURI", uri);
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
extraCSSClass);
item.addEventListener("click", onItemClick);
if (icon) {
let iconURL = "moz-anno:favicon:" + icon;
item.setAttribute("image", iconURL);
}
fragment.appendChild(item);
}
container.appendChild(fragment);
},
handleError: function (aError) {
Cu.reportError("Error while attempting to show recent bookmarks: " + aError);
},
handleCompletion: function (aReason) {
},
});
},
/**
* Handles star styling based on page proxy state changes.
*/
@ -1550,6 +1607,7 @@ var BookmarkingUI = {
onMainMenuPopupShowing: function BUI_onMainMenuPopupShowing(event) {
this._updateBookmarkPageMenuItem();
PlacesCommandHook.updateBookmarkAllTabsCommand();
this._updateRecentBookmarks(document.getElementById("menu_recentBookmarks"));
},
_showBookmarkedNotification: function BUI_showBookmarkedNotification() {

View File

@ -8,9 +8,14 @@
var gSafeBrowsing = {
setReportPhishingMenu: function() {
// A phishing page will have a specific about:blocked content documentURI
var uri = gBrowser.currentURI;
var isPhishingPage = uri && uri.spec.startsWith("about:blocked?e=phishingBlocked");
// In order to detect whether or not we're at the phishing warning
// page, we have to check the documentURI instead of the currentURI.
// This is because when the DocShell loads an error page, the
// currentURI stays at the original target, while the documentURI
// will point to the internal error page we loaded instead.
var docURI = gBrowser.selectedBrowser.documentURI;
var isPhishingPage =
docURI && docURI.spec.startsWith("about:blocked?e=phishingBlocked");
// Show/hide the appropriate menu item.
document.getElementById("menu_HelpPopup_reportPhishingtoolmenu")
@ -26,6 +31,9 @@ var gSafeBrowsing = {
if (!broadcaster)
return;
// Now look at the currentURI to learn which page we were trying
// to browse to.
let uri = gBrowser.currentURI;
if (uri && (uri.schemeIs("http") || uri.schemeIs("https")))
broadcaster.removeAttribute("disabled");
else

View File

@ -812,6 +812,11 @@
command="Browser:ShowAllBookmarks"
key="manBookmarkKb"/>
<menuseparator/>
<menuitem label="&recentBookmarks.label;"
disabled="true"
class="subviewbutton"/>
<vbox id="BMB_recentBookmarks"/>
<menuseparator/>
<menu id="BMB_bookmarksToolbar"
class="menu-iconic bookmark-item subviewbutton"
label="&personalbarCmd.label;"

View File

@ -144,9 +144,11 @@ nsContextMenu.prototype = {
var shouldShow = this.onSaveableLink || isMailtoInternal || this.onPlainTextLink;
var isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
var showContainers = Services.prefs.getBoolPref("privacy.userContext.enabled");
this.showItem("context-openlink", shouldShow && !isWindowPrivate);
this.showItem("context-openlinkprivate", shouldShow);
this.showItem("context-openlinkintab", shouldShow);
this.showItem("context-openlinkinusercontext-menu", shouldShow && showContainers);
this.showItem("context-openlinkincurrent", this.onPlainTextLink);
this.showItem("context-sep-open", shouldShow);
},
@ -960,7 +962,7 @@ nsContextMenu.prototype = {
},
// Open linked-to URL in a new tab.
openLinkInTab: function() {
openLinkInTab: function(event) {
urlSecurityCheck(this.linkURL, this.principal);
let referrerURI = gContextMenuContentData.documentURIObject;
@ -981,6 +983,7 @@ nsContextMenu.prototype = {
let params = this._openLinkInParameters({
allowMixedContent: persistAllowMixedContentInChildTab,
userContextId: event.target.getAttribute('usercontextid'),
});
openLinkIn(this.linkURL, "tab", params);
},

View File

@ -121,7 +121,7 @@ SocialErrorListener = {
.getInterface(Ci.nsIDOMWindowUtils);
dwu.allowScriptsToClose();
content.addEventListener("DOMWindowClose", function _mozSocialDOMWindowClose(evt) {
addEventListener("DOMWindowClose", function _mozSocialDOMWindowClose(evt) {
sendAsyncMessage("DOMWindowClose");
// preventDefault stops the default window.close() function being called,
// which doesn't actually close anything but causes things to get into
@ -135,7 +135,7 @@ SocialErrorListener = {
break;
case "Social:ListenForEvents":
for (let eventName of message.data.eventNames) {
content.addEventListener(eventName, this);
addEventListener(eventName, this);
}
break;
case "Social:SetDocumentTitle":

View File

@ -207,6 +207,16 @@
content.setAttribute("origin", this.content.getAttribute("origin"));
content.popupnotificationanchor.className = this.content.popupnotificationanchor.className;
content.swapDocShells(this.content);
// When a chat window is attached or detached, the docShell hosting
// the chat document is swapped to the newly created chat window.
// (Be it inside a popup or back inside a chatbox element attached to
// the chatbar.)
// Since a swapDocShells call does not swap the messageManager instances
// attached to a browser, we'll need to add the message listeners to
// the new messageManager. This is not a bug in swapDocShells, merely
// a design decision.
content.messageManager.addMessageListener("DOMTitleChanged", content);
]]></body>
</method>

View File

@ -1828,6 +1828,13 @@
var uriIsAboutBlank = !aURI || aURI == "about:blank";
if (!aURI || isBlankPageURL(aURI)) {
t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
} else if (aURI.toLowerCase().startsWith("javascript:")) {
// This can go away when bug 672618 or bug 55696 are fixed.
t.setAttribute("label", aURI);
}
if (aUserContextId)
t.setAttribute("usercontextid", aUserContextId);
t.setAttribute("crop", "end");
@ -1906,15 +1913,6 @@
this.mPanelContainer.appendChild(notificationbox);
}
// We've waited until the tab is in the DOM to set the label. This
// allows the TabLabelModified event to be properly dispatched.
if (!aURI || isBlankPageURL(aURI)) {
t.label = this.mStringBundle.getString("tabs.emptyTabTitle");
} else if (aURI.toLowerCase().startsWith("javascript:")) {
// This can go away when bug 672618 or bug 55696 are fixed.
t.label = aURI;
}
this.tabContainer.updateVisibility();
// wire up a progress listener for the new browser object.
@ -6073,8 +6071,7 @@
class="tab-icon-overlay"
role="presentation"/>
<xul:label flex="1"
anonid="tab-label"
xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected,visuallyselected,attention"
xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected,visuallyselected,attention"
class="tab-text tab-label"
role="presentation"/>
<xul:image xbl:inherits="soundplaying,pinned,muted,visuallyselected"
@ -6140,32 +6137,6 @@
</setter>
</property>
<property name="label">
<getter>
return this.getAttribute("label");
</getter>
<setter>
this.setAttribute("label", val);
let event = new CustomEvent("TabLabelModified", {
bubbles: true,
cancelable: true
});
this.dispatchEvent(event);
// Let listeners prevent synchronizing the actual label to the
// visible label (allowing them to override the visible label).
if (!event.defaultPrevented)
this.visibleLabel = val;
</setter>
</property>
<property name="visibleLabel">
<getter>
return this.getAttribute("visibleLabel");
</getter>
<setter>
this.setAttribute("visibleLabel", val);
</setter>
</property>
<property name="pinned" readonly="true">
<getter>
return this.getAttribute("pinned") == "true";

View File

@ -8,4 +8,3 @@ support-files =
skip-if = true # Bug 1245937 - Intermittent failures/timeouts.
[browser_focus.js]
[browser_tearoff.js]
skip-if = true # Bug 1245805 - tearing off chat windows causes a browser crash.

View File

@ -65,7 +65,7 @@ add_chat_task(function* testTearoffChat() {
Assert.equal(chatbox.getAttribute("label"), chatTitle, "window should have same title as chat");
yield ContentTask.spawn(chatbox.content, null, function* () {
div = content.document.getElementById("testdiv");
let div = content.document.getElementById("testdiv");
is(div.getAttribute("test"), "1", "docshell should have been swapped");
div.setAttribute("test", "2");
});

View File

@ -491,7 +491,6 @@ skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliabil
[browser_utilityOverlay.js]
[browser_viewSourceInTabOnViewSource.js]
[browser_visibleFindSelection.js]
[browser_visibleLabel.js]
[browser_visibleTabs.js]
[browser_visibleTabs_bookmarkAllPages.js]
skip-if = true # Bug 1005420 - fails intermittently. also with e10s enabled: bizarre problem with hidden tab having _mouseenter called, via _setPositionalAttributes, and tab not being found resulting in 'candidate is undefined'

View File

@ -1,94 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* Tests:
* verify that the visibleLabel attribute works
* verify the TabLabelModified event works for both existing and new tabs
*/
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
gBrowser.removeCurrentTab({animate: false});
});
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank",
{skipAnimation: true});
tab.linkedBrowser.addEventListener("load", function onLoad(event) {
event.currentTarget.removeEventListener("load", onLoad, true);
executeSoon(afterLoad);
}, true);
}
function afterLoad() {
let tab = gBrowser.selectedTab;
let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid",
"tab-label");
// Verify we're starting out on the right foot
is(tab.label, "New Tab", "Initial tab label is default");
is(xulLabel.value, "New Tab", "Label element is default");
is(tab.visibleLabel, "New Tab", "visibleLabel is default");
// Check that a normal label setting works correctly
tab.label = "Hello, world!";
is(tab.label, "Hello, world!", "tab label attribute set via tab.label");
is(xulLabel.value, "Hello, world!", "xul:label set via tab.label");
is(tab.visibleLabel, "Hello, world!", "visibleLabel set via tab.label");
// Check that setting visibleLabel only affects the label element
tab.visibleLabel = "Goodnight, Irene";
is(tab.label, "Hello, world!", "Tab.label unaffected by visibleLabel setter");
is(xulLabel.value, "Goodnight, Irene",
"xul:label set by visibleLabel setter");
is(tab.visibleLabel, "Goodnight, Irene",
"visibleLabel attribute set by visibleLabel setter");
// Check that setting the label property hits everything
tab.label = "One more label";
is(tab.label, "One more label",
"Tab label set via label property after diverging from visibleLabel");
is(xulLabel.value, "One more label",
"xul:label set via label property after diverging from visibleLabel");
is(tab.visibleLabel, "One more label",
"visibleLabel set from label property after diverging from visibleLabel");
tab.addEventListener("TabLabelModified", overrideTabLabel, true);
tab.label = "This won't be the visibleLabel";
}
function overrideTabLabel(aEvent) {
aEvent.target.removeEventListener("TabLabelModified", overrideTabLabel, true);
aEvent.preventDefault();
aEvent.stopPropagation();
aEvent.target.visibleLabel = "Handler set this as the visible label";
executeSoon(checkTabLabelModified);
}
function checkTabLabelModified() {
let tab = gBrowser.selectedTab;
let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid",
"tab-label");
is(tab.label, "This won't be the visibleLabel",
"Tab label set via label property that triggered event");
is(xulLabel.value, "Handler set this as the visible label",
"xul:label set by TabLabelModified handler");
is(tab.visibleLabel, "Handler set this as the visible label",
"visibleLabel set by TabLabelModified handler");
gBrowser.removeCurrentTab({animate: false});
executeSoon(checkTabLabelModifiedOnNewTab);
}
function checkTabLabelModifiedOnNewTab() {
gBrowser.tabContainer.addEventListener("TabLabelModified",
handleTabLabelModifiedOnNewTab, true);
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank",
{skipAnimation: true});
}
function handleTabLabelModifiedOnNewTab(aEvent) {
gBrowser.tabContainer.removeEventListener("TabLabelModified",
handleTabLabelModifiedOnNewTab, true);
ok(true, "Event received from new tab default being set");
executeSoon(finish);
}

View File

@ -184,8 +184,6 @@ const CustomizableWidgets = [
let options = PlacesUtils.history.getNewQueryOptions();
options.excludeQueries = true;
options.includeHidden = false;
options.resultType = options.RESULTS_AS_URI;
options.queryType = options.QUERY_TYPE_HISTORY;
options.sortingMode = options.SORT_BY_DATE_DESCENDING;
options.maxResults = kMaxResults;

View File

@ -5,8 +5,6 @@ support-files = head.js
[browser_bug400731.js]
skip-if = e10s
[browser_bug415846.js]
skip-if = true
# Disabled because it seems to now touch network resources
# skip-if = os == "mac"
skip-if = os == "mac" || e10s
# Disabled on Mac because of its bizarre special-and-unique
# snowflake of a help menu.

View File

@ -3,60 +3,84 @@ menu items.
Mac makes this astonishingly painful to test since their help menu is special magic,
but we can at least test it on the other platforms.*/
var menu;
function test() {
waitForExplicitFinish();
const NORMAL_PAGE = "http://example.com";
const PHISH_PAGE = "http://www.itisatrap.org/firefox/its-a-trap.html";
gBrowser.selectedTab = gBrowser.addTab();
/**
* Opens a new tab and browses to some URL, tests for the existence
* of the phishing menu items, and then runs a test function to check
* the state of the menu once opened. This function will take care of
* opening and closing the menu.
*
* @param url (string)
* The URL to browse the tab to.
* @param testFn (function)
* The function to run once the menu has been opened. This
* function will be passed the "reportMenu" and "errorMenu"
* DOM nodes as arguments, in that order. This function
* should not yield anything.
* @returns Promise
*/
function check_menu_at_page(url, testFn) {
return BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank",
}, function*(browser) {
// We don't get load events when the DocShell redirects to error
// pages, but we do get DOMContentLoaded, so we'll wait for that.
let dclPromise = ContentTask.spawn(browser, null, function*() {
yield ContentTaskUtils.waitForEvent(this, "DOMContentLoaded", false);
});
browser.loadURI(url);
yield dclPromise;
// Navigate to a normal site
gBrowser.addEventListener("DOMContentLoaded", testNormal, false);
content.location = "http://example.com/";
let menu = document.getElementById("menu_HelpPopup");
ok(menu, "Help menu should exist");
let reportMenu =
document.getElementById("menu_HelpPopup_reportPhishingtoolmenu");
ok(reportMenu, "Report phishing menu item should exist");
let errorMenu =
document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu");
ok(errorMenu, "Report phishing error menu item should exist");
let menuOpen = BrowserTestUtils.waitForEvent(menu, "popupshown");
menu.openPopup(null, "", 0, 0, false, null);
yield menuOpen;
testFn(reportMenu, errorMenu);
let menuClose = BrowserTestUtils.waitForEvent(menu, "popuphidden");
menu.hidePopup();
yield menuClose;
});
}
function testNormal() {
gBrowser.removeEventListener("DOMContentLoaded", testNormal, false);
/**
* Tests that we show the "Report this page" menu item at a normal
* page.
*/
add_task(function*() {
yield check_menu_at_page(NORMAL_PAGE, (reportMenu, errorMenu) => {
ok(!reportMenu.hidden,
"Report phishing menu should be visible on normal sites");
ok(errorMenu.hidden,
"Report error menu item should be hidden on normal sites");
});
});
// open the menu, to force it to update
menu = document.getElementById("menu_HelpPopup");
ok(menu, "Help menu should exist!");
/**
* Tests that we show the "Report this page is okay" menu item at
* a reported attack site.
*/
add_task(function*() {
yield check_menu_at_page(PHISH_PAGE, (reportMenu, errorMenu) => {
ok(reportMenu.hidden,
"Report phishing menu should be hidden on phishing sites");
ok(!errorMenu.hidden,
"Report error menu item should be visible on phishing sites");
});
});
menu.addEventListener("popupshown", testNormal_PopupListener, false);
menu.openPopup(null, "", 0, 0, false, null);
}
function testNormal_PopupListener() {
menu.removeEventListener("popupshown", testNormal_PopupListener, false);
var reportMenu = document.getElementById("menu_HelpPopup_reportPhishingtoolmenu");
var errorMenu = document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu");
is(reportMenu.hidden, false, "Report phishing menu should be visible on normal sites");
is(errorMenu.hidden, true, "Report error menu item should be hidden on normal sites");
menu.hidePopup();
// Now launch the phishing test. Can't use onload here because error pages don't
// fire normal load events.
window.addEventListener("DOMContentLoaded", testPhishing, true);
content.location = "http://www.itisatrap.org/firefox/its-a-trap.html";
}
function testPhishing() {
window.removeEventListener("DOMContentLoaded", testPhishing, true);
menu.addEventListener("popupshown", testPhishing_PopupListener, false);
menu.openPopup(null, "", 0, 0, false, null);
}
function testPhishing_PopupListener() {
menu.removeEventListener("popupshown", testPhishing_PopupListener, false);
var reportMenu = document.getElementById("menu_HelpPopup_reportPhishingtoolmenu");
var errorMenu = document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu");
is(reportMenu.hidden, true, "Report phishing menu should be hidden on phishing sites");
is(errorMenu.hidden, false, "Report error menu item should be visible on phishing sites");
menu.hidePopup();
gBrowser.removeCurrentTab();
finish();
}

View File

@ -77,7 +77,7 @@ run-if = e10s
[browser_cleaner.js]
[browser_cookies.js]
[browser_crashedTabs.js]
skip-if = true # bug 1236414
skip-if = !e10s || !crashreporter
[browser_unrestored_crashedTabs.js]
skip-if = !e10s || !crashreporter
[browser_revive_crashed_bg_tabs.js]

View File

@ -3,7 +3,7 @@
"use strict";
requestLongerTimeout(2);
requestLongerTimeout(10);
const PAGE_1 = "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
const PAGE_2 = "data:text/html,<html><body>Another%20regular,%20everyday,%20normal%20page.";
@ -17,9 +17,6 @@ registerCleanupFunction(() => {
// Allow tabs to restore on demand so we can test pending states
Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
// Running this test in ASAN is slow.
requestLongerTimeout(2);
function clickButton(browser, id) {
info("Clicking " + id);

View File

@ -1,3 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.4.42
Current extension version is: 1.4.64

View File

@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdf = {}));
// Use strict in our context only - users might not want it
'use strict';
var pdfjsVersion = '1.4.42';
var pdfjsBuild = '4c59712';
var pdfjsVersion = '1.4.64';
var pdfjsBuild = '2f145d8';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?
@ -6258,9 +6258,9 @@ PDFJS.getDocument = function getDocument(src,
throw new Error('Loading aborted');
}
var messageHandler = new MessageHandler(docId, workerId, worker.port);
messageHandler.send('Ready', null);
var transport = new WorkerTransport(messageHandler, task, rangeTransport);
task._transport = transport;
messageHandler.send('Ready', null);
});
}).catch(task._capability.reject);
@ -7102,7 +7102,7 @@ var PDFWorker = (function PDFWorkerClosure() {
_initialize: function PDFWorker_initialize() {
// If worker support isn't disabled explicit and the browser has worker
// support, create a new web worker and test if it/the browser fullfills
// support, create a new web worker and test if it/the browser fulfills
// all requirements to run parts of pdf.js in a web worker.
// Right now, the requirement is, that an Uint8Array is still an
// Uint8Array as it arrives on the worker. (Chrome added this with v.15.)

View File

@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdfWorker = {}));
// Use strict in our context only - users might not want it
'use strict';
var pdfjsVersion = '1.4.42';
var pdfjsBuild = '4c59712';
var pdfjsVersion = '1.4.64';
var pdfjsBuild = '2f145d8';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?
@ -29687,15 +29687,21 @@ var Type1Parser = (function Type1ParserClosure() {
}
function decrypt(data, key, discardNumber) {
var r = key | 0, c1 = 52845, c2 = 22719;
var count = data.length;
if (discardNumber >= data.length) {
return new Uint8Array(0);
}
var r = key | 0, c1 = 52845, c2 = 22719, i, j;
for (i = 0; i < discardNumber; i++) {
r = ((data[i] + r) * c1 + c2) & ((1 << 16) - 1);
}
var count = data.length - discardNumber;
var decrypted = new Uint8Array(count);
for (var i = 0; i < count; i++) {
for (i = discardNumber, j = 0; j < count; i++, j++) {
var value = data[i];
decrypted[i] = value ^ (r >> 8);
decrypted[j] = value ^ (r >> 8);
r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
}
return Array.prototype.slice.call(decrypted, discardNumber);
return decrypted;
}
function decryptAscii(data, key, discardNumber) {
@ -33249,15 +33255,15 @@ var ColorSpace = (function ColorSpaceClosure() {
case 'DeviceCmykCS':
return this.singletons.cmyk;
case 'CalGrayCS':
whitePoint = IR[1].WhitePoint;
blackPoint = IR[1].BlackPoint;
gamma = IR[1].Gamma;
whitePoint = IR[1];
blackPoint = IR[2];
gamma = IR[3];
return new CalGrayCS(whitePoint, blackPoint, gamma);
case 'CalRGBCS':
whitePoint = IR[1].WhitePoint;
blackPoint = IR[1].BlackPoint;
gamma = IR[1].Gamma;
var matrix = IR[1].Matrix;
whitePoint = IR[1];
blackPoint = IR[2];
gamma = IR[3];
var matrix = IR[4];
return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
case 'PatternCS':
var basePatternCS = IR[1];
@ -33276,11 +33282,11 @@ var ColorSpace = (function ColorSpaceClosure() {
var tintFnIR = IR[3];
return new AlternateCS(numComps, ColorSpace.fromIR(alt),
PDFFunction.fromIR(tintFnIR));
PDFFunction.fromIR(tintFnIR));
case 'LabCS':
whitePoint = IR[1].WhitePoint;
blackPoint = IR[1].BlackPoint;
var range = IR[1].Range;
whitePoint = IR[1];
blackPoint = IR[2];
var range = IR[3];
return new LabCS(whitePoint, blackPoint, range);
default:
error('Unknown name ' + name);
@ -33324,7 +33330,7 @@ var ColorSpace = (function ColorSpaceClosure() {
} else if (isArray(cs)) {
mode = xref.fetchIfRef(cs[0]).name;
this.mode = mode;
var numComps, params, alt;
var numComps, params, alt, whitePoint, blackPoint, gamma;
switch (mode) {
case 'DeviceGray':
@ -33337,11 +33343,18 @@ var ColorSpace = (function ColorSpaceClosure() {
case 'CMYK':
return 'DeviceCmykCS';
case 'CalGray':
params = xref.fetchIfRef(cs[1]).getAll();
return ['CalGrayCS', params];
params = xref.fetchIfRef(cs[1]);
whitePoint = params.get('WhitePoint');
blackPoint = params.get('BlackPoint');
gamma = params.get('Gamma');
return ['CalGrayCS', whitePoint, blackPoint, gamma];
case 'CalRGB':
params = xref.fetchIfRef(cs[1]).getAll();
return ['CalRGBCS', params];
params = xref.fetchIfRef(cs[1]);
whitePoint = params.get('WhitePoint');
blackPoint = params.get('BlackPoint');
gamma = params.get('Gamma');
var matrix = params.get('Matrix');
return ['CalRGBCS', whitePoint, blackPoint, gamma, matrix];
case 'ICCBased':
var stream = xref.fetchIfRef(cs[1]);
var dict = stream.dict;
@ -33393,8 +33406,11 @@ var ColorSpace = (function ColorSpaceClosure() {
var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
return ['AlternateCS', numComps, alt, tintFnIR];
case 'Lab':
params = xref.fetchIfRef(cs[1]).getAll();
return ['LabCS', params];
params = xref.fetchIfRef(cs[1]);
whitePoint = params.get('WhitePoint');
blackPoint = params.get('BlackPoint');
var range = params.get('Range');
return ['LabCS', whitePoint, blackPoint, range];
default:
error('unimplemented color space object "' + mode + '"');
}
@ -35949,17 +35965,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
processed[resources.objId] = true;
}
var nodes = [resources];
var nodes = [resources], xref = this.xref;
while (nodes.length) {
var key;
var key, i, ii;
var node = nodes.shift();
// First check the current resources for blend modes.
var graphicStates = node.get('ExtGState');
if (isDict(graphicStates)) {
graphicStates = graphicStates.getAll();
for (key in graphicStates) {
var graphicState = graphicStates[key];
var bm = graphicState['BM'];
var graphicStatesKeys = graphicStates.getKeys();
for (i = 0, ii = graphicStatesKeys.length; i < ii; i++) {
key = graphicStatesKeys[i];
var graphicState = graphicStates.get(key);
var bm = graphicState.get('BM');
if (isName(bm) && bm.name !== 'Normal') {
return true;
}
@ -35970,9 +35988,20 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (!isDict(xObjects)) {
continue;
}
xObjects = xObjects.getAll();
for (key in xObjects) {
var xObject = xObjects[key];
var xObjectsKeys = xObjects.getKeys();
for (i = 0, ii = xObjectsKeys.length; i < ii; i++) {
key = xObjectsKeys[i];
var xObject = xObjects.getRaw(key);
if (isRef(xObject)) {
if (processed[xObject.toString()]) {
// The XObject has already been processed, and by avoiding a
// redundant `xref.fetch` we can *significantly* reduce the load
// time for badly generated PDF files (fixes issue6961.pdf).
continue;
}
xObject = xref.fetch(xObject);
}
if (!isStream(xObject)) {
continue;
}
@ -36266,11 +36295,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
xref, stateManager) {
// This array holds the converted/processed state data.
var gStateObj = [];
var gStateMap = gState.map;
var gStateKeys = gState.getKeys();
var self = this;
var promise = Promise.resolve();
for (var key in gStateMap) {
var value = gStateMap[key];
for (var i = 0, ii = gStateKeys.length; i < ii; i++) {
var key = gStateKeys[i];
var value = gState.get(key);
switch (key) {
case 'Type':
break;
@ -36303,12 +36333,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
gStateObj.push([key, false]);
break;
}
var dict = xref.fetchIfRef(value);
if (isDict(dict)) {
promise = promise.then(function () {
if (isDict(value)) {
promise = promise.then(function (dict) {
return self.handleSMask(dict, resources, operatorList,
task, stateManager);
});
}.bind(this, value));
gStateObj.push([key, true]);
} else {
warn('Unsupported SMask type');
@ -36340,7 +36369,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
}
return promise.then(function () {
if (gStateObj.length >= 0) {
if (gStateObj.length > 0) {
operatorList.addOp(OPS.setGState, [gStateObj]);
}
});
@ -37885,13 +37914,13 @@ var TranslatedFont = (function TranslatedFontClosure() {
var translatedFont = this.font;
var loadCharProcsPromise = Promise.resolve();
var charProcs = this.dict.get('CharProcs').getAll();
var charProcs = this.dict.get('CharProcs');
var fontResources = this.dict.get('Resources') || resources;
var charProcKeys = Object.keys(charProcs);
var charProcKeys = charProcs.getKeys();
var charProcOperatorList = Object.create(null);
for (var i = 0, n = charProcKeys.length; i < n; ++i) {
loadCharProcsPromise = loadCharProcsPromise.then(function (key) {
var glyphStream = charProcs[key];
var glyphStream = charProcs.get(key);
var operatorList = new OperatorList();
return evaluator.getOperatorList(glyphStream, task, fontResources,
operatorList).then(function () {

View File

@ -168,6 +168,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
<!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
<!ENTITY showAllBookmarks2.label "Show All Bookmarks">
<!ENTITY recentBookmarks.label "Recently Bookmarked">
<!ENTITY unsortedBookmarksCmd.label "Unsorted Bookmarks">
<!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
@ -528,6 +529,8 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY openFrameCmdInTab.accesskey "T">
<!ENTITY openFrameCmd.label "Open Frame in New Window">
<!ENTITY openFrameCmd.accesskey "W">
<!ENTITY openLinkCmdInContainerTab.label "Open Link in New Container Tab">
<!ENTITY openLinkCmdInContainerTab.accesskey "C">
<!ENTITY showOnlyThisFrameCmd.label "Show Only This Frame">
<!ENTITY showOnlyThisFrameCmd.accesskey "S">
<!ENTITY reloadCmd.commandkey "r">

View File

@ -4,4 +4,3 @@ support-files =
head.js
[browser_screenshots.js]
tags = screenshots

View File

@ -5,15 +5,12 @@
"use strict";
add_task(function* capture() {
if (!shouldCapture()) {
let setsEnv = env.get("MOZSCREENSHOTS_SETS");
if (!setsEnv) {
ok(true, "MOZSCREENSHOTS_SETS wasn't specified so there's nothing to capture");
return;
}
let { TestRunner } = Cu.import("chrome://mozscreenshots/content/TestRunner.jsm", {});
let sets = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes"];
let setsEnv = env.get("MOZSCREENSHOTS_SETS");
if (setsEnv) {
sets = setsEnv.trim().split(",");
}
let sets = setsEnv.trim().split(",");
yield TestRunner.start(sets);
});

View File

@ -0,0 +1,6 @@
[DEFAULT]
subsuite = screenshots
support-files =
../head.js
[browser_devtools.js]

View File

@ -0,0 +1,14 @@
/* 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/. */
"use strict";
add_task(function* capture() {
if (!shouldCapture()) {
return;
}
let sets = ["DevTools"];
yield TestRunner.start(sets);
});

View File

@ -6,6 +6,7 @@
const {AddonWatcher} = Cu.import("resource://gre/modules/AddonWatcher.jsm", {});
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
let TestRunner;
function setup() {
requestLongerTimeout(20);
@ -15,18 +16,25 @@ function setup() {
AddonManager.getAddonByID("mozscreenshots@mozilla.org", function(aAddon) {
isnot(aAddon, null, "The mozscreenshots extension should be installed");
AddonWatcher.ignoreAddonPermanently(aAddon.id);
TestRunner = Cu.import("chrome://mozscreenshots/content/TestRunner.jsm", {}).TestRunner;
resolve();
});
});
}
function shouldCapture() {
// Try pushes only capture in browser_screenshots.js with MOZSCREENSHOTS_SETS.
if (env.get("MOZSCREENSHOTS_SETS")) {
ok(true, "MOZSCREENSHOTS_SETS was specified so only capture what was " +
"requested (in browser_screenshots.js)");
return false;
}
// Automation isn't able to schedule test jobs to only run on nightlies so we handle it here
// (see also: bug 1116275). Try pushes and local builds should also capture.
// (see also: bug 1116275).
let capture = AppConstants.MOZ_UPDATE_CHANNEL == "nightly" ||
(AppConstants.SOURCE_REVISION_URL.includes("/try/rev/") &&
env.get("MOZSCREENSHOTS_SETS")) ||
AppConstants.SOURCE_REVISION_URL == "";
AppConstants.SOURCE_REVISION_URL == "" ||
AppConstants.SOURCE_REVISION_URL == "1"; // bug 1248027
if (!capture) {
ok(true, "Capturing is disabled for this MOZ_UPDATE_CHANNEL or REPO");
}

View File

@ -4,7 +4,14 @@
# 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/.
BROWSER_CHROME_MANIFESTS += ['browser.ini']
BROWSER_CHROME_MANIFESTS += [
# Each test is in it's own directory so it gets run in a clean profile with
# run-by-dir.
'browser.ini',
'devtools/browser.ini',
'preferences/browser.ini',
'primaryUI/browser.ini',
]
TEST_DIRS += [
'mozscreenshots/extension',

View File

@ -11,7 +11,6 @@ const defaultSetNames = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "Li
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
const HOME_PAGE = "chrome://mozscreenshots/content/lib/mozscreenshots.html";
Cu.import("resource://testing-common/BrowserTestUtils.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
@ -19,6 +18,9 @@ Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserTestUtils",
"resource://testing-common/BrowserTestUtils.jsm");
Cu.import("chrome://mozscreenshots/content/Screenshot.jsm");
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
@ -42,6 +44,7 @@ this.TestRunner = {
_libDir: null,
init(extensionPath) {
log.info("init");
this._extensionPath = extensionPath;
},

View File

@ -9,7 +9,9 @@ this.EXPORTED_SYMBOLS = ["Preferences"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://testing-common/TestUtils.jsm");
this.Preferences = {
@ -31,7 +33,7 @@ this.Preferences = {
["paneAdvanced", "encryptionTab"],
];
for (let [primary, advanced] of panes) {
let configName = primary + ("-" + advanced || "");
let configName = primary.replace(/^pane/, "prefs") + (advanced ? "-" + advanced : "");
this.configurations[configName] = {};
this.configurations[configName].applyConfig = prefHelper.bind(null, primary, advanced);
}
@ -40,14 +42,27 @@ this.Preferences = {
configurations: {},
};
function prefHelper(primary, advanced) {
return new Promise((resolve) => {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (primary == "paneAdvanced") {
browserWindow.openAdvancedPreferences(advanced);
} else {
browserWindow.openPreferences(primary);
}
setTimeout(resolve, 50);
});
}
let prefHelper = Task.async(function*(primary, advanced) {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let selectedBrowser = browserWindow.gBrowser;
let readyPromise = null;
if (selectedBrowser.currentURI.specIgnoringRef == "about:preferences") {
readyPromise = new Promise((resolve) => {
browserWindow.addEventListener("MozAfterPaint", function paneSwitch() {
browserWindow.removeEventListener("MozAfterPaint", paneSwitch);
resolve();
});
});
} else {
readyPromise = TestUtils.topicObserved("advanced-pane-loaded");
}
if (primary == "paneAdvanced") {
browserWindow.openAdvancedPreferences(advanced);
} else {
browserWindow.openPreferences(primary);
}
yield readyPromise;
});

View File

@ -0,0 +1,6 @@
[DEFAULT]
subsuite = screenshots
support-files =
../head.js
[browser_preferences.js]

View File

@ -0,0 +1,14 @@
/* 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/. */
"use strict";
add_task(function* capture() {
if (!shouldCapture()) {
return;
}
let sets = ["Preferences"];
yield TestRunner.start(sets);
});

View File

@ -0,0 +1,6 @@
[DEFAULT]
subsuite = screenshots
support-files =
../head.js
[browser_primaryUI.js]

View File

@ -0,0 +1,14 @@
/* 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/. */
"use strict";
add_task(function* capture() {
if (!shouldCapture()) {
return;
}
let sets = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes"];
yield TestRunner.start(sets);
});

View File

@ -19,19 +19,11 @@ buildscript {
repositories {
jcenter()
// For spoon-gradle-plugin SNAPSHOT release. This needs to go before
// the snapshots repository, otherwise we find a remote 1.0.3-SNAPSHOT
// that doesn't include nalexander's local changes.
maven {
url "file://${gradle.mozconfig.topsrcdir}/mobile/android/gradle/m2repo"
}
}
dependencies {
// Unit testing support was added in 1.1.0. IntelliJ 14.1.4 and Android
// Studio 1.2.1.1 appear to work fine with plugin version 1.3.0.
classpath 'com.android.tools.build:gradle:1.3.0'
classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.3-SNAPSHOT') {
classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.4') {
// Without these, we get errors linting.
exclude module: 'guava'
}

View File

@ -106,6 +106,7 @@ leak:nsBaseWidget::StoreWindowClipRegion
leak:libcairo.so
leak:libdl.so
leak:libdricore.so
leak:libdricore9.2.1.so
leak:libGL.so
leak:libglib-2.0.so
leak:libp11-kit.so

View File

@ -3758,6 +3758,7 @@ MOZ_SCTP=
MOZ_ANDROID_OMX=
MOZ_MEDIA_NAVIGATOR=
MOZ_OMX_PLUGIN=
MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE=
MOZ_VPX_ERROR_CONCEALMENT=
MOZ_WEBSPEECH=1
MOZ_WEBSPEECH_MODELS=
@ -5366,8 +5367,26 @@ if test -n "$MOZ_OMX_PLUGIN"; then
dnl Only allow building OMX plugin on Gonk (B2G) or Android
AC_DEFINE(MOZ_OMX_PLUGIN)
else
dnl fail if we're not building on Gonk or Android
AC_MSG_ERROR([OMX media plugin can only be built on B2G or Android])
dnl fail if we're not building on Gonk or Android
AC_MSG_ERROR([OMX media plugin can only be built on B2G or Android])
fi
fi
dnl ========================================================
dnl = Enable building mobile/android with Gradle
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(gradle-mobile-android-builds,
[ --enable-gradle-mobile-android-builds Enable building mobile/android with Gradle],
MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE=1,
MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE=)
if test -n "$MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE"; then
if test "$OS_TARGET" = "Android" -a x"$MOZ_WIDGET_TOOLKIT" != x"gonk"; then
dnl Only allow building mobile/android with Gradle.
AC_DEFINE(MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE)
else
dnl fail if we're not building mobile/android.
AC_MSG_ERROR([Can only build mobile/android with Gradle])
fi
fi
@ -8900,6 +8919,7 @@ AC_SUBST(MOZ_DIRECTSHOW)
AC_SUBST(MOZ_ANDROID_OMX)
AC_SUBST(MOZ_APPLEMEDIA)
AC_SUBST(MOZ_OMX_PLUGIN)
AC_SUBST(MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE)
AC_SUBST(MOZ_VPX_ERROR_CONCEALMENT)
AC_SUBST(VPX_AS)
AC_SUBST_LIST(VPX_ASFLAGS)

View File

@ -5,10 +5,13 @@
"use strict";
const l10n = require("gcli/l10n");
const {
getCssDocs,
PAGE_LINK_URL
} = require("devtools/client/shared/widgets/MdnDocsWidget");
var MdnDocsWidget;
try {
MdnDocsWidget = require("devtools/client/shared/widgets/MdnDocsWidget");
} catch (e) {
// DevTools MdnDocsWidget only available in Firefox Desktop
}
exports.items = [{
name: "mdn",
@ -26,10 +29,14 @@ exports.items = [{
description: l10n.lookup("mdnCssProp")
}],
exec: function(args) {
return getCssDocs(args.property).then(result => {
if (!MdnDocsWidget) {
return null;
}
return MdnDocsWidget.getCssDocs(args.property).then(result => {
return {
data: result,
url: PAGE_LINK_URL + args.property,
url: MdnDocsWidget.PAGE_LINK_URL + args.property,
property: args.property
};
}, error => {

View File

@ -3513,22 +3513,19 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
if (!!targetDS != !!accessingDS) {
// We must be able to convert both or neither to nsIDocShell.
if (!targetDS || !accessingDS) {
// We must be able to convert both to nsIDocShell.
return false;
}
if (targetDS && accessingDS &&
(targetDS->GetIsInBrowserElement() !=
accessingDS->GetIsInBrowserElement() ||
targetDS->GetAppId() != accessingDS->GetAppId())) {
if (targetDS->GetIsInBrowserElement() != accessingDS->GetIsInBrowserElement() ||
targetDS->GetAppId() != accessingDS->GetAppId()) {
return false;
}
// A private document can't access a non-private one, and vice versa.
if (aTargetItem->GetDocument()->GetLoadContext()->UsePrivateBrowsing() !=
aAccessingItem->GetDocument()->GetLoadContext()->UsePrivateBrowsing())
{
if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
return false;
}

View File

@ -6,7 +6,6 @@
document.write("<h5 id='dynamic'>document.written content</h5>");
document.close();
window.history.go(-1);
opener.setTimeout("isTestDynamic()", 2500);
}
function start() {
@ -14,6 +13,15 @@
setTimeout(run, 0);
}
}
window.addEventListener("pageshow",
function() {
++opener.file_document_write_1_loadCount;
if (opener.file_document_write_1_loadCount == 2) {
opener.setTimeout("isTestDynamic()", 0);
}
opener.ok(opener.file_document_write_1_loadCount <= 2);
});
</script>
</head>
<body onload="start();">

View File

@ -49,6 +49,7 @@ function nextTest_() {
}
// Needed by file_document_write_1.html
window.file_document_write_1_loadCount = 0;
function isTestDynamic() {
var dyn = testWindow.document.getElementById("dynamic");
is(dyn, null, "Should have gone back to the static page!");

View File

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "mozilla/dom/AnimationEffectTiming.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/AnimationEffectTimingBinding.h"
namespace mozilla {
namespace dom {
JSObject*
AnimationEffectTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return AnimationEffectTimingBinding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_AnimationEffectTiming_h
#define mozilla_dom_AnimationEffectTiming_h
#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
namespace mozilla {
namespace dom {
class AnimationEffectTiming : public AnimationEffectTimingReadOnly
{
public:
explicit AnimationEffectTiming(const TimingParams& aTiming)
: AnimationEffectTimingReadOnly(aTiming) { }
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_AnimationEffectTiming_h

View File

@ -11,6 +11,7 @@
#include "nsIAtom.h"
#include "nsIContent.h"
#include "nsString.h"
#include "mozilla/Attributes.h"
#include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction
#include "mozilla/dom/Element.h" // For dom::Element
@ -69,7 +70,7 @@ AnimationUtils::ParseEasing(const dom::Element* aTarget,
NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR) {
return Nothing();
}
// Fall through
MOZ_FALLTHROUGH;
case eCSSUnit_Cubic_Bezier:
case eCSSUnit_Steps: {
nsTimingFunction timingFunction;

View File

@ -76,14 +76,24 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly(
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const TimingParams& aTiming)
: KeyframeEffectReadOnly(aDocument, aTarget, aPseudoType,
new AnimationEffectTimingReadOnly(aTiming))
{
}
KeyframeEffectReadOnly::KeyframeEffectReadOnly(
nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
AnimationEffectTimingReadOnly* aTiming)
: AnimationEffectReadOnly(aDocument)
, mTarget(aTarget)
, mTiming(*aTiming)
, mPseudoType(aPseudoType)
, mInEffectOnLastAnimationTimingUpdate(false)
{
MOZ_ASSERT(aTiming);
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
mTiming = new AnimationEffectTimingReadOnly(aTiming);
}
JSObject*
@ -595,6 +605,72 @@ KeyframeEffectReadOnly::~KeyframeEffectReadOnly()
{
}
template <class KeyframeEffectType>
/* static */ already_AddRefed<KeyframeEffectType>
KeyframeEffectReadOnly::ConstructKeyframeEffect(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv)
{
if (aTarget.IsNull()) {
// We don't support null targets yet.
aRv.Throw(NS_ERROR_DOM_ANIM_NO_TARGET_ERR);
return nullptr;
}
const ElementOrCSSPseudoElement& target = aTarget.Value();
MOZ_ASSERT(target.IsElement() || target.IsCSSPseudoElement(),
"Uninitialized target");
RefPtr<Element> targetElement;
nsCSSPseudoElements::Type pseudoType =
nsCSSPseudoElements::ePseudo_NotPseudoElement;
if (target.IsElement()) {
targetElement = &target.GetAsElement();
} else {
targetElement = target.GetAsCSSPseudoElement().ParentElement();
pseudoType = target.GetAsCSSPseudoElement().GetType();
}
if (!targetElement->GetComposedDoc()) {
aRv.Throw(NS_ERROR_DOM_ANIM_TARGET_NOT_IN_DOC_ERR);
return nullptr;
}
InfallibleTArray<AnimationProperty> animationProperties;
BuildAnimationPropertyList(aGlobal.Context(), targetElement, pseudoType,
aFrames, animationProperties, aRv);
if (aRv.Failed()) {
return nullptr;
}
RefPtr<KeyframeEffectType> effect =
new KeyframeEffectType(targetElement->OwnerDoc(), targetElement,
pseudoType, aTiming);
effect->mProperties = Move(animationProperties);
return effect.forget();
}
// Explicit instantiations to avoid linker errors.
template
already_AddRefed<KeyframeEffectReadOnly>
KeyframeEffectReadOnly::ConstructKeyframeEffect<>(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv);
template
already_AddRefed<KeyframeEffect>
KeyframeEffectReadOnly::ConstructKeyframeEffect<>(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv);
void
KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
{
@ -1635,55 +1711,6 @@ KeyframeEffectReadOnly::BuildAnimationPropertyList(
}
}
/* static */ already_AddRefed<KeyframeEffectReadOnly>
KeyframeEffectReadOnly::Constructor(
const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv)
{
if (aTarget.IsNull()) {
// We don't support null targets yet.
aRv.Throw(NS_ERROR_DOM_ANIM_NO_TARGET_ERR);
return nullptr;
}
const ElementOrCSSPseudoElement& target = aTarget.Value();
MOZ_ASSERT(target.IsElement() || target.IsCSSPseudoElement(),
"Uninitialized target");
RefPtr<Element> targetElement;
nsCSSPseudoElements::Type pseudoType =
nsCSSPseudoElements::ePseudo_NotPseudoElement;
if (target.IsElement()) {
targetElement = &target.GetAsElement();
} else {
targetElement = target.GetAsCSSPseudoElement().ParentElement();
pseudoType = target.GetAsCSSPseudoElement().GetType();
}
if (!targetElement->GetCurrentDoc()) {
// Bug 1245748: We don't support targets that are not in a document yet.
aRv.Throw(NS_ERROR_DOM_ANIM_TARGET_NOT_IN_DOC_ERR);
return nullptr;
}
InfallibleTArray<AnimationProperty> animationProperties;
BuildAnimationPropertyList(aGlobal.Context(), targetElement, pseudoType,
aFrames, animationProperties, aRv);
if (aRv.Failed()) {
return nullptr;
}
RefPtr<KeyframeEffectReadOnly> effect =
new KeyframeEffectReadOnly(targetElement->OwnerDoc(), targetElement,
pseudoType, aTiming);
effect->mProperties = Move(animationProperties);
return effect.forget();
}
void
KeyframeEffectReadOnly::GetTarget(
Nullable<OwningElementOrCSSPseudoElement>& aRv) const
@ -2091,5 +2118,27 @@ KeyframeEffectReadOnly::ShouldBlockCompositorAnimations(const nsIFrame*
return false;
}
//---------------------------------------------------------------------
//
// KeyframeEffect
//
//---------------------------------------------------------------------
KeyframeEffect::KeyframeEffect(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const TimingParams& aTiming)
: KeyframeEffectReadOnly(aDocument, aTarget, aPseudoType,
new AnimationEffectTiming(aTiming))
{
}
JSObject*
KeyframeEffect::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
{
return KeyframeEffectBinding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom
} // namespace mozilla

View File

@ -20,6 +20,7 @@
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/AnimationEffectReadOnly.h"
#include "mozilla/dom/AnimationEffectTiming.h"
#include "mozilla/dom/AnimationEffectTimingReadOnly.h" // TimingParams
#include "mozilla/dom/Element.h"
#include "mozilla/dom/KeyframeBinding.h"
@ -195,20 +196,11 @@ public:
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
ErrorResult& aRv)
{
return Constructor(aGlobal, aTarget, aFrames,
TimingParams::FromOptionsUnion(aOptions, aTarget),
aRv);
return ConstructKeyframeEffect<KeyframeEffectReadOnly>(
aGlobal, aTarget, aFrames,
TimingParams::FromOptionsUnion(aOptions, aTarget), aRv);
}
// More generalized version for Animatable.animate.
// Not exposed to content.
static already_AddRefed<KeyframeEffectReadOnly>
Constructor(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv);
void GetTarget(Nullable<OwningElementOrCSSPseudoElement>& aRv) const;
void GetFrames(JSContext*& aCx,
nsTArray<JSObject*>& aResult,
@ -328,7 +320,21 @@ public:
inline AnimationCollection* GetCollection() const;
protected:
KeyframeEffectReadOnly(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
AnimationEffectTimingReadOnly* aTiming);
virtual ~KeyframeEffectReadOnly();
template<typename KeyframeEffectType>
static already_AddRefed<KeyframeEffectType>
ConstructKeyframeEffect(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv);
void ResetIsRunningOnCompositor();
// This effect is registered with its target element so long as:
@ -384,6 +390,43 @@ private:
static const TimeDuration OverflowRegionRefreshInterval();
};
class KeyframeEffect : public KeyframeEffectReadOnly
{
public:
KeyframeEffect(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const TimingParams& aTiming);
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<KeyframeEffect>
Constructor(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
ErrorResult& aRv)
{
return ConstructKeyframeEffect<KeyframeEffect>(
aGlobal, aTarget, aFrames,
TimingParams::FromOptionsUnion(aOptions, aTarget), aRv);
}
// More generalized version for Animatable.animate.
// Not exposed to content.
static already_AddRefed<KeyframeEffect>
inline Constructor(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv)
{
return ConstructKeyframeEffect<KeyframeEffect>(aGlobal, aTarget, aFrames,
aTiming, aRv);
}
};
} // namespace dom
} // namespace mozilla

View File

@ -10,6 +10,7 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
EXPORTS.mozilla.dom += [
'Animation.h',
'AnimationEffectReadOnly.h',
'AnimationEffectTiming.h',
'AnimationEffectTimingReadOnly.h',
'AnimationTimeline.h',
'CSSPseudoElement.h',
@ -31,6 +32,7 @@ EXPORTS.mozilla += [
UNIFIED_SOURCES += [
'Animation.cpp',
'AnimationEffectReadOnly.cpp',
'AnimationEffectTiming.cpp',
'AnimationEffectTimingReadOnly.cpp',
'AnimationTimeline.cpp',
'AnimationUtils.cpp',

View File

@ -1004,7 +1004,8 @@ ParentRunnable::Run()
// Metadata is now open.
if (!SendOnOpenMetadataForRead(mMetadata)) {
Unused << Send__delete__(this, JS::AsmJSCache_InternalError);
Fail();
return NS_OK;
}
return NS_OK;
@ -1038,7 +1039,8 @@ ParentRunnable::Run()
FileDescriptor::PlatformHandleType handle =
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
if (!SendOnOpenCacheFile(mFileSize, FileDescriptor(handle))) {
Unused << Send__delete__(this, JS::AsmJSCache_InternalError);
Fail();
return NS_OK;
}
return NS_OK;

View File

@ -1547,7 +1547,7 @@ bool
Console::ProcessArguments(JSContext* aCx,
const Sequence<JS::Value>& aData,
Sequence<JS::Value>& aSequence,
Sequence<JS::Value>& aStyles) const
Sequence<nsString>& aStyles) const
{
AssertIsOnMainThread();
@ -1693,13 +1693,18 @@ Console::ProcessArguments(JSContext* aCx,
int32_t diff = aSequence.Length() - aStyles.Length();
if (diff > 0) {
for (int32_t i = 0; i < diff; i++) {
if (!aStyles.AppendElement(JS::NullValue(), fallible)) {
if (!aStyles.AppendElement(NullString(), fallible)) {
return false;
}
}
}
if (!aStyles.AppendElement(JS::StringValue(jsString), fallible)) {
nsAutoJSString string;
if (!string.init(aCx, jsString)) {
return false;
}
if (!aStyles.AppendElement(string, fallible)) {
return false;
}
}

View File

@ -169,7 +169,7 @@ private:
bool
ProcessArguments(JSContext* aCx, const Sequence<JS::Value>& aData,
Sequence<JS::Value>& aSequence,
Sequence<JS::Value>& aStyles) const;
Sequence<nsString>& aStyles) const;
void
MakeFormatString(nsCString& aFormat, int32_t aInteger, int32_t aMantissa,

View File

@ -918,7 +918,7 @@ already_AddRefed<DOMRect>
Element::GetBoundingClientRect()
{
RefPtr<DOMRect> rect = new DOMRect(this);
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
if (!frame) {
// display:none, perhaps? Return the empty rect
@ -1462,7 +1462,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
if (xulElem) {
xulElem->SetXULBindingParent(aBindingParent);
}
else
else
#endif
{
if (aBindingParent) {
@ -1522,7 +1522,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// XXXbz ordering issues here? Probably not, since ChangeDocumentFor is
// just pretty broken anyway.... Need to get it working.
// XXXbz XBL doesn't handle this (asserts), and we don't really want
// to be doing this during parsing anyway... sort this out.
// to be doing this during parsing anyway... sort this out.
// aDocument->BindingManager()->ChangeDocumentFor(this, nullptr,
// aDocument);
@ -1850,7 +1850,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
}
}
// This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,
// This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,
// because it has to happen after unsetting the parent pointer, but before
// recursively unbinding the kids.
if (IsHTMLElement()) {
@ -2542,7 +2542,7 @@ Element::GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const
return nsAttrInfo(nullptr, nullptr);
}
bool
Element::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
@ -2563,7 +2563,7 @@ Element::FindAttrValueIn(int32_t aNameSpaceID,
NS_ASSERTION(aName, "Must have attr name");
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
NS_ASSERTION(aValues, "Null value array");
const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
if (val) {
for (int32_t i = 0; aValues[i]; ++i) {
@ -2767,7 +2767,7 @@ Element::List(FILE* out, int32_t aIndent,
nsIContent* child = GetFirstChild();
if (child) {
fputs("\n", out);
for (; child; child = child->GetNextSibling()) {
child->List(out, aIndent + 1);
}
@ -2776,7 +2776,7 @@ Element::List(FILE* out, int32_t aIndent,
}
fputs(">\n", out);
Element* nonConstThis = const_cast<Element*>(this);
// XXX sXBL/XBL2 issue! Owner or current document?
@ -3341,9 +3341,8 @@ Element::Animate(JSContext* aContext,
Nullable<ElementOrCSSPseudoElement> target;
target.SetValue().SetAsElement() = this;
// Bug 1211783: Use KeyframeEffect here (instead of KeyframeEffectReadOnly)
RefPtr<KeyframeEffectReadOnly> effect =
KeyframeEffectReadOnly::Constructor(global, target, frames,
RefPtr<KeyframeEffect> effect =
KeyframeEffect::Constructor(global, target, frames,
TimingParams::FromOptionsUnion(aOptions, target), aError);
if (aError.Failed()) {
return nullptr;
@ -3525,7 +3524,7 @@ Element::InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
// Needed when insertAdjacentHTML is used in combination with contenteditable
mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
nsAutoScriptLoaderDisabler sld(doc);
// Batch possible DOMSubtreeModified events.
mozAutoSubtreeModified subtree(doc, nullptr);

View File

@ -2660,6 +2660,9 @@ nsDocument::ApplySettingsFromCSP(bool aSpeculative)
rv = csp->GetUpgradeInsecureRequests(&mUpgradeInsecureRequests);
NS_ENSURE_SUCCESS_VOID(rv);
}
if (!mUpgradeInsecurePreloads) {
mUpgradeInsecurePreloads = mUpgradeInsecureRequests;
}
}
return;
}

View File

@ -151,6 +151,34 @@ GetNextRangeCommonAncestor(nsINode* aNode)
return aNode;
}
/**
* A Comparator suitable for mozilla::BinarySearchIf for searching a collection
* of nsRange* for an overlap of (mNode, mStartOffset) .. (mNode, mEndOffset).
*/
struct IsItemInRangeComparator
{
nsINode* mNode;
uint32_t mStartOffset;
uint32_t mEndOffset;
int operator()(const nsRange* const aRange) const
{
int32_t cmp = nsContentUtils::ComparePoints(mNode, mEndOffset,
aRange->GetStartParent(),
aRange->StartOffset());
if (cmp == 1) {
cmp = nsContentUtils::ComparePoints(mNode, mStartOffset,
aRange->GetEndParent(),
aRange->EndOffset());
if (cmp == -1) {
return 0;
}
return 1;
}
return -1;
}
};
/* static */ bool
nsRange::IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
uint32_t aEndOffset)
@ -160,24 +188,45 @@ nsRange::IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
nsINode* n = GetNextRangeCommonAncestor(aNode);
NS_ASSERTION(n || !aNode->IsSelectionDescendant(),
"orphan selection descendant");
// Collect the potential ranges and their selection objects.
RangeHashTable ancestorSelectionRanges;
nsTHashtable<nsPtrHashKey<Selection>> ancestorSelections;
uint32_t maxRangeCount = 0;
for (; n; n = GetNextRangeCommonAncestor(n->GetParentNode())) {
RangeHashTable* ranges =
static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
for (auto iter = ranges->ConstIter(); !iter.Done(); iter.Next()) {
nsRange* range = iter.Get()->GetKey();
if (range->IsInSelection() && !range->Collapsed()) {
int32_t cmp = nsContentUtils::ComparePoints(aNode, aEndOffset,
range->GetStartParent(),
range->StartOffset());
if (cmp == 1) {
cmp = nsContentUtils::ComparePoints(aNode, aStartOffset,
range->GetEndParent(),
range->EndOffset());
if (cmp == -1) {
return true;
}
ancestorSelectionRanges.PutEntry(range);
Selection* selection = range->mSelection;
ancestorSelections.PutEntry(selection);
maxRangeCount = std::max(maxRangeCount, selection->RangeCount());
}
}
}
if (!ancestorSelectionRanges.IsEmpty()) {
nsTArray<const nsRange*> sortedRanges(maxRangeCount);
for (auto iter = ancestorSelections.ConstIter(); !iter.Done(); iter.Next()) {
Selection* selection = iter.Get()->GetKey();
// Sort the found ranges for |selection| in document order
// (Selection::GetRangeAt returns its ranges ordered).
for (uint32_t i = 0, len = selection->RangeCount(); i < len; ++i) {
nsRange* range = selection->GetRangeAt(i);
if (ancestorSelectionRanges.Contains(range)) {
sortedRanges.AppendElement(range);
}
}
MOZ_ASSERT(!sortedRanges.IsEmpty());
// Binary search the now sorted ranges.
IsItemInRangeComparator comparator = { aNode, aStartOffset, aEndOffset };
size_t unused;
if (mozilla::BinarySearchIf(sortedRanges, 0, sortedRanges.Length(), comparator, &unused)) {
return true;
}
sortedRanges.ClearAndRetainStorage();
}
}
return false;
@ -3105,6 +3154,12 @@ nsRange::Constructor(const GlobalObject& aGlobal,
return window->GetDoc()->CreateRange(aRv);
}
static bool ExcludeIfNextToNonSelectable(nsIContent* aContent)
{
return aContent->IsNodeOfType(nsINode::eTEXT) &&
aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE);
}
void
nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges)
{
@ -3123,6 +3178,10 @@ nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges)
bool added = false;
bool seenSelectable = false;
// |firstNonSelectableContent| is the first node in a consecutive sequence
// of non-IsSelectable nodes. When we find a selectable node after such
// a sequence we'll end the last nsRange, create a new one and restart
// the outer loop.
nsIContent* firstNonSelectableContent = nullptr;
while (true) {
ErrorResult err;
@ -3132,12 +3191,19 @@ nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges)
nsIContent* content =
node && node->IsContent() ? node->AsContent() : nullptr;
if (content) {
nsIFrame* frame = content->GetPrimaryFrame();
for (nsIContent* p = content; !frame && (p = p->GetParent()); ) {
frame = p->GetPrimaryFrame();
if (firstNonSelectableContent && ExcludeIfNextToNonSelectable(content)) {
// Ignorable whitespace next to a sequence of non-selectable nodes
// counts as non-selectable (bug 1216001).
selectable = false;
}
if (frame) {
frame->IsSelectable(&selectable, nullptr);
if (selectable) {
nsIFrame* frame = content->GetPrimaryFrame();
for (nsIContent* p = content; !frame && (p = p->GetParent()); ) {
frame = p->GetPrimaryFrame();
}
if (frame) {
frame->IsSelectable(&selectable, nullptr);
}
}
}

View File

@ -252,6 +252,14 @@ public:
bool *outNodeBefore,
bool *outNodeAfter);
/**
* Return true if any part of (aNode, aStartOffset) .. (aNode, aEndOffset)
* overlaps any nsRange in aNode's GetNextRangeCommonAncestor ranges (i.e.
* where aNode is a descendant of a range's common ancestor node).
* If a nsRange starts in (aNode, aEndOffset) or if it ends in
* (aNode, aStartOffset) then it is non-overlapping and the result is false
* for that nsRange. Collapsed ranges always counts as non-overlapping.
*/
static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
uint32_t aEndOffset);
@ -298,6 +306,14 @@ protected:
*/
nsINode* GetRegisteredCommonAncestor();
// Helper to IsNodeSelected.
static bool IsNodeInSortedRanges(nsINode* aNode,
uint32_t aStartOffset,
uint32_t aEndOffset,
const nsTArray<const nsRange*>& aRanges,
size_t aRangeStart,
size_t aRangeEnd);
struct MOZ_STACK_CLASS AutoInvalidateSelection
{
explicit AutoInvalidateSelection(nsRange* aRange) : mRange(aRange)

View File

@ -133,9 +133,15 @@ nsScreen::GetRect(nsRect& aRect)
}
context->GetRect(aRect);
LayoutDevicePoint screenTopLeftDev =
LayoutDevicePixel::FromAppUnits(aRect.TopLeft(),
context->AppUnitsPerDevPixel());
DesktopPoint screenTopLeftDesk =
screenTopLeftDev / context->GetDesktopToDeviceScale();
aRect.x = NSToIntRound(screenTopLeftDesk.x);
aRect.y = NSToIntRound(screenTopLeftDesk.y);
aRect.x = nsPresContext::AppUnitsToIntCSSPixels(aRect.x);
aRect.y = nsPresContext::AppUnitsToIntCSSPixels(aRect.y);
aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width);
@ -156,10 +162,21 @@ nsScreen::GetAvailRect(nsRect& aRect)
return NS_ERROR_FAILURE;
}
nsRect r;
context->GetRect(r);
LayoutDevicePoint screenTopLeftDev =
LayoutDevicePixel::FromAppUnits(r.TopLeft(),
context->AppUnitsPerDevPixel());
DesktopPoint screenTopLeftDesk =
screenTopLeftDev / context->GetDesktopToDeviceScale();
context->GetClientRect(aRect);
aRect.x = nsPresContext::AppUnitsToIntCSSPixels(aRect.x);
aRect.y = nsPresContext::AppUnitsToIntCSSPixels(aRect.y);
aRect.x = NSToIntRound(screenTopLeftDesk.x) +
nsPresContext::AppUnitsToIntCSSPixels(aRect.x - r.x);
aRect.y = NSToIntRound(screenTopLeftDesk.y) +
nsPresContext::AppUnitsToIntCSSPixels(aRect.y - r.y);
aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width);

View File

@ -12,7 +12,7 @@
src: url("Ahem.ttf");
}
body { font-family: Ahem; font-size: 20px; }
s { -moz-user-select: none; }
s, .non-selectable { -moz-user-select: none; }
n { display: none; }
a { position:absolute; bottom: 0; right:0; }
.text { -moz-user-select: text; }
@ -34,6 +34,16 @@ a { position:absolute; bottom: 0; right:0; }
<div id="testB"><n><s>aaaa</s>aaa</n>bbbbbbbbccccccc</div>
<div id="testC">aaaaaaabbbbbbbb<n>cc<s>c</s>cccc</n></div>
<div id="testE">aaa<s id="testEc1">aaaa<a class="text">bbbb</a>dd<a>cccc</a>ddddddd</s>eeee</div>
<div id="testF">aaaa
<div class="non-selectable">x</div>
<div class="non-selectable">x</div>
<div class="non-selectable">x</div>
bbbb</div>
<div id="testG" style="white-space:pre">aaaa
<div class="non-selectable">x</div>
<div class="non-selectable">x</div>
<div class="non-selectable">x</div>
bbbb</div>
<iframe id="testD" src="data:text/html,<body>aaaa<span style='-moz-user-select:none'>bbbb</span>cccc"></iframe>
@ -100,9 +110,11 @@ function test()
is(NL(r.toString()), text, e.id + ": range["+index+"].toString()")
}
function node(e, index)
function node(e, arg)
{
return index == -1 ? e : e.childNodes[index];
if (typeof arg == "number")
return arg == -1 ? e : e.childNodes[arg];
return arg;
}
function checkRangeCount(n, e)
@ -258,6 +270,22 @@ function test()
checkRanges([[0,1,-1,1]], e);
doneTest(e);
clear();
e = document.getElementById('testF');
synthesizeMouse(e, 1, 1, {});
synthesizeMouse(e, 400, 100, { shiftKey: true });
checkText("aaaa bbbb", e);
checkRanges([[0,0,-1,1],[6,0,6,5]], e);
doneTest(e);
clear();
e = document.getElementById('testG');
synthesizeMouse(e, 1, 1, {});
synthesizeMouse(e, 400, 180, { shiftKey: true });
checkText("aaaa bbbb", e); // XXX this doesn't seem right - bug 1247799
checkRanges([[0,0,-1,1],[2,0,-1,3],[4,0,-1,5],[6,0,6,5]], e);
doneTest(e);
// ======================================================
// ==================== Script tests ====================
// ======================================================

View File

@ -31,8 +31,9 @@ ENUM_ENTRY_VARIABLE_NAME = 'strings'
INSTANCE_RESERVED_SLOTS = 1
def memberReservedSlot(member):
return "(DOM_INSTANCE_RESERVED_SLOTS + %d)" % member.slotIndex
def memberReservedSlot(member, descriptor):
return ("(DOM_INSTANCE_RESERVED_SLOTS + %d)" %
member.slotIndices[descriptor.interface.identifier.name])
def toStringBool(arg):
@ -2149,7 +2150,7 @@ def clearableCachedAttrs(descriptor):
m.isAttr() and
# Constants should never need clearing!
m.dependsOn != "Nothing" and
m.slotIndex is not None)
m.slotIndices is not None)
def MakeClearCachedValueNativeName(member):
@ -3805,8 +3806,6 @@ class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
}
// Getter handled setting our reserved slots
""",
slot=memberReservedSlot(m),
interface=self.descriptor.interface.identifier.name,
member=m.identifier.name)
body += "\nreturn true;\n"
@ -3828,7 +3827,7 @@ class CGClearCachedValueMethod(CGAbstractMethod):
CGAbstractMethod.__init__(self, descriptor, name, returnType, args)
def definition_body(self):
slotIndex = memberReservedSlot(self.member)
slotIndex = memberReservedSlot(self.member, self.descriptor)
if self.member.getExtendedAttribute("StoreInSlot"):
# We have to root things and save the old value in case
# regetting fails, so we can restore it.
@ -7371,7 +7370,7 @@ class CGPerSignatureCall(CGThing):
"NewObject implies that we need to keep the object alive with a strong reference.");
""")
setSlot = self.idlNode.isAttr() and self.idlNode.slotIndex is not None
setSlot = self.idlNode.isAttr() and self.idlNode.slotIndices is not None
if setSlot:
# For attributes in slots, we want to do some
# post-processing once we've wrapped them.
@ -7418,7 +7417,7 @@ class CGPerSignatureCall(CGThing):
"args.rval().isObject()")
postSteps += freezeValue.define()
postSteps += ("js::SetReservedSlot(reflector, %s, args.rval());\n" %
memberReservedSlot(self.idlNode))
memberReservedSlot(self.idlNode, self.descriptor))
# For the case of Cached attributes, go ahead and preserve our
# wrapper if needed. We need to do this because otherwise the
# wrapper could get garbage-collected and the cached value would
@ -8003,7 +8002,7 @@ class CGSetterCall(CGPerSignatureCall):
def wrap_return_value(self):
attr = self.idlNode
if self.descriptor.wrapperCache and attr.slotIndex is not None:
if self.descriptor.wrapperCache and attr.slotIndices is not None:
if attr.getExtendedAttribute("StoreInSlot"):
args = "cx, self"
else:
@ -8550,7 +8549,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
self.attr)
if self.attr.slotIndex is not None:
if self.attr.slotIndices is not None:
if self.descriptor.hasXPConnectImpls:
raise TypeError("Interface '%s' has XPConnect impls, so we "
"can't use our slot for property '%s'!" %
@ -8576,7 +8575,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
}
""",
slot=memberReservedSlot(self.attr),
slot=memberReservedSlot(self.attr, self.descriptor),
maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))
else:
prefix = ""
@ -8827,10 +8826,13 @@ class CGMemberJITInfo(CGThing):
slotIndex=slotIndex)
return initializer.rstrip()
slotAssert = dedent(
slotAssert = fill(
"""
static_assert(%s <= JSJitInfo::maxSlotIndex, "We won't fit");
""" % slotIndex)
static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
""",
slotIndex=slotIndex,
classReservedSlots=INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots)
if args is not None:
argTypes = "%s_argTypes" % infoName
args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
@ -8878,10 +8880,10 @@ class CGMemberJITInfo(CGThing):
getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
if self.member.slotIndex is not None:
if self.member.slotIndices is not None:
assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
isLazilyCachedInSlot = not isAlwaysInSlot
slotIndex = memberReservedSlot(self.member)
slotIndex = memberReservedSlot(self.member, self.descriptor)
# We'll statically assert that this is not too big in
# CGUpdateMemberSlotsMethod, in the case when
# isAlwaysInSlot is true.
@ -15328,7 +15330,7 @@ def getMaplikeOrSetlikeBackingObject(descriptor, maplikeOrSetlike, helperImpl=No
PreserveWrapper<${selfType}>(self);
}
""",
slot=memberReservedSlot(maplikeOrSetlike),
slot=memberReservedSlot(maplikeOrSetlike, descriptor),
func_prefix=func_prefix,
errorReturn=getMaplikeOrSetlikeErrorReturn(helperImpl),
selfType=descriptor.nativeType)

View File

@ -978,7 +978,9 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
(member.getExtendedAttribute("StoreInSlot") or
member.getExtendedAttribute("Cached"))) or
member.isMaplikeOrSetlike()):
member.slotIndex = self.totalMembersInSlots
if member.slotIndices is None:
member.slotIndices = dict()
member.slotIndices[self.identifier.name] = self.totalMembersInSlots
self.totalMembersInSlots += 1
if member.getExtendedAttribute("StoreInSlot"):
self._ownMembersInSlots += 1
@ -3599,7 +3601,7 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, maplikeOrSetlikeType,
keyType, valueType, IDLInterfaceMember.Tags.MaplikeOrSetlike)
self.readonly = readonly
self.slotIndex = None
self.slotIndices = None
# When generating JSAPI access code, we need to know the backing object
# type prefix to create the correct function. Generate here for reuse.
@ -3793,7 +3795,7 @@ class IDLAttribute(IDLInterfaceMember):
self.stringifier = stringifier
self.enforceRange = False
self.clamp = False
self.slotIndex = None
self.slotIndices = None
assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike)
self.maplikeOrSetlike = maplikeOrSetlike
self.dependsOn = "Everything"

View File

@ -1570,9 +1570,7 @@ CanvasRenderingContext2D::ReturnTarget()
{
if (mTarget && mBufferProvider) {
CurrentState().transform = mTarget->GetTransform();
DrawTarget* oldDT = mTarget;
mTarget = nullptr;
mBufferProvider->ReturnAndUseDT(oldDT);
mBufferProvider->ReturnAndUseDT(mTarget.forget());
}
}
@ -4916,6 +4914,9 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& aWindow, double aX,
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
Unused << shell->RenderDocument(r, renderDocFlags, backgroundColor, thebes);
// If this canvas was contained in the drawn window, the pre-transaction callback
// may have returned its DT. If so, we must reacquire it here.
EnsureTarget();
if (drawDT) {
RefPtr<SourceSurface> snapshot = drawDT->Snapshot();
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();

View File

@ -20,28 +20,33 @@ GetFBInfoForBlit(const WebGLFramebuffer* fb, const char* const fbInfo,
const webgl::FormatInfo** const out_depthFormat,
const webgl::FormatInfo** const out_stencilFormat)
{
*out_samples = 1; // TODO
*out_samples = 0;
*out_colorFormat = nullptr;
*out_depthFormat = nullptr;
*out_stencilFormat = nullptr;
if (fb->ColorAttachment(0).IsDefined()) {
const auto& attachment = fb->ColorAttachment(0);
*out_samples = attachment.Samples();
*out_colorFormat = attachment.Format()->format;
}
if (fb->DepthStencilAttachment().IsDefined()) {
const auto& attachment = fb->DepthStencilAttachment();
*out_samples = attachment.Samples();
*out_depthFormat = attachment.Format()->format;
*out_stencilFormat = *out_depthFormat;
} else {
if (fb->DepthAttachment().IsDefined()) {
const auto& attachment = fb->DepthAttachment();
*out_samples = attachment.Samples();
*out_depthFormat = attachment.Format()->format;
}
if (fb->StencilAttachment().IsDefined()) {
const auto& attachment = fb->StencilAttachment();
*out_samples = attachment.Samples();
*out_stencilFormat = attachment.Format()->format;
}
}
@ -133,7 +138,7 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
return;
}
} else {
srcSamples = 1; // Always 1.
srcSamples = 0; // Always 0.
GetBackbufferFormats(mOptions, &srcColorFormat, &srcDepthFormat,
&srcStencilFormat);
@ -221,13 +226,13 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
return;
}
if (dstSamples != 1) {
if (dstSamples != 0) {
ErrorInvalidOperation("blitFramebuffer: DRAW_FRAMEBUFFER may not have"
" multiple samples.");
return;
}
if (srcSamples != 1) {
if (srcSamples != 0) {
if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
dstColorFormat != srcColorFormat)
{

View File

@ -15,43 +15,45 @@ void
WebGL2Context::GetInternalformatParameter(JSContext* cx, GLenum target,
GLenum internalformat, GLenum pname,
JS::MutableHandleValue retval,
ErrorResult& rv)
ErrorResult& out_rv)
{
if (IsContextLost())
return;
const char funcName[] = "getInternalfomratParameter";
if (IsContextLost())
return;
if (target != LOCAL_GL_RENDERBUFFER) {
return ErrorInvalidEnumInfo("getInternalfomratParameter: target must be "
"RENDERBUFFER. Was:", target);
}
if (target != LOCAL_GL_RENDERBUFFER) {
ErrorInvalidEnum("%s: `target` must be RENDERBUFFER, was: 0x%04x.", funcName,
target);
return;
}
// GL_INVALID_ENUM is generated if internalformat is not color-,
// depth-, or stencil-renderable.
// TODO: When format table queries lands.
// GL_INVALID_ENUM is generated if internalformat is not color-, depth-, or
// stencil-renderable.
// TODO: When format table queries lands.
if (pname != LOCAL_GL_SAMPLES) {
return ErrorInvalidEnumInfo("getInternalformatParameter: pname must be SAMPLES. "
"Was:", pname);
}
if (pname != LOCAL_GL_SAMPLES) {
ErrorInvalidEnumInfo("%s: `pname` must be SAMPLES, was 0x%04x.", funcName, pname);
return;
}
GLint* samples = nullptr;
GLint sampleCount = 0;
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat,
LOCAL_GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
if (sampleCount > 0) {
samples = new GLint[sampleCount];
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, LOCAL_GL_SAMPLES,
sampleCount, samples);
}
GLint* samples = nullptr;
GLint sampleCount = 0;
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat,
LOCAL_GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
if (sampleCount > 0) {
samples = new GLint[sampleCount];
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, LOCAL_GL_SAMPLES,
sampleCount, samples);
}
JSObject* obj = dom::Int32Array::Create(cx, this, sampleCount, samples);
if (!obj) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
JSObject* obj = dom::Int32Array::Create(cx, this, sampleCount, samples);
if (!obj) {
out_rv = NS_ERROR_OUT_OF_MEMORY;
}
delete[] samples;
delete[] samples;
retval.setObjectOrNull(obj);
retval.setObjectOrNull(obj);
}
void
@ -59,14 +61,11 @@ WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
GLenum internalFormat,
GLsizei width, GLsizei height)
{
const char funcName[] = "renderbufferStorageMultisample";
if (IsContextLost())
return;
const char funcName[] = "renderbufferStorageMultisample";
if (IsContextLost())
return;
//RenderbufferStorage_base(funcName, target, samples, internalFormat, width, height);
ErrorInvalidOperation("%s: Multisampling is still under development, and is currently"
" disabled.", funcName);
RenderbufferStorage_base(funcName, target, samples, internalFormat, width, height);
}
} // namespace mozilla

View File

@ -106,7 +106,6 @@ WebGLContext::WebGLContext()
, mMaxFetchedVertices(0)
, mMaxFetchedInstances(0)
, mBypassShaderValidation(false)
, mGLMaxSamples(1)
, mNeedsFakeNoAlpha(false)
, mNeedsFakeNoDepth(false)
, mNeedsFakeNoStencil(false)

View File

@ -1114,7 +1114,6 @@ protected:
int32_t mGLMaxVertexUniformVectors;
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
GLuint mGLMaxUniformBufferBindings;
GLsizei mGLMaxSamples;
// What is supported:
uint32_t mGLMaxColorAttachments;

View File

@ -173,17 +173,13 @@ WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb)
if (wrb && wrb->IsDeleted())
return;
MakeContextCurrent();
// Usually, we would now call into glBindRenderbuffer. However, since we have to
// potentially emulate packed-depth-stencil, there's not a specific renderbuffer that
// we know we should bind here.
// Instead, we do all renderbuffer binding lazily.
// Sometimes we emulate renderbuffers (depth-stencil emu), so there's not
// always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it.
if (wrb) {
wrb->BindRenderbuffer();
#ifdef ANDROID
wrb->mIsRB = true;
#endif
} else {
gl->fBindRenderbuffer(target, 0);
wrb->mHasBeenBound = true;
}
mBoundRenderbuffer = wrb;
@ -1068,16 +1064,7 @@ WebGLContext::IsRenderbuffer(WebGLRenderbuffer* rb)
if (rb->IsDeleted())
return false;
#ifdef ANDROID
if (gl->WorkAroundDriverBugs() &&
gl->Renderer() == GLRenderer::AndroidEmulator)
{
return rb->mIsRB;
}
#endif
MakeContextCurrent();
return gl->fIsRenderbuffer(rb->PrimaryGLName());
return rb->mHasBeenBound;
}
bool
@ -1799,66 +1786,41 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
void
WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target,
GLsizei samples,
GLenum internalFormat, GLsizei width,
GLsizei height)
GLsizei samples, GLenum internalFormat,
GLsizei width, GLsizei height)
{
if (IsContextLost())
return;
if (!mBoundRenderbuffer) {
ErrorInvalidOperation("%s: Called on renderbuffer 0.", funcName);
return;
}
if (target != LOCAL_GL_RENDERBUFFER) {
ErrorInvalidEnumInfo("`target`", funcName, target);
return;
}
if (samples < 0 || samples > mGLMaxSamples) {
ErrorInvalidValue("%s: `samples` is out of the valid range.", funcName);
if (!mBoundRenderbuffer) {
ErrorInvalidOperation("%s: Called on renderbuffer 0.", funcName);
return;
}
if (samples < 0) {
ErrorInvalidValue("%s: `samples` must be >= 0.", funcName);
return;
}
if (width < 0 || height < 0) {
ErrorInvalidValue("%s: Width and height must be >= 0.", funcName);
ErrorInvalidValue("%s: `width` and `height` must be >= 0.", funcName);
return;
}
if (uint32_t(width) > mImplMaxRenderbufferSize ||
uint32_t(height) > mImplMaxRenderbufferSize)
{
ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
" size.", funcName);
return;
}
const auto usage = mFormatUsage->GetRBUsage(internalFormat);
if (!usage) {
ErrorInvalidEnumInfo("`internalFormat`", funcName, internalFormat);
return;
}
// Validation complete.
MakeContextCurrent();
GetAndFlushUnderlyingGLErrors();
mBoundRenderbuffer->RenderbufferStorage(samples, usage, width, height);
GLenum error = GetAndFlushUnderlyingGLErrors();
if (error) {
GenerateWarning("%s generated error %s", funcName,
ErrorName(error));
return;
}
mBoundRenderbuffer->RenderbufferStorage(funcName, uint32_t(samples), internalFormat,
uint32_t(width), uint32_t(height));
}
void
WebGLContext::RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
{
RenderbufferStorage_base("renderbufferStorage", target, 0,
internalFormat, width, height);
RenderbufferStorage_base("renderbufferStorage", target, 0, internalFormat, width,
height);
}
void
@ -2323,6 +2285,8 @@ WebGLContext::CreateRenderbuffer()
{
if (IsContextLost())
return nullptr;
MakeContextCurrent();
RefPtr<WebGLRenderbuffer> globj = new WebGLRenderbuffer(this);
return globj.forget();
}

View File

@ -727,6 +727,8 @@ WebGLContext::AssertCachedBindings()
MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
#endif
// We do not check the renderbuffer binding, because we never rely on it matching.
}
void

View File

@ -786,8 +786,6 @@ WebGLContext::InitAndValidateGL()
mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
mGLMaxSamples = 1;
} else {
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*)&mImplMaxTextureSize);
gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&mImplMaxCubeMapTextureSize);
@ -800,9 +798,6 @@ WebGLContext::InitAndValidateGL()
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
if (!gl->GetPotentialInteger(LOCAL_GL_MAX_SAMPLES, (GLint*)&mGLMaxSamples))
mGLMaxSamples = 1;
}
// If we don't support a target, its max size is 0. We should only floor-to-POT if the

View File

@ -416,8 +416,6 @@ BytesPerPixel(const PackingInfo& packing)
//////////////////////////////////////////////////////////////////////////////////////////
// FormatUsageAuthority
bool
FormatUsageInfo::IsUnpackValid(const PackingInfo& key,
const DriverUnpackInfo** const out_value) const
@ -430,6 +428,29 @@ FormatUsageInfo::IsUnpackValid(const PackingInfo& key,
return true;
}
void
FormatUsageInfo::ResolveMaxSamples(gl::GLContext* gl)
{
MOZ_ASSERT(!this->maxSamplesKnown);
MOZ_ASSERT(this->maxSamples == 0);
MOZ_ASSERT(gl->IsCurrent());
this->maxSamplesKnown = true;
const GLenum internalFormat = this->format->sizedFormat;
if (!internalFormat)
return;
if (!gl->IsSupported(gl::GLFeature::internalformat_query))
return; // Leave it at 0.
GLint maxSamplesGL = 0;
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalFormat, LOCAL_GL_SAMPLES, 1,
&maxSamplesGL);
this->maxSamples = maxSamplesGL;
}
////////////////////////////////////////
static void

View File

@ -248,10 +248,15 @@ struct FormatUsageInfo
const FormatInfo* const format;
bool isRenderable;
bool isFilterable;
std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
const DriverUnpackInfo* idealUnpack;
const GLint* textureSwizzleRGBA;
bool maxSamplesKnown;
uint32_t maxSamples;
static const GLint kLuminanceSwizzleRGBA[4];
static const GLint kAlphaSwizzleRGBA[4];
static const GLint kLumAlphaSwizzleRGBA[4];
@ -262,10 +267,14 @@ struct FormatUsageInfo
, isFilterable(false)
, idealUnpack(nullptr)
, textureSwizzleRGBA(nullptr)
, maxSamplesKnown(false)
, maxSamples(0)
{ }
bool IsUnpackValid(const PackingInfo& key,
const DriverUnpackInfo** const out_value) const;
void ResolveMaxSamples(gl::GLContext* gl);
};
class FormatUsageAuthority

View File

@ -69,6 +69,17 @@ WebGLFBAttachPoint::Format() const
return nullptr;
}
uint32_t
WebGLFBAttachPoint::Samples() const
{
MOZ_ASSERT(IsDefined());
if (mRenderbufferPtr)
return mRenderbufferPtr->Samples();
return 0;
}
bool
WebGLFBAttachPoint::HasAlpha() const
{
@ -394,11 +405,11 @@ WebGLFBAttachPoint::FinalizeAttachment(gl::GLContext* gl, GLenum attachment) con
}
break;
}
return ;
return;
}
if (Renderbuffer()) {
Renderbuffer()->FramebufferRenderbuffer(attachment);
Renderbuffer()->DoFramebufferRenderbuffer(attachment);
return;
}
@ -790,28 +801,6 @@ WebGLFramebuffer::HasIncompleteAttachments(nsCString* const out_info) const
return hasIncomplete;
}
static bool
MatchOrReplaceSize(const WebGLFBAttachPoint& cur, uint32_t* const out_width,
uint32_t* const out_height)
{
if (!cur.HasImage())
return true;
uint32_t width;
uint32_t height;
cur.Size(&width, &height);
if (!*out_width) {
MOZ_ASSERT(!*out_height);
*out_width = width;
*out_height = height;
return true;
}
return (width == *out_width &&
height == *out_height);
}
bool
WebGLFramebuffer::AllImageRectsMatch() const
{
@ -819,20 +808,84 @@ WebGLFramebuffer::AllImageRectsMatch() const
DebugOnly<nsCString> fbStatusInfo;
MOZ_ASSERT(!HasIncompleteAttachments(&fbStatusInfo));
bool needsInit = true;
uint32_t width = 0;
uint32_t height = 0;
bool imageRectsMatch = true;
imageRectsMatch &= MatchOrReplaceSize(mColorAttachment0, &width, &height);
imageRectsMatch &= MatchOrReplaceSize(mDepthAttachment, &width, &height);
imageRectsMatch &= MatchOrReplaceSize(mStencilAttachment, &width, &height);
imageRectsMatch &= MatchOrReplaceSize(mDepthStencilAttachment, &width, &height);
const auto fnInitializeOrMatch = [&needsInit, &width,
&height](const WebGLFBAttachPoint& attach)
{
if (!attach.HasImage())
return true;
uint32_t curWidth;
uint32_t curHeight;
attach.Size(&curWidth, &curHeight);
if (needsInit) {
needsInit = false;
width = curWidth;
height = curHeight;
return true;
}
return (curWidth == width &&
curHeight == height);
};
bool matches = true;
matches &= fnInitializeOrMatch(mColorAttachment0 );
matches &= fnInitializeOrMatch(mDepthAttachment );
matches &= fnInitializeOrMatch(mStencilAttachment );
matches &= fnInitializeOrMatch(mDepthStencilAttachment);
for (const auto& cur : mMoreColorAttachments) {
imageRectsMatch &= MatchOrReplaceSize(cur, &width, &height);
matches &= fnInitializeOrMatch(cur);
}
return imageRectsMatch;
return matches;
}
bool
WebGLFramebuffer::AllImageSamplesMatch() const
{
MOZ_ASSERT(HasDefinedAttachments());
DebugOnly<nsCString> fbStatusInfo;
MOZ_ASSERT(!HasIncompleteAttachments(&fbStatusInfo));
bool needsInit = true;
uint32_t samples = 0;
const auto fnInitializeOrMatch = [&needsInit,
&samples](const WebGLFBAttachPoint& attach)
{
if (!attach.HasImage())
return true;
const uint32_t curSamples = attach.Samples();
if (needsInit) {
needsInit = false;
samples = curSamples;
return true;
}
return (curSamples == samples);
};
bool matches = true;
matches &= fnInitializeOrMatch(mColorAttachment0 );
matches &= fnInitializeOrMatch(mDepthAttachment );
matches &= fnInitializeOrMatch(mStencilAttachment );
matches &= fnInitializeOrMatch(mDepthStencilAttachment);
for (const auto& cur : mMoreColorAttachments) {
matches &= fnInitializeOrMatch(cur);
}
return matches;
}
FBStatus
@ -850,7 +903,11 @@ WebGLFramebuffer::PrecheckFramebufferStatus(nsCString* const out_info) const
if (!AllImageRectsMatch())
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // Inconsistent sizes
if (!AllImageSamplesMatch())
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; // Inconsistent samples
if (!mContext->IsWebGL2()) {
// INCOMPLETE_DIMENSIONS doesn't exist in GLES3.
const auto depthOrStencilCount = int(mDepthAttachment.IsDefined()) +
int(mStencilAttachment.IsDefined()) +
int(mDepthStencilAttachment.IsDefined());

View File

@ -49,7 +49,6 @@ private:
, mAttachmentPoint(0)
{ }
public:
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
~WebGLFBAttachPoint();
@ -60,6 +59,7 @@ public:
bool IsDeleteRequested() const;
const webgl::FormatUsageInfo* Format() const;
uint32_t Samples() const;
bool HasAlpha() const;
bool IsReadableFloat() const;
@ -98,7 +98,6 @@ public:
void SetImageDataStatus(WebGLImageDataStatus x);
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
//const WebGLRectangleObject& RectangleObject() const;
bool HasImage() const;
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
@ -229,6 +228,7 @@ public:
bool HasDefinedAttachments() const;
bool HasIncompleteAttachments(nsCString* const out_info) const;
bool AllImageRectsMatch() const;
bool AllImageSamplesMatch() const;
FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
FBStatus CheckFramebufferStatus(nsCString* const out_info) const;

View File

@ -15,7 +15,7 @@
namespace mozilla {
static GLenum
DepthStencilDepthFormat(gl::GLContext* gl)
DepthFormatForDepthStencilEmu(gl::GLContext* gl)
{
// We might not be able to get 24-bit, so let's pretend!
if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
@ -24,46 +24,38 @@ DepthStencilDepthFormat(gl::GLContext* gl)
return LOCAL_GL_DEPTH_COMPONENT24;
}
static bool
NeedsDepthStencilEmu(gl::GLContext* gl, GLenum internalFormat)
{
MOZ_ASSERT(internalFormat != LOCAL_GL_DEPTH_STENCIL);
if (internalFormat != LOCAL_GL_DEPTH24_STENCIL8)
return false;
if (gl->IsSupported(gl::GLFeature::packed_depth_stencil))
return false;
return true;
}
JSObject*
WebGLRenderbuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLRenderbufferBinding::Wrap(cx, this, givenProto);
}
static GLuint
DoCreateRenderbuffer(gl::GLContext* gl)
{
MOZ_ASSERT(gl->IsCurrent());
GLuint ret = 0;
gl->fGenRenderbuffers(1, &ret);
return ret;
}
static bool
EmulatePackedDepthStencil(gl::GLContext* gl)
{
return !gl->IsSupported(gl::GLFeature::packed_depth_stencil);
}
WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
: WebGLContextBoundObject(webgl)
, mPrimaryRB(0)
, mPrimaryRB( DoCreateRenderbuffer(webgl->gl) )
, mEmulatePackedDepthStencil( EmulatePackedDepthStencil(webgl->gl) )
, mSecondaryRB(0)
, mFormat(nullptr)
, mSamples(0)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
, mSamples(1)
, mIsUsingSecondary(false)
#ifdef ANDROID
, mIsRB(false)
#endif
, mHasBeenBound(false)
{
mContext->MakeContextCurrent();
mContext->gl->fGenRenderbuffers(1, &mPrimaryRB);
if (!mContext->gl->IsSupported(gl::GLFeature::packed_depth_stencil)) {
mContext->gl->fGenRenderbuffers(1, &mSecondaryRB);
}
mContext->mRenderbuffers.insertBack(this);
}
@ -77,9 +69,6 @@ WebGLRenderbuffer::Delete()
mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
#ifdef ANDROID
mIsRB = false;
#endif
}
int64_t
@ -89,156 +78,173 @@ WebGLRenderbuffer::MemoryUsage() const
if (!mFormat)
return 0;
auto bytesPerPixel = mFormat->format->estimatedBytesPerPixel;
uint64_t pixels = uint64_t(mWidth) * uint64_t(mHeight);
const auto bytesPerPixel = mFormat->format->estimatedBytesPerPixel;
const int64_t pixels = int64_t(mWidth) * int64_t(mHeight);
uint64_t totalSize = pixels * bytesPerPixel;
// If we have the same bytesPerPixel whether or not we have a secondary RB.
if (mSecondaryRB && !mIsUsingSecondary) {
totalSize += 2; // 1x1xRGBA4
}
return int64_t(totalSize);
const int64_t totalSize = pixels * bytesPerPixel;
return totalSize;
}
void
WebGLRenderbuffer::BindRenderbuffer() const
{
/* Do this explicitly here, since the meaning changes for depth-stencil emu.
* Under normal circumstances, there's only one RB: `mPrimaryRB`.
* `mSecondaryRB` is used when we have to pretend that the renderbuffer is
* DEPTH_STENCIL, when it's actually one DEPTH buffer `mPrimaryRB` and one
* STENCIL buffer `mSecondaryRB`.
*
* In the DEPTH_STENCIL emulation case, we're actually juggling two RBs, but
* we can only bind one of them at a time. We choose to unconditionally bind
* the depth RB. When we need to ask about the stencil buffer (say, how many
* stencil bits we have), we temporarily bind the stencil RB, so that it
* looks like we're just asking the question of a combined DEPTH_STENCIL
* buffer.
*/
mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
}
static void
RenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
GLenum internalFormat, GLsizei width,
GLsizei height)
static GLenum
DoRenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
GLenum internalFormat, GLsizei width,
GLsizei height)
{
MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample));
MOZ_ASSERT(samples >= 0);
MOZ_ASSERT(samples <= gl->MaxSamples());
// certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
GLenum internalFormatForGL = internalFormat;
// Certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL.
switch (internalFormat) {
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
// 16-bit RGBA formats are not supported on desktop GL
// 16-bit RGBA formats are not supported on desktop GL.
if (!gl->IsGLES())
internalFormatForGL = LOCAL_GL_RGBA8;
internalFormat = LOCAL_GL_RGBA8;
break;
case LOCAL_GL_RGB565:
// the RGB565 format is not supported on desktop GL
// RGB565 is not supported on desktop GL.
if (!gl->IsGLES())
internalFormatForGL = LOCAL_GL_RGB8;
internalFormat = LOCAL_GL_RGB8;
break;
case LOCAL_GL_DEPTH_COMPONENT16:
if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
internalFormatForGL = LOCAL_GL_DEPTH_COMPONENT24;
internalFormat = LOCAL_GL_DEPTH_COMPONENT24;
else if (gl->IsSupported(gl::GLFeature::packed_depth_stencil))
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
break;
case LOCAL_GL_DEPTH_STENCIL:
// We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
MOZ_CRASH("GL_DEPTH_STENCIL is not valid here.");
break;
default:
break;
}
gl::GLContext::LocalErrorScope errorScope(*gl);
if (samples > 0) {
gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
internalFormatForGL, width, height);
internalFormat, width, height);
} else {
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormatForGL, width,
height);
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width, height);
}
return errorScope.GetError();
}
void
WebGLRenderbuffer::RenderbufferStorage(GLsizei samples,
const webgl::FormatUsageInfo* format,
GLsizei width, GLsizei height)
GLenum
WebGLRenderbuffer::DoRenderbufferStorage(uint32_t samples,
const webgl::FormatUsageInfo* format,
uint32_t width, uint32_t height)
{
MOZ_ASSERT(mContext->mBoundRenderbuffer == this);
gl::GLContext* gl = mContext->gl;
MOZ_ASSERT(samples >= 0 && samples <= 256); // Sanity check.
MOZ_ASSERT(samples <= 256); // Sanity check.
GLenum primaryFormat = format->format->sizedFormat;
GLenum secondaryFormat = 0;
if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
primaryFormat = DepthStencilDepthFormat(gl);
if (mEmulatePackedDepthStencil && primaryFormat == LOCAL_GL_DEPTH24_STENCIL8) {
primaryFormat = DepthFormatForDepthStencilEmu(gl);
secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
}
RenderbufferStorageMaybeMultisample(gl, samples, primaryFormat, width,
height);
gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
GLenum error = DoRenderbufferStorageMaybeMultisample(gl, samples, primaryFormat,
width, height);
if (error)
return error;
if (mSecondaryRB) {
// We can't leave the secondary RB unspecified either, since we should
// handle the case where we attach a non-depth-stencil RB to a
// depth-stencil attachment point, or attach this depth-stencil RB to a
// non-depth-stencil attachment point.
gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
if (secondaryFormat) {
RenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat, width,
height);
} else {
RenderbufferStorageMaybeMultisample(gl, samples, LOCAL_GL_RGBA4, 1, 1);
if (secondaryFormat) {
if (!mSecondaryRB) {
gl->fGenRenderbuffers(1, &mSecondaryRB);
}
gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mSecondaryRB);
error = DoRenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat,
width, height);
if (error)
return error;
} else if (mSecondaryRB) {
gl->fDeleteRenderbuffers(1, &mSecondaryRB);
mSecondaryRB = 0;
}
return 0;
}
void
WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
GLenum internalFormat, uint32_t width,
uint32_t height)
{
const auto usage = mContext->mFormatUsage->GetRBUsage(internalFormat);
if (!usage) {
mContext->ErrorInvalidEnum("%s: Invalid `internalFormat`: 0x%04x.", funcName,
internalFormat);
return;
}
if (width > mContext->mImplMaxRenderbufferSize ||
height > mContext->mImplMaxRenderbufferSize)
{
mContext->ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
" size.",
funcName);
return;
}
mContext->MakeContextCurrent();
if (!usage->maxSamplesKnown) {
const_cast<webgl::FormatUsageInfo*>(usage)->ResolveMaxSamples(mContext->gl);
}
MOZ_ASSERT(usage->maxSamplesKnown);
if (samples > usage->maxSamples) {
mContext->ErrorInvalidValue("%s: `samples` is out of the valid range.", funcName);
return;
}
// Validation complete.
const GLenum error = DoRenderbufferStorage(samples, usage, width, height);
if (error) {
const char* errorName = mContext->ErrorName(error);
mContext->GenerateWarning("%s generated error %s", funcName, errorName);
return;
}
mSamples = samples;
mFormat = format;
mFormat = usage;
mWidth = width;
mHeight = height;
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
mIsUsingSecondary = bool(secondaryFormat);
InvalidateStatusOfAttachedFBs();
}
void
WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment) const
WebGLRenderbuffer::DoFramebufferRenderbuffer(GLenum attachment) const
{
gl::GLContext* gl = mContext->gl;
if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_DEPTH_ATTACHMENT,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_STENCIL_ATTACHMENT,
LOCAL_GL_RENDERBUFFER, stencilRB);
return;
}
GLuint stencilRB = mPrimaryRB;
if (mIsUsingSecondary) {
MOZ_ASSERT(mSecondaryRB);
stencilRB = mSecondaryRB;
}
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_DEPTH_ATTACHMENT,
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_STENCIL_ATTACHMENT,
LOCAL_GL_RENDERBUFFER, stencilRB);
}
GLint
@ -266,6 +272,7 @@ WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
{
gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
GLint i = 0;
gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
return i;
@ -285,8 +292,7 @@ WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
}
}
MOZ_ASSERT(false,
"This function should only be called with valid `pname`.");
MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
return 0;
}

View File

@ -26,7 +26,26 @@ class WebGLRenderbuffer final
, public WebGLContextBoundObject
, public WebGLFramebufferAttachable
{
friend class WebGLContext;
friend class WebGLFramebuffer;
friend class WebGLFBAttachPoint;
public:
const GLuint mPrimaryRB;
protected:
const bool mEmulatePackedDepthStencil;
GLuint mSecondaryRB;
const webgl::FormatUsageInfo* mFormat;
GLsizei mSamples;
WebGLImageDataStatus mImageDataStatus;
bool mHasBeenBound;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
explicit WebGLRenderbuffer(WebGLContext* webgl);
void Delete();
@ -46,8 +65,6 @@ public:
GLsizei Samples() const { return mSamples; }
GLuint PrimaryGLName() const { return mPrimaryRB; }
const webgl::FormatUsageInfo* Format() const { return mFormat; }
int64_t MemoryUsage() const;
@ -56,41 +73,21 @@ public:
return mContext;
}
void BindRenderbuffer() const;
void RenderbufferStorage(GLsizei samples, const webgl::FormatUsageInfo* format,
GLsizei width, GLsizei height);
void FramebufferRenderbuffer(GLenum attachment) const;
void RenderbufferStorage(const char* funcName, uint32_t samples,
GLenum internalFormat, uint32_t width, uint32_t height);
// Only handles a subset of `pname`s.
GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
protected:
~WebGLRenderbuffer() {
DeleteOnce();
}
GLuint mPrimaryRB;
GLuint mSecondaryRB;
const webgl::FormatUsageInfo* mFormat;
WebGLImageDataStatus mImageDataStatus;
GLsizei mSamples;
bool mIsUsingSecondary;
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
// give reasonable answers for IsRenderbuffer, maybe others.
// This shows up on Android 2.3 emulator.
//
// So we track the `is a Renderbuffer` state ourselves.
bool mIsRB;
#endif
friend class WebGLContext;
friend class WebGLFramebuffer;
friend class WebGLFBAttachPoint;
void DoFramebufferRenderbuffer(GLenum attachment) const;
GLenum DoRenderbufferStorage(uint32_t samples, const webgl::FormatUsageInfo* format,
uint32_t width, uint32_t height);
};
} // namespace mozilla

View File

@ -0,0 +1,15 @@
<html>
<head>
<script>
function boom()
{
var canvas = document.getElementById("canvas");
var ctx = SpecialPowers.wrap(canvas.getContext("2d"));
ctx.drawWindow(window, 0, 0, canvas.width, canvas.height, "red");
}
</script>
</head>
<body onload="boom();">
<canvas id="canvas" width="10" height="10"></canvas>
</body>
</html>

View File

@ -29,4 +29,5 @@ skip-if(azureCairo) load 1229983-1.html
load 1229932-1.html
load 1233613.html
load 1244850-1.html
load 1246775-1.html
load texImage2D.html

View File

@ -2170,11 +2170,9 @@ private:
mJwk.mExt.Construct(mExtractable);
if (!mKeyUsages.IsEmpty()) {
mJwk.mKey_ops.Construct();
if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
mJwk.mKey_ops.Construct();
if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;

View File

@ -250,6 +250,58 @@ TestArray.addTest(
);
}
);
// --------
TestArray.addTest(
"Check JWK parameters on generated ECDSA key pair",
function() {
crypto.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, ['sign', 'verify'])
.then(pair => Promise.all([
crypto.subtle.exportKey('jwk', pair.privateKey),
crypto.subtle.exportKey('jwk', pair.publicKey)
]))
.then(
complete(this, function(x) {
var priv = x[0];
var pub = x[1];
var pubIsSubsetOfPriv = Object.keys(pub)
.filter(k => k !== 'key_ops') // key_ops is the only complex attr
.reduce((all, k) => all && pub[k] === priv[k], true);
// Can't use hasBaseJwkFields() because EC keys don't get "alg":
// "alg" matches curve to hash, but WebCrypto keys are more flexible.
return hasFields(pub, ['kty', 'crv', 'key_ops', 'ext']) &&
pub.kty === 'EC' &&
pub.crv === 'P-256' &&
pub.ext &&
typeof(pub.x) === 'string' &&
typeof(pub.y) === 'string' &&
shallowArrayEquals(pub.key_ops, ['verify']) &&
pubIsSubsetOfPriv &&
shallowArrayEquals(priv.key_ops, ['sign']) &&
typeof(priv.d) === 'string';
}),
error(this));
}
);
// --------
TestArray.addTest(
"Check key_ops parameter on an unusable RSA public key",
function() {
var parameters = {
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 1024,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256'
};
// The public key generated here will have no usages and will therefore
// have an empty key_ops list.
crypto.subtle.generateKey(parameters, true, ['sign'])
.then(pair => crypto.subtle.exportKey('jwk', pair.publicKey))
.then(complete(this, x => x.key_ops.length === 0),
error(this));
}
);
/*]]>*/</script>
</head>

View File

@ -194,7 +194,6 @@ TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
}
prefValue = sIsTouchDeviceSupportPresent;
#else
NS_WARNING("dom.w3c_touch_events.enabled=2 not implemented!");
prefValue = false;
#endif
} else {

View File

@ -487,20 +487,6 @@ MediaSource::NotifyEvicted(double aStart, double aEnd)
mSourceBuffers->Evict(aStart, aEnd);
}
#if defined(DEBUG)
void
MediaSource::Dump(const char* aPath)
{
char buf[255];
PR_snprintf(buf, sizeof(buf), "%s/mediasource-%p", aPath, this);
PR_MkDir(buf, 0700);
if (mSourceBuffers) {
mSourceBuffers->Dump(buf);
}
}
#endif
void
MediaSource::GetMozDebugReaderData(nsAString& aString)
{

View File

@ -100,12 +100,6 @@ public:
// that were evicted are provided.
void NotifyEvicted(double aStart, double aEnd);
#if defined(DEBUG)
// Dump the contents of each SourceBuffer to a series of files under aPath.
// aPath must exist. Debug only, invoke from your favourite debugger.
void Dump(const char* aPath);
#endif
// Returns a string describing the state of the MediaSource internal
// buffered data. Used for debugging purposes.
void GetMozDebugReaderData(nsAString& aString);

View File

@ -256,6 +256,12 @@ MediaDecoderOwner::NextFrameStatus
MediaSourceDecoder::NextFrameBufferedStatus()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mMediaSource ||
mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
}
// Next frame hasn't been decoded yet.
// Use the buffered range to consider if we have the next frame available.
TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition());

View File

@ -22,7 +22,7 @@ using media::TimeIntervals;
MediaSourceDemuxer::MediaSourceDemuxer()
: mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
/* aSupportsTailDispatch = */ true))
/* aSupportsTailDispatch = */ false))
, mMonitor("MediaSourceDemuxer")
{
MOZ_ASSERT(NS_IsMainThread());

View File

@ -39,27 +39,6 @@ using media::TimeUnit;
namespace dom {
class BufferAppendRunnable : public nsRunnable {
public:
BufferAppendRunnable(SourceBuffer* aSourceBuffer,
uint32_t aUpdateID)
: mSourceBuffer(aSourceBuffer)
, mUpdateID(aUpdateID)
{
}
NS_IMETHOD Run() override final {
mSourceBuffer->BufferAppend(mUpdateID);
return NS_OK;
}
private:
RefPtr<SourceBuffer> mSourceBuffer;
uint32_t mUpdateID;
};
void
SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
{
@ -226,10 +205,13 @@ void
SourceBuffer::AbortBufferAppend()
{
if (mUpdating) {
mPendingAppend.DisconnectIfExists();
// TODO: Abort stream append loop algorithms.
// cancel any pending buffer append.
mContentManager->AbortAppendData();
if (mPendingAppend.Exists()) {
mPendingAppend.Disconnect();
mContentManager->AbortAppendData();
// Some data may have been added by the Segment Parser Loop.
// Check if we need to update the duration.
CheckEndTime();
}
AbortUpdating();
}
}
@ -309,7 +291,6 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
, mMediaSource(aMediaSource)
, mUpdating(false)
, mActive(false)
, mUpdateID(0)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread());
@ -381,7 +362,6 @@ SourceBuffer::StartUpdating()
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mUpdating);
mUpdating = true;
mUpdateID++;
QueueAsyncSimpleEvent("updatestart");
}
@ -390,12 +370,8 @@ SourceBuffer::StopUpdating()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mUpdating) {
// The buffer append algorithm has been interrupted by abort().
//
// If the sequence appendBuffer(), abort(), appendBuffer() occurs before
// the first StopUpdating() runnable runs, then a second StopUpdating()
// runnable will be scheduled, but still only one (the first) will queue
// events.
// The buffer append or range removal algorithm has been interrupted by
// abort().
return;
}
mUpdating = false;
@ -407,7 +383,6 @@ void
SourceBuffer::AbortUpdating()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mUpdating);
mUpdating = false;
QueueAsyncSimpleEvent("abort");
QueueAsyncSimpleEvent("updateend");
@ -438,23 +413,13 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
StartUpdating();
nsCOMPtr<nsIRunnable> task = new BufferAppendRunnable(this, mUpdateID);
NS_DispatchToMainThread(task);
BufferAppend();
}
void
SourceBuffer::BufferAppend(uint32_t aUpdateID)
SourceBuffer::BufferAppend()
{
if (!mUpdating || aUpdateID != mUpdateID) {
// The buffer append algorithm has been interrupted by abort().
//
// If the sequence appendBuffer(), abort(), appendBuffer() occurs before
// the first StopUpdating() runnable runs, then a second StopUpdating()
// runnable will be scheduled, but still only one (the first) will queue
// events.
return;
}
MOZ_ASSERT(mUpdating);
MOZ_ASSERT(mMediaSource);
MOZ_ASSERT(!mPendingAppend.Exists());
@ -467,11 +432,8 @@ SourceBuffer::BufferAppend(uint32_t aUpdateID)
void
SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
{
MOZ_ASSERT(mUpdating);
mPendingAppend.Complete();
if (!mUpdating) {
// The buffer append algorithm has been interrupted by abort().
return;
}
if (aHasActiveTracks) {
if (!mActive) {
@ -494,7 +456,9 @@ SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
void
SourceBuffer::AppendDataErrored(nsresult aError)
{
MOZ_ASSERT(mUpdating);
mPendingAppend.Complete();
switch (aError) {
case NS_ERROR_ABORT:
// Nothing further to do as the trackbuffer has been shutdown.
@ -510,10 +474,7 @@ void
SourceBuffer::AppendError(bool aDecoderError)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mUpdating) {
// The buffer append algorithm has been interrupted by abort().
return;
}
mContentManager->ResetParserState();
mUpdating = false;
@ -625,16 +586,6 @@ SourceBuffer::Evict(double aStart, double aEnd)
mContentManager->EvictBefore(TimeUnit::FromSeconds(evictTime));
}
#if defined(DEBUG)
void
SourceBuffer::Dump(const char* aPath)
{
if (mContentManager) {
mContentManager->Dump(aPath);
}
}
#endif
NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)

View File

@ -213,10 +213,6 @@ public:
return mActive;
}
#if defined(DEBUG)
void Dump(const char* aPath);
#endif
private:
~SourceBuffer();
@ -238,7 +234,7 @@ private:
// Shared implementation of AppendBuffer overloads.
void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
void BufferAppend(uint32_t aAppendID);
void BufferAppend();
// Implement the "Append Error Algorithm".
// Will call endOfStream() with "decode" error if aDecodeError is true.
@ -266,11 +262,6 @@ private:
mozilla::Atomic<bool> mActive;
// Each time mUpdating is set to true, mUpdateID will be incremented.
// This allows for a queued AppendData task to identify if it was earlier
// aborted and another AppendData queued.
uint32_t mUpdateID;
MozPromiseRequestHolder<SourceBufferContentManager::AppendPromise> mPendingAppend;
const nsCString mType;

View File

@ -108,10 +108,6 @@ public:
virtual void RestartGroupStartTimestamp() {}
virtual media::TimeUnit GroupEndTimestamp() = 0;
#if defined(DEBUG)
virtual void Dump(const char* aPath) { }
#endif
protected:
virtual ~SourceBufferContentManager() { }
};

View File

@ -176,16 +176,6 @@ SourceBufferList::QueueAsyncSimpleEvent(const char* aName)
NS_DispatchToMainThread(event);
}
#if defined(DEBUG)
void
SourceBufferList::Dump(const char* aPath)
{
for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
mSourceBuffers[i]->Dump(aPath);
}
}
#endif
SourceBufferList::SourceBufferList(MediaSource* aMediaSource)
: DOMEventTargetHelper(aMediaSource->GetParentObject())
, mMediaSource(aMediaSource)

View File

@ -84,10 +84,6 @@ public:
// No event is fired and no action is performed on the sourcebuffers.
void ClearSimple();
#if defined(DEBUG)
void Dump(const char* aPath);
#endif
private:
~SourceBufferList();

View File

@ -96,24 +96,17 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute
, mType(aType)
, mParser(ContainerParser::CreateForMIMEType(aType))
, mProcessedInput(0)
, mAppendRunning(false)
, mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
, mSourceBufferAttributes(aAttributes)
, mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
, mMediaSourceDuration(mTaskQueue, Maybe<double>(), "TrackBuffersManager::mMediaSourceDuration (Mirror)")
, mAbort(false)
, mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold",
100 * (1 << 20)))
, mEvictionOccurred(false)
, mMonitor("TrackBuffersManager")
, mAppendRunning(false)
, mSegmentParserLoopRunning(false)
{
MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
RefPtr<TrackBuffersManager> self = this;
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableFunction([self] () {
self->mMediaSourceDuration.Connect(self->mParentDecoder->CanonicalExplicitDuration());
});
GetTaskQueue()->Dispatch(task.forget());
}
TrackBuffersManager::~TrackBuffersManager()
@ -142,7 +135,6 @@ TrackBuffersManager::AppendIncomingBuffer(IncomingBuffer aData)
{
MOZ_ASSERT(OnTaskQueue());
mIncomingBuffers.AppendElement(aData);
mAbort = false;
}
RefPtr<TrackBuffersManager::AppendPromise>
@ -151,49 +143,42 @@ TrackBuffersManager::BufferAppend()
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("");
mAppendRunning = true;
return InvokeAsync(GetTaskQueue(), this,
__func__, &TrackBuffersManager::InitSegmentParserLoop);
}
// Abort any pending AppendData.
// We don't really care about really aborting our inner loop as by spec the
// process is happening asynchronously, as such where and when we would abort is
// non-deterministic. The SourceBuffer also makes sure BufferAppend
// isn't called should the appendBuffer be immediately aborted.
// We do however want to ensure that no new task will be dispatched on our task
// queue and only let the current one finish its job. For this we set mAbort
// to true.
// The MSE spec requires that we abort the current SegmentParserLoop
// which is then followed by a call to ResetParserState.
// However due to our asynchronous design this causes inherent difficulities.
// As the spec behaviour is non deterministic anyway, we instead wait until the
// current AppendData has completed its run.
void
TrackBuffersManager::AbortAppendData()
{
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("");
mAbort = true;
MonitorAutoLock mon(mMonitor);
while (mAppendRunning) {
mon.Wait();
}
}
void
TrackBuffersManager::ResetParserState()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mAppendRunning, "AbortAppendData must have been called");
MOZ_RELEASE_ASSERT(!mAppendRunning, "Append is running, abort must have been called");
MSE_DEBUG("");
// 1. If the append state equals PARSING_MEDIA_SEGMENT and the input buffer contains some complete coded frames, then run the coded frame processing algorithm until all of these complete coded frames have been processed.
if (mAppendState == AppendState::PARSING_MEDIA_SEGMENT) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &TrackBuffersManager::FinishCodedFrameProcessing);
GetTaskQueue()->Dispatch(task.forget());
} else {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &TrackBuffersManager::CompleteResetParserState);
GetTaskQueue()->Dispatch(task.forget());
}
// SourceBuffer.abort() has ensured that all complete coded frames have been
// processed. As such, we don't need to check for the value of mAppendState.
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &TrackBuffersManager::CompleteResetParserState);
GetTaskQueue()->Dispatch(task.forget());
// Our ResetParserState is really asynchronous, the current task has been
// interrupted and will complete shortly (or has already completed).
// We must however present to the main thread a stable, reset state.
// So we run the following operation now in the main thread.
// 7. Set append state to WAITING_FOR_SEGMENT.
SetAppendState(AppendState::WAITING_FOR_SEGMENT);
}
@ -202,6 +187,7 @@ RefPtr<TrackBuffersManager::RangeRemovalPromise>
TrackBuffersManager::RangeRemoval(TimeUnit aStart, TimeUnit aEnd)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mAppendRunning, "Append is running");
MSE_DEBUG("From %.2f to %.2f", aStart.ToSeconds(), aEnd.ToSeconds());
mEnded = false;
@ -309,54 +295,13 @@ TrackBuffersManager::Detach()
{
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("");
// Abort pending operations if any.
AbortAppendData();
RefPtr<TrackBuffersManager> self = this;
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableFunction([self] () {
// Clear our sourcebuffer
self->CodedFrameRemoval(TimeInterval(TimeUnit::FromSeconds(0),
TimeUnit::FromInfinity()));
self->mProcessingPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
self->mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
self->mMediaSourceDuration.DisconnectIfConnected();
});
GetTaskQueue()->Dispatch(task.forget());
}
#if defined(DEBUG)
void
TrackBuffersManager::Dump(const char* aPath)
{
}
#endif
void
TrackBuffersManager::FinishCodedFrameProcessing()
{
MOZ_ASSERT(OnTaskQueue());
if (mProcessingRequest.Exists()) {
NS_WARNING("Processing request pending");
mProcessingRequest.Disconnect();
}
// The spec requires us to complete parsing synchronously any outstanding
// frames in the current media segment. This can't be implemented in a way
// that makes sense.
// As such we simply completely ignore the result of any pending input buffer.
// TODO: Link to W3C bug.
CompleteResetParserState();
}
void
TrackBuffersManager::CompleteResetParserState()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(!mAppendRunning);
MOZ_RELEASE_ASSERT(!mSegmentParserLoopRunning);
MSE_DEBUG("");
for (auto& track : GetTracksList()) {
@ -492,19 +437,11 @@ bool
TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(!mAppendRunning, "Logic error: Append in progress");
MOZ_ASSERT(!mSegmentParserLoopRunning, "Logic error: Append in progress");
MSE_DEBUG("From %.2fs to %.2f",
aInterval.mStart.ToSeconds(), aInterval.mEnd.ToSeconds());
if (mMediaSourceDuration.Ref().isNothing() ||
IsNaN(mMediaSourceDuration.Ref().ref())) {
MSE_DEBUG("Nothing to remove, aborting");
return false;
}
TimeUnit duration{TimeUnit::FromSeconds(mMediaSourceDuration.Ref().ref())};
#if DEBUG
MSE_DEBUG("duration:%.2f", duration.ToSeconds());
if (HasVideo()) {
MSE_DEBUG("before video ranges=%s",
DumpTimeRanges(mVideoTracks.mBufferedRanges).get());
@ -527,7 +464,14 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
MSE_DEBUGV("Processing %s track", track->mInfo->mMimeType.get());
// 1. Let remove end timestamp be the current value of duration
// See bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28727
TimeUnit removeEndTimestamp = std::max(duration, track->mBufferedRanges.GetEnd());
// At worse we will remove all frames until the end, unless a key frame is
// found between the current interval's end and the trackbuffer's end.
TimeUnit removeEndTimestamp = track->mBufferedRanges.GetEnd();
if (start > removeEndTimestamp) {
// Nothing to remove.
continue;
}
// 2. If this track buffer has a random access point timestamp that is greater than or equal to end,
// then update remove end timestamp to that random access point timestamp.
@ -595,8 +539,9 @@ RefPtr<TrackBuffersManager::AppendPromise>
TrackBuffersManager::InitSegmentParserLoop()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_RELEASE_ASSERT(mAppendPromise.IsEmpty());
MSE_DEBUG("");
MOZ_ASSERT(mAppendPromise.IsEmpty() && !mAppendRunning);
RefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__);
AppendIncomingBuffers();
@ -630,6 +575,9 @@ void
TrackBuffersManager::SegmentParserLoop()
{
MOZ_ASSERT(OnTaskQueue());
mSegmentParserLoopRunning = true;
while (true) {
// 1. If the input buffer is empty, then jump to the need more data step below.
if (!mInputBuffer || mInputBuffer->IsEmpty()) {
@ -733,7 +681,7 @@ TrackBuffersManager::SegmentParserLoop()
->Then(GetTaskQueue(), __func__,
[self] (bool aNeedMoreData) {
self->mProcessingRequest.Complete();
if (aNeedMoreData || self->mAbort) {
if (aNeedMoreData) {
self->NeedMoreData();
} else {
self->ScheduleSegmentParserLoop();
@ -752,10 +700,14 @@ void
TrackBuffersManager::NeedMoreData()
{
MSE_DEBUG("");
if (!mAbort) {
RestoreCachedVariables();
}
RestoreCachedVariables();
mAppendRunning = false;
mSegmentParserLoopRunning = false;
{
// Wake-up any pending Abort()
MonitorAutoLock mon(mMonitor);
mon.NotifyAll();
}
mAppendPromise.ResolveIfExists(mActiveTrack, __func__);
}
@ -764,6 +716,12 @@ TrackBuffersManager::RejectAppend(nsresult aRejectValue, const char* aName)
{
MSE_DEBUG("rv=%d", aRejectValue);
mAppendRunning = false;
mSegmentParserLoopRunning = false;
{
// Wake-up any pending Abort()
MonitorAutoLock mon(mMonitor);
mon.NotifyAll();
}
mAppendPromise.RejectIfExists(aRejectValue, aName);
}
@ -840,12 +798,7 @@ void
TrackBuffersManager::OnDemuxerResetDone(nsresult)
{
MOZ_ASSERT(OnTaskQueue());
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
mDemuxerInitRequest.Complete();
if (mAbort) {
RejectAppend(NS_ERROR_ABORT, __func__);
return;
}
// mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
// request was being processed. See bug 1239983.
MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer);
@ -917,13 +870,8 @@ void
TrackBuffersManager::OnDemuxerInitDone(nsresult)
{
MOZ_ASSERT(OnTaskQueue());
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
mDemuxerInitRequest.Complete();
if (mAbort) {
RejectAppend(NS_ERROR_ABORT, __func__);
return;
}
// mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
// request was being processed. See bug 1239983.
MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer);
@ -1183,9 +1131,8 @@ TrackBuffersManager::OnDemuxFailed(TrackType aTrack,
DemuxerFailureReason aFailure)
{
MOZ_ASSERT(OnTaskQueue());
MSE_DEBUG("Failed to demux %s, failure:%d mAbort:%d",
aTrack == TrackType::kVideoTrack ? "video" : "audio",
aFailure, static_cast<bool>(mAbort));
MSE_DEBUG("Failed to demux %s, failure:%d",
aTrack == TrackType::kVideoTrack ? "video" : "audio", aFailure);
switch (aFailure) {
case DemuxerFailureReason::END_OF_STREAM:
case DemuxerFailureReason::WAITING_FOR_DATA:
@ -1212,15 +1159,10 @@ void
TrackBuffersManager::DoDemuxVideo()
{
MOZ_ASSERT(OnTaskQueue());
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
if (!HasVideo()) {
DoDemuxAudio();
return;
}
if (mAbort) {
RejectProcessing(NS_ERROR_ABORT, __func__);
return;
}
mVideoTracks.mDemuxRequest.Begin(mVideoTracks.mDemuxer->GetSamples(-1)
->Then(GetTaskQueue(), __func__, this,
&TrackBuffersManager::OnVideoDemuxCompleted,
@ -1241,15 +1183,10 @@ void
TrackBuffersManager::DoDemuxAudio()
{
MOZ_ASSERT(OnTaskQueue());
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
if (!HasAudio()) {
CompleteCodedFrameProcessing();
return;
}
if (mAbort) {
RejectProcessing(NS_ERROR_ABORT, __func__);
return;
}
mAudioTracks.mDemuxRequest.Begin(mAudioTracks.mDemuxer->GetSamples(-1)
->Then(GetTaskQueue(), __func__, this,
&TrackBuffersManager::OnAudioDemuxCompleted,
@ -1270,7 +1207,6 @@ void
TrackBuffersManager::CompleteCodedFrameProcessing()
{
MOZ_ASSERT(OnTaskQueue());
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
// 1. For each coded frame in the media segment run the following steps:
// Coded Frame Processing steps 1.1 to 1.21.
@ -1341,22 +1277,12 @@ TrackBuffersManager::CompleteCodedFrameProcessing()
void
TrackBuffersManager::RejectProcessing(nsresult aRejectValue, const char* aName)
{
if (mAbort) {
// mAppendPromise will be resolved immediately upon mProcessingPromise
// completing.
mAppendRunning = false;
}
mProcessingPromise.RejectIfExists(aRejectValue, __func__);
}
void
TrackBuffersManager::ResolveProcessing(bool aResolveValue, const char* aName)
{
if (mAbort) {
// mAppendPromise will be resolved immediately upon mProcessingPromise
// completing.
mAppendRunning = false;
}
mProcessingPromise.ResolveIfExists(aResolveValue, __func__);
}

View File

@ -98,10 +98,6 @@ public:
bool& aError);
media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack);
#if defined(DEBUG)
void Dump(const char* aPath) override;
#endif
void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes);
private:
@ -123,9 +119,7 @@ private:
// media segment have been processed.
RefPtr<CodedFrameProcessingPromise> CodedFrameProcessing();
void CompleteCodedFrameProcessing();
// Called by ResetParserState. Complete parsing the input buffer for the
// current media segment.
void FinishCodedFrameProcessing();
// Called by ResetParserState.
void CompleteResetParserState();
RefPtr<RangeRemovalPromise>
CodedFrameRemovalWithPromise(media::TimeInterval aInterval);
@ -310,10 +304,6 @@ private:
MozPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
MozPromiseHolder<AppendPromise> mAppendPromise;
// Set to true while SegmentParserLoop is running. This is used for diagnostic
// purposes only. We can't rely on mAppendPromise to be empty as it is only
// cleared in a follow up task.
bool mAppendRunning;
// Trackbuffers definition.
nsTArray<TrackData*> GetTracksList();
@ -349,11 +339,6 @@ private:
RefPtr<dom::SourceBufferAttributes> mSourceBufferAttributes;
nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
// MediaSource duration mirrored from MediaDecoder on the main thread..
Mirror<Maybe<double>> mMediaSourceDuration;
// Set to true if abort was called.
Atomic<bool> mAbort;
// Set to true if mediasource state changed to ended.
Atomic<bool> mEnded;
@ -363,7 +348,13 @@ private:
Atomic<bool> mEvictionOccurred;
// Monitor to protect following objects accessed across multipple threads.
// mMonitor is also notified if the value of mAppendRunning becomes false.
mutable Monitor mMonitor;
// Set to true while SegmentParserLoop is running.
Atomic<bool> mAppendRunning;
// Set to true while SegmentParserLoop is running.
// This is for diagnostic only. Only accessed on the task queue.
bool mSegmentParserLoopRunning;
// Stable audio and video track time ranges.
media::TimeIntervals mVideoBufferedRanges;
media::TimeIntervals mAudioBufferedRanges;

View File

@ -126,6 +126,8 @@ var interfaceNamesInGlobalScope =
{name: "Animation", release: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "AnimationEffectReadOnly", release: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "AnimationEffectTiming", release: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "AnimationEffectTimingReadOnly", release: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -727,6 +729,8 @@ var interfaceNamesInGlobalScope =
"KeyboardEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "KeyframeEffectReadOnly", release: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "KeyframeEffect", release: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
"LocalMediaStream",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -0,0 +1,31 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this IDL file is
* https://w3c.github.io/web-animations/#animationeffecttiming
*
* Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[Func="nsDocument::IsWebAnimationsEnabled"]
interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
//Bug 1244633 - implement AnimationEffectTiming delay
//inherit attribute double delay;
//Bug 1244635 - implement AnimationEffectTiming endDelay
//inherit attribute double endDelay;
//Bug 1244637 - implement AnimationEffectTiming fill
//inherit attribute FillMode fill;
//Bug 1244638 - implement AnimationEffectTiming iterationStart
//inherit attribute double iterationStart;
//Bug 1244640 - implement AnimationEffectTiming iterations
//inherit attribute unrestricted double iterations;
//Bug 1244641 - implement AnimationEffectTiming duration
//inherit attribute (unrestricted double or DOMString) duration;
//Bug 1244642 - implement AnimationEffectTiming direction
//inherit attribute PlaybackDirection direction;
//Bug 1244643 - implement AnimationEffectTiming easing
//inherit attribute DOMString easing;
};

View File

@ -52,10 +52,7 @@ dictionary ConsoleEvent {
DOMString functionName = "";
double timeStamp = 0;
sequence<any> arguments;
// This array will only hold strings or null elements.
sequence<any> styles;
sequence<DOMString?> styles;
boolean private = false;
// stacktrace is handled via a getter in some cases so we can construct it
// lazily. Note that we're not making this whole thing an interface because

View File

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://w3c.github.io/web-animations/#the-keyframeeffect-interfaces
* https://w3c.github.io/web-animations/#the-keyframeeffect-interfaces
*
* Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
@ -44,3 +44,20 @@ interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
// property-value pairs on the object.
[Throws] sequence<object> getFrames();
};
[Constructor ((Element or CSSPseudoElement)? target,
object? frames,
optional (unrestricted double or KeyframeEffectOptions) options)]
interface KeyframeEffect : KeyframeEffectReadOnly {
// Bug 1067769 - Allow setting KeyframeEffect.target
// inherit attribute Animatable? target;
// Bug 1216843 - implement animation composition
// inherit attribute IterationCompositeOperation iterationComposite;
// Bug 1216844 - implement additive animation
// inherit attribute CompositeOperation composite;
// Bug 1244590 - implement spacing modes
// inherit attribute DOMString spacing;
// Bug 1244591 - implement setFrames
// void setFrames (object? frames);
};

View File

@ -190,7 +190,7 @@ Navigator implements NavigatorMobileId;
// nsIDOMNavigator
partial interface Navigator {
[Throws]
[Throws, Constant, Cached]
readonly attribute DOMString oscpu;
// WebKit/Blink support this; Trident/Presto do not.
readonly attribute DOMString vendor;
@ -200,7 +200,7 @@ partial interface Navigator {
readonly attribute DOMString productSub;
// WebKit/Blink/Trident/Presto support this.
readonly attribute boolean cookieEnabled;
[Throws]
[Throws, Constant, Cached]
readonly attribute DOMString buildID;
[Throws, CheckAnyPermissions="power", UnsafeInPrerendering]
readonly attribute MozPowerManager mozPower;

View File

@ -25,6 +25,7 @@ WEBIDL_FILES = [
'Animatable.webidl',
'Animation.webidl',
'AnimationEffectReadOnly.webidl',
'AnimationEffectTiming.webidl',
'AnimationEffectTimingReadOnly.webidl',
'AnimationEvent.webidl',
'AnimationTimeline.webidl',

View File

@ -886,23 +886,10 @@ class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
public:
// The heap size passed here doesn't matter, we will change it later in the
// call to JS_SetGCParameter inside CreateJSContextForWorker.
WorkerJSRuntime(JSRuntime* aParentRuntime, WorkerPrivate* aWorkerPrivate)
: CycleCollectedJSRuntime(aParentRuntime,
WORKER_DEFAULT_RUNTIME_HEAPSIZE,
WORKER_DEFAULT_NURSERY_SIZE),
mWorkerPrivate(aWorkerPrivate)
explicit WorkerJSRuntime(WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate)
{
JSRuntime* rt = Runtime();
MOZ_ASSERT(rt);
JS_SetRuntimePrivate(rt, new WorkerThreadRuntimePrivate(aWorkerPrivate));
js::SetPreserveWrapperCallback(rt, PreserveWrapper);
JS_InitDestroyPrincipalsCallback(rt, DestroyWorkerPrincipals);
JS_SetWrapObjectCallbacks(rt, &WrapObjectCallbacks);
if (aWorkerPrivate->IsDedicatedWorker()) {
JS_SetFutexCanWait(rt);
}
MOZ_ASSERT(aWorkerPrivate);
}
~WorkerJSRuntime()
@ -924,6 +911,31 @@ public:
mWorkerPrivate = nullptr;
}
nsresult Initialize(JSRuntime* aParentRuntime)
{
nsresult rv =
CycleCollectedJSRuntime::Initialize(aParentRuntime,
WORKER_DEFAULT_RUNTIME_HEAPSIZE,
WORKER_DEFAULT_NURSERY_SIZE);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
JSRuntime* rt = Runtime();
MOZ_ASSERT(rt);
JS_SetRuntimePrivate(rt, new WorkerThreadRuntimePrivate(mWorkerPrivate));
js::SetPreserveWrapperCallback(rt, PreserveWrapper);
JS_InitDestroyPrincipalsCallback(rt, DestroyWorkerPrincipals);
JS_SetWrapObjectCallbacks(rt, &WrapObjectCallbacks);
if (mWorkerPrivate->IsDedicatedWorker()) {
JS_SetFutexCanWait(rt);
}
return NS_OK;
}
virtual void
PrepareForForgetSkippable() override
{
@ -2695,7 +2707,12 @@ WorkerThreadPrimaryRunnable::Run()
{
nsCycleCollector_startup();
WorkerJSRuntime runtime(mParentRuntime, mWorkerPrivate);
WorkerJSRuntime runtime(mWorkerPrivate);
nsresult rv = runtime.Initialize(mParentRuntime);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
JSRuntime* rt = runtime.Runtime();
JSContext* cx = CreateJSContextForWorker(mWorkerPrivate, rt);

View File

@ -2391,6 +2391,7 @@ nsWebBrowserPersist::FixRedirectedChannelEntry(nsIChannel *aNewChannel)
// matching the one specified.
nsCOMPtr<nsIURI> originalURI;
aNewChannel->GetOriginalURI(getter_AddRefs(originalURI));
nsISupports* matchingKey = nullptr;
for (auto iter = mOutputMap.Iter(); !iter.Done(); iter.Next()) {
nsISupports* key = iter.Key();
nsCOMPtr<nsIChannel> thisChannel = do_QueryInterface(key);
@ -2402,21 +2403,25 @@ nsWebBrowserPersist::FixRedirectedChannelEntry(nsIChannel *aNewChannel)
bool matchingURI = false;
thisURI->Equals(originalURI, &matchingURI);
if (matchingURI) {
// If a match is found, remove the data entry with the old channel
// key and re-add it with the new channel key.
nsAutoPtr<OutputData> outputData;
mOutputMap.RemoveAndForget(key, outputData);
NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE);
// Store data again with new channel unless told to ignore redirects
if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA)) {
nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
mOutputMap.Put(keyPtr, outputData.forget());
}
matchingKey = key;
break;
}
}
if (matchingKey) {
// If a match was found, remove the data entry with the old channel
// key and re-add it with the new channel key.
nsAutoPtr<OutputData> outputData;
mOutputMap.RemoveAndForget(matchingKey, outputData);
NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE);
// Store data again with new channel unless told to ignore redirects.
if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA)) {
nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
mOutputMap.Put(keyPtr, outputData.forget());
}
}
return NS_OK;
}

Some files were not shown because too many files have changed in this diff Show More