Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-05-06 13:14:52 +02:00
commit b187a55721
279 changed files with 4132 additions and 2548 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1128037 needed a clobber to properly build on OS X
Bug 1155494 seems to need a clobber to pick up a change the ipdl parser.

View File

@ -10,6 +10,7 @@ var FullScreen = {
// called when we go into full screen, even if initiated by a web page script
window.addEventListener("fullscreen", this, true);
window.messageManager.addMessageListener("MozEnteredDomFullscreen", this);
window.messageManager.addMessageListener("MozExitedDomFullscreen", this);
if (window.fullScreen)
this.toggle();
@ -17,6 +18,7 @@ var FullScreen = {
uninit: function() {
window.messageManager.removeMessageListener("MozEnteredDomFullscreen", this);
window.messageManager.removeMessageListener("MozExitedDomFullscreen", this);
this.cleanup();
},
@ -70,23 +72,16 @@ var FullScreen = {
document.addEventListener("keypress", this._keyToggleCallback, false);
document.addEventListener("popupshown", this._setPopupOpen, false);
document.addEventListener("popuphidden", this._setPopupOpen, false);
this._shouldAnimate = true;
// We don't animate the toolbar collapse if in DOM full-screen mode,
// as the size of the content area would still be changing after the
// mozfullscreenchange event fired, which could confuse content script.
this._shouldAnimate = !document.mozFullScreen;
this.mouseoverToggle(false);
this.hideNavToolbox(document.mozFullScreen);
}
else {
// The user may quit fullscreen during an animation
this._cancelAnimation();
gNavToolbox.style.marginTop = "";
if (this._isChromeCollapsed)
this.mouseoverToggle(true);
this.showNavToolbox(false);
// This is needed if they use the context menu to quit fullscreen
this._isPopupOpen = false;
document.documentElement.removeAttribute("inDOMFullscreen");
this.cleanup();
}
},
@ -127,6 +122,16 @@ var FullScreen = {
windowUtils.remoteFrameFullscreenChanged(browser, data.origin);
}
this.enterDomFullscreen(browser, data.origin);
} else if (aMessage.name == "MozExitedDomFullscreen") {
document.documentElement.removeAttribute("inDOMFullscreen");
this.cleanupDomFullscreen();
this.showNavToolbox();
// If we are still in fullscreen mode, re-hide
// the toolbox with animation.
if (window.fullScreen) {
this._shouldAnimate = true;
this.hideNavToolbox();
}
}
},
@ -172,8 +177,8 @@ var FullScreen = {
// Cancel any "hide the toolbar" animation which is in progress, and make
// the toolbar hide immediately.
this._cancelAnimation();
this.mouseoverToggle(false);
this.hideNavToolbox(true);
this._fullScrToggler.hidden = true;
},
cleanup: function () {
@ -183,6 +188,11 @@ var FullScreen = {
document.removeEventListener("popupshown", this._setPopupOpen, false);
document.removeEventListener("popuphidden", this._setPopupOpen, false);
this.cleanupDomFullscreen();
}
},
cleanupDomFullscreen: function () {
this.cancelWarning();
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
@ -192,7 +202,6 @@ var FullScreen = {
window.messageManager
.broadcastAsyncMessage("DOMFullscreen:Cleanup");
}
},
getMouseTargetRect: function()
@ -203,23 +212,22 @@ var FullScreen = {
// Event callbacks
_expandCallback: function()
{
FullScreen.mouseoverToggle(true);
FullScreen.showNavToolbox();
},
onMouseEnter: function()
{
FullScreen.mouseoverToggle(false);
FullScreen.hideNavToolbox();
},
_keyToggleCallback: function(aEvent)
{
// if we can use the keyboard (eg Ctrl+L or Ctrl+E) to open the toolbars, we
// should provide a way to collapse them too.
if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
FullScreen._shouldAnimate = false;
FullScreen.mouseoverToggle(false, true);
FullScreen.hideNavToolbox(true);
}
// F6 is another shortcut to the address bar, but its not covered in OpenLocation()
else if (aEvent.keyCode == aEvent.DOM_VK_F6)
FullScreen.mouseoverToggle(true);
FullScreen.showNavToolbox();
},
// Checks whether we are allowed to collapse the chrome
@ -273,47 +281,6 @@ var FullScreen = {
// Animate the toolbars disappearing
_shouldAnimate: true,
_isAnimating: false,
_animationTimeout: 0,
_animationHandle: 0,
_animateUp: function() {
// check again, the user may have done something before the animation was due to start
if (!window.fullScreen || !this._safeToCollapse(false)) {
this._isAnimating = false;
this._shouldAnimate = true;
return;
}
this._animateStartTime = window.mozAnimationStartTime;
if (!this._animationHandle)
this._animationHandle = window.mozRequestAnimationFrame(this);
},
sample: function (timeStamp) {
const duration = 1500;
const timePassed = timeStamp - this._animateStartTime;
const pos = timePassed >= duration ? 1 :
1 - Math.pow(1 - timePassed / duration, 4);
if (pos >= 1) {
// We've animated enough
this._cancelAnimation();
gNavToolbox.style.marginTop = "";
this.mouseoverToggle(false);
return;
}
gNavToolbox.style.marginTop = (gNavToolbox.boxObject.height * pos * -1) + "px";
this._animationHandle = window.mozRequestAnimationFrame(this);
},
_cancelAnimation: function() {
window.mozCancelAnimationFrame(this._animationHandle);
this._animationHandle = 0;
clearTimeout(this._animationTimeout);
this._isAnimating = false;
this._shouldAnimate = false;
},
cancelWarning: function(event) {
if (!this.warningBox)
@ -470,38 +437,18 @@ var FullScreen = {
3000);
},
mouseoverToggle: function(aShow, forceHide)
{
// Don't do anything if:
// a) we're already in the state we want,
// b) we're animating and will become collapsed soon, or
// c) we can't collapse because it would be undesirable right now
if (aShow != this._isChromeCollapsed || (!aShow && this._isAnimating) ||
(!aShow && !this._safeToCollapse(forceHide)))
return;
showNavToolbox: function(trackMouse = true) {
this._fullScrToggler.hidden = true;
gNavToolbox.removeAttribute("fullscreenShouldAnimate");
gNavToolbox.style.marginTop = "";
// browser.fullscreen.animateUp
// 0 - never animate up
// 1 - animate only for first collapse after entering fullscreen (default for perf's sake)
// 2 - animate every time it collapses
if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 0)
this._shouldAnimate = false;
if (!aShow && this._shouldAnimate) {
this._isAnimating = true;
this._shouldAnimate = false;
this._animationTimeout = setTimeout(this._animateUp.bind(this), 800);
if (!this._isChromeCollapsed) {
return;
}
// Hiding/collapsing the toolbox interferes with the tab bar's scrollbox,
// so we just move it off-screen instead. See bug 430687.
gNavToolbox.style.marginTop =
aShow ? "" : -gNavToolbox.getBoundingClientRect().height + "px";
this._fullScrToggler.hidden = aShow || document.mozFullScreen;
if (aShow) {
// Track whether mouse is near the toolbox
this._isChromeCollapsed = false;
if (trackMouse) {
let rect = gBrowser.mPanelContainer.getBoundingClientRect();
this._mouseTargetRect = {
top: rect.top + 50,
@ -510,13 +457,49 @@ var FullScreen = {
right: rect.right
};
MousePosTracker.addListener(this);
} else {
MousePosTracker.removeListener(this);
}
},
hideNavToolbox: function(forceHide = false) {
this._fullScrToggler.hidden = document.mozFullScreen;
if (this._isChromeCollapsed) {
if (forceHide) {
gNavToolbox.removeAttribute("fullscreenShouldAnimate");
}
return;
}
if (!this._safeToCollapse(forceHide)) {
this._fullScrToggler.hidden = true;
return;
}
this._isChromeCollapsed = !aShow;
if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
// browser.fullscreen.animateUp
// 0 - never animate up
// 1 - animate only for first collapse after entering fullscreen (default for perf's sake)
// 2 - animate every time it collapses
let animateUp = gPrefService.getIntPref("browser.fullscreen.animateUp");
if (animateUp == 0) {
this._shouldAnimate = false;
} else if (animateUp == 2) {
this._shouldAnimate = true;
}
if (this._shouldAnimate && !forceHide) {
gNavToolbox.setAttribute("fullscreenShouldAnimate", true);
this._shouldAnimate = false;
// Hide the fullscreen toggler until the transition ends.
let listener = () => {
gNavToolbox.removeEventListener("transitionend", listener, true);
if (this._isChromeCollapsed)
this._fullScrToggler.hidden = false;
};
gNavToolbox.addEventListener("transitionend", listener, true);
this._fullScrToggler.hidden = true;
}
gNavToolbox.style.marginTop =
-gNavToolbox.getBoundingClientRect().height + "px";
this._isChromeCollapsed = true;
MousePosTracker.removeListener(this);
},
showXULChrome: function(aTag, aShow)

View File

@ -300,6 +300,10 @@ toolbar[customizing] > .overflow-button {
visibility: collapse;
}
#navigator-toolbox[fullscreenShouldAnimate] {
transition: 1.5s margin-top ease-out;
}
/* Rules to help integrate SDK widgets */
toolbaritem[sdkstylewidget="true"] > toolbarbutton,
toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe,

View File

@ -1955,7 +1955,7 @@ function loadOneOrMoreURIs(aURIString)
function focusAndSelectUrlBar() {
if (gURLBar) {
if (window.fullScreen)
FullScreen.mouseoverToggle(true);
FullScreen.showNavToolbox();
gURLBar.select();
if (document.activeElement == gURLBar.inputField)
@ -3418,7 +3418,7 @@ const BrowserSearch = {
}
if (searchBar) {
if (window.fullScreen)
FullScreen.mouseoverToggle(true);
FullScreen.showNavToolbox();
searchBar.select();
}
openSearchPageIfFieldIsNotActive(searchBar);

View File

@ -590,6 +590,7 @@ let DOMFullscreenHandler = {
addMessageListener("DOMFullscreen:Approved", this);
addMessageListener("DOMFullscreen:CleanUp", this);
addEventListener("MozEnteredDomFullscreen", this);
addEventListener("MozExitedDomFullscreen", this);
},
receiveMessage: function(aMessage) {
@ -615,6 +616,8 @@ let DOMFullscreenHandler = {
sendAsyncMessage("MozEnteredDomFullscreen", {
origin: this._fullscreenDoc.nodePrincipal.origin,
});
} else if (aEvent.type == "MozExitedDomFullscreen") {
sendAsyncMessage("MozExitedDomFullscreen");
}
}
};

View File

@ -477,3 +477,4 @@ support-files =
[browser_bug1124271_readerModePinnedTab.js]
support-files =
readerModeArticle.html
[browser_domFullscreen_fullscreenMode.js]

View File

@ -0,0 +1,208 @@
"use strict";
let gMessageManager;
function frameScript() {
addMessageListener("Test:RequestFullscreen", () => {
content.document.body.mozRequestFullScreen();
});
addMessageListener("Test:ExitFullscreen", () => {
content.document.mozCancelFullScreen();
});
addMessageListener("Test:QueryFullscreenState", () => {
sendAsyncMessage("Test:FullscreenState", {
inDOMFullscreen: content.document.mozFullScreen,
inFullscreen: content.fullScreen
});
});
content.document.addEventListener("mozfullscreenchange", () => {
sendAsyncMessage("Test:FullscreenChanged", {
inDOMFullscreen: content.document.mozFullScreen,
inFullscreen: content.fullScreen
});
});
function waitUntilActive() {
let doc = content.document;
if (doc.docShell.isActive && doc.hasFocus()) {
sendAsyncMessage("Test:Activated");
} else {
setTimeout(waitUntilActive, 10);
}
}
waitUntilActive();
}
function listenOneMessage(aMsg, aListener) {
function listener({ data }) {
gMessageManager.removeMessageListener(aMsg, listener);
aListener(data);
}
gMessageManager.addMessageListener(aMsg, listener);
}
function listenOneEvent(aEvent, aListener) {
function listener(evt) {
removeEventListener(aEvent, listener);
aListener(evt);
}
addEventListener(aEvent, listener);
}
function queryFullscreenState() {
return new Promise(resolve => {
listenOneMessage("Test:FullscreenState", resolve);
gMessageManager.sendAsyncMessage("Test:QueryFullscreenState");
});
}
function captureUnexpectedFullscreenChange() {
ok(false, "catched an unexpected fullscreen change");
}
const FS_CHANGE_DOM = 1 << 0;
const FS_CHANGE_SIZE = 1 << 1;
const FS_CHANGE_BOTH = FS_CHANGE_DOM | FS_CHANGE_SIZE;
function waitForFullscreenChanges(aFlags) {
return new Promise(resolve => {
let fullscreenData = null;
let sizemodeChanged = false;
function tryResolve() {
if ((!(aFlags & FS_CHANGE_DOM) || fullscreenData) &&
(!(aFlags & FS_CHANGE_SIZE) || sizemodeChanged)) {
if (!fullscreenData) {
queryFullscreenState().then(resolve);
} else {
resolve(fullscreenData);
}
}
}
if (aFlags & FS_CHANGE_SIZE) {
listenOneEvent("sizemodechange", () => {
sizemodeChanged = true;
tryResolve();
});
}
if (aFlags & FS_CHANGE_DOM) {
gMessageManager.removeMessageListener(
"Test:FullscreenChanged", captureUnexpectedFullscreenChange);
listenOneMessage("Test:FullscreenChanged", data => {
gMessageManager.addMessageListener(
"Test:FullscreenChanged", captureUnexpectedFullscreenChange);
fullscreenData = data;
tryResolve();
});
}
});
}
let gTests = [
{
desc: "document method",
affectsFullscreenMode: false,
exitFunc: () => {
gMessageManager.sendAsyncMessage("Test:ExitFullscreen");
}
},
{
desc: "escape key",
affectsFullscreenMode: false,
exitFunc: () => {
executeSoon(() => EventUtils.synthesizeKey("VK_ESCAPE", {}));
}
},
{
desc: "F11 key",
affectsFullscreenMode: true,
exitFunc: function () {
executeSoon(() => EventUtils.synthesizeKey("VK_F11", {}));
}
}
];
add_task(function* () {
let tab = gBrowser.addTab("about:robots");
let browser = tab.linkedBrowser;
gBrowser.selectedTab = tab;
yield waitForDocLoadComplete();
registerCleanupFunction(() => {
if (browser.contentWindow.fullScreen) {
BrowserFullScreen();
}
gBrowser.removeTab(tab);
});
gMessageManager = browser.messageManager;
gMessageManager.loadFrameScript(
"data:,(" + frameScript.toString() + ")();", false);
gMessageManager.addMessageListener(
"Test:FullscreenChanged", captureUnexpectedFullscreenChange);
// Wait for the document being activated, so that
// fullscreen request won't be denied.
yield new Promise(resolve => listenOneMessage("Test:Activated", resolve));
for (let test of gTests) {
info("Testing exit DOM fullscreen via " + test.desc);
var { inDOMFullscreen, inFullscreen } = yield queryFullscreenState();
ok(!inDOMFullscreen, "Shouldn't have been in DOM fullscreen");
ok(!inFullscreen, "Shouldn't have been in fullscreen");
/* DOM fullscreen without fullscreen mode */
// Enter DOM fullscreen
gMessageManager.sendAsyncMessage("Test:RequestFullscreen");
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_BOTH);
ok(inDOMFullscreen, "Should now be in DOM fullscreen");
ok(inFullscreen, "Should now be in fullscreen");
// Exit DOM fullscreen
test.exitFunc();
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_BOTH);
ok(!inDOMFullscreen, "Should no longer be in DOM fullscreen");
ok(!inFullscreen, "Should no longer be in fullscreen");
/* DOM fullscreen with fullscreen mode */
// Enter fullscreen mode
// Need to be asynchronous because sizemodechange event could be
// dispatched synchronously, which would cause the event listener
// miss that event and wait infinitely.
executeSoon(() => BrowserFullScreen());
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_SIZE);
ok(!inDOMFullscreen, "Shouldn't have been in DOM fullscreen");
ok(inFullscreen, "Should now be in fullscreen mode");
// Enter DOM fullscreen
gMessageManager.sendAsyncMessage("Test:RequestFullscreen");
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_DOM);
ok(inDOMFullscreen, "Should now be in DOM fullscreen");
ok(inFullscreen, "Should still be in fullscreen");
// Exit DOM fullscreen
test.exitFunc();
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(test.affectsFullscreenMode ?
FS_CHANGE_BOTH : FS_CHANGE_DOM);
ok(!inDOMFullscreen, "Should no longer be in DOM fullscreen");
if (test.affectsFullscreenMode) {
ok(!inFullscreen, "Should no longer be in fullscreen mode");
} else {
ok(inFullscreen, "Should still be in fullscreen mode");
}
/* Cleanup */
// Exit fullscreen mode if we are still in
if (browser.contentWindow.fullScreen) {
executeSoon(() => BrowserFullScreen());
yield waitForFullscreenChanges(FS_CHANGE_SIZE);
}
}
});

View File

@ -23,6 +23,9 @@ const EXPECTED_REFLOWS = [
// Sometimes sessionstore collects data during this test, which causes a sync reflow
// (https://bugzilla.mozilla.org/show_bug.cgi?id=892154 will fix this)
"ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm",
// We may get a resize event, see bug 1149555.
"PreviewController.prototype.wasResizedSinceLastPreview@resource:///modules/WindowsPreviewPerTab.jsm"
];
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {

View File

@ -72,8 +72,8 @@ var tests = {
[chatWidth*2+popupWidth+2, 2, "big enough to fit 2 - nub remains visible as first is still hidden"],
[chatWidth*3+popupWidth-2, 2, "one smaller than the size necessary to display all three - first still hidden"],
[chatWidth*3+popupWidth+2, 3, "big enough to fit all - all exposed (which removes the nub)"],
[chatWidth*3+2, 3, "now the nub is hidden we can resize back down to chatWidth*3 before overflow."],
[chatWidth*3-2, 2, "2 pixels less and the first is again collapsed (and the nub re-appears)"],
[chatWidth*3+4, 3, "now the nub is hidden we can resize back down to chatWidth*3 before overflow."],
[chatWidth*3-4, 2, "4 pixels less and the first is again collapsed (and the nub re-appears)"],
[chatWidth*2+popupWidth+2, 2, "back down to just big enough to fit 2"],
[chatWidth*2+popupWidth-2, 1, "back down to just not enough to fit 2"],
[chatWidth*3+popupWidth+2, 3, "now a large jump to make all 3 visible (ie, affects 2)"],

View File

@ -4,6 +4,11 @@
"use strict";
function isFullscreenSizeMode() {
let sizemode = document.documentElement.getAttribute("sizemode");
return sizemode == "fullscreen";
}
// Observers should be disabled when in customization mode.
add_task(function() {
// Open and close the panel to make sure that the
@ -17,9 +22,10 @@ add_task(function() {
let fullscreenButton = document.getElementById("fullscreen-button");
ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.")
ok(!isFullscreenSizeMode(), "Should not be in fullscreen sizemode before we enter fullscreen.");
BrowserFullScreen();
yield waitForCondition(function() fullscreenButton.checked);
yield waitForCondition(() => isFullscreenSizeMode());
ok(fullscreenButton.checked, "Fullscreen button should be checked when in fullscreen.")
yield startCustomizing();
@ -34,6 +40,6 @@ add_task(function() {
BrowserFullScreen();
fullscreenButton = document.getElementById("fullscreen-button");
yield waitForCondition(function() !fullscreenButton.checked);
yield waitForCondition(() => !isFullscreenSizeMode());
ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.")
});

View File

@ -105,7 +105,7 @@ var PKT_SAVED_OVERLAY = function (options)
};
this.startCloseTimer = function(manualtime)
{
/*var settime = manualtime ? manualtime : myself.autocloseTiming;
var settime = manualtime ? manualtime : myself.autocloseTiming;
if (typeof myself.autocloseTimer == 'number')
{
clearTimeout(myself.autocloseTimer);
@ -117,7 +117,7 @@ var PKT_SAVED_OVERLAY = function (options)
myself.preventCloseTimerCancel = false;
myself.closePopup();
}
}, settime);*/
}, settime);
};
this.stopCloseTimer = function()
{

View File

@ -301,10 +301,16 @@ let gSyncPane = {
// If the account is verified the next promise in the chain will
// fetch profile data.
return data.verified;
}).then(shouldGetProfile => {
if (shouldGetProfile) {
}).then(isVerified => {
if (isVerified) {
let enabled;
try {
enabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled");
} catch (ex) {}
if (enabled) {
return fxAccounts.getSignedInUserProfile();
}
}
}).then(data => {
if (data && data.avatar) {
// Make sure the image is available before displaying it,

View File

@ -68,6 +68,11 @@ MozSelfSupportInterface.prototype = {
resetPref: function(name) {
Services.prefs.clearUserPref(name);
},
resetSearchEngines: function() {
Services.search.restoreDefaultEngines();
Services.search.resetToOriginalDefaultEngine();
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozSelfSupportInterface]);

View File

@ -1,6 +1,6 @@
Cu.import("resource://gre/modules/Preferences.jsm");
function test() {
function test_resetPref() {
const prefNewName = "browser.newpref.fake";
Assert.ok(!Preferences.has(prefNewName), "pref should not exist");
@ -45,3 +45,44 @@ function test() {
// clearUserPref can't undo its action
// see discussion in bug 1075160
}
function test_resetSearchEngines()
{
const defaultEngineOriginal = Services.search.defaultEngine;
const visibleEnginesOriginal = Services.search.getVisibleEngines();
// 1. do nothing on unchanged search configuration
MozSelfSupport.resetSearchEngines();
Assert.equal(Services.search.defaultEngine, defaultEngineOriginal, "default engine should be reset");
Assert.deepEqual(Services.search.getVisibleEngines(), visibleEnginesOriginal,
"default visible engines set should be reset");
// 2. change the default search engine
const defaultEngineNew = visibleEnginesOriginal[3];
Assert.notEqual(defaultEngineOriginal, defaultEngineNew, "new default engine should be different from original");
Services.search.defaultEngine = defaultEngineNew;
Assert.equal(Services.search.defaultEngine, defaultEngineNew, "default engine should be set to new");
MozSelfSupport.resetSearchEngines();
Assert.equal(Services.search.defaultEngine, defaultEngineOriginal, "default engine should be reset");
Assert.deepEqual(Services.search.getVisibleEngines(), visibleEnginesOriginal,
"default visible engines set should be reset");
// 3. remove an engine
const engineRemoved = visibleEnginesOriginal[2];
Services.search.removeEngine(engineRemoved);
Assert.ok(Services.search.getVisibleEngines().indexOf(engineRemoved) == -1,
"removed engine should not be visible any more");
MozSelfSupport.resetSearchEngines();
Assert.equal(Services.search.defaultEngine, defaultEngineOriginal, "default engine should be reset");
Assert.deepEqual(Services.search.getVisibleEngines(), visibleEnginesOriginal,
"default visible engines set should be reset");
// 4. add an angine
// we don't remove user-added engines as they are only used if selected
}
function test()
{
test_resetPref();
test_resetSearchEngines();
}

View File

@ -638,7 +638,6 @@ IsOnFullDomainWhitelist(nsIURI* aURI)
// 0th entry only active when testing:
NS_LITERAL_CSTRING("test1.example.org"),
NS_LITERAL_CSTRING("map.baidu.com"),
NS_LITERAL_CSTRING("music.baidu.com"),
NS_LITERAL_CSTRING("3g.163.com"),
NS_LITERAL_CSTRING("3glogo.gtimg.com"), // for 3g.163.com
NS_LITERAL_CSTRING("info.3g.qq.com"), // for 3g.qq.com
@ -646,6 +645,16 @@ IsOnFullDomainWhitelist(nsIURI* aURI)
NS_LITERAL_CSTRING("img.m.baidu.com"), // for [shucheng|ks].baidu.com
NS_LITERAL_CSTRING("m.mogujie.com"),
NS_LITERAL_CSTRING("touch.qunar.com"),
NS_LITERAL_CSTRING("mjs.sinaimg.cn"), // for sina.cn
NS_LITERAL_CSTRING("static.qiyi.com"), // for m.iqiyi.com
NS_LITERAL_CSTRING("www.kuaidi100.com"), // for m.kuaidi100.com
NS_LITERAL_CSTRING("m.pc6.com"),
NS_LITERAL_CSTRING("m.haosou.com"),
NS_LITERAL_CSTRING("m.mi.com"),
NS_LITERAL_CSTRING("wappass.baidu.com"),
NS_LITERAL_CSTRING("m.video.baidu.com"),
NS_LITERAL_CSTRING("m.video.baidu.com"),
NS_LITERAL_CSTRING("imgcache.gtimg.cn"), // for m.v.qq.com
};
static const size_t sNumFullDomainsOnWhitelist =
MOZ_ARRAY_LENGTH(sFullDomainsOnWhitelist);

View File

@ -18,6 +18,7 @@
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsIURL.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
@ -42,7 +43,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
URL::URL(nsIURI* aURI)
URL::URL(already_AddRefed<nsIURI> aURI)
: mURI(aURI)
{
}
@ -57,56 +58,55 @@ URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHa
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
URL& aBase, ErrorResult& aRv)
{
nsresult rv;
nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
return Constructor(aUrl, aBase.GetURI(), aRv);
}
/* static */ already_AddRefed<URL>
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
const Optional<nsAString>& aBase, ErrorResult& aRv)
{
if (aBase.WasPassed()) {
return Constructor(aUrl, aBase.Value(), aRv);
}
nsCOMPtr<nsIURI> uri;
rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, aBase.GetURI(),
getter_AddRefs(uri));
if (NS_FAILED(rv)) {
nsAutoString label(aUrl);
aRv.ThrowTypeError(MSG_INVALID_URL, &label);
return nullptr;
}
nsRefPtr<URL> url = new URL(uri);
return url.forget();
return Constructor(aUrl, nullptr, aRv);
}
/* static */ already_AddRefed<URL>
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
const nsAString& aBase, ErrorResult& aRv)
{
nsresult rv;
nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return Constructor(aUrl, aBase, aRv);
}
/* static */ already_AddRefed<URL>
URL::Constructor(const nsAString& aUrl, const nsAString& aBase,
ErrorResult& aRv)
{
nsCOMPtr<nsIURI> baseUri;
rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aBase), nullptr, nullptr,
getter_AddRefs(baseUri));
if (NS_FAILED(rv)) {
nsAutoString label(aBase);
aRv.ThrowTypeError(MSG_INVALID_URL, &label);
nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr,
nsContentUtils::GetIOService());
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.ThrowTypeError(MSG_INVALID_URL, &aBase);
return nullptr;
}
return Constructor(aUrl, baseUri, aRv);
}
/* static */
already_AddRefed<URL>
URL::Constructor(const nsAString& aUrl, nsIURI* aBase, ErrorResult& aRv)
{
nsCOMPtr<nsIURI> uri;
rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, baseUri,
getter_AddRefs(uri));
if (NS_FAILED(rv)) {
nsAutoString label(aUrl);
aRv.ThrowTypeError(MSG_INVALID_URL, &label);
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl, nullptr, aBase,
nsContentUtils::GetIOService());
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.ThrowTypeError(MSG_INVALID_URL, &aUrl);
return nullptr;
}
nsRefPtr<URL> url = new URL(uri);
nsRefPtr<URL> url = new URL(uri.forget());
return url.forget();
}

View File

@ -39,7 +39,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(URL)
explicit URL(nsIURI* aURI);
explicit URL(already_AddRefed<nsIURI> aURI);
// WebIDL methods
bool
@ -49,8 +49,16 @@ public:
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
URL& aBase, ErrorResult& aRv);
static already_AddRefed<URL>
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
const Optional<nsAString>& aBase, ErrorResult& aRv);
// Versions of Constructor that we can share with workers and other code.
static already_AddRefed<URL>
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
const nsAString& aBase, ErrorResult& aRv);
static already_AddRefed<URL>
Constructor(const nsAString& aUrl, const nsAString& aBase, ErrorResult& aRv);
static already_AddRefed<URL>
Constructor(const nsAString& aUrl, nsIURI* aBase, ErrorResult& aRv);
static void CreateObjectURL(const GlobalObject& aGlobal,
File& aBlob,

View File

@ -11266,6 +11266,12 @@ ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
NS_ASSERTION(!root->IsFullScreenDoc(),
"Fullscreen root should no longer be a fullscreen doc...");
// Dispatch MozExitedDomFullscreen to the last document in
// the list since we want this event to follow the same path
// MozEnteredDomFullscreen dispatched.
nsRefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
changed.LastElement(), NS_LITERAL_STRING("MozExitedDomFullscreen"), true, true);
asyncDispatcher->PostDOMEvent();
// Move the top-level window out of fullscreen mode.
SetWindowFullScreen(root, false);
}
@ -11422,6 +11428,9 @@ nsDocument::RestorePreviousFullScreenState()
// move the top-level window out of fullscreen mode.
NS_ASSERTION(!GetFullscreenRootDocument(this)->IsFullScreenDoc(),
"Should have cleared all docs' stacks");
nsRefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
this, NS_LITERAL_STRING("MozExitedDomFullscreen"), true, true);
asyncDispatcher->PostDOMEvent();
SetWindowFullScreen(this, false);
}
}

View File

@ -1084,6 +1084,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
mAddActiveEventFuzzTime(true),
mIsFrozen(false),
mFullScreen(false),
mFullscreenMode(false),
mIsClosed(false),
mInClose(false),
mHavePendingClose(false),
@ -6082,6 +6083,22 @@ nsGlobalWindow::SetFullScreenInternal(bool aFullScreen, bool aRequireTrust, gfx:
if (mFullScreen == aFullScreen)
return NS_OK;
// If a fullscreen is originated from chrome, we are switching to
// the fullscreen mode, otherwise, we are entering DOM fullscreen.
// Note that although entering DOM fullscreen could also cause
// consequential calls to this method, those calls will be skipped
// at the condition above.
if (aRequireTrust) {
mFullscreenMode = aFullScreen;
} else {
// If we are exiting from DOM fullscreen while we
// initially make the window fullscreen because of
// fullscreen mode, don't restore the window.
if (!aFullScreen && mFullscreenMode) {
return NS_OK;
}
}
// dispatch a "fullscreen" DOM event so that XUL apps can
// respond visually if we are kicked into full screen mode
if (!DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"))) {

View File

@ -1538,6 +1538,7 @@ protected:
// These members are only used on outer window objects. Make sure
// you never set any of these on an inner object!
bool mFullScreen : 1;
bool mFullscreenMode : 1;
bool mIsClosed : 1;
bool mInClose : 1;
// mHavePendingClose means we've got a termination function set to

View File

@ -48,12 +48,11 @@ addLoadEvent(function() {
// Now flush out layout on the subdocument, to trigger the resize handler
is(bod.getBoundingClientRect().width, 50, "Width of body should still be 50px");
window.requestAnimationFrame(function() {
is(resizeHandlerRan, true, "Resize handler should have run");
win.removeEventListener("resize", handleResize, false);
SimpleTest.finish();
});
});
</script>
</pre>

View File

@ -146,7 +146,7 @@ ErrorResult::ThrowErrorWithMessage(va_list ap, const dom::ErrNum errorNumber,
MOZ_ASSERT(argCount <= 10);
argCount = std::min<uint16_t>(argCount, 10);
while (argCount--) {
message->mArgs.AppendElement(*va_arg(ap, nsString*));
message->mArgs.AppendElement(*va_arg(ap, const nsAString*));
}
mMessage = message;
#ifdef DEBUG

View File

@ -1049,7 +1049,7 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
// We can end up here in all sorts of compartments, per above. Make
// sure to JS_WrapValue!
rval.set(JS::ObjectValue(*obj));
return JS_WrapValue(cx, rval);
return MaybeWrapObjectValue(cx, rval);
}
// Create a JSObject wrapping "value", for cases when "value" is a
@ -1097,7 +1097,7 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
// We can end up here in all sorts of compartments, per above. Make
// sure to JS_WrapValue!
rval.set(JS::ObjectValue(*obj));
return JS_WrapValue(cx, rval);
return MaybeWrapObjectValue(cx, rval);
}
// Helper for smart pointers (nsRefPtr/nsCOMPtr).

View File

@ -314,6 +314,30 @@ CacheStorage::PrefEnabled(JSContext* aCx, JSObject* aObj)
return Cache::PrefEnabled(aCx, aObj);
}
// static
already_AddRefed<CacheStorage>
CacheStorage::Constructor(const GlobalObject& aGlobal,
CacheStorageNamespace aNamespace,
nsIPrincipal* aPrincipal, ErrorResult& aRv)
{
if (NS_WARN_IF(!NS_IsMainThread())) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
// TODO: remove Namespace in favor of CacheStorageNamespace
static_assert(DEFAULT_NAMESPACE == (uint32_t)CacheStorageNamespace::Content,
"Default namespace should match webidl Content enum");
static_assert(CHROME_ONLY_NAMESPACE == (uint32_t)CacheStorageNamespace::Chrome,
"Chrome namespace should match webidl Chrome enum");
static_assert(NUMBER_OF_NAMESPACES == (uint32_t)CacheStorageNamespace::EndGuard_,
"Number of namespace should match webidl endguard enum");
Namespace ns = static_cast<Namespace>(aNamespace);
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
return CreateOnMainThread(ns, global, aPrincipal, aRv);
}
nsISupports*
CacheStorage::GetParentObject() const
{

View File

@ -7,7 +7,6 @@
#ifndef mozilla_dom_cache_CacheStorage_h
#define mozilla_dom_cache_CacheStorage_h
#include "mozilla/dom/CacheBinding.h"
#include "mozilla/dom/cache/Types.h"
#include "mozilla/dom/cache/TypeUtils.h"
#include "nsAutoPtr.h"
@ -29,6 +28,7 @@ namespace ipc {
namespace dom {
enum class CacheStorageNamespace : uint32_t;
class Promise;
namespace workers {
@ -64,6 +64,11 @@ public:
already_AddRefed<Promise> Delete(const nsAString& aKey, ErrorResult& aRv);
already_AddRefed<Promise> Keys(ErrorResult& aRv);
// chrome-only webidl interface methods
static already_AddRefed<CacheStorage>
Constructor(const GlobalObject& aGlobal, CacheStorageNamespace aNamespace,
nsIPrincipal* aPrincipal, ErrorResult& aRv);
// binding methods
static bool PrefEnabled(JSContext* aCx, JSObject* aObj);

4
dom/cache/moz.build vendored
View File

@ -94,3 +94,7 @@ FINAL_LIBRARY = 'xul'
MOCHITEST_MANIFESTS += [
'test/mochitest/mochitest.ini',
]
MOCHITEST_CHROME_MANIFESTS += [
'test/mochitest/chrome.ini',
]

1
dom/cache/test/mochitest/chrome.ini vendored Normal file
View File

@ -0,0 +1 @@
[test_chrome_constructor.html]

View File

@ -0,0 +1,43 @@
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
<title>Validate Interfaces Exposed to Workers</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">
var Cu = Components.utils;
Cu.import('resource://gre/modules/Services.jsm');
SimpleTest.waitForExplicitFinish();
// attach to a different origin's CacheStorage
var url = 'http://example.com/';
var uri = Services.io.newURI(url, null, null);
var principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
var storage = new CacheStorage('content', principal);
// verify we can use the other origin's CacheStorage as normal
var req = new Request('http://example.com/index.html');
var res = new Response('hello world');
var cache;
storage.open('foo').then(function(c) {
cache = c;
ok(cache, 'storage should create cache');
return cache.put(req, res.clone());
}).then(function() {
return cache.match(req);
}).then(function(foundResponse) {
return Promise.all([res.text(), foundResponse.text()]);
}).then(function(results) {
is(results[0], results[1], 'cache should contain response');
return storage.delete('foo');
}).then(function(deleted) {
ok(deleted, 'storage should delete cache');
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@ -21,6 +21,7 @@ skip-if = android_version == '10' || android_version == '18' #Android 2.3 and 4.
[webgl-mochitest/test_noprog_draw.html]
[webgl-mochitest/test_privileged_exts.html]
[webgl-mochitest/test_texsubimage_float.html]
[webgl-mochitest/test_uninit_data.html]
[webgl-mochitest/test_webgl_available.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
#[webgl-mochitest/test_webgl_color_buffer_float.html]

View File

@ -0,0 +1,84 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=utf-8'/>
<title>Test contents of uninitialized buffers</title>
<script src='/tests/SimpleTest/SimpleTest.js'></script>
<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
<script src='webgl-util.js'></script>
</head>
<body>
<script>
'use strict';
function TestFB(gl) {
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
ok(status == gl.FRAMEBUFFER_COMPLETE, 'FB should be complete.');
var pixel = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
ok(!pixel[0], 'R channel should be 0, was ' + pixel[0] + '.');
ok(!pixel[1], 'G channel should be 0, was ' + pixel[1] + '.');
ok(!pixel[2], 'B channel should be 0, was ' + pixel[2] + '.');
ok(!pixel[3], 'A channel should be 0, was ' + pixel[3] + '.');
}
function Test(contextAttribs) {
ok(true, '===============================');
ok(true, 'Testing ' + JSON.stringify(contextAttribs));
var c = document.createElement('canvas');
var gl = c.getContext('webgl', contextAttribs);
if (!gl) {
todo(false, 'WebGL is unavailable.');
return;
}
var rb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
var err = gl.getError();
ok(!err, 'Error should be 0x0, was 0x' + err.toString(16));
if (err)
return;
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
ok(true, 'Backed with RB');
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 1, 1);
TestFB(gl);
ok(true, 'Backed with texture');
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
TestFB(gl);
err = gl.getError();
ok(!err, 'Error should be 0x0, was 0x' + err.toString(16));
}
// Give ourselves a scope to return early from:
(function() {
// We test multiple configurations because we've had bugs regarding faking RGBX on
// ANGLE: With alpha:false, uninitialized buffers were being filled with (0,0,0,1)
// instead of (0,0,0,0).
Test({alpha: false, antialias: false});
Test({alpha: true, antialias: false});
Test({alpha: false, antialias: true});
Test({alpha: true, antialias: true});
ok(true, 'Test complete.');
})();
</script>
</body>
</html>

View File

@ -1528,6 +1528,9 @@ EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
getter_AddRefs(mGestureDownContent));
mGestureDownFrameOwner = inDownFrame->GetContent();
if (!mGestureDownFrameOwner) {
mGestureDownFrameOwner = mGestureDownContent;
}
}
mGestureModifiers = inDownEvent->modifiers;
mGestureDownButtons = inDownEvent->buttons;

View File

@ -1566,13 +1566,6 @@ nsHTMLDocument::Open(JSContext* cx,
return nullptr;
}
// We can't depend on channels implementing property bags, so do our
// base URI manually after reset.
if (rv.Failed()) {
return nullptr;
}
if (callerChannel) {
nsLoadFlags callerLoadFlags;
rv = callerChannel->GetLoadFlags(&callerLoadFlags);

View File

@ -51,7 +51,7 @@ interface nsIJSRAIIHelper;
interface nsIContentPermissionRequest;
interface nsIObserver;
[scriptable, uuid(9bb4a34f-de8f-43d3-a58c-10757cac95a0)]
[scriptable, uuid(1a75c351-d115-4d51-94df-731dd1723a1f)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -613,6 +613,11 @@ interface nsIDOMWindowUtils : nsISupports {
*/
const unsigned long MOUSESCROLL_PREFER_WIDGET_AT_POINT = 0x00000001;
/**
* Interpret the scroll delta values as lines rather than pixels.
*/
const unsigned long MOUSESCROLL_SCROLL_LINES = 0x00000002;
/**
* The platform specific values of aAdditionalFlags. Must be over 0x00010000.
*/

View File

@ -545,7 +545,7 @@ child:
CacheFileDescriptor(nsString path, FileDescriptor fd);
UpdateDimensions(IntRect rect, ScreenIntSize size, ScreenOrientation orientation,
LayoutDeviceIntPoint chromeDisp) compress;
LayoutDeviceIntPoint chromeDisp) compressall;
UpdateFrame(FrameMetrics frame);

View File

@ -934,11 +934,20 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
nsRefPtr<MediaDecoderStateMachine> self = this;
WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::WaitForData, aType)
->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnWaitForDataResolved,
&MediaDecoderStateMachine::OnWaitForDataRejected));
->RefableThen(TaskQueue(), __func__,
[self] (MediaData::Type aType) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->WaitRequestRef(aType).Complete();
self->DispatchDecodeTasksIfNeeded();
},
[self] (WaitForDataRejectValue aRejection) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->WaitRequestRef(aRejection.mType).Complete();
}));
return;
}
@ -1901,12 +1910,24 @@ MediaDecoderStateMachine::InitiateSeek()
Reset();
// Do the seek.
nsRefPtr<MediaDecoderStateMachine> self = this;
mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
GetEndTime())
->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnSeekCompleted,
&MediaDecoderStateMachine::OnSeekFailed));
->RefableThen(TaskQueue(), __func__,
[self] (int64_t) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->mSeekRequest.Complete();
// We must decode the first samples of active streams, so we can determine
// the new stream time. So dispatch tasks to do that.
self->mDecodeToSeekTarget = true;
self->DispatchDecodeTasksIfNeeded();
}, [self] (nsresult aResult) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->mSeekRequest.Complete();
MOZ_ASSERT(NS_FAILED(aResult), "Cancels should also disconnect mSeekRequest");
self->DecodeError();
}));
}
nsresult
@ -2386,30 +2407,6 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
return NS_OK;
}
void
MediaDecoderStateMachine::OnSeekCompleted(int64_t aTime)
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mSeekRequest.Complete();
// We must decode the first samples of active streams, so we can determine
// the new stream time. So dispatch tasks to do that.
mDecodeToSeekTarget = true;
DispatchDecodeTasksIfNeeded();
}
void
MediaDecoderStateMachine::OnSeekFailed(nsresult aResult)
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mSeekRequest.Complete();
MOZ_ASSERT(NS_FAILED(aResult), "Cancels should also disconnect mSeekRequest");
DecodeError();
}
void
MediaDecoderStateMachine::SeekCompleted()
{

View File

@ -427,22 +427,6 @@ public:
OnNotDecoded(MediaData::VIDEO_DATA, aReason);
}
void OnSeekCompleted(int64_t aTime);
void OnSeekFailed(nsresult aResult);
void OnWaitForDataResolved(MediaData::Type aType)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
WaitRequestRef(aType).Complete();
DispatchDecodeTasksIfNeeded();
}
void OnWaitForDataRejected(WaitForDataRejectValue aRejection)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
WaitRequestRef(aRejection.mType).Complete();
}
// Resets all state related to decoding and playback, emptying all buffers
// and aborting all pending operations on the decode task queue.
void Reset();

View File

@ -49,6 +49,31 @@ class MediaPromise
public:
typedef ResolveValueT ResolveValueType;
typedef RejectValueT RejectValueType;
class ResolveOrRejectValue
{
public:
void SetResolve(ResolveValueType& aResolveValue)
{
MOZ_ASSERT(IsNothing());
mResolveValue.emplace(aResolveValue);
}
void SetReject(RejectValueType& aRejectValue)
{
MOZ_ASSERT(IsNothing());
mRejectValue.emplace(aRejectValue);
}
bool IsResolve() const { return mResolveValue.isSome(); }
bool IsReject() const { return mRejectValue.isSome(); }
bool IsNothing() const { return mResolveValue.isNothing() && mRejectValue.isNothing(); }
ResolveValueType& ResolveValue() { return mResolveValue.ref(); }
RejectValueType& RejectValue() { return mRejectValue.ref(); }
private:
Maybe<ResolveValueType> mResolveValue;
Maybe<RejectValueType> mRejectValue;
};
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPromise)
@ -119,64 +144,74 @@ protected:
class ThenValueBase : public Consumer
{
public:
class ResolveRunnable : public nsRunnable
class ResolveOrRejectRunnable : public nsRunnable
{
public:
ResolveRunnable(ThenValueBase* aThenValue, ResolveValueType aResolveValue)
ResolveOrRejectRunnable(ThenValueBase* aThenValue, ResolveOrRejectValue& aValue)
: mThenValue(aThenValue)
, mResolveValue(aResolveValue) {}
, mValue(aValue) {}
~ResolveRunnable()
~ResolveOrRejectRunnable()
{
MOZ_DIAGNOSTIC_ASSERT(!mThenValue || mThenValue->IsDisconnected());
}
NS_IMETHODIMP Run()
{
PROMISE_LOG("ResolveRunnable::Run() [this=%p]", this);
mThenValue->DoResolve(mResolveValue);
PROMISE_LOG("ResolveOrRejectRunnable::Run() [this=%p]", this);
mThenValue->DoResolveOrReject(mValue);
mThenValue = nullptr;
return NS_OK;
}
private:
nsRefPtr<ThenValueBase> mThenValue;
ResolveValueType mResolveValue;
ResolveOrRejectValue mValue;
};
class RejectRunnable : public nsRunnable
{
public:
RejectRunnable(ThenValueBase* aThenValue, RejectValueType aRejectValue)
: mThenValue(aThenValue)
, mRejectValue(aRejectValue) {}
explicit ThenValueBase(AbstractThread* aResponseTarget, const char* aCallSite)
: mResponseTarget(aResponseTarget), mCallSite(aCallSite) {}
~RejectRunnable()
void Dispatch(MediaPromise *aPromise)
{
MOZ_DIAGNOSTIC_ASSERT(!mThenValue || mThenValue->IsDisconnected());
aPromise->mMutex.AssertCurrentThreadOwns();
MOZ_ASSERT(!aPromise->IsPending());
nsRefPtr<nsRunnable> runnable =
static_cast<nsRunnable*>(new (typename ThenValueBase::ResolveOrRejectRunnable)(this, aPromise->mValue));
PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
aPromise->mValue.IsResolve() ? "Resolving" : "Rejecting", ThenValueBase::mCallSite,
runnable.get(), aPromise, this);
// Promise consumers are allowed to disconnect the Consumer object and
// then shut down the thread or task queue that the promise result would
// be dispatched on. So we unfortunately can't assert that promise
// dispatch succeeds. :-(
mResponseTarget->Dispatch(runnable.forget(), AbstractThread::DontAssertDispatchSuccess);
}
NS_IMETHODIMP Run()
virtual void Disconnect() override
{
PROMISE_LOG("RejectRunnable::Run() [this=%p]", this);
mThenValue->DoReject(mRejectValue);
mThenValue = nullptr;
return NS_OK;
MOZ_ASSERT(ThenValueBase::mResponseTarget->IsCurrentThreadIn());
MOZ_DIAGNOSTIC_ASSERT(!Consumer::mComplete);
Consumer::mDisconnected = true;
}
private:
nsRefPtr<ThenValueBase> mThenValue;
RejectValueType mRejectValue;
};
explicit ThenValueBase(const char* aCallSite) : mCallSite(aCallSite) {}
virtual void Dispatch(MediaPromise *aPromise) = 0;
protected:
virtual void DoResolve(ResolveValueType aResolveValue) = 0;
virtual void DoReject(RejectValueType aRejectValue) = 0;
virtual void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) = 0;
void DoResolveOrReject(ResolveOrRejectValue& aValue)
{
Consumer::mComplete = true;
if (Consumer::mDisconnected) {
PROMISE_LOG("ThenValue::DoResolveOrReject disconnected - bailing out [this=%p]", this);
return;
}
DoResolveOrRejectInternal(aValue);
}
nsRefPtr<AbstractThread> mResponseTarget; // May be released on any thread.
const char* mCallSite;
};
@ -207,51 +242,20 @@ protected:
}
template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
class ThenValue : public ThenValueBase
class MethodThenValue : public ThenValueBase
{
public:
ThenValue(AbstractThread* aResponseTarget, ThisType* aThisVal,
MethodThenValue(AbstractThread* aResponseTarget, ThisType* aThisVal,
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod,
const char* aCallSite)
: ThenValueBase(aCallSite)
, mResponseTarget(aResponseTarget)
: ThenValueBase(aResponseTarget, aCallSite)
, mThisVal(aThisVal)
, mResolveMethod(aResolveMethod)
, mRejectMethod(aRejectMethod) {}
void Dispatch(MediaPromise *aPromise) override
{
aPromise->mMutex.AssertCurrentThreadOwns();
MOZ_ASSERT(!aPromise->IsPending());
bool resolved = aPromise->mResolveValue.isSome();
nsRefPtr<nsRunnable> runnable =
resolved ? static_cast<nsRunnable*>(new (typename ThenValueBase::ResolveRunnable)(this, aPromise->mResolveValue.ref()))
: static_cast<nsRunnable*>(new (typename ThenValueBase::RejectRunnable)(this, aPromise->mRejectValue.ref()));
PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
resolved ? "Resolving" : "Rejecting", ThenValueBase::mCallSite,
runnable.get(), aPromise, this);
// Promise consumers are allowed to disconnect the Consumer object and
// then shut down the thread or task queue that the promise result would
// be dispatched on. So we unfortunately can't assert that promise
// dispatch succeeds. :-(
mResponseTarget->Dispatch(runnable.forget(), AbstractThread::DontAssertDispatchSuccess);
}
#ifdef DEBUG
void AssertOnDispatchThread()
{
MOZ_ASSERT(mResponseTarget->IsCurrentThreadIn());
}
#else
void AssertOnDispatchThread() {}
#endif
virtual void Disconnect() override
{
AssertOnDispatchThread();
MOZ_DIAGNOSTIC_ASSERT(!Consumer::mComplete);
Consumer::mDisconnected = true;
ThenValueBase::Disconnect();
// If a Consumer has been disconnected, we don't guarantee that the
// resolve/reject runnable will be dispatched. Null out our refcounted
@ -260,32 +264,13 @@ protected:
}
protected:
virtual void DoResolve(ResolveValueType aResolveValue) override
virtual void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override
{
Consumer::mComplete = true;
if (Consumer::mDisconnected) {
MOZ_ASSERT(!mThisVal);
PROMISE_LOG("ThenValue::DoResolve disconnected - bailing out [this=%p]", this);
return;
if (aValue.IsResolve()) {
InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aValue.ResolveValue());
} else {
InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aValue.RejectValue());
}
InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aResolveValue);
// Null out mThisVal after invoking the callback so that any references are
// released predictably on the dispatch thread. Otherwise, it would be
// released on whatever thread last drops its reference to the ThenValue,
// which may or may not be ok.
mThisVal = nullptr;
}
virtual void DoReject(RejectValueType aRejectValue) override
{
Consumer::mComplete = true;
if (Consumer::mDisconnected) {
MOZ_ASSERT(!mThisVal);
PROMISE_LOG("ThenValue::DoReject disconnected - bailing out [this=%p]", this);
return;
}
InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aRejectValue);
// Null out mThisVal after invoking the callback so that any references are
// released predictably on the dispatch thread. Otherwise, it would be
@ -295,31 +280,96 @@ protected:
}
private:
nsRefPtr<AbstractThread> mResponseTarget; // May be released on any thread.
nsRefPtr<ThisType> mThisVal; // Only accessed and refcounted on dispatch thread.
ResolveMethodType mResolveMethod;
RejectMethodType mRejectMethod;
};
// NB: We could use std::function here instead of a template if it were supported. :-(
template<typename ResolveFunction, typename RejectFunction>
class FunctionThenValue : public ThenValueBase
{
public:
FunctionThenValue(AbstractThread* aResponseTarget,
ResolveFunction&& aResolveFunction,
RejectFunction&& aRejectFunction,
const char* aCallSite)
: ThenValueBase(aResponseTarget, aCallSite)
{
mResolveFunction.emplace(Move(aResolveFunction));
mRejectFunction.emplace(Move(aRejectFunction));
}
virtual void Disconnect() override
{
ThenValueBase::Disconnect();
// If a Consumer has been disconnected, we don't guarantee that the
// resolve/reject runnable will be dispatched. Destroy our callbacks
// now so that any references in closures are released predictable on
// the dispatch thread.
mResolveFunction.reset();
mRejectFunction.reset();
}
protected:
virtual void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override
{
if (aValue.IsResolve()) {
mResolveFunction.ref()(aValue.ResolveValue());
} else {
mRejectFunction.ref()(aValue.RejectValue());
}
// Destroy callbacks after invocation so that any references in closures are
// released predictably on the dispatch thread. Otherwise, they would be
// released on whatever thread last drops its reference to the ThenValue,
// which may or may not be ok.
mResolveFunction.reset();
mRejectFunction.reset();
}
private:
Maybe<ResolveFunction> mResolveFunction; // Only accessed and deleted on dispatch thread.
Maybe<RejectFunction> mRejectFunction; // Only accessed and deleted on dispatch thread.
};
public:
void ThenInternal(AbstractThread* aResponseThread, ThenValueBase* aThenValue,
const char* aCallSite)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(aResponseThread->IsDispatchReliable());
MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveConsumer);
mHaveConsumer = true;
PROMISE_LOG("%s invoking Then() [this=%p, aThenValue=%p, isPending=%d]",
aCallSite, this, aThenValue, (int) IsPending());
if (!IsPending()) {
aThenValue->Dispatch(this);
} else {
mThenValues.AppendElement(aThenValue);
}
}
public:
template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
already_AddRefed<Consumer> RefableThen(AbstractThread* aResponseThread, const char* aCallSite, ThisType* aThisVal,
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(aResponseThread->IsDispatchReliable());
MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveConsumer);
mHaveConsumer = true;
nsRefPtr<ThenValueBase> thenValue = new ThenValue<ThisType, ResolveMethodType, RejectMethodType>(
nsRefPtr<ThenValueBase> thenValue = new MethodThenValue<ThisType, ResolveMethodType, RejectMethodType>(
aResponseThread, aThisVal, aResolveMethod, aRejectMethod, aCallSite);
PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]",
aCallSite, this, thenValue.get(), aThisVal, (int) IsPending());
if (!IsPending()) {
thenValue->Dispatch(this);
} else {
mThenValues.AppendElement(thenValue);
ThenInternal(aResponseThread, thenValue, aCallSite);
return thenValue.forget();
}
template<typename ResolveFunction, typename RejectFunction>
already_AddRefed<Consumer> RefableThen(AbstractThread* aResponseThread, const char* aCallSite,
ResolveFunction&& aResolveFunction, RejectFunction&& aRejectFunction)
{
nsRefPtr<ThenValueBase> thenValue = new FunctionThenValue<ResolveFunction, RejectFunction>(aResponseThread,
Move(aResolveFunction), Move(aRejectFunction), aCallSite);
ThenInternal(aResponseThread, thenValue, aCallSite);
return thenValue.forget();
}
@ -332,6 +382,15 @@ public:
return;
}
template<typename ThisType, typename ResolveFunction, typename RejectFunction>
void Then(AbstractThread* aResponseThread, const char* aCallSite,
ResolveFunction&& aResolveFunction, RejectFunction&& aRejectFunction)
{
nsRefPtr<Consumer> c =
RefableThen(aResponseThread, aCallSite, Move(aResolveFunction), Move(aRejectFunction));
return;
}
void ChainTo(already_AddRefed<Private> aChainedPromise, const char* aCallSite)
{
MutexAutoLock lock(mMutex);
@ -348,7 +407,7 @@ public:
}
protected:
bool IsPending() { return mResolveValue.isNothing() && mRejectValue.isNothing(); }
bool IsPending() { return mValue.IsNothing(); }
void DispatchAll()
{
mMutex.AssertCurrentThreadOwns();
@ -366,10 +425,10 @@ protected:
void ForwardTo(Private* aOther)
{
MOZ_ASSERT(!IsPending());
if (mResolveValue.isSome()) {
aOther->Resolve(mResolveValue.ref(), "<chained promise>");
if (mValue.IsResolve()) {
aOther->Resolve(mValue.ResolveValue(), "<chained promise>");
} else {
aOther->Reject(mRejectValue.ref(), "<chained promise>");
aOther->Reject(mValue.RejectValue(), "<chained promise>");
}
}
@ -383,8 +442,7 @@ protected:
const char* mCreationSite; // For logging
Mutex mMutex;
Maybe<ResolveValueType> mResolveValue;
Maybe<RejectValueType> mRejectValue;
ResolveOrRejectValue mValue;
nsTArray<nsRefPtr<ThenValueBase>> mThenValues;
nsTArray<nsRefPtr<Private>> mChainedPromises;
bool mHaveConsumer;
@ -402,7 +460,7 @@ public:
MutexAutoLock lock(mMutex);
MOZ_ASSERT(IsPending());
PROMISE_LOG("%s resolving MediaPromise (%p created at %s)", aResolveSite, this, mCreationSite);
mResolveValue.emplace(aResolveValue);
mValue.SetResolve(aResolveValue);
DispatchAll();
}
@ -411,7 +469,7 @@ public:
MutexAutoLock lock(mMutex);
MOZ_ASSERT(IsPending());
PROMISE_LOG("%s rejecting MediaPromise (%p created at %s)", aRejectSite, this, mCreationSite);
mRejectValue.emplace(aRejectValue);
mValue.SetReject(aRejectValue);
DispatchAll();
}
};

View File

@ -98,9 +98,12 @@ SharedDecoderManager::CreateVideoDecoder(
mPDM = nullptr;
return nullptr;
}
mPDM = aPDM;
nsresult rv = mDecoder->Init();
NS_ENSURE_SUCCESS(rv, nullptr);
if (NS_FAILED(rv)) {
mDecoder = nullptr;
return nullptr;
}
mPDM = aPDM;
}
nsRefPtr<SharedDecoderProxy> proxy(new SharedDecoderProxy(this, aCallback));
@ -147,12 +150,20 @@ void
SharedDecoderManager::SetIdle(MediaDataDecoder* aProxy)
{
if (aProxy && mActiveProxy == aProxy) {
mWaitForInternalDrain = true;
mActiveProxy->Drain();
MonitorAutoLock mon(mMonitor);
mWaitForInternalDrain = true;
nsresult rv;
{
// We don't want to hold the lock while calling Drain() has some
// platform implementations call DrainComplete() immediately.
MonitorAutoUnlock mon(mMonitor);
rv = mActiveProxy->Drain();
}
if (NS_SUCCEEDED(rv)) {
while (mWaitForInternalDrain) {
mon.Wait();
}
}
mActiveProxy->Flush();
mActiveProxy = nullptr;
}
@ -161,13 +172,15 @@ SharedDecoderManager::SetIdle(MediaDataDecoder* aProxy)
void
SharedDecoderManager::DrainComplete()
{
if (mWaitForInternalDrain) {
{
MonitorAutoLock mon(mMonitor);
if (mWaitForInternalDrain) {
mWaitForInternalDrain = false;
mon.NotifyAll();
} else {
mActiveCallback->DrainComplete();
return;
}
}
mActiveCallback->DrainComplete();
}
void

View File

@ -364,6 +364,7 @@ AppleVDADecoder::SubmitFrame(MediaRawData* aSample)
if (rv != noErr) {
NS_WARNING("AppleVDADecoder: Couldn't pass frame to decoder");
mCallback->Error();
return NS_ERROR_FAILURE;
}

View File

@ -168,8 +168,7 @@ PlatformCallback(void* decompressionOutputRefCon,
return;
}
if (flags & kVTDecodeInfo_FrameDropped) {
NS_WARNING(" ...frame dropped...");
return;
NS_WARNING(" ...frame tagged as dropped...");
}
MOZ_ASSERT(CFGetTypeID(image) == CVPixelBufferGetTypeID(),
"VideoToolbox returned an unexpected image type");
@ -246,7 +245,9 @@ AppleVTDecoder::SubmitFrame(MediaRawData* aSample)
CreateAppleFrameRef(aSample),
&infoFlags);
if (rv != noErr && !(infoFlags & kVTDecodeInfo_FrameDropped)) {
LOG("AppleVTDecoder: Error %d VTDecompressionSessionDecodeFrame", rv);
NS_WARNING("Couldn't pass frame to decoder");
mCallback->Error();
return NS_ERROR_FAILURE;
}

View File

@ -37,23 +37,21 @@ var innerWidthMax = (isWin8 ? 125 : 100);
function test() {
var w = window.open('data:text/html,null', null, 'width=300,height=300');
var nbResize = 0;
SimpleTest.waitForFocus(function() {
w.onresize = function() {
nbResize++;
if (nbResize == 1) {
if (!(w.innerWidth + epsilon >= innerWidthMin &&
w.innerWidth - epsilon <= innerWidthMax)) {
// We need still another resize event.
return;
}
ok(w.innerWidth + epsilon >= innerWidthMin && w.innerWidth - epsilon <= innerWidthMax,
"innerWidth should be between " + innerWidthMin + " and " + innerWidthMax);
ok(w.innerHeight + epsilon >= 100 && w.innerHeight - epsilon <= 100,
"innerHeight should be around 100");
// It's not clear why 2 events are coming...
is(nbResize, 2, "We should get 2 events.");
if (!(w.innerHeight + epsilon >= 100 &&
w.innerHeight - epsilon <= 100)) {
// ditto
return;
}
ok(true, "innerWidth should be between " + innerWidthMin + " and " + innerWidthMax);
ok(true, "innerHeight should be around 100");
w.close();

View File

@ -60,7 +60,18 @@ function thirdEntry(event) {
is(event.target, gOuterDoc, "Third MozEnteredDomFullscreen should be targeted at outer doc");
ok(gOuterDoc.mozFullScreenElement != null, "Outer doc return to fullscreen after cancel fullscreen in inner doc");
window.removeEventListener("MozEnteredDomFullscreen", thirdEntry, false);
window.removeEventListener("MozExitedDomFullscreen", earlyExit, false);
window.addEventListener("MozExitedDomFullscreen", lastExit, false);
gOuterDoc.mozCancelFullScreen();
}
function earlyExit(event) {
ok(false, "MozExitedDomFullscreen should only be triggered after cancel all fullscreen");
}
function lastExit(event) {
is(event.target, gOuterDoc, "MozExitedDomFullscreen should be targeted at the last exited doc");
ok(gOuterDoc.mozFullScreenElement == null, "Fullscreen should have been fully exited");
window.opener.wrappedJSObject.done();
}
@ -71,6 +82,7 @@ function start() {
gOuterDoc = gBrowser.contentDocument;
gBrowser.contentWindow.focus();
window.addEventListener("MozEnteredDomFullscreen", firstEntry, false);
window.addEventListener("MozExitedDomFullscreen", earlyExit, false);
gOuterDoc.body.mozRequestFullScreen();
});
}
@ -78,6 +90,6 @@ function start() {
]]>
</script>
<!-- chrome://mochitests/content/chrome/dom/tests/mochitest/chrome/test_MozEnteredDomFullscreen_event.xul -->
<browser type="content" id="browser" width="400" height="400" src="http://mochi.test:8888/tests/dom/tests/mochitest/general/file_MozEnteredDomFullscreen.html"/>
<browser type="content" id="browser" width="400" height="400" src="http://mochi.test:8888/tests/dom/tests/mochitest/general/file_MozDomFullscreen.html"/>
</window>

View File

@ -4,7 +4,7 @@ support-files =
489127.html
DOMWindowCreated_chrome.xul
DOMWindowCreated_content.html
MozEnteredDomFullscreen_chrome.xul
MozDomFullscreen_chrome.xul
child_focus_frame.html
file_DOM_element_instanceof.xul
file_bug799299.xul
@ -49,7 +49,7 @@ skip-if = os == 'linux'
[test_indexedSetter.html]
[test_moving_nodeList.xul]
[test_moving_xhr.xul]
[test_MozEnteredDomFullscreen_event.xul]
[test_MozDomFullscreen_event.xul]
# disabled on OS X for intermittent failures--bug-798848
skip-if = toolkit == 'cocoa'
[test_nodesFromRect.html]

View File

@ -36,7 +36,7 @@ SpecialPowers.pushPrefEnv({"set": [['full-screen-api.enabled', true],
['full-screen-api.allow-trusted-requests-only', false]]}, setup);
function setup() {
newwindow = window.open("MozEnteredDomFullscreen_chrome.xul", "_blank","chrome,resizable=yes,width=400,height=400");
newwindow = window.open("MozDomFullscreen_chrome.xul", "_blank","chrome,resizable=yes,width=400,height=400");
}
function done()

View File

@ -1,7 +1,7 @@
[DEFAULT]
support-files =
497633.html
file_MozEnteredDomFullscreen.html
file_MozDomFullscreen.html
file_bug628069.html
file_clonewrapper.html
file_domWindowUtils_scrollbarSize.html

View File

@ -13,32 +13,32 @@
[Exposed=(Window,Worker),
Func="mozilla::dom::cache::Cache::PrefEnabled"]
interface Cache {
[Throws]
Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
[Throws]
Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
[Throws]
Promise<void> add(RequestInfo request);
[Throws]
Promise<void> addAll(sequence<RequestInfo> requests);
[Throws]
Promise<void> put(RequestInfo request, Response response);
[Throws]
Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
[Throws]
Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
[NewObject]
Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
[NewObject]
Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
[NewObject]
Promise<void> add(RequestInfo request);
[NewObject]
Promise<void> addAll(sequence<RequestInfo> requests);
[NewObject]
Promise<void> put(RequestInfo request, Response response);
[NewObject]
Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
[NewObject]
Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
};
dictionary CacheQueryOptions {
boolean ignoreSearch = false;
boolean ignoreMethod = false;
boolean ignoreVary = false;
DOMString cacheName;
boolean ignoreSearch = false;
boolean ignoreMethod = false;
boolean ignoreVary = false;
DOMString cacheName;
};
dictionary CacheBatchOperation {
DOMString type;
Request request;
Response response;
CacheQueryOptions options;
DOMString type;
Request request;
Response response;
CacheQueryOptions options;
};

View File

@ -10,17 +10,25 @@
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#cache-storage
interface Principal;
[Exposed=(Window,Worker),
ChromeConstructor(CacheStorageNamespace namespace, Principal principal),
Func="mozilla::dom::cache::CacheStorage::PrefEnabled"]
interface CacheStorage {
[Throws]
Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
[Throws]
Promise<boolean> has(DOMString cacheName);
[Throws]
Promise<Cache> open(DOMString cacheName);
[Throws]
Promise<boolean> delete(DOMString cacheName);
[Throws]
Promise<sequence<DOMString>> keys();
[NewObject]
Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
[NewObject]
Promise<boolean> has(DOMString cacheName);
[NewObject]
Promise<Cache> open(DOMString cacheName);
[NewObject]
Promise<boolean> delete(DOMString cacheName);
[NewObject]
Promise<sequence<DOMString>> keys();
};
// chrome-only, gecko specific extension
enum CacheStorageNamespace {
"content", "chrome"
};

View File

@ -50,4 +50,9 @@ interface MozSelfSupport
* The name of the pref to reset.
*/
void resetPref(DOMString name);
/**
* Resets original search engines, and resets the default one.
*/
void resetSearchEngines();
};

View File

@ -14,7 +14,7 @@
// [Constructor(DOMString url, optional (URL or DOMString) base = "about:blank")]
[Constructor(DOMString url, URL base),
Constructor(DOMString url, optional DOMString base = "about:blank"),
Constructor(DOMString url, optional DOMString base),
Exposed=(Window,Worker)]
interface URL {
};

View File

@ -16,6 +16,7 @@
#include "nsIHttpHeaderVisitor.h"
#include "nsINetworkInterceptController.h"
#include "nsIMutableArray.h"
#include "nsIUploadChannel2.h"
#include "nsPIDOMWindow.h"
#include "nsScriptLoader.h"
#include "nsDebug.h"
@ -2357,6 +2358,7 @@ class FetchEventRunnable : public WorkerRunnable
RequestMode mRequestMode;
RequestCredentials mRequestCredentials;
nsContentPolicyType mContentPolicyType;
nsCOMPtr<nsIInputStream> mUploadStream;
public:
FetchEventRunnable(WorkerPrivate* aWorkerPrivate,
nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
@ -2451,6 +2453,13 @@ public:
mContentPolicyType = loadInfo->GetContentPolicyType();
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
if (uploadChannel) {
MOZ_ASSERT(!mUploadStream);
rv = uploadChannel->CloneUploadStream(getter_AddRefs(mUploadStream));
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@ -2510,8 +2519,6 @@ private:
reqInit.mHeaders.Construct();
reqInit.mHeaders.Value().SetAsHeaders() = headers;
//TODO(jdm): set request body
reqInit.mMode.Construct(mRequestMode);
reqInit.mCredentials.Construct(mRequestCredentials);
@ -2525,6 +2532,8 @@ private:
MOZ_ASSERT(internalReq);
internalReq->SetCreatedByFetchEvent();
internalReq->SetBody(mUploadStream);
request->SetContentPolicyType(mContentPolicyType);
RootedDictionary<FetchEventInit> init(aCx);

View File

@ -34,7 +34,7 @@ class URLProxy final
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy)
explicit URLProxy(mozilla::dom::URL* aURL)
explicit URLProxy(already_AddRefed<mozilla::dom::URL> aURL)
: mURL(aURL)
{
AssertIsOnMainThread();
@ -228,7 +228,7 @@ class ConstructorRunnable : public WorkerMainThreadRunnable
private:
const nsString mURL;
const nsString mBase;
nsString mBase; // IsVoid() if we have no base URI string.
nsRefPtr<URLProxy> mBaseProxy;
mozilla::ErrorResult& mRv;
@ -236,13 +236,17 @@ private:
public:
ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
const nsAString& aURL, const nsAString& aBase,
const nsAString& aURL, const Optional<nsAString>& aBase,
mozilla::ErrorResult& aRv)
: WorkerMainThreadRunnable(aWorkerPrivate)
, mURL(aURL)
, mBase(aBase)
, mRv(aRv)
{
if (aBase.WasPassed()) {
mBase = aBase.Value();
} else {
mBase.SetIsVoid(true);
}
mWorkerPrivate->AssertIsOnWorkerThread();
}
@ -254,6 +258,7 @@ public:
, mBaseProxy(aBaseProxy)
, mRv(aRv)
{
mBase.SetIsVoid(true);
mWorkerPrivate->AssertIsOnWorkerThread();
}
@ -262,35 +267,20 @@ public:
{
AssertIsOnMainThread();
nsresult rv;
nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
mRv.Throw(rv);
return true;
}
nsCOMPtr<nsIURI> baseURL;
if (!mBaseProxy) {
rv = ioService->NewURI(NS_ConvertUTF16toUTF8(mBase), nullptr, nullptr,
getter_AddRefs(baseURL));
if (NS_FAILED(rv)) {
mRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return true;
}
nsRefPtr<mozilla::dom::URL> url;
if (mBaseProxy) {
url = mozilla::dom::URL::Constructor(mURL, mBaseProxy->URI(), mRv);
} else if (!mBase.IsVoid()) {
url = mozilla::dom::URL::Constructor(mURL, mBase, mRv);
} else {
baseURL = mBaseProxy->URI();
url = mozilla::dom::URL::Constructor(mURL, nullptr, mRv);
}
nsCOMPtr<nsIURI> url;
rv = ioService->NewURI(NS_ConvertUTF16toUTF8(mURL), nullptr, baseURL,
getter_AddRefs(url));
if (NS_FAILED(rv)) {
mRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
if (mRv.Failed()) {
return true;
}
mRetval = new URLProxy(new mozilla::dom::URL(url));
mRetval = new URLProxy(url.forget());
return true;
}
@ -522,18 +512,21 @@ URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
nsRefPtr<ConstructorRunnable> runnable =
new ConstructorRunnable(workerPrivate, aUrl, aBase.GetURLProxy(), aRv);
if (!runnable->Dispatch(cx)) {
JS_ReportPendingException(cx);
}
return FinishConstructor(cx, workerPrivate, runnable, aRv);
}
nsRefPtr<URLProxy> proxy = runnable->GetURLProxy();
if (!proxy) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return nullptr;
}
// static
already_AddRefed<URL>
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
const Optional<nsAString>& aBase, ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
nsRefPtr<URL> url = new URL(workerPrivate, proxy);
return url.forget();
nsRefPtr<ConstructorRunnable> runnable =
new ConstructorRunnable(workerPrivate, aUrl, aBase, aRv);
return FinishConstructor(cx, workerPrivate, runnable, aRv);
}
// static
@ -544,20 +537,34 @@ URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
JSContext* cx = aGlobal.Context();
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
Optional<nsAString> base;
base = &aBase;
nsRefPtr<ConstructorRunnable> runnable =
new ConstructorRunnable(workerPrivate, aUrl, aBase, aRv);
new ConstructorRunnable(workerPrivate, aUrl, base, aRv);
if (!runnable->Dispatch(cx)) {
JS_ReportPendingException(cx);
return FinishConstructor(cx, workerPrivate, runnable, aRv);
}
// static
already_AddRefed<URL>
URL::FinishConstructor(JSContext* aCx, WorkerPrivate* aPrivate,
ConstructorRunnable* aRunnable, ErrorResult& aRv)
{
if (!aRunnable->Dispatch(aCx)) {
JS_ReportPendingException(aCx);
}
nsRefPtr<URLProxy> proxy = runnable->GetURLProxy();
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<URLProxy> proxy = aRunnable->GetURLProxy();
if (!proxy) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return nullptr;
}
nsRefPtr<URL> url = new URL(workerPrivate, proxy);
nsRefPtr<URL> url = new URL(aPrivate, proxy);
return url.forget();
}

View File

@ -23,6 +23,7 @@ struct objectURLOptions;
BEGIN_WORKERS_NAMESPACE
class URLProxy;
class ConstructorRunnable;
class URL final : public mozilla::dom::URLSearchParamsObserver
{
@ -52,6 +53,9 @@ public:
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
URL& aBase, ErrorResult& aRv);
static already_AddRefed<URL>
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
const Optional<nsAString>& aBase, ErrorResult& aRv);
static already_AddRefed<URL>
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
const nsAString& aBase, ErrorResult& aRv);
@ -123,6 +127,10 @@ private:
return mURLProxy;
}
static already_AddRefed<URL>
FinishConstructor(JSContext* aCx, WorkerPrivate* aPrivate,
ConstructorRunnable* aRunnable, ErrorResult& aRv);
void CreateSearchParamsIfNeeded();
void SetSearchInternal(const nsAString& aSearch);

View File

@ -180,3 +180,73 @@ fetch('http://example.com/cors-for-no-cors', { mode: "no-cors" })
my_ok(false, "intercepted non-opaque response for no-cors request should resolve to opaque response. It should not fail.");
finish();
});
function arrayBufferFromString(str) {
var arr = new Uint8Array(str.length);
for (var i = 0; i < str.length; ++i) {
arr[i] = str.charCodeAt(i);
}
return arr;
}
expectAsyncResult();
fetch(new Request('body-simple', {method: 'POST', body: 'my body'}))
.then(function(res) {
return res.text();
}).then(function(body) {
my_ok(body == 'my bodymy body', "the body of the intercepted fetch should be visible in the SW");
finish();
});
expectAsyncResult();
fetch(new Request('body-arraybufferview', {method: 'POST', body: arrayBufferFromString('my body')}))
.then(function(res) {
return res.text();
}).then(function(body) {
my_ok(body == 'my bodymy body', "the ArrayBufferView body of the intercepted fetch should be visible in the SW");
finish();
});
expectAsyncResult();
fetch(new Request('body-arraybuffer', {method: 'POST', body: arrayBufferFromString('my body').buffer}))
.then(function(res) {
return res.text();
}).then(function(body) {
my_ok(body == 'my bodymy body', "the ArrayBuffer body of the intercepted fetch should be visible in the SW");
finish();
});
expectAsyncResult();
var usp = new URLSearchParams();
usp.set("foo", "bar");
usp.set("baz", "qux");
fetch(new Request('body-urlsearchparams', {method: 'POST', body: usp}))
.then(function(res) {
return res.text();
}).then(function(body) {
my_ok(body == 'foo=bar&baz=quxfoo=bar&baz=qux', "the URLSearchParams body of the intercepted fetch should be visible in the SW");
finish();
});
expectAsyncResult();
var fd = new FormData();
fd.set("foo", "bar");
fd.set("baz", "qux");
fetch(new Request('body-formdata', {method: 'POST', body: fd}))
.then(function(res) {
return res.text();
}).then(function(body) {
my_ok(body.indexOf("Content-Disposition: form-data; name=\"foo\"\r\n\r\nbar") <
body.indexOf("Content-Disposition: form-data; name=\"baz\"\r\n\r\nqux"),
"the FormData body of the intercepted fetch should be visible in the SW");
finish();
});
expectAsyncResult();
fetch(new Request('body-blob', {method: 'POST', body: new Blob(new String('my body'))}))
.then(function(res) {
return res.text();
}).then(function(body) {
my_ok(body == 'my bodymy body', "the Blob body of the intercepted fetch should be visible in the SW");
finish();
});

View File

@ -172,4 +172,10 @@ onfetch = function(ev) {
ev.respondWith(fetch(ev.request.url));
}
}
else if (ev.request.url.includes("body-")) {
ev.respondWith(ev.request.text().then(function (body) {
return new Response(body + body);
}));
}
}

View File

@ -94,12 +94,28 @@
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
// The handling of "dom.caches.enabled" here is a bit complicated. What we
// want to happen is that Cache is always enabled in service workers. So
// if service workers are disabled by default we want to force on both
// service workers and "dom.caches.enabled". But if service workers are
// enabled by default, we do not want to mess with the "dom.caches.enabled"
// value, since that would defeat the purpose of the test. Use a subframe
// to decide whether service workers are enabled by default, so we don't
// force creation of our own Navigator object before our prefs are set.
var prefs = [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.caches.enabled", true]
]}, runTest);
];
var subframe = document.createElement("iframe");
document.body.appendChild(subframe);
if (!("serviceWorker" in subframe.contentWindow.navigator)) {
prefs.push(["dom.caches.enabled", true]);
}
subframe.remove();
SpecialPowers.pushPrefEnv({"set": prefs}, runTest);
};
</script>
</body>

View File

@ -91,9 +91,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"BroadcastChannel",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Cache", release: false },
"Cache",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "CacheStorage", release: false },
"CacheStorage",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Client",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -17,24 +17,18 @@
var registration;
var promise;
SimpleTest.requestCompleteLog();
function start() {
info("start got called");
return navigator.serviceWorker.register("worker_updatefoundevent.js",
{ scope: "./updatefoundevent.html" })
.then((swr) => registration = swr);
}
function startWaitForUpdateFound() {
info("startWaitForUpdateFound got called");
registration.onupdatefound = function(e) {
info("onupdatefound");
}
promise = new Promise(function(resolve, reject) {
window.onmessage = function(e) {
info("Got message " + e.data);
if (e.data == "finish") {
ok(true, "Received updatefound");
@ -52,18 +46,16 @@
}
function registerNext() {
info("registerNext got called");
return navigator.serviceWorker.register("worker_updatefoundevent2.js",
{ scope: "./updatefoundevent.html" });
}
function waitForUpdateFound() {
info("waitForUpdateFound got called");
return promise;
}
function unregister() {
info("unregister got called");
window.onmessage = null;
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
});
@ -85,7 +77,6 @@
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["browser.dom.window.dump.enabled", true],
]}, runTest);
</script>
</pre>

View File

@ -6,10 +6,8 @@
onactivate = function(e) {
e.waitUntil(new Promise(function(resolve, reject) {
registration.onupdatefound = function(e) {
dump("Update found for scope " + registration.scope + "\n");
clients.matchAll().then(function(clients) {
if (!clients.length) {
dump("No clients found\n");
reject("No clients found");
}

View File

@ -1,2 +1 @@
// Not useful.
dump("worker_updatefoundevent2.js loaded\n");

View File

@ -0,0 +1,72 @@
// Utilities for synthesizing of native events.
function getPlatform() {
if (navigator.platform.indexOf("Win") == 0) {
return "windows";
}
if (navigator.platform.indexOf("Mac") == 0) {
return "mac";
}
if (navigator.platform.indexOf("Linux") == 0) {
return "linux";
}
return "unknown";
}
function nativeVerticalWheelEventMsg() {
switch (getPlatform()) {
case "windows": return 0x020A; // WM_MOUSEWHEEL
case "mac": return 0; // value is unused, can be anything
}
throw "Native wheel events not supported on platform " + getPlatform();
}
function nativeHorizontalWheelEventMsg() {
switch (getPlatform()) {
case "windows": return 0x020E; // WM_MOUSEHWHEEL
case "mac": return 0; // value is unused, can be anything
}
throw "Native wheel events not supported on platform " + getPlatform();
}
// Synthesizes a native mousewheel event and returns immediately. This does not
// guarantee anything; you probably want to use one of the other functions below
// which actually wait for results.
// aX and aY are relative to |window|'s top-left. aDeltaX and aDeltaY
// are pixel deltas, and aObserver can be left undefined if not needed.
function synthesizeNativeWheel(aElement, aX, aY, aDeltaX, aDeltaY, aObserver) {
aX += window.mozInnerScreenX;
aY += window.mozInnerScreenY;
if (aDeltaX && aDeltaY) {
throw "Simultaneous wheeling of horizontal and vertical is not supported on all platforms.";
}
var msg = aDeltaX ? nativeHorizontalWheelEventMsg() : nativeVerticalWheelEventMsg();
_getDOMWindowUtils().sendNativeMouseScrollEvent(aX, aY, msg, aDeltaX, aDeltaY, 0, 0, 0, aElement, aObserver);
return true;
}
// Synthesizes a native mousewheel event and invokes the callback once the
// request has been successfully made to the OS. This does not necessarily
// guarantee that the OS generates the event we requested. See
// synthesizeNativeWheel for details on the parameters.
function synthesizeNativeWheelAndWaitForObserver(aElement, aX, aY, aDeltaX, aDeltaY, aCallback) {
var observer = {
observe: function(aSubject, aTopic, aData) {
if (aCallback && aTopic == "mousescrollevent") {
setTimeout(aCallback, 0);
}
}
};
return synthesizeNativeWheel(aElement, aX, aY, aDeltaX, aDeltaY, observer);
}
// Synthesizes a native mousewheel event and invokes the callback once the
// wheel event is dispatched to the window. See synthesizeNativeWheel for
// details on the parameters.
function synthesizeNativeWheelAndWaitForEvent(aElement, aX, aY, aDeltaX, aDeltaY, aCallback) {
window.addEventListener("wheel", function wheelWaiter(e) {
window.removeEventListener("wheel", wheelWaiter);
setTimeout(aCallback, 0);
});
return synthesizeNativeWheel(aElement, aX, aY, aDeltaX, aDeltaY);
}

View File

@ -1,9 +1,13 @@
[DEFAULT]
support-files =
apz_test_utils.js
apz_test_native_event_utils.js
helper_bug982141.html
helper_bug1151663.html
tags = apz
[test_bug982141.html]
skip-if = toolkit != 'gonk' # bug 991198
[test_bug1151663.html]
skip-if = toolkit != 'gonk' # bug 991198
[test_wheel_scroll.html]
skip-if = toolkit != 'windows' && toolkit != 'cocoa'

View File

@ -0,0 +1,109 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1013412
-->
<head>
<title>Test for Bug 1013412</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
#content {
height: 800px;
overflow: scroll;
}
#scroller {
height: 2000px;
background: repeating-linear-gradient(#EEE, #EEE 100px, #DDD 100px, #DDD 200px);
}
#scrollbox {
margin-top: 200px;
width: 500px;
height: 500px;
border-radius: 250px;
box-shadow: inset 0 0 0 60px #555;
background: #777;
}
#circle {
position: relative;
left: 240px;
top: 20px;
border: 10px solid white;
border-radius: 10px;
width: 0px;
height: 0px;
transform-origin: 10px 230px;
will-change: transform;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1161206">Mozilla Bug 1161206</a>
<p id="display"></p>
<div id="content">
<p>Scrolling the page should be async, but scrolling over the dark circle should not scroll the page and instead rotate the white ball.</p>
<div id="scroller">
<div id="scrollbox">
<div id="circle"></div>
</div>
</div>
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
var rotation = 0;
var rotationAdjusted = false;
var incrementForMode = function (mode) {
switch (mode) {
case WheelEvent.DOM_DELTA_PIXEL: return 1;
case WheelEvent.DOM_DELTA_LINE: return 15;
case WheelEvent.DOM_DELTA_PAGE: return 400;
}
return 0;
};
document.getElementById("scrollbox").addEventListener("wheel", function (e) {
rotation += e.deltaY * incrementForMode(e.deltaMode) * 0.2;
document.getElementById("circle").style.transform = "rotate(" + rotation + "deg)";
rotationAdjusted = true;
e.preventDefault();
});
function* runTest() {
var content = document.getElementById('content');
for (i = 0; i < 300; i++) { // enough iterations that we would scroll to the bottom of 'content'
yield synthesizeNativeWheelAndWaitForEvent(content, 100, 150, 0, -5, continueTest);
}
var scrollbox = document.getElementById('scrollbox');
is(content.scrollTop > 0, true, "We should have scrolled down somewhat");
is(content.scrollTop < content.scrollTopMax, true, "We should not have scrolled to the bottom of the scrollframe");
is(rotationAdjusted, true, "The rotation should have been adjusted");
}
var gTestContinuation = null;
function continueTest() {
if (!gTestContinuation) {
gTestContinuation = runTest();
}
var ret = gTestContinuation.next();
if (ret.done) {
SimpleTest.finish();
} else {
is(ret.value, true, "Wheel event successfully synthesized");
}
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(continueTest, window);
</script>
</pre>
</body>
</html>

View File

@ -206,7 +206,7 @@ DeviceManagerD3D9::Init()
if (!mNv3DVUtils) {
mNv3DVUtils = new Nv3DVUtils();
if (!mNv3DVUtils) {
NS_WARNING("Could not create a new instance of Nv3DVUtils.\n");
NS_WARNING("Could not create a new instance of Nv3DVUtils.");
}
}

View File

@ -666,7 +666,7 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
}
if (UseVsyncComposition()) {
NS_WARNING("Enabling vsync compositor\n");
NS_WARNING("Enabling vsync compositor");
mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
} else {
mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);

View File

@ -1087,7 +1087,7 @@ CompositorOGL::DrawQuad(const Rect& aRect,
TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
if (!sourceY && !sourceCb && !sourceCr) {
if (!sourceY || !sourceCb || !sourceCr) {
NS_WARNING("Invalid layer texture.");
return;
}

View File

@ -497,7 +497,7 @@ gfxAndroidPlatform::CreateHardwareVsyncSource()
VsyncSource::Display& display = vsyncSource->GetGlobalDisplay();
display.EnableVsync();
if (!display.IsVsyncEnabled()) {
NS_WARNING("Error enabling gonk vsync. Falling back to software vsync\n");
NS_WARNING("Error enabling gonk vsync. Falling back to software vsync");
return gfxPlatform::CreateHardwareVsyncSource();
}
display.DisableVsync();

View File

@ -2344,7 +2344,7 @@ gfxPlatform::UsesOffMainThreadCompositing()
already_AddRefed<mozilla::gfx::VsyncSource>
gfxPlatform::CreateHardwareVsyncSource()
{
NS_WARNING("Hardware Vsync support not yet implemented. Falling back to software timers\n");
NS_WARNING("Hardware Vsync support not yet implemented. Falling back to software timers");
nsRefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
return softwareVsync.forget();
}

View File

@ -482,7 +482,7 @@ public:
// situations. According to the docs, it is compatible with all displays running on the computer
// But if we have different monitors at different display rates, we may hit issues.
if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not create a display link with all active displays. Retrying\n");
NS_WARNING("Could not create a display link with all active displays. Retrying");
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
@ -586,7 +586,7 @@ gfxPlatformMac::CreateHardwareVsyncSource()
VsyncSource::Display& primaryDisplay = osxVsyncSource->GetGlobalDisplay();
primaryDisplay.EnableVsync();
if (!primaryDisplay.IsVsyncEnabled()) {
NS_WARNING("OS X Vsync source not enabled. Falling back to software vsync.\n");
NS_WARNING("OS X Vsync source not enabled. Falling back to software vsync.");
return gfxPlatform::CreateHardwareVsyncSource();
}

View File

@ -1319,7 +1319,7 @@ gfxUtils::WriteAsPNG(SourceSurface* aSurface, const char* aFile)
}
}
if (!file) {
NS_WARNING("Failed to open file to create PNG!\n");
NS_WARNING("Failed to open file to create PNG!");
return;
}
}

View File

@ -2135,7 +2135,7 @@ public:
void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp)
{
MOZ_ASSERT(IsInVsyncThread());
NS_WARNING("DwmComposition dynamically disabled, falling back to software timers\n");
NS_WARNING("DwmComposition dynamically disabled, falling back to software timers");
TimeStamp nextVsync = aVsyncTimestamp + mSoftwareVsyncRate;
TimeDuration delay = nextVsync - TimeStamp::Now();
@ -2246,14 +2246,14 @@ gfxWindowsPlatform::CreateHardwareVsyncSource()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!WinUtils::dwmIsCompositionEnabledPtr) {
NS_WARNING("Dwm composition not available, falling back to software vsync\n");
NS_WARNING("Dwm composition not available, falling back to software vsync");
return gfxPlatform::CreateHardwareVsyncSource();
}
BOOL dwmEnabled = false;
WinUtils::dwmIsCompositionEnabledPtr(&dwmEnabled);
if (!dwmEnabled) {
NS_WARNING("DWM not enabled, falling back to software vsync\n");
NS_WARNING("DWM not enabled, falling back to software vsync");
return gfxPlatform::CreateHardwareVsyncSource();
}

View File

@ -719,16 +719,16 @@ nsJPEGDecoder::OutputScanlines(bool* suspend)
}
}
if (top != mInfo.output_scanline) {
if (mDownscaler && mDownscaler->HasInvalidation()) {
DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
PostInvalidation(invalidRect.mOriginalSizeRect,
Some(invalidRect.mTargetSizeRect));
MOZ_ASSERT(!mDownscaler->HasInvalidation());
} else if (!mDownscaler && top != mInfo.output_scanline) {
PostInvalidation(nsIntRect(0, top,
mInfo.output_width,
mInfo.output_scanline - top),
mDownscaler ? Some(mDownscaler->TakeInvalidRect())
: Nothing());
mInfo.output_scanline - top));
}
MOZ_ASSERT(!mDownscaler || !mDownscaler->HasInvalidation(),
"Didn't send downscaler's invalidation");
}
// Override the standard error method in the IJG JPEG decoder code.

View File

@ -473,7 +473,8 @@ Decoder::InternalAddFrame(uint32_t aFrameNum,
return RawAccessFrameRef();
}
if (!SurfaceCache::CanHold(aTargetSize)) {
const uint32_t bytesPerPixel = aPaletteDepth == 0 ? 4 : 1;
if (!SurfaceCache::CanHold(aFrameRect.Size(), bytesPerPixel)) {
NS_WARNING("Trying to add frame that's too large for the SurfaceCache");
return RawAccessFrameRef();
}

View File

@ -69,6 +69,8 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
"Invalid original size");
mOriginalSize = aOriginalSize;
mScale = gfxSize(double(mOriginalSize.width) / mTargetSize.width,
double(mOriginalSize.height) / mTargetSize.height);
mOutputBuffer = aOutputBuffer;
mHasAlpha = aHasAlpha;
@ -183,17 +185,25 @@ Downscaler::HasInvalidation() const
return mCurrentOutLine > mPrevInvalidatedLine;
}
nsIntRect
DownscalerInvalidRect
Downscaler::TakeInvalidRect()
{
if (MOZ_UNLIKELY(!HasInvalidation())) {
return nsIntRect();
return DownscalerInvalidRect();
}
nsIntRect invalidRect(0, mPrevInvalidatedLine,
mTargetSize.width,
mCurrentOutLine - mPrevInvalidatedLine);
DownscalerInvalidRect invalidRect;
// Compute the target size invalid rect.
invalidRect.mTargetSizeRect =
nsIntRect(0, mPrevInvalidatedLine,
mTargetSize.width, mCurrentOutLine - mPrevInvalidatedLine);
mPrevInvalidatedLine = mCurrentOutLine;
// Compute the original size invalid rect.
invalidRect.mOriginalSizeRect = invalidRect.mTargetSizeRect;
invalidRect.mOriginalSizeRect.ScaleRoundOut(mScale.width, mScale.height);
return invalidRect;
}

View File

@ -24,6 +24,16 @@ namespace skia {
namespace mozilla {
namespace image {
/**
* DownscalerInvalidRect wraps two invalidation rects: one in terms of the
* original image size, and one in terms of the target size.
*/
struct DownscalerInvalidRect
{
nsIntRect mOriginalSizeRect;
nsIntRect mTargetSizeRect;
};
/**
* Downscaler is a high-quality, streaming image downscaler based upon Skia's
* scaling implementation.
@ -47,6 +57,7 @@ public:
const nsIntSize& OriginalSize() const { return mOriginalSize; }
const nsIntSize& TargetSize() const { return mTargetSize; }
const gfxSize& Scale() const { return mScale; }
/**
* Begins a new frame and reinitializes the Downscaler.
@ -73,7 +84,7 @@ public:
bool HasInvalidation() const;
/// Takes the Downscaler's current invalid rect and resets it.
nsIntRect TakeInvalidRect();
DownscalerInvalidRect TakeInvalidRect();
/**
* Resets the Downscaler's position in the image, for a new progressive pass
@ -88,6 +99,7 @@ private:
nsIntSize mOriginalSize;
nsIntSize mTargetSize;
gfxSize mScale;
uint8_t* mOutputBuffer;

View File

@ -32,6 +32,7 @@
#include "nsSize.h"
#include "nsTArray.h"
#include "prsystem.h"
#include "ShutdownTracker.h"
#include "SVGImageContext.h"
using std::max;
@ -66,9 +67,10 @@ static StaticRefPtr<SurfaceCacheImpl> sInstance;
typedef size_t Cost;
static Cost
ComputeCost(const IntSize& aSize)
ComputeCost(const IntSize& aSize, uint32_t aBytesPerPixel)
{
return aSize.width * aSize.height * 4; // width * height * 4 bytes (32bpp)
MOZ_ASSERT(aBytesPerPixel == 1 || aBytesPerPixel == 4);
return aSize.width * aSize.height * aBytesPerPixel;
}
/**
@ -526,7 +528,8 @@ public:
} else {
// Our call to AddObject must have failed in StartTracking; most likely
// we're in XPCOM shutdown right now.
NS_WARNING("Not expiration-tracking an unlocked surface!");
NS_WARN_IF_FALSE(ShutdownTracker::ShutdownHasStarted(),
"Not expiration-tracking an unlocked surface!");
}
DebugOnly<bool> foundInCosts = mCosts.RemoveElementSorted(costEntry);
@ -1001,18 +1004,18 @@ SurfaceCache::Insert(imgFrame* aSurface,
}
MutexAutoLock lock(sInstance->GetMutex());
Cost cost = ComputeCost(aSurfaceKey.Size());
Cost cost = ComputeCost(aSurface->GetSize(), aSurface->GetBytesPerPixel());
return sInstance->Insert(aSurface, cost, aImageKey, aSurfaceKey, aLifetime);
}
/* static */ bool
SurfaceCache::CanHold(const IntSize& aSize)
SurfaceCache::CanHold(const IntSize& aSize, uint32_t aBytesPerPixel /* = 4 */)
{
if (!sInstance) {
return false;
}
Cost cost = ComputeCost(aSize);
Cost cost = ComputeCost(aSize, aBytesPerPixel);
return sInstance->CanHold(cost);
}

View File

@ -288,10 +288,13 @@ struct SurfaceCache
* for sure the cache can't hold it.
*
* @param aSize The dimensions of a surface in pixels.
* @param aBytesPerPixel How many bytes each pixel of the surface requires.
* Defaults to 4, which is appropriate for RGBA or RGBX
* images.
*
* @return false if the surface cache can't hold a surface of that size.
*/
static bool CanHold(const IntSize& aSize);
static bool CanHold(const IntSize& aSize, uint32_t aBytesPerPixel = 4);
static bool CanHold(size_t aSize);
/**

View File

@ -236,6 +236,14 @@ public:
*/
void WaitUntilComplete() const;
/**
* Returns the number of bytes per pixel this imgFrame requires. This is a
* worst-case value that does not take into account the effects of format
* changes caused by Optimize(), since an imgFrame is not optimized throughout
* its lifetime.
*/
uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
IntSize GetImageSize() const { return mImageSize; }
nsIntRect GetRect() const;
IntSize GetSize() const { return mSize; }

View File

@ -17,6 +17,7 @@ nsMacGujaratiToUnicodeConstructor(nsISupports *aOuter, REFNSIID aIID,
#include "macgujarati.ut"
};
Telemetry::Accumulate(Telemetry::DECODER_INSTANTIATED_MACGUJARATI, true);
return CreateOneByteDecoder((uMappingTable*) &g_utMappingTable,
aOuter, aIID, aResult);
}

View File

@ -49,6 +49,8 @@ Message::Message(int32_t routing_id, msgid_t type, PriorityValue priority,
header()->flags = priority;
if (compression == COMPRESSION_ENABLED)
header()->flags |= COMPRESS_BIT;
else if (compression == COMPRESSION_ALL)
header()->flags |= COMPRESSALL_BIT;
#if defined(OS_POSIX)
header()->num_fds = 0;
#endif

View File

@ -56,7 +56,8 @@ class Message : public Pickle {
enum MessageCompression {
COMPRESSION_NONE,
COMPRESSION_ENABLED
COMPRESSION_ENABLED,
COMPRESSION_ALL
};
virtual ~Message();
@ -99,8 +100,12 @@ class Message : public Pickle {
}
// True if compression is enabled for this message.
bool compress() const {
return (header()->flags & COMPRESS_BIT) != 0;
MessageCompression compress_type() const {
return (header()->flags & COMPRESS_BIT) ?
COMPRESSION_ENABLED :
(header()->flags & COMPRESSALL_BIT) ?
COMPRESSION_ALL :
COMPRESSION_NONE;
}
// Set this on a reply to a synchronous message.
@ -285,6 +290,7 @@ class Message : public Pickle {
HAS_SENT_TIME_BIT = 0x0080,
INTERRUPT_BIT = 0x0100,
COMPRESS_BIT = 0x0200,
COMPRESSALL_BIT = 0x0400,
};
struct Header : Pickle::Header {

View File

@ -612,6 +612,19 @@ MessageChannel::ShouldDeferMessage(const Message& aMsg)
return mSide == ParentSide && aMsg.transaction_id() != mCurrentTransaction;
}
// Predicate that is true for messages that should be consolidated if 'compress' is set.
class MatchingKinds {
typedef IPC::Message Message;
Message::msgid_t mType;
int32_t mRoutingId;
public:
MatchingKinds(Message::msgid_t aType, int32_t aRoutingId) :
mType(aType), mRoutingId(aRoutingId) {}
bool operator()(const Message &msg) {
return msg.type() == mType && msg.routing_id() == mRoutingId;
}
};
void
MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
{
@ -653,18 +666,36 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
}
// Prioritized messages cannot be compressed.
MOZ_ASSERT(!aMsg.compress() || aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
MOZ_ASSERT_IF(aMsg.compress_type() != IPC::Message::COMPRESSION_NONE,
aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
bool compress = (aMsg.compress() && !mPending.empty() &&
bool compress = false;
if (aMsg.compress_type() == IPC::Message::COMPRESSION_ENABLED) {
compress = (!mPending.empty() &&
mPending.back().type() == aMsg.type() &&
mPending.back().routing_id() == aMsg.routing_id());
if (compress) {
// This message type has compression enabled, and the back of the
// queue was the same message type and routed to the same destination.
// Replace it with the newer message.
MOZ_ASSERT(mPending.back().compress());
MOZ_ASSERT(mPending.back().compress_type() ==
IPC::Message::COMPRESSION_ENABLED);
mPending.pop_back();
}
} else if (aMsg.compress_type() == IPC::Message::COMPRESSION_ALL) {
// Check the message queue for another message with this type/destination.
auto it = std::find_if(mPending.rbegin(), mPending.rend(),
MatchingKinds(aMsg.type(), aMsg.routing_id()));
if (it != mPending.rend()) {
// This message type has compression enabled, and the queue holds
// a message with the same message type and routed to the same destination.
// Erase it. Note that, since we always compress these redundancies, There Can
// Be Only One.
compress = true;
MOZ_ASSERT((*it).compress_type() == IPC::Message::COMPRESSION_ALL);
mPending.erase((++it).base());
}
}
bool shouldWakeUp = AwaitingInterruptReply() ||
(AwaitingSyncReply() && !ShouldDeferMessage(aMsg)) ||

View File

@ -1860,8 +1860,11 @@ def _generateMessageClass(clsname, msgid, priority, prettyName, compress):
cls.addstmt(StmtDecl(Decl(idenum, '')))
# make the message constructor
if compress:
if compress == 'compress':
compression = ExprVar('COMPRESSION_ENABLED')
elif compress:
assert compress == 'compressall'
compression = ExprVar('COMPRESSION_ALL')
else:
compression = ExprVar('COMPRESSION_NONE')
if priority == ipdl.ast.NORMAL_PRIORITY:

View File

@ -123,6 +123,7 @@ reserved = set((
'child',
'class',
'compress',
'compressall',
'__delete__',
'delete', # reserve 'delete' to prevent its use
'from',
@ -546,12 +547,17 @@ def p_MessageOutParams(p):
p[0] = p[3]
def p_OptionalMessageCompress(p):
"""OptionalMessageCompress : COMPRESS
"""OptionalMessageCompress : MessageCompress
| """
if 1 == len(p):
p[0] = ''
else:
p[0] = 'compress'
p[0] = p[1]
def p_MessageCompress(p):
"""MessageCompress : COMPRESS
| COMPRESSALL"""
p[0] = p[1]
##--------------------
## State machine

View File

@ -1101,7 +1101,7 @@ class GatherDecls(TcheckVisitor):
msgtype = MessageType(md.priority, md.sendSemantics, md.direction,
ctor=isctor, dtor=isdtor, cdtype=cdtype,
compress=(md.compress == 'compress'))
compress=md.compress)
# replace inparam Param nodes with proper Decls
def paramToDecl(param):

View File

@ -204,8 +204,8 @@ struct JS_PUBLIC_API(NullPtr)
static void * const constNullValue;
};
JS_FRIEND_API(void) HeapCellPostBarrier(js::gc::Cell** cellp);
JS_FRIEND_API(void) HeapCellRelocate(js::gc::Cell** cellp);
JS_FRIEND_API(void) HeapObjectPostBarrier(JSObject** objp);
JS_FRIEND_API(void) HeapObjectRelocate(JSObject** objp);
#ifdef JS_DEBUG
/*
@ -214,9 +214,13 @@ JS_FRIEND_API(void) HeapCellRelocate(js::gc::Cell** cellp);
*/
extern JS_FRIEND_API(void)
AssertGCThingMustBeTenured(JSObject* obj);
extern JS_FRIEND_API(void)
AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell);
#else
inline void
AssertGCThingMustBeTenured(JSObject* obj) {}
inline void
AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {}
#endif
/*
@ -639,7 +643,10 @@ struct GCMethods<T*>
{
static T* initial() { return nullptr; }
static bool needsPostBarrier(T* v) { return false; }
static void postBarrier(T** vp) {}
static void postBarrier(T** vp) {
if (vp)
JS::AssertGCThingIsNotAnObjectSubclass(reinterpret_cast<js::gc::Cell*>(vp));
}
static void relocate(T** vp) {}
};
@ -657,10 +664,10 @@ struct GCMethods<JSObject*>
return v != nullptr && gc::IsInsideNursery(reinterpret_cast<gc::Cell*>(v));
}
static void postBarrier(JSObject** vp) {
JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell**>(vp));
JS::HeapObjectPostBarrier(vp);
}
static void relocate(JSObject** vp) {
JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell**>(vp));
JS::HeapObjectRelocate(vp);
}
};
@ -672,10 +679,10 @@ struct GCMethods<JSFunction*>
return v != nullptr && gc::IsInsideNursery(reinterpret_cast<gc::Cell*>(v));
}
static void postBarrier(JSFunction** vp) {
JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell**>(vp));
JS::HeapObjectPostBarrier(reinterpret_cast<JSObject**>(vp));
}
static void relocate(JSFunction** vp) {
JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell**>(vp));
JS::HeapObjectRelocate(reinterpret_cast<JSObject**>(vp));
}
};

View File

@ -75,3 +75,33 @@ template void js::PreBarrierFunctor<JS::Value>::operator()<JSObject>(JSObject*);
template void js::PreBarrierFunctor<JS::Value>::operator()<JSString>(JSString*);
template void js::PreBarrierFunctor<jsid>::operator()<JS::Symbol>(JS::Symbol*);
template void js::PreBarrierFunctor<jsid>::operator()<JSString>(JSString*);
JS_PUBLIC_API(void)
JS::HeapObjectPostBarrier(JSObject** objp)
{
MOZ_ASSERT(objp);
MOZ_ASSERT(*objp);
js::InternalGCMethods<JSObject*>::postBarrierRelocate(objp);
}
JS_PUBLIC_API(void)
JS::HeapObjectRelocate(JSObject** objp)
{
MOZ_ASSERT(objp);
MOZ_ASSERT(*objp);
js::InternalGCMethods<JSObject*>::postBarrierRemove(objp);
}
JS_PUBLIC_API(void)
JS::HeapValuePostBarrier(JS::Value* valuep)
{
MOZ_ASSERT(valuep);
js::InternalGCMethods<JS::Value>::postBarrierRelocate(valuep);
}
JS_PUBLIC_API(void)
JS::HeapValueRelocate(JS::Value* valuep)
{
MOZ_ASSERT(valuep);
js::InternalGCMethods<JS::Value>::postBarrierRemove(valuep);
}

View File

@ -202,50 +202,6 @@ StoreBuffer::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSi
sizes->storeBufferGenerics += bufferGeneric.sizeOfExcludingThis(mallocSizeOf);
}
JS_PUBLIC_API(void)
JS::HeapCellPostBarrier(js::gc::Cell** cellp)
{
MOZ_ASSERT(cellp);
MOZ_ASSERT(*cellp);
StoreBuffer* storeBuffer = (*cellp)->storeBuffer();
if (storeBuffer)
storeBuffer->putRelocatableCellFromAnyThread(cellp);
}
JS_PUBLIC_API(void)
JS::HeapCellRelocate(js::gc::Cell** cellp)
{
/* Called with old contents of *cellp before overwriting. */
MOZ_ASSERT(cellp);
MOZ_ASSERT(*cellp);
JSRuntime* runtime = (*cellp)->runtimeFromMainThread();
runtime->gc.storeBuffer.removeRelocatableCellFromAnyThread(cellp);
}
JS_PUBLIC_API(void)
JS::HeapValuePostBarrier(JS::Value* valuep)
{
MOZ_ASSERT(valuep);
MOZ_ASSERT(valuep->isMarkable());
if (valuep->isObject()) {
StoreBuffer* storeBuffer = valuep->toObject().storeBuffer();
if (storeBuffer)
storeBuffer->putRelocatableValueFromAnyThread(valuep);
}
}
JS_PUBLIC_API(void)
JS::HeapValueRelocate(JS::Value* valuep)
{
/* Called with old contents of *valuep before overwriting. */
MOZ_ASSERT(valuep);
MOZ_ASSERT(valuep->isMarkable());
if (valuep->isString() && valuep->toString()->isPermanentAtom())
return;
JSRuntime* runtime = static_cast<js::gc::Cell*>(valuep->toGCThing())->runtimeFromMainThread();
runtime->gc.storeBuffer.removeRelocatableValueFromAnyThread(valuep);
}
template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>;
template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotsEdge>;

View File

@ -6816,6 +6816,13 @@ JS::AssertGCThingMustBeTenured(JSObject* obj)
(!IsNurseryAllocable(obj->asTenured().getAllocKind()) || obj->getClass()->finalize));
}
JS_FRIEND_API(void)
JS::AssertGCThingIsNotAnObjectSubclass(Cell* cell)
{
MOZ_ASSERT(cell);
MOZ_ASSERT(cell->getTraceKind() != JSTRACE_OBJECT);
}
JS_FRIEND_API(void)
js::gc::AssertGCThingHasType(js::gc::Cell* cell, JSGCTraceKind kind)
{

View File

@ -9579,7 +9579,7 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
FCItemIterator iter(aItems);
do {
// Advance iter past children that don't want to be wrapped
if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState)) {
if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, containerType)) {
// Hit the end of the items without finding any remaining children that
// need to be wrapped. We're finished!
return;
@ -9601,7 +9601,8 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
FCItemIterator afterWhitespaceIter(iter);
bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
bool nextChildNeedsAnonItem =
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState);
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState,
containerType);
if (!nextChildNeedsAnonItem) {
// There's nothing after the whitespace that we need to wrap, so we
@ -9615,7 +9616,7 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
// we jump back to the beginning of the loop to skip over that child
// (and anything else non-wrappable after it)
MOZ_ASSERT(!iter.IsDone() &&
!iter.item().NeedsAnonFlexOrGridItem(aState),
!iter.item().NeedsAnonFlexOrGridItem(aState, containerType),
"hitEnd and/or nextChildNeedsAnonItem lied");
continue;
}
@ -9625,7 +9626,7 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
// anonymous flex/grid item. Now we see how many children after it also want
// to be wrapped in an anonymous flex/grid item.
FCItemIterator endIter(iter); // iterator to find the end of the group
endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState);
endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, containerType);
NS_ASSERTION(iter != endIter,
"Should've had at least one wrappable child to seek past");
@ -11831,8 +11832,9 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// Check if we're adding to-be-wrapped content right *after* an existing
// anonymous flex or grid item (which would need to absorb this content).
nsIAtom* containerType = aFrame->GetType();
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
iter.item().NeedsAnonFlexOrGridItem(aState)) {
iter.item().NeedsAnonFlexOrGridItem(aState, containerType)) {
RecreateFramesForContent(aFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr);
return true;
@ -11844,7 +11846,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// Jump to the last entry in the list
iter.SetToEnd();
iter.Prev();
if (iter.item().NeedsAnonFlexOrGridItem(aState)) {
if (iter.item().NeedsAnonFlexOrGridItem(aState, containerType)) {
RecreateFramesForContent(aFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr);
return true;
@ -11869,10 +11871,11 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
FCItemIterator iter(aItems);
// Skip over things that _do_ need an anonymous flex item, because
// they're perfectly happy to go here -- they won't cause a reframe.
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState)) {
nsIFrame* containerFrame = aFrame->GetParent();
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState,
containerFrame->GetType())) {
// We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out.
nsIFrame* containerFrame = aFrame->GetParent();
RecreateFramesForContent(containerFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr);
return true;
@ -12324,14 +12327,17 @@ Iterator::SkipItemsNotWantingParentType(ParentType aParentType)
bool
nsCSSFrameConstructor::FrameConstructionItem::
NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState)
NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
nsIAtom* aContainerType)
{
if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
// This will be an inline non-replaced box.
return true;
}
if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
// Bug 874718: Flex containers still wrap placeholders; Grid containers don't.
if (aContainerType == nsGkAtoms::flexContainerFrame &&
!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
aState.GetGeometricParent(mStyleContext->StyleDisplay(), nullptr)) {
// We're abspos or fixedpos, which means we'll spawn a placeholder which
// we'll need to wrap in an anonymous flex item. So, we just treat
@ -12346,10 +12352,11 @@ nsCSSFrameConstructor::FrameConstructionItem::
inline bool
nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState)
const nsFrameConstructorState& aState,
nsIAtom* aContainerType)
{
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (item().NeedsAnonFlexOrGridItem(aState)) {
while (item().NeedsAnonFlexOrGridItem(aState, aContainerType)) {
Next();
if (IsDone()) {
return true;
@ -12361,10 +12368,11 @@ Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
inline bool
nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState)
const nsFrameConstructorState& aState,
nsIAtom* aContainerType)
{
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (!(item().NeedsAnonFlexOrGridItem(aState))) {
while (!(item().NeedsAnonFlexOrGridItem(aState, aContainerType))) {
Next();
if (IsDone()) {
return true;

View File

@ -931,13 +931,13 @@ private:
// Return whether the iterator is done after doing that.
// The iterator must not be done when this is called.
inline bool SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState);
const nsFrameConstructorState& aState, nsIAtom* aContainerType);
// Skip to the first frame that is a non-replaced inline or is
// positioned. Return whether the iterator is done after doing that.
// The iterator must not be done when this is called.
inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState);
const nsFrameConstructorState& aState, nsIAtom* aContainerType);
// Skip over all items that do not want a ruby parent. Return whether
// the iterator is done after doing that. The iterator must not be done
@ -1074,7 +1074,8 @@ private:
// Indicates whether (when in a flex or grid container) this item needs
// to be wrapped in an anonymous block.
bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState);
bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
nsIAtom* aContainerType);
// Don't call this unless the frametree really depends on the answer!
// Especially so for generated content, where we don't want to reframe

View File

@ -138,10 +138,10 @@ typedef struct CapturingContentInfo {
mozilla::StaticRefPtr<nsIContent> mContent;
} CapturingContentInfo;
// d910f009-d209-74c1-6b04-30c83c051c78
// b7b89561-4f03-44b3-9afa-b47e7f313ffb
#define NS_IPRESSHELL_IID \
{ 0x025264c6, 0x0b12, 0x4804, \
{ 0xa3, 0x3e, 0xb7, 0x73, 0xf2, 0x19, 0x48, 0x90 } }
{ 0xb7b89561, 0x4f03, 0x44b3, \
{ 0x9a, 0xfa, 0xb4, 0x7e, 0x7f, 0x31, 0x3f, 0xfb } }
// debug VerifyReflow flags
#define VERIFY_REFLOW_ON 0x01
@ -1550,6 +1550,8 @@ public:
// Whether we should assume all images are visible.
virtual bool AssumeAllImagesVisible() = 0;
virtual void FireResizeEvent() = 0;
/**
* Refresh observer management.
*/

View File

@ -1216,6 +1216,9 @@ PresShell::Destroy()
// Revoke any pending events. We need to do this and cancel pending reflows
// before we destroy the frame manager, since apparently frame destruction
// sometimes spins the event queue when plug-ins are involved(!).
if (mResizeEventPending) {
rd->RemoveResizeEventFlushObserver(this);
}
rd->RemoveLayoutFlushObserver(this);
if (mHiddenInvalidationObserverRefreshDriver) {
mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this);
@ -1225,12 +1228,6 @@ PresShell::Destroy()
rd->RevokeViewManagerFlush();
}
mResizeEvent.Revoke();
if (mAsyncResizeTimerIsActive) {
mAsyncResizeEventTimer->Cancel();
mAsyncResizeTimerIsActive = false;
}
CancelAllPendingReflows();
CancelPostedReflowCallbacks();
@ -1998,12 +1995,6 @@ PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
self->UnsuppressPainting();
}
void
PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
{
static_cast<PresShell*>(aPresShell)->FireResizeEvent();
}
nsresult
PresShell::ResizeReflowOverride(nscoord aWidth, nscoord aHeight)
{
@ -2088,26 +2079,9 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
nsRect(0, 0, aWidth, rootFrame->GetRect().height));
}
if (!mIsDestroying && !mResizeEvent.IsPending() &&
!mAsyncResizeTimerIsActive) {
if (mInResize) {
if (!mAsyncResizeEventTimer) {
mAsyncResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
}
if (mAsyncResizeEventTimer) {
mAsyncResizeTimerIsActive = true;
mAsyncResizeEventTimer->InitWithFuncCallback(AsyncResizeEventCallback,
this, 15,
nsITimer::TYPE_ONE_SHOT);
}
} else {
nsRefPtr<nsRunnableMethod<PresShell> > resizeEvent =
NS_NewRunnableMethod(this, &PresShell::FireResizeEvent);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
mResizeEvent = resizeEvent;
mDocument->SetNeedStyleFlush();
}
}
if (!mIsDestroying && !mResizeEventPending) {
mResizeEventPending = true;
GetPresContext()->RefreshDriver()->AddResizeEventFlushObserver(this);
}
return NS_OK; //XXX this needs to be real. MMP
@ -2116,25 +2090,19 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
void
PresShell::FireResizeEvent()
{
if (mAsyncResizeTimerIsActive) {
mAsyncResizeTimerIsActive = false;
mAsyncResizeEventTimer->Cancel();
}
mResizeEvent.Revoke();
if (mIsDocumentGone)
if (mIsDocumentGone) {
return;
}
mResizeEventPending = false;
//Send resize event from here.
WidgetEvent event(true, NS_RESIZE_EVENT);
nsEventStatus status = nsEventStatus_eIgnore;
nsPIDOMWindow *window = mDocument->GetWindow();
nsPIDOMWindow* window = mDocument->GetWindow();
if (window) {
nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
mInResize = true;
EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
mInResize = false;
}
}
@ -4215,13 +4183,6 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
// hold weak refs when calling FlushPendingNotifications(). :(
nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
if (mResizeEvent.IsPending()) {
FireResizeEvent();
if (mIsDestroying) {
return;
}
}
// We need to make sure external resource documents are flushed too (for
// example, svg filters that reference a filter in an external document
// need the frames in the external document to be constructed for the

View File

@ -390,6 +390,8 @@ public:
void SetNextPaintCompressed() { mNextPaintCompressed = true; }
virtual void FireResizeEvent() override;
protected:
virtual ~PresShell();
@ -700,9 +702,6 @@ protected:
mozilla::LayoutDeviceIntPoint& aTargetPt,
nsIWidget *aRootWidget);
void FireResizeEvent();
static void AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell);
virtual void SynthesizeMouseMove(bool aFromScroll) override;
PresShell* GetRootPresShell();
@ -792,8 +791,6 @@ protected:
nsTArray<nsIFrame*> mDirtyRoots;
nsTArray<nsAutoPtr<DelayedEvent> > mDelayedEvents;
nsRevocableEventPtr<nsRunnableMethod<PresShell> > mResizeEvent;
nsCOMPtr<nsITimer> mAsyncResizeEventTimer;
private:
nsIFrame* mCurrentEventFrame;
nsCOMPtr<nsIContent> mCurrentEventContent;
@ -861,8 +858,7 @@ protected:
// have been processed.
bool mShouldUnsuppressPainting : 1;
bool mAsyncResizeTimerIsActive : 1;
bool mInResize : 1;
bool mResizeEventPending : 1;
bool mImageVisibilityVisited : 1;

View File

@ -859,7 +859,7 @@ CreateVsyncRefreshTimer()
return;
}
NS_WARNING("Enabling vsync refresh driver\n");
NS_WARNING("Enabling vsync refresh driver");
if (XRE_IsParentProcess()) {
// Make sure all vsync systems are ready.
@ -1330,6 +1330,7 @@ nsRefreshDriver::ObserverCount() const
// changes can trigger transitions which fire events when they complete, and
// layout changes can affect media queries on child documents, triggering
// style changes, etc.
sum += mResizeEventFlushObservers.Length();
sum += mStyleFlushObservers.Length();
sum += mLayoutFlushObservers.Length();
sum += mFrameRequestCallbackDocs.Length();
@ -1627,6 +1628,24 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
AutoRestore<TimeStamp> restoreTickStart(mTickStart);
mTickStart = TimeStamp::Now();
// Resize events should be fired before layout flushes or
// calling animation frame callbacks.
nsAutoTArray<nsIPresShell*, 16> observers;
observers.AppendElements(mResizeEventFlushObservers);
for (uint32_t i = observers.Length(); i; --i) {
if (!mPresContext || !mPresContext->GetPresShell()) {
break;
}
// Make sure to not process observers which might have been removed
// during previous iterations.
nsIPresShell* shell = observers[i - 1];
if (!mResizeEventFlushObservers.Contains(shell)) {
continue;
}
mResizeEventFlushObservers.RemoveElement(shell);
shell->FireResizeEvent();
}
/*
* The timer holds a reference to |this| while calling |Notify|.
* However, implementations of |WillRefresh| are permitted to destroy

View File

@ -148,6 +148,22 @@ public:
bool AddImageRequest(imgIRequest* aRequest);
void RemoveImageRequest(imgIRequest* aRequest);
/**
* Add / remove presshells which have pending resize event.
*/
void AddResizeEventFlushObserver(nsIPresShell* aShell)
{
NS_ASSERTION(!mResizeEventFlushObservers.Contains(aShell),
"Double-adding resize event flush observer");
mResizeEventFlushObservers.AppendElement(aShell);
EnsureTimerStarted();
}
void RemoveResizeEventFlushObserver(nsIPresShell* aShell)
{
mResizeEventFlushObservers.RemoveElement(aShell);
}
/**
* Add / remove presshells that we should flush style and layout on
*/
@ -392,6 +408,7 @@ private:
RequestTable mRequests;
ImageStartTable mStartTable;
nsAutoTArray<nsIPresShell*, 16> mResizeEventFlushObservers;
nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;

View File

@ -4741,8 +4741,20 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
NS_ASSERTION(!mSupppressScrollbarUpdate,
"This should have been suppressed");
nsIPresShell* presShell = mOuter->PresContext()->PresShell();
bool hasResizer = HasResizer();
bool scrollbarOnLeft = !IsScrollbarOnRight();
bool overlayScrollBarsWithZoom =
mIsRoot && LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) &&
presShell->IsScrollPositionClampingScrollPortSizeSet();
nsSize scrollPortClampingSize = mScrollPort.Size();
double res = 1.0;
if (overlayScrollBarsWithZoom) {
scrollPortClampingSize = presShell->GetScrollPositionClampingScrollPortSize();
res = presShell->GetCumulativeResolution();
}
// place the scrollcorner
if (mScrollCornerBox || mResizerBox) {
@ -4805,8 +4817,11 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
if (mVScrollbarBox) {
NS_PRECONDITION(mVScrollbarBox->IsBoxFrame(), "Must be a box frame!");
vRect = mScrollPort;
if (overlayScrollBarsWithZoom) {
vRect.height = NSToCoordRound(res * scrollPortClampingSize.height);
}
vRect.width = aContentArea.width - mScrollPort.width;
vRect.x = scrollbarOnLeft ? aContentArea.x : mScrollPort.XMost();
vRect.x = scrollbarOnLeft ? aContentArea.x : mScrollPort.x + NSToCoordRound(res * scrollPortClampingSize.width);
if (mHasVerticalScrollbar) {
nsMargin margin;
mVScrollbarBox->GetMargin(margin);
@ -4819,8 +4834,11 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
if (mHScrollbarBox) {
NS_PRECONDITION(mHScrollbarBox->IsBoxFrame(), "Must be a box frame!");
hRect = mScrollPort;
if (overlayScrollBarsWithZoom) {
hRect.width = NSToCoordRound(res * scrollPortClampingSize.width);
}
hRect.height = aContentArea.height - mScrollPort.height;
hRect.y = true ? mScrollPort.YMost() : aContentArea.y;
hRect.y = mScrollPort.y + NSToCoordRound(res * scrollPortClampingSize.height);
if (mHasHorizontalScrollbar) {
nsMargin margin;
mHScrollbarBox->GetMargin(margin);

View File

@ -26,19 +26,22 @@
using namespace mozilla;
typedef nsGridContainerFrame::TrackSize TrackSize;
const uint32_t nsGridContainerFrame::kAutoLine = 12345U;
const uint32_t nsGridContainerFrame::kTranslatedMaxLine =
uint32_t(nsStyleGridLine::kMaxLine - nsStyleGridLine::kMinLine - 1);
const uint32_t nsGridContainerFrame::kAutoLine = kTranslatedMaxLine + 3457U;
class nsGridContainerFrame::GridItemCSSOrderIterator
{
public:
enum OrderState { eUnknownOrder, eKnownOrdered, eKnownUnordered };
enum ChildFilter { eSkipPlaceholders, eIncludeAll };
GridItemCSSOrderIterator(nsIFrame* aGridContainer,
nsIFrame::ChildListID aListID,
ChildFilter aFilter = eSkipPlaceholders,
OrderState aState = eUnknownOrder)
: mChildren(aGridContainer->GetChildList(aListID))
, mArrayIndex(0)
, mSkipPlaceholders(aFilter == eSkipPlaceholders)
#ifdef DEBUG
, mGridContainer(aGridContainer)
, mListID(aListID)
@ -69,6 +72,10 @@ public:
// XXX replace this with nsTArray::StableSort when bug 1147091 is fixed.
std::stable_sort(mArray->begin(), mArray->end(), IsCSSOrderLessThan);
}
if (mSkipPlaceholders) {
SkipPlaceholders();
}
}
nsIFrame* operator*() const
@ -80,6 +87,28 @@ public:
return (*mArray)[mArrayIndex];
}
/**
* Skip over placeholder children.
*/
void SkipPlaceholders()
{
if (mEnumerator) {
for (; !mEnumerator->AtEnd(); mEnumerator->Next()) {
nsIFrame* child = mEnumerator->get();
if (child->GetType() != nsGkAtoms::placeholderFrame) {
return;
}
}
} else {
for (; mArrayIndex < mArray->Length(); ++mArrayIndex) {
nsIFrame* child = (*mArray)[mArrayIndex];
if (child->GetType() != nsGkAtoms::placeholderFrame) {
return;
}
}
}
}
bool AtEnd() const
{
MOZ_ASSERT(mEnumerator || mArrayIndex <= mArray->Length());
@ -100,9 +129,12 @@ public:
MOZ_ASSERT(mArrayIndex < mArray->Length(), "iterating past end");
++mArrayIndex;
}
if (mSkipPlaceholders) {
SkipPlaceholders();
}
}
void Reset()
void Reset(ChildFilter aFilter = eSkipPlaceholders)
{
if (mEnumerator) {
mEnumerator.reset();
@ -110,6 +142,10 @@ public:
} else {
mArrayIndex = 0;
}
mSkipPlaceholders = aFilter == eSkipPlaceholders;
if (mSkipPlaceholders) {
SkipPlaceholders();
}
}
bool ItemsAreAlreadyInOrder() const { return mEnumerator.isSome(); }
@ -124,6 +160,8 @@ private:
// Used if child list is *not* in ascending 'order'.
Maybe<nsTArray<nsIFrame*>> mArray;
size_t mArrayIndex;
// Skip placeholder children in the iteration?
bool mSkipPlaceholders;
#ifdef DEBUG
nsIFrame* mGridContainer;
nsIFrame::ChildListID mListID;
@ -1213,13 +1251,19 @@ nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator& aIter,
nsPresContext* pc = PresContext();
for (; !aIter.AtEnd(); aIter.Next()) {
nsIFrame* child = *aIter;
const bool isGridItem = child->GetType() != nsGkAtoms::placeholderFrame;
LogicalRect cb(wm);
if (MOZ_LIKELY(isGridItem)) {
GridArea* area = GetGridAreaForChild(child);
MOZ_ASSERT(area && area->IsDefinite());
LogicalRect cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
cb += gridOrigin;
} else {
cb = aContentArea;
}
nsHTMLReflowState childRS(pc, aReflowState, child, cb.Size(wm));
const LogicalMargin margin = childRS.ComputedLogicalMargin();
if (childRS.ComputedBSize() == NS_AUTOHEIGHT) {
if (childRS.ComputedBSize() == NS_AUTOHEIGHT && MOZ_LIKELY(isGridItem)) {
// XXX the start of an align-self:stretch impl. Needs min-/max-bsize
// clamping though, and check the prop value is actually 'stretch'!
LogicalMargin bp = childRS.ComputedLogicalBorderPadding();
@ -1234,6 +1278,7 @@ nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator& aIter,
nsReflowStatus childStatus;
ReflowChild(child, pc, childSize, childRS, wm, childPos,
containerWidth, 0, childStatus);
childRS.ApplyRelativePositioning(&childPos, containerWidth);
FinishReflowChild(child, pc, childSize, &childRS, wm, childPos,
containerWidth, 0);
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
@ -1330,7 +1375,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
computedISize, bSize);
normalFlowIter.Reset();
normalFlowIter.Reset(GridItemCSSOrderIterator::eIncludeAll);
ReflowChildren(normalFlowIter, contentArea, colSizes, rowSizes, aDesiredSize,
aReflowState, aStatus);
@ -1367,7 +1412,8 @@ nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
typedef GridItemCSSOrderIterator::OrderState OrderState;
OrderState order = mIsNormalFlowInCSSOrder ? OrderState::eKnownOrdered
: OrderState::eKnownUnordered;
GridItemCSSOrderIterator iter(this, kPrincipalList, order);
GridItemCSSOrderIterator iter(this, kPrincipalList,
GridItemCSSOrderIterator::eIncludeAll, order);
for (; !iter.AtEnd(); iter.Next()) {
nsIFrame* child = *iter;
BuildDisplayListForChild(aBuilder, child, aDirtyRect, childLists,
@ -1437,8 +1483,7 @@ FrameWantsToBeInAnonymousGridItem(nsIFrame* aFrame)
{
// Note: This needs to match the logic in
// nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem()
return (aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
nsGkAtoms::placeholderFrame == aFrame->GetType());
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
}
// Debugging method, to let us assert that our anonymous grid items are

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=325">
<style> html { direction: rtl; } </style>
</head>
<body>
<div style="width: 9000px;"></div>
</body>
</html>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=325">
</head>
<body>
<div style="width: 9000px;"></div>
</body>
</html>

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