mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
bd9cd9ac32
@ -219,6 +219,13 @@ RunProcesses(int argc, const char *argv[], FdArray& aReservedFds)
|
||||
aReservedFds);
|
||||
}
|
||||
|
||||
// Reap zombie child process.
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGCHLD, &sa, nullptr);
|
||||
|
||||
// The b2g process
|
||||
int childPid = pid;
|
||||
XRE_ProcLoaderClientInit(childPid, parentSock, aReservedFds);
|
||||
|
@ -770,13 +770,11 @@ pref("hal.processPriorityManager.gonk.notifyLowMemUnderKB", 14336);
|
||||
// blocked on a poll(), and this pref has no effect.)
|
||||
pref("gonk.systemMemoryPressureRecoveryPollMS", 5000);
|
||||
|
||||
#ifndef DEBUG
|
||||
// Enable pre-launching content processes for improved startup time
|
||||
// (hiding latency).
|
||||
pref("dom.ipc.processPrelaunch.enabled", true);
|
||||
// Wait this long before pre-launching a new subprocess.
|
||||
pref("dom.ipc.processPrelaunch.delayMs", 5000);
|
||||
#endif
|
||||
|
||||
pref("dom.ipc.reuse_parent_app", false);
|
||||
|
||||
@ -788,6 +786,9 @@ pref("dom.ipc.systemMessageCPULockTimeoutSec", 30);
|
||||
// Ignore the "dialog=1" feature in window.open.
|
||||
pref("dom.disable_window_open_dialog_feature", true);
|
||||
|
||||
// Enable before keyboard events and after keyboard events.
|
||||
pref("dom.beforeAfterKeyboardEvent.enabled", true);
|
||||
|
||||
// Screen reader support
|
||||
pref("accessibility.accessfu.activate", 2);
|
||||
pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem");
|
||||
@ -1032,8 +1033,8 @@ pref("dom.wakelock.enabled", true);
|
||||
// Enable touch caret by default
|
||||
pref("touchcaret.enabled", true);
|
||||
|
||||
// Disable selection caret by default
|
||||
pref("selectioncaret.enabled", false);
|
||||
// Enable selection caret by default
|
||||
pref("selectioncaret.enabled", true);
|
||||
|
||||
// Enable sync and mozId with Firefox Accounts.
|
||||
pref("services.sync.fxaccounts.enabled", true);
|
||||
|
@ -78,6 +78,10 @@ SettingsListener.observe('debug.console.enabled', true, function(value) {
|
||||
Services.prefs.setBoolPref('layout.css.report_errors', value);
|
||||
});
|
||||
|
||||
SettingsListener.observe('homescreen.manifestURL', 'Sentinel Value' , function(value) {
|
||||
Services.prefs.setCharPref('dom.mozApps.homescreenURL', value);
|
||||
});
|
||||
|
||||
// =================== Languages ====================
|
||||
SettingsListener.observe('language.current', 'en-US', function(value) {
|
||||
Services.prefs.setCharPref('general.useragent.locale', value);
|
||||
|
@ -321,7 +321,6 @@ var shell = {
|
||||
// if they did, they would use keycodes that conform to DOM 3 Events.
|
||||
// See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=762362
|
||||
chromeEventHandler.addEventListener('keydown', this, true);
|
||||
chromeEventHandler.addEventListener('keypress', this, true);
|
||||
chromeEventHandler.addEventListener('keyup', this, true);
|
||||
|
||||
window.addEventListener('MozApplicationManifest', this);
|
||||
@ -353,7 +352,6 @@ var shell = {
|
||||
stop: function shell_stop() {
|
||||
window.removeEventListener('unload', this);
|
||||
window.removeEventListener('keydown', this, true);
|
||||
window.removeEventListener('keypress', this, true);
|
||||
window.removeEventListener('keyup', this, true);
|
||||
window.removeEventListener('MozApplicationManifest', this);
|
||||
window.removeEventListener('mozfullscreenchange', this);
|
||||
@ -368,9 +366,10 @@ var shell = {
|
||||
IndexedDBPromptHelper.uninit();
|
||||
},
|
||||
|
||||
// If this key event actually represents a hardware button, filter it here
|
||||
// and send a mozChromeEvent with detail.type set to xxx-button-press or
|
||||
// xxx-button-release instead.
|
||||
// If this key event actually represents a hardware button, send a
|
||||
// mozChromeEvent with detail.type set to 'xxx-button-press' or
|
||||
// 'xxx-button-release' instead. Note that no more mozChromeEvent for hardware
|
||||
// buttons needed after Bug 1014418 is landed.
|
||||
filterHardwareKeys: function shell_filterHardwareKeys(evt) {
|
||||
var type;
|
||||
switch (evt.keyCode) {
|
||||
@ -381,10 +380,10 @@ var shell = {
|
||||
case evt.DOM_VK_END: // On desktop we don't have a sleep button
|
||||
type = 'sleep-button';
|
||||
break;
|
||||
case evt.DOM_VK_PAGE_UP: // Volume up button
|
||||
case evt.DOM_VK_VOLUME_UP: // Volume up button
|
||||
type = 'volume-up-button';
|
||||
break;
|
||||
case evt.DOM_VK_PAGE_DOWN: // Volume down button
|
||||
case evt.DOM_VK_VOLUME_DOWN: // Volume down button
|
||||
type = 'volume-down-button';
|
||||
break;
|
||||
case evt.DOM_VK_ESCAPE: // Back button (should be disabled)
|
||||
@ -415,17 +414,11 @@ var shell = {
|
||||
type = mediaKeys[evt.key];
|
||||
}
|
||||
|
||||
// The key doesn't represent a hardware button, so no mozChromeEvent.
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we didn't return, then the key event represents a hardware key
|
||||
// and we need to prevent it from propagating to Gaia
|
||||
evt.stopImmediatePropagation();
|
||||
evt.preventDefault(); // Prevent keypress events (when #501496 is fixed).
|
||||
|
||||
// If it is a key down or key up event, we send a chrome event to Gaia.
|
||||
// If it is a keypress event we just ignore it.
|
||||
switch (evt.type) {
|
||||
case 'keydown':
|
||||
type = type + '-press';
|
||||
@ -433,8 +426,6 @@ var shell = {
|
||||
case 'keyup':
|
||||
type = type + '-release';
|
||||
break;
|
||||
case 'keypress':
|
||||
return;
|
||||
}
|
||||
|
||||
// Let applications receive the headset button key press/release event.
|
||||
@ -471,7 +462,6 @@ var shell = {
|
||||
switch (evt.type) {
|
||||
case 'keydown':
|
||||
case 'keyup':
|
||||
case 'keypress':
|
||||
this.filterHardwareKeys(evt);
|
||||
break;
|
||||
case 'mozfullscreenchange':
|
||||
|
@ -228,6 +228,11 @@ this.PermissionsTable = { geolocation: {
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"homescreen-webapps-manage": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"backgroundservice": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
@ -498,6 +503,12 @@ this.PermissionsTable = { geolocation: {
|
||||
app: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"before-after-keyboard-event": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,11 @@ Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
|
||||
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||
"@mozilla.org/AppsService;1",
|
||||
"nsIAppsService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
@ -214,7 +219,7 @@ WebappsRegistry.prototype = {
|
||||
if (!this._mgmt) {
|
||||
let mgmt = Cc["@mozilla.org/webapps/manager;1"]
|
||||
.createInstance(Ci.nsISupports);
|
||||
mgmt.wrappedJSObject.init(this._window);
|
||||
mgmt.wrappedJSObject.init(this._window, this.hasFullMgmtPrivilege);
|
||||
mgmt.wrappedJSObject._windowId = this._id;
|
||||
this._mgmt = mgmt.__DOM_IMPL__
|
||||
? mgmt.__DOM_IMPL__
|
||||
@ -245,6 +250,10 @@ WebappsRegistry.prototype = {
|
||||
|
||||
// nsIDOMGlobalPropertyInitializer implementation
|
||||
init: function(aWindow) {
|
||||
const prefs = new Preferences();
|
||||
|
||||
this._window = aWindow;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, "Webapps:Install:Return:OK");
|
||||
|
||||
let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
@ -254,12 +263,24 @@ WebappsRegistry.prototype = {
|
||||
{ messages: ["Webapps:Install:Return:OK"]});
|
||||
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
let perm = Services.perms
|
||||
.testExactPermissionFromPrincipal(principal, "webapps-manage");
|
||||
let appId = principal.appId;
|
||||
let app = appId && appsService.getAppByLocalId(appId);
|
||||
|
||||
// Only pages with the webapps-manage permission set can get access to
|
||||
// the mgmt object.
|
||||
this.hasMgmtPrivilege = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
let isCurrentHomescreen = app &&
|
||||
app.manifestURL == prefs.get("dom.mozApps.homescreenURL") &&
|
||||
app.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
|
||||
|
||||
let hasWebappsPermission = Ci.nsIPermissionManager.ALLOW_ACTION ==
|
||||
Services.perms.testExactPermissionFromPrincipal(
|
||||
principal, "webapps-manage");
|
||||
|
||||
let hasHomescreenPermission = Ci.nsIPermissionManager.ALLOW_ACTION ==
|
||||
Services.perms.testExactPermissionFromPrincipal(
|
||||
principal, "homescreen-webapps-manage");
|
||||
|
||||
this.hasMgmtPrivilege = hasWebappsPermission ||
|
||||
(isCurrentHomescreen && hasHomescreenPermission);
|
||||
this.hasFullMgmtPrivilege = hasWebappsPermission;
|
||||
},
|
||||
|
||||
classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
|
||||
@ -294,13 +315,13 @@ WebappsApplication.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
init: function(aWindow, aApp) {
|
||||
this._window = aWindow;
|
||||
|
||||
let proxyHandler = DOMApplicationRegistry.addDOMApp(this,
|
||||
aApp.manifestURL,
|
||||
aApp.id);
|
||||
this._proxy = new Proxy(this, proxyHandler);
|
||||
|
||||
this._window = aWindow;
|
||||
|
||||
this.initDOMRequestHelper(aWindow);
|
||||
},
|
||||
|
||||
@ -719,7 +740,9 @@ function WebappsApplicationMgmt() {
|
||||
WebappsApplicationMgmt.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
init: function(aWindow) {
|
||||
init: function(aWindow, aHasFullMgmtPrivilege) {
|
||||
this._window = aWindow;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, ["Webapps:Uninstall:Return:OK",
|
||||
"Webapps:Uninstall:Broadcast:Return:OK",
|
||||
"Webapps:Uninstall:Return:KO",
|
||||
@ -736,6 +759,11 @@ WebappsApplicationMgmt.prototype = {
|
||||
"Webapps:SetEnabled:Return"]
|
||||
}
|
||||
);
|
||||
|
||||
if (!aHasFullMgmtPrivilege) {
|
||||
this.getNotInstalled = null;
|
||||
this.applyDownload = null;
|
||||
}
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
@ -751,12 +779,16 @@ WebappsApplicationMgmt.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
|
||||
cpmm.sendAsyncMessage("Webapps:ApplyDownload",
|
||||
{ manifestURL: aApp.manifestURL });
|
||||
{ manifestURL: aApp.manifestURL },
|
||||
null, principal);
|
||||
},
|
||||
|
||||
uninstall: function(aApp) {
|
||||
let request = this.createRequest();
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
|
||||
cpmm.sendAsyncMessage("Webapps:Uninstall", {
|
||||
origin: aApp.origin,
|
||||
@ -765,7 +797,8 @@ WebappsApplicationMgmt.prototype = {
|
||||
from: this._window.location.href,
|
||||
windowId: this._windowId,
|
||||
requestID: this.getRequestId(request)
|
||||
});
|
||||
}, null, principal);
|
||||
|
||||
return request;
|
||||
},
|
||||
|
||||
@ -782,12 +815,18 @@ WebappsApplicationMgmt.prototype = {
|
||||
|
||||
getNotInstalled: function() {
|
||||
let request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("Webapps:GetNotInstalled", { oid: this._id,
|
||||
requestID: this.getRequestId(request) });
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
|
||||
cpmm.sendAsyncMessage("Webapps:GetNotInstalled", {
|
||||
oid: this._id,
|
||||
requestID: this.getRequestId(request)
|
||||
}, null, principal);
|
||||
|
||||
return request;
|
||||
},
|
||||
|
||||
import: function(aBlob) {
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
return this.createPromise((aResolve, aReject) => {
|
||||
cpmm.sendAsyncMessage("Webapps:Import",
|
||||
{ blob: aBlob,
|
||||
@ -795,11 +834,12 @@ WebappsApplicationMgmt.prototype = {
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})});
|
||||
})}, null, principal);
|
||||
});
|
||||
},
|
||||
|
||||
extractManifest: function(aBlob) {
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
return this.createPromise((aResolve, aReject) => {
|
||||
cpmm.sendAsyncMessage("Webapps:ExtractManifest",
|
||||
{ blob: aBlob,
|
||||
@ -807,14 +847,16 @@ WebappsApplicationMgmt.prototype = {
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})});
|
||||
})}, null, principal);
|
||||
});
|
||||
},
|
||||
|
||||
setEnabled: function(aApp, aValue) {
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
|
||||
cpmm.sendAsyncMessage("Webapps:SetEnabled",
|
||||
{ manifestURL: aApp.manifestURL,
|
||||
enabled: aValue });
|
||||
enabled: aValue }, null, principal);
|
||||
},
|
||||
|
||||
get oninstall() {
|
||||
|
@ -128,6 +128,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
|
||||
"@mozilla.org/datastore-service;1",
|
||||
"nsIDataStoreService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||
"@mozilla.org/AppsService;1",
|
||||
"nsIAppsService");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "msgmgr", function() {
|
||||
return Cc["@mozilla.org/system-message-internal;1"]
|
||||
.getService(Ci.nsISystemMessagesInternal);
|
||||
@ -138,6 +142,11 @@ XPCOMUtils.defineLazyGetter(this, "updateSvc", function() {
|
||||
.getService(Ci.nsIOfflineCacheUpdateService);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "permMgr", function() {
|
||||
return Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
});
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
const DIRECTORY_NAME = "webappsDir";
|
||||
#elifdef ANDROID
|
||||
@ -625,8 +634,6 @@ this.DOMApplicationRegistry = {
|
||||
continue;
|
||||
// Remove the permissions, cookies and private data for this app.
|
||||
let localId = this.webapps[id].localId;
|
||||
let permMgr = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
permMgr.removePermissionsForApp(localId, false);
|
||||
Services.cookies.removeCookiesForApp(localId, false);
|
||||
this._clearPrivateData(localId, false);
|
||||
@ -1199,36 +1206,58 @@ this.DOMApplicationRegistry = {
|
||||
// the pref instead of first checking if it is false.
|
||||
Services.prefs.setBoolPref("dom.mozApps.used", true);
|
||||
|
||||
// We need to check permissions for calls coming from mozApps.mgmt.
|
||||
// These are: getNotInstalled(), applyDownload(), uninstall(), import(),
|
||||
// extractManifest(), setEnabled().
|
||||
if (["Webapps:GetNotInstalled",
|
||||
"Webapps:ApplyDownload",
|
||||
"Webapps:Uninstall",
|
||||
"Webapps:Import",
|
||||
"Webapps:ExtractManifest",
|
||||
"Webapps:SetEnabled"].indexOf(aMessage.name) != -1) {
|
||||
if (!aMessage.target.assertPermission("webapps-manage")) {
|
||||
debug("mozApps message " + aMessage.name +
|
||||
" from a content process with no 'webapps-manage' privileges.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// And RegisterBEP requires "browser" permission...
|
||||
if ("Webapps:RegisterBEP" == aMessage.name) {
|
||||
if (!aMessage.target.assertPermission("browser")) {
|
||||
debug("mozApps message " + aMessage.name +
|
||||
" from a content process with no 'browser' privileges.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let msg = aMessage.data || {};
|
||||
let mm = aMessage.target;
|
||||
msg.mm = mm;
|
||||
|
||||
let principal = aMessage.principal;
|
||||
|
||||
let checkPermission = function(aPermission) {
|
||||
if (!permMgr.testPermissionFromPrincipal(principal, aPermission)) {
|
||||
debug("mozApps message " + aMessage.name +
|
||||
" from a content process with no " + aPermission + " privileges.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// We need to check permissions for calls coming from mozApps.mgmt.
|
||||
|
||||
let allowed = true;
|
||||
switch (aMessage.name) {
|
||||
case "Webapps:Uninstall":
|
||||
let isCurrentHomescreen =
|
||||
Services.prefs.prefHasUserValue("dom.mozApps.homescreenURL") &&
|
||||
Services.prefs.getCharPref("dom.mozApps.homescreenURL") ==
|
||||
appsService.getManifestURLByLocalId(principal.appId);
|
||||
|
||||
allowed = checkPermission("webapps-manage") ||
|
||||
(checkPermission("homescreen-webapps-manage") && isCurrentHomescreen);
|
||||
break;
|
||||
|
||||
case "Webapps:GetNotInstalled":
|
||||
case "Webapps:ApplyDownload":
|
||||
case "Webapps:Import":
|
||||
case "Webapps:ExtractManifest":
|
||||
case "Webapps:SetEnabled":
|
||||
allowed = checkPermission("webapps-manage");
|
||||
break;
|
||||
|
||||
case "Webapps:RegisterBEP":
|
||||
allowed = checkPermission("browser");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
let processedImmediately = true;
|
||||
|
||||
if (!allowed) {
|
||||
mm.killChild();
|
||||
return null;
|
||||
}
|
||||
|
||||
// There are two kind of messages: the messages that only make sense once the
|
||||
// registry is ready, and those that can (or have to) be treated as soon as
|
||||
// they're received.
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "nsIObjectFrame.h"
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "SelectionCarets.h"
|
||||
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
@ -1566,6 +1567,11 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<SelectionCarets> selectionCarets = presShell->GetSelectionCarets();
|
||||
if (selectionCarets) {
|
||||
selectionCarets->SetVisibility(false);
|
||||
}
|
||||
|
||||
bool clearFirstBlurEvent = false;
|
||||
if (!mFirstBlurEvent) {
|
||||
mFirstBlurEvent = content;
|
||||
|
@ -797,6 +797,10 @@ GK_ATOM(onmouseover, "onmouseover")
|
||||
GK_ATOM(onMozMouseHittest, "onMozMouseHittest")
|
||||
GK_ATOM(onmouseup, "onmouseup")
|
||||
GK_ATOM(onMozAfterPaint, "onMozAfterPaint")
|
||||
GK_ATOM(onmozbrowserafterkeydown, "onmozbrowserafterkeydown")
|
||||
GK_ATOM(onmozbrowserafterkeyup, "onmozbrowserafterkeyup")
|
||||
GK_ATOM(onmozbrowserbeforekeydown, "onmozbrowserbeforekeydown")
|
||||
GK_ATOM(onmozbrowserbeforekeyup, "onmozbrowserbeforekeyup")
|
||||
GK_ATOM(onmozfullscreenchange, "onmozfullscreenchange")
|
||||
GK_ATOM(onmozfullscreenerror, "onmozfullscreenerror")
|
||||
GK_ATOM(onmozpointerlockchange, "onmozpointerlockchange")
|
||||
|
@ -27,7 +27,8 @@
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsISizeOfEventTarget.h"
|
||||
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
@ -463,6 +464,11 @@ public:
|
||||
void Send(nsIInputStream* aStream, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(aStream, "Null should go to string version");
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aStream);
|
||||
if (wjs) {
|
||||
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
||||
return;
|
||||
}
|
||||
aRv = Send(RequestBody(aStream));
|
||||
}
|
||||
void SendAsBinary(const nsAString& aBody, ErrorResult& aRv);
|
||||
|
@ -15,16 +15,6 @@ Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
|
||||
|
||||
let kLongestReturnedString = 128;
|
||||
|
||||
// Event whitelisted for bubbling.
|
||||
let whitelistedEvents = [
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE, // Back button.
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_SLEEP, // Power button.
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU,
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_F5, // Search button.
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP, // Volume up.
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN // Volume down.
|
||||
];
|
||||
|
||||
function debug(msg) {
|
||||
//dump("BrowserElementChildPreload - " + msg + "\n");
|
||||
}
|
||||
@ -240,15 +230,6 @@ BrowserElementChild.prototype = {
|
||||
|
||||
// We are using the system group for those events so if something in the
|
||||
// content called .stopPropagation() this will still be called.
|
||||
els.addSystemEventListener(global, 'keydown',
|
||||
this._keyEventHandler.bind(this),
|
||||
/* useCapture = */ true);
|
||||
els.addSystemEventListener(global, 'keypress',
|
||||
this._keyEventHandler.bind(this),
|
||||
/* useCapture = */ true);
|
||||
els.addSystemEventListener(global, 'keyup',
|
||||
this._keyEventHandler.bind(this),
|
||||
/* useCapture = */ true);
|
||||
els.addSystemEventListener(global, 'DOMWindowClose',
|
||||
this._windowCloseHandler.bind(this),
|
||||
/* useCapture = */ false);
|
||||
@ -1144,16 +1125,6 @@ BrowserElementChild.prototype = {
|
||||
sendAsyncMsg('got-set-input-method-active', msgData);
|
||||
},
|
||||
|
||||
_keyEventHandler: function(e) {
|
||||
if (whitelistedEvents.indexOf(e.keyCode) != -1 && !e.defaultPrevented) {
|
||||
sendAsyncMsg('keyevent', {
|
||||
type: e.type,
|
||||
keyCode: e.keyCode,
|
||||
charCode: e.charCode,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// The docShell keeps a weak reference to the progress listener, so we need
|
||||
// to keep a strong ref to it ourselves.
|
||||
_progressListener: {
|
||||
|
@ -245,7 +245,6 @@ BrowserElementParent.prototype = {
|
||||
"firstpaint": this._fireProfiledEventFromMsg,
|
||||
"documentfirstpaint": this._fireProfiledEventFromMsg,
|
||||
"nextpaint": this._recvNextPaint,
|
||||
"keyevent": this._fireKeyEvent,
|
||||
"got-purge-history": this._gotDOMRequestResult,
|
||||
"got-screenshot": this._gotDOMRequestResult,
|
||||
"got-contentdimensions": this._gotDOMRequestResult,
|
||||
@ -871,16 +870,6 @@ BrowserElementParent.prototype = {
|
||||
{isActive: isActive});
|
||||
},
|
||||
|
||||
_fireKeyEvent: function(data) {
|
||||
let evt = this._window.document.createEvent("KeyboardEvent");
|
||||
evt.initKeyEvent(data.json.type, true, true, this._window,
|
||||
false, false, false, false, // modifiers
|
||||
data.json.keyCode,
|
||||
data.json.charCode);
|
||||
|
||||
this._frameElement.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the visibility of the window which owns this iframe changes.
|
||||
*/
|
||||
|
@ -1,123 +0,0 @@
|
||||
/* Any copyright is dedicated to the public domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that an iframe with the |mozbrowser| attribute does bubble some
|
||||
// whitelisted key events.
|
||||
"use strict";
|
||||
|
||||
let Ci = SpecialPowers.Ci;
|
||||
|
||||
let whitelistedKeyCodes = [
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE, // Back button.
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_SLEEP, // Power button
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU,
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_F5, // Search button.
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP, // Volume up.
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN // Volume down.
|
||||
];
|
||||
|
||||
let blacklistedKeyCodes = [
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_A,
|
||||
Ci.nsIDOMKeyEvent.DOM_VK_B
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
browserElementTestHelpers.setEnabledPref(true);
|
||||
browserElementTestHelpers.addPermission();
|
||||
|
||||
// Number of expected events at which point we will consider the test as done.
|
||||
var nbEvents = whitelistedKeyCodes.length * 3;
|
||||
|
||||
var iframe;
|
||||
var finished = false;
|
||||
function runTest() {
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
iframe.src = browserElementTestHelpers.focusPage;
|
||||
|
||||
var gotFocus = false;
|
||||
var gotLoadend = false;
|
||||
|
||||
function maybeTest2() {
|
||||
if (gotFocus && gotLoadend) {
|
||||
SimpleTest.executeSoon(test2);
|
||||
}
|
||||
}
|
||||
|
||||
iframe.addEventListener('mozbrowserloadend', function() {
|
||||
gotLoadend = true;
|
||||
maybeTest2();
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
SimpleTest.waitForFocus(function() {
|
||||
iframe.focus();
|
||||
gotFocus = true;
|
||||
maybeTest2();
|
||||
});
|
||||
}
|
||||
|
||||
function eventHandler(e) {
|
||||
if (whitelistedKeyCodes.indexOf(e.keyCode) == -1 &&
|
||||
blacklistedKeyCodes.indexOf(e.keyCode) == -1) {
|
||||
// See bug 856006: We sometimes get unexpected key presses, and we don't
|
||||
// know why. Don't turn the test orange over this.
|
||||
ok(true, "Ignoring unexpected " + e.type +
|
||||
" with keyCode " + e.keyCode + ".");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(e.type == 'keydown' || e.type == 'keypress' || e.type == 'keyup',
|
||||
"e.type was " + e.type + ", expected keydown, keypress, or keyup");
|
||||
ok(!e.defaultPrevented, "expected !e.defaultPrevented");
|
||||
ok(whitelistedKeyCodes.indexOf(e.keyCode) != -1,
|
||||
"Expected a whitelited keycode, but got " + e.keyCode + " instead.");
|
||||
|
||||
nbEvents--;
|
||||
|
||||
// Prevent default for F5 because on desktop that reloads the page.
|
||||
if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_F5) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (nbEvents == 0) {
|
||||
//removeEventListener, otherwise a key event is fired
|
||||
//for some reason, with keyCode 95
|
||||
removeEventListener('keydown', eventHandler);
|
||||
removeEventListener('keypress', eventHandler);
|
||||
removeEventListener('keyup', eventHandler);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (nbEvents < 0 && !finished) {
|
||||
ok(false, "got an unexpected event! " + e.type + " " + e.keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
function test2() {
|
||||
is(document.activeElement, iframe, "iframe should be focused");
|
||||
|
||||
addEventListener('keydown', eventHandler);
|
||||
addEventListener('keypress', eventHandler);
|
||||
addEventListener('keyup', eventHandler);
|
||||
|
||||
// These events should not be received because they are not whitelisted.
|
||||
synthesizeKey("VK_A", {});
|
||||
synthesizeKey("VK_B", {});
|
||||
|
||||
// These events should not be received because preventDefault is called.
|
||||
synthesizeKey("VK_ESCAPE", {});
|
||||
|
||||
// These events should be received.
|
||||
synthesizeKey("VK_F5", {});
|
||||
synthesizeKey("VK_ESCAPE", {});
|
||||
synthesizeKey("VK_PAGE_UP", {});
|
||||
synthesizeKey("VK_PAGE_DOWN", {});
|
||||
synthesizeKey("VK_CONTEXT_MENU", {});
|
||||
synthesizeKey("VK_SLEEP", {});
|
||||
finished = true;
|
||||
}
|
||||
|
||||
addEventListener('testready', runTest);
|
@ -32,7 +32,6 @@ support-files =
|
||||
browserElement_GetScreenshot.js
|
||||
browserElement_GetScreenshotDppx.js
|
||||
browserElement_Iconchange.js
|
||||
browserElement_KeyEvents.js
|
||||
browserElement_LoadEvents.js
|
||||
browserElement_Manifestchange.js
|
||||
browserElement_Metachange.js
|
||||
@ -156,8 +155,6 @@ skip-if = (toolkit == 'gonk' && !debug)
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_browserElement_inproc_GetScreenshotDppx.html]
|
||||
[test_browserElement_inproc_Iconchange.html]
|
||||
[test_browserElement_inproc_KeyEvents.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_inproc_LoadEvents.html]
|
||||
[test_browserElement_inproc_Manifestchange.html]
|
||||
[test_browserElement_inproc_Metachange.html]
|
||||
@ -205,7 +202,4 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
# Disabled due to https://bugzilla.mozilla.org/show_bug.cgi?id=774100
|
||||
[test_browserElement_inproc_Reload.html]
|
||||
disabled = bug 774100
|
||||
# Disabled due to focus issues (no bug that I'm aware of)
|
||||
[test_browserElement_oop_KeyEvents.html]
|
||||
disabled =
|
||||
[test_browserElement_inproc_GetContentDimensions.html]
|
||||
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=757486
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 757486</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757486">Mozilla Bug 757486</a>
|
||||
|
||||
<script type="application/javascript;version=1.7" src="browserElement_KeyEvents.js">
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=757486
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 757486</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757486">Mozilla Bug 757486</a>
|
||||
|
||||
<script type="application/javascript;version=1.7" src="browserElement_KeyEvents.js">
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -69,6 +69,7 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.source-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.source-out.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
# xor and lighter aren't well handled by cairo; they mostly work, but we don't want
|
||||
# to test that
|
||||
[test_2d.composite.solid.xor.html]
|
||||
@ -108,7 +109,7 @@ disabled =
|
||||
[test_2d.composite.solid.soft-light.html]
|
||||
[test_2d.composite.uncovered.image.destination-atop.html]
|
||||
# This test fails in Suite on Linux for some reason, disable it there
|
||||
skip-if = os == 'linux' && buildapp == 'suite'
|
||||
skip-if = (os == 'linux' && buildapp == 'suite') || (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.uncovered.fill.color-burn.html]
|
||||
[test_2d.composite.uncovered.fill.color-dodge.html]
|
||||
[test_2d.composite.uncovered.fill.color.html]
|
||||
@ -214,7 +215,7 @@ disabled = bug 407107
|
||||
skip-if = (toolkit == 'gonk' && debug) #bug 1045153
|
||||
[test_bug902651.html]
|
||||
[test_canvas.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only crash; bug 933541
|
||||
skip-if = (toolkit == 'gonk' && debug) || (toolkit == 'android' && processor == 'x86') #debug-only crash; bug 933541 #x86 only bug 913662
|
||||
[test_canvas_focusring.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug) || (os == 'win' && debug) #specialpowers.wrap
|
||||
[test_canvas_font_setter.html]
|
||||
|
@ -10,7 +10,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
|
||||
[test_contacts_events.html]
|
||||
[test_contacts_getall.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
|
||||
skip-if = (toolkit == 'gonk' && debug) || (toolkit == 'android' && processor == 'x86') #debug-only failure #x86 only
|
||||
[test_contacts_getall2.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
|
||||
[test_contacts_international.html]
|
||||
|
@ -1212,6 +1212,7 @@ public:
|
||||
{
|
||||
mFormat = aFormat;
|
||||
mDataIsSet = false;
|
||||
mDataIsJwk = false;
|
||||
|
||||
// Get the current global object from the context
|
||||
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
@ -1280,6 +1281,7 @@ public:
|
||||
ClearException ce(aCx);
|
||||
JS::RootedValue value(aCx, JS::ObjectValue(*aKeyData));
|
||||
if (!mJwk.Init(aCx, value)) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
mDataIsJwk = true;
|
||||
@ -1358,6 +1360,7 @@ public:
|
||||
}
|
||||
|
||||
SetKeyData(aCx, aKeyData);
|
||||
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
|
||||
if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
@ -1504,6 +1507,7 @@ public:
|
||||
}
|
||||
|
||||
SetKeyData(aCx, aKeyData);
|
||||
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
|
||||
if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
@ -1658,6 +1662,7 @@ public:
|
||||
}
|
||||
|
||||
SetKeyData(aCx, aKeyData);
|
||||
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1772,6 +1777,7 @@ public:
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_SUCCEEDED(mEarlyRv)) {
|
||||
SetKeyData(aCx, aKeyData);
|
||||
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ TestArray.addTest(
|
||||
function () {
|
||||
var that = this;
|
||||
var alg = "AES-GCM";
|
||||
var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ" };
|
||||
var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", kty: "oct" };
|
||||
|
||||
function doExport(k) {
|
||||
return crypto.subtle.exportKey("jwk", k);
|
||||
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s # bug 781789 & bug 782275
|
||||
skip-if = e10s || (toolkit == 'android' && processor == 'x86') # bug 781789 & bug 782275
|
||||
support-files = devicestorage_common.js
|
||||
|
||||
[test_823965.html]
|
||||
|
92
dom/events/BeforeAfterKeyboardEvent.cpp
Normal file
92
dom/events/BeforeAfterKeyboardEvent.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEvent.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "prtime.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
BeforeAfterKeyboardEvent::BeforeAfterKeyboardEvent(
|
||||
EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
InternalBeforeAfterKeyboardEvent* aEvent)
|
||||
: KeyboardEvent(aOwner, aPresContext,
|
||||
aEvent ? aEvent :
|
||||
new InternalBeforeAfterKeyboardEvent(false, 0,
|
||||
nullptr))
|
||||
{
|
||||
MOZ_ASSERT(mEvent->mClass == eBeforeAfterKeyboardEventClass,
|
||||
"event type mismatch eBeforeAfterKeyboardEventClass");
|
||||
|
||||
if (!aEvent) {
|
||||
mEventIsInternal = true;
|
||||
mEvent->time = PR_Now();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
BeforeAfterKeyboardEvent::Constructor(
|
||||
EventTarget* aOwner,
|
||||
const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aParam)
|
||||
{
|
||||
nsRefPtr<BeforeAfterKeyboardEvent> event =
|
||||
new BeforeAfterKeyboardEvent(aOwner, nullptr, nullptr);
|
||||
ErrorResult rv;
|
||||
event->InitWithKeyboardEventInit(aOwner, aType, aParam, rv);
|
||||
NS_WARN_IF(rv.Failed());
|
||||
|
||||
event->mEvent->AsBeforeAfterKeyboardEvent()->mEmbeddedCancelled =
|
||||
aParam.mEmbeddedCancelled;
|
||||
|
||||
return event.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
BeforeAfterKeyboardEvent::Constructor(
|
||||
const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
return Constructor(owner, aType, aParam);
|
||||
}
|
||||
|
||||
Nullable<bool>
|
||||
BeforeAfterKeyboardEvent::GetEmbeddedCancelled()
|
||||
{
|
||||
nsAutoString type;
|
||||
GetType(type);
|
||||
if (type.EqualsLiteral("mozbrowserafterkeydown") ||
|
||||
type.EqualsLiteral("mozbrowserafterkeyup")) {
|
||||
return mEvent->AsBeforeAfterKeyboardEvent()->mEmbeddedCancelled;
|
||||
}
|
||||
return Nullable<bool>();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
nsresult
|
||||
NS_NewDOMBeforeAfterKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
InternalBeforeAfterKeyboardEvent* aEvent)
|
||||
{
|
||||
BeforeAfterKeyboardEvent* it =
|
||||
new BeforeAfterKeyboardEvent(aOwner, aPresContext, aEvent);
|
||||
|
||||
NS_ADDREF(it);
|
||||
*aInstancePtrResult = static_cast<Event*>(it);
|
||||
return NS_OK;
|
||||
}
|
45
dom/events/BeforeAfterKeyboardEvent.h
Normal file
45
dom/events/BeforeAfterKeyboardEvent.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_BeforeAfterKeyboardEvent_h_
|
||||
#define mozilla_dom_BeforeAfterKeyboardEvent_h_
|
||||
|
||||
#include "mozilla/dom/KeyboardEvent.h"
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEventBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BeforeAfterKeyboardEvent : public KeyboardEvent
|
||||
{
|
||||
public:
|
||||
BeforeAfterKeyboardEvent(EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
InternalBeforeAfterKeyboardEvent* aEvent);
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
|
||||
{
|
||||
return BeforeAfterKeyboardEventBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
static already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aParam,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
Constructor(EventTarget* aOwner, const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aEventInitDict);
|
||||
|
||||
// This function returns a boolean value when event typs is either
|
||||
// "mozbrowserafterkeydown" or "mozbrowserafterkeyup".
|
||||
Nullable<bool> GetEmbeddedCancelled();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_BeforeAfterKeyboardEvent_h_
|
@ -701,6 +701,9 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
|
||||
case eKeyboardEventClass:
|
||||
return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsKeyboardEvent());
|
||||
case eBeforeAfterKeyboardEventClass:
|
||||
return NS_NewDOMBeforeAfterKeyboardEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsBeforeAfterKeyboardEvent());
|
||||
case eCompositionEventClass:
|
||||
return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsCompositionEvent());
|
||||
|
@ -237,6 +237,22 @@ EVENT(keyup,
|
||||
NS_KEY_UP,
|
||||
EventNameType_HTMLXUL,
|
||||
eKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserbeforekeydown,
|
||||
NS_KEY_BEFORE_DOWN,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserafterkeydown,
|
||||
NS_KEY_AFTER_DOWN,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserbeforekeyup,
|
||||
NS_KEY_BEFORE_UP,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserafterkeyup,
|
||||
NS_KEY_AFTER_UP,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
EVENT(loadeddata,
|
||||
NS_LOADEDDATA,
|
||||
EventNameType_HTML,
|
||||
|
@ -656,8 +656,12 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
// then fall through...
|
||||
case NS_KEY_BEFORE_DOWN:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_AFTER_DOWN:
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
{
|
||||
nsIContent* content = GetFocusedContent();
|
||||
if (content)
|
||||
@ -3171,7 +3175,9 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
|
||||
break;
|
||||
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
break;
|
||||
|
||||
case NS_KEY_PRESS:
|
||||
|
@ -17,10 +17,8 @@ KeyboardEvent::KeyboardEvent(EventTarget* aOwner,
|
||||
: UIEvent(aOwner, aPresContext,
|
||||
aEvent ? aEvent : new WidgetKeyboardEvent(false, 0, nullptr))
|
||||
, mInitializedByCtor(false)
|
||||
, mInitialzedWhichValue(0)
|
||||
, mInitializedWhichValue(0)
|
||||
{
|
||||
NS_ASSERTION(mEvent->mClass == eKeyboardEventClass, "event type mismatch");
|
||||
|
||||
if (aEvent) {
|
||||
mEventIsInternal = false;
|
||||
}
|
||||
@ -257,8 +255,12 @@ KeyboardEvent::CharCode()
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_BEFORE_DOWN:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_AFTER_DOWN:
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
return 0;
|
||||
case NS_KEY_PRESS:
|
||||
return mEvent->AsKeyboardEvent()->charCode;
|
||||
@ -282,10 +284,7 @@ KeyboardEvent::KeyCode()
|
||||
return mEvent->AsKeyboardEvent()->keyCode;
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_PRESS:
|
||||
case NS_KEY_DOWN:
|
||||
if (mEvent->HasKeyEventMessage()) {
|
||||
return mEvent->AsKeyboardEvent()->keyCode;
|
||||
}
|
||||
return 0;
|
||||
@ -296,12 +295,16 @@ KeyboardEvent::Which()
|
||||
{
|
||||
// If this event is initialized with ctor, which can have independent value.
|
||||
if (mInitializedByCtor) {
|
||||
return mInitialzedWhichValue;
|
||||
return mInitializedWhichValue;
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_BEFORE_DOWN:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_AFTER_DOWN:
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
return KeyCode();
|
||||
case NS_KEY_PRESS:
|
||||
//Special case for 4xp bug 62878. Try to make value of which
|
||||
@ -343,26 +346,35 @@ KeyboardEvent::Constructor(const GlobalObject& aGlobal,
|
||||
nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
nsRefPtr<KeyboardEvent> newEvent =
|
||||
new KeyboardEvent(target, nullptr, nullptr);
|
||||
bool trusted = newEvent->Init(target);
|
||||
aRv = newEvent->InitKeyEvent(aType, aParam.mBubbles, aParam.mCancelable,
|
||||
aParam.mView, aParam.mCtrlKey, aParam.mAltKey,
|
||||
aParam.mShiftKey, aParam.mMetaKey,
|
||||
aParam.mKeyCode, aParam.mCharCode);
|
||||
newEvent->SetTrusted(trusted);
|
||||
newEvent->mDetail = aParam.mDetail;
|
||||
newEvent->mInitializedByCtor = true;
|
||||
newEvent->mInitialzedWhichValue = aParam.mWhich;
|
||||
newEvent->InitWithKeyboardEventInit(target, aType, aParam, aRv);
|
||||
|
||||
WidgetKeyboardEvent* internalEvent = newEvent->mEvent->AsKeyboardEvent();
|
||||
return newEvent.forget();
|
||||
}
|
||||
|
||||
void
|
||||
KeyboardEvent::InitWithKeyboardEventInit(EventTarget* aOwner,
|
||||
const nsAString& aType,
|
||||
const KeyboardEventInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
bool trusted = Init(aOwner);
|
||||
aRv = InitKeyEvent(aType, aParam.mBubbles, aParam.mCancelable,
|
||||
aParam.mView, aParam.mCtrlKey, aParam.mAltKey,
|
||||
aParam.mShiftKey, aParam.mMetaKey,
|
||||
aParam.mKeyCode, aParam.mCharCode);
|
||||
SetTrusted(trusted);
|
||||
mDetail = aParam.mDetail;
|
||||
mInitializedByCtor = true;
|
||||
mInitializedWhichValue = aParam.mWhich;
|
||||
|
||||
WidgetKeyboardEvent* internalEvent = mEvent->AsKeyboardEvent();
|
||||
internalEvent->location = aParam.mLocation;
|
||||
internalEvent->mIsRepeat = aParam.mRepeat;
|
||||
internalEvent->mIsComposing = aParam.mIsComposing;
|
||||
internalEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
|
||||
internalEvent->mKeyValue = aParam.mKey;
|
||||
internalEvent->mCodeNameIndex = CODE_NAME_INDEX_USE_STRING;
|
||||
internalEvent->mKeyValue = aParam.mKey;
|
||||
internalEvent->mCodeValue = aParam.mCode;
|
||||
|
||||
return newEvent.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -74,13 +74,19 @@ public:
|
||||
protected:
|
||||
~KeyboardEvent() {}
|
||||
|
||||
void InitWithKeyboardEventInit(EventTarget* aOwner,
|
||||
const nsAString& aType,
|
||||
const KeyboardEventInit& aParam,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
// True, if the instance is created with Constructor().
|
||||
bool mInitializedByCtor;
|
||||
|
||||
// If the instance is created with Constructor(), which may have independent
|
||||
// value. mInitializedWhichValue stores it. I.e., this is invalid when
|
||||
// mInitializedByCtor is false.
|
||||
uint32_t mInitialzedWhichValue;
|
||||
uint32_t mInitializedWhichValue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -32,6 +32,7 @@ EXPORTS.mozilla += [
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'AnimationEvent.h',
|
||||
'BeforeAfterKeyboardEvent.h',
|
||||
'BeforeUnloadEvent.h',
|
||||
'ClipboardEvent.h',
|
||||
'CommandEvent.h',
|
||||
@ -71,6 +72,7 @@ if CONFIG['MOZ_WEBSPEECH']:
|
||||
UNIFIED_SOURCES += [
|
||||
'AnimationEvent.cpp',
|
||||
'AsyncEventDispatcher.cpp',
|
||||
'BeforeAfterKeyboardEvent.cpp',
|
||||
'BeforeUnloadEvent.cpp',
|
||||
'ClipboardEvent.cpp',
|
||||
'CommandEvent.cpp',
|
||||
|
20
dom/events/test/bug989198_embedded.html
Normal file
20
dom/events/test/bug989198_embedded.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Embedded iframe</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="getFocus();">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<input id="input" style="display: block;">
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
function getFocus() {
|
||||
input = document.getElementById("input");
|
||||
input.focus();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
192
dom/events/test/bug989198_helper.js
Normal file
192
dom/events/test/bug989198_helper.js
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Helper functions for testing BeforeAfterKeyboardEvent.
|
||||
*/
|
||||
|
||||
const kUnknownEvent = 0x000;
|
||||
const kKeyDownEvent = 0x001;
|
||||
const kKeyUpEvent = 0x002;
|
||||
const kBeforeEvent = 0x010;
|
||||
const kAfterEvent = 0x020;
|
||||
const kParent = 0x100;
|
||||
const kChild = 0x200;
|
||||
|
||||
var gCurrentTest;
|
||||
|
||||
function frameScript()
|
||||
{
|
||||
function handler(e) {
|
||||
var results = sendSyncMessage("forwardevent", { type: e.type });
|
||||
if (results[0]) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
addEventListener('keydown', handler);
|
||||
addEventListener('keyup', handler);
|
||||
addEventListener('mozbrowserbeforekeydown', handler);
|
||||
addEventListener('mozbrowserbeforekeyup', handler);
|
||||
addEventListener('mozbrowserafterkeydown', handler);
|
||||
addEventListener('mozbrowserafterkeyup', handler);
|
||||
}
|
||||
|
||||
function prepareTest(useRemote)
|
||||
{
|
||||
if (useRemote) {
|
||||
setupHandlers(window, embedderHandler);
|
||||
} else {
|
||||
setupHandlers(window, embedderHandlerWithCheck);
|
||||
}
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.id = "embedded";
|
||||
iframe.src = "bug989198_embedded.html";
|
||||
iframe.setAttribute("remote", useRemote ? "true" : "false");
|
||||
SpecialPowers.wrap(iframe).mozbrowser = true;
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function onloadend() {
|
||||
iframe.removeEventListener("mozbrowserloadend", onloadend);
|
||||
iframe.focus();
|
||||
var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
mm.addMessageListener("forwardevent", function(msg) {
|
||||
return embeddedHandler(msg.json);
|
||||
});
|
||||
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", false);
|
||||
runTests();
|
||||
return;
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
function setupHandlers(element, handler)
|
||||
{
|
||||
element.addEventListener('keydown', handler);
|
||||
element.addEventListener('keyup', handler);
|
||||
element.addEventListener('mozbrowserbeforekeydown', handler);
|
||||
element.addEventListener('mozbrowserbeforekeyup', handler);
|
||||
element.addEventListener('mozbrowserafterkeydown', handler);
|
||||
element.addEventListener('mozbrowserafterkeyup', handler);
|
||||
}
|
||||
|
||||
function teardownHandlers(element, handler)
|
||||
{
|
||||
element.removeEventListener('keydown', handler);
|
||||
element.removeEventListener('keyup', handler);
|
||||
element.removeEventListener('mozbrowserbeforekeydown', handler);
|
||||
element.removeEventListener('mozbrowserbeforekeyup', handler);
|
||||
element.removeEventListener('mozbrowserafterkeydown', handler);
|
||||
element.removeEventListener('mozbrowserafterkeyup', handler);
|
||||
}
|
||||
|
||||
function convertNameToCode(name)
|
||||
{
|
||||
switch (name) {
|
||||
case "mozbrowserbeforekeydown":
|
||||
return kBeforeEvent | kKeyDownEvent;
|
||||
case "mozbrowserafterkeydown":
|
||||
return kAfterEvent | kKeyDownEvent;
|
||||
case "mozbrowserbeforekeyup":
|
||||
return kBeforeEvent | kKeyUpEvent;
|
||||
case "mozbrowserafterkeyup":
|
||||
return kAfterEvent | kKeyUpEvent;
|
||||
case "keydown":
|
||||
return kKeyDownEvent;
|
||||
case "keyup":
|
||||
return kKeyUpEvent;
|
||||
default:
|
||||
return kUnknownEvent;
|
||||
}
|
||||
}
|
||||
|
||||
function classifyEvents(test)
|
||||
{
|
||||
// Categorize resultEvents into KEYDOWN group and KEYUP group.
|
||||
for (var i = 0; i < gCurrentTest.resultEvents.length ; i++) {
|
||||
var code = test.resultEvents[i];
|
||||
if ((code & 0xF) == 0x1) { // KEYDOWN
|
||||
test.classifiedEvents[0].push(code);
|
||||
} else if ((code & 0xF) == 0x2) { // KEYUP
|
||||
test.classifiedEvents[1].push(code);
|
||||
} else {
|
||||
ok(false, "Invalid code for events");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function verifyResults(test)
|
||||
{
|
||||
for (var i = 0; i < gCurrentTest.expectedEvents.length; i++) {
|
||||
is(test.classifiedEvents[i].length,
|
||||
test.expectedEvents[i].length,
|
||||
test.description + ": Wrong number of events");
|
||||
|
||||
for (var j = 0; j < gCurrentTest.classifiedEvents[i].length; j++) {
|
||||
var item = test.classifiedEvents[i][j];
|
||||
is(item, test.expectedEvents[i][j],
|
||||
test.description + ": Wrong order of events");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function embeddedHandler(e)
|
||||
{
|
||||
return handler(e, kChild);
|
||||
}
|
||||
|
||||
function embedderHandler(e, callback)
|
||||
{
|
||||
handler(e, kParent, callback);
|
||||
}
|
||||
|
||||
function handler(e, highBit, callback)
|
||||
{
|
||||
var code = convertNameToCode(e.type);
|
||||
var newCode = highBit | code;
|
||||
gCurrentTest.resultEvents.push(newCode);
|
||||
|
||||
if (callback) {
|
||||
callback(code);
|
||||
}
|
||||
|
||||
if (highBit == kChild) {
|
||||
// return and let frameScript to handle
|
||||
return newCode == gCurrentTest.doPreventDefaultAt;
|
||||
}
|
||||
|
||||
if (newCode == gCurrentTest.doPreventDefaultAt) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function embedderHandlerWithCheck(e)
|
||||
{
|
||||
// Verify value of attribute embeddedCancelled
|
||||
embedderHandler(e, function checkEmbeddedCancelled(code){
|
||||
switch (code) {
|
||||
case kBeforeEvent | kKeyDownEvent:
|
||||
case kBeforeEvent | kKeyUpEvent:
|
||||
is(e.embeddedCancelled, null,
|
||||
gCurrentTest.description + ": embeddedCancelled should be null");
|
||||
break;
|
||||
case kAfterEvent | kKeyDownEvent:
|
||||
if ((gCurrentTest.doPreventDefaultAt & 0xFF) == kKeyDownEvent) {
|
||||
is(e.embeddedCancelled, true,
|
||||
gCurrentTest.description + ": embeddedCancelled should be true");
|
||||
} else {
|
||||
is(e.embeddedCancelled, false,
|
||||
gCurrentTest.description + ": embeddedCancelled should be false");
|
||||
}
|
||||
break;
|
||||
case kAfterEvent | kKeyUpEvent:
|
||||
if ((gCurrentTest.doPreventDefaultAt & 0xFF) == kKeyUpEvent) {
|
||||
is(e.embeddedCancelled, true,
|
||||
gCurrentTest.description + ": embeddedCancelled should be true");
|
||||
} else {
|
||||
is(e.embeddedCancelled, false,
|
||||
gCurrentTest.description + ": embeddedCancelled should be false");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
@ -167,3 +167,12 @@ skip-if = buildapp == 'mulet'
|
||||
[test_onerror_handler_args.html]
|
||||
[test_wheel_default_action.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || e10s
|
||||
[test_dom_before_after_keyboard_event.html]
|
||||
support-files =
|
||||
bug989198_embedded.html
|
||||
bug989198_helper.js
|
||||
[test_dom_before_after_keyboard_event_remote.html]
|
||||
support-files =
|
||||
bug989198_embedded.html
|
||||
bug989198_helper.js
|
||||
skip-if = buildapp == 'b2g' || e10s
|
||||
|
@ -34,6 +34,10 @@ const kEventConstructors = {
|
||||
},
|
||||
AudioProcessingEvent: { create: null, // Cannot create untrusted event from JS.
|
||||
},
|
||||
BeforeAfterKeyboardEvent: { create: function (aName, aProps) {
|
||||
return new BeforeAfterKeyboardEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
BeforeUnloadEvent: { create: function (aName, aProps) {
|
||||
var e = document.createEvent("beforeunloadevent");
|
||||
e.initEvent(aName, aProps.bubbles, aProps.cancelable);
|
||||
|
135
dom/events/test/test_dom_before_after_keyboard_event.html
Normal file
135
dom/events/test/test_dom_before_after_keyboard_event.html
Normal file
@ -0,0 +1,135 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Bug 989198</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/NativeKeyCodes.js"></script>
|
||||
<script type="text/javascript" src="bug989198_helper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="runTests();">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=989198">Mozilla Bug 989198</a>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function cleanupTest()
|
||||
{
|
||||
teardownHandlers(window, embedderHandler);
|
||||
runTests();
|
||||
}
|
||||
|
||||
function testEventOrderAndAttr()
|
||||
{
|
||||
const kTests = [
|
||||
{
|
||||
description: "Testing the order of the events",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kUnknownEvent
|
||||
},
|
||||
{
|
||||
description: "Testing the order of the events, calling preventDefault() at \"mozbrowserbeforekeydown\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: "Testing the order of the events, calling preventDefault() at \"mozbrowserbeforekeyup\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyUpEvent
|
||||
},
|
||||
{
|
||||
description: "Testing the order of the events, calling preventDefault() at \"keydown\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: "Testing the order of the events, calling preventDefault() at \"keyup\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyUpEvent
|
||||
}
|
||||
];
|
||||
|
||||
for (var k = 0; k < kTests.length; k++ ) {
|
||||
gCurrentTest = kTests[k];
|
||||
synthesizeKey('a', {}, document.getElementById("embedded").contentWindow);
|
||||
classifyEvents(kTests[k]);
|
||||
verifyResults(kTests[k]);
|
||||
}
|
||||
|
||||
runTests();
|
||||
}
|
||||
|
||||
var tests = [
|
||||
function addPermissions() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ type: "before-after-keyboard-event", allow: true, context: document },
|
||||
{ type: "browser", allow: true, context: document }],
|
||||
runTests);
|
||||
},
|
||||
function addPreferences() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.beforeAfterKeyboardEvent.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.tabs.disabled", false]] },
|
||||
runTests);
|
||||
},
|
||||
|
||||
// Tests for in-process iframe, i.e. <iframe mozbrowser>.
|
||||
function () {
|
||||
prepareTest(false);
|
||||
},
|
||||
testEventOrderAndAttr,
|
||||
cleanupTest,
|
||||
];
|
||||
|
||||
function runTests()
|
||||
{
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
162
dom/events/test/test_dom_before_after_keyboard_event_remote.html
Normal file
162
dom/events/test/test_dom_before_after_keyboard_event_remote.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Bug 989198</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/NativeKeyCodes.js"></script>
|
||||
<script type="text/javascript" src="bug989198_helper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="runTests();">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=989198">Mozilla Bug 989198</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var testsForEventOrder = [
|
||||
{
|
||||
description: "Testing the order of the events (OOP)",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kUnknownEvent
|
||||
},
|
||||
{
|
||||
description: "Testing the order of the events (OOP), calling preventDefault() at \"mozbrowserbeforekeydown\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: "Testing the order of the events (OOP), calling preventDefault() at \"mozbrowserbeforekeyup\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyUpEvent
|
||||
},
|
||||
|
||||
{
|
||||
description: "Testing the order of the events (OOP), calling preventDefault() at \"keydown\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: "Testing the order of the events (OOP), calling preventDefault() at \"keyup\" event",
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyUpEvent
|
||||
}
|
||||
];
|
||||
|
||||
function cleanupTest()
|
||||
{
|
||||
teardownHandlers(window, embedderHandler);
|
||||
runTests();
|
||||
}
|
||||
|
||||
function testEventOrder()
|
||||
{
|
||||
if (!testsForEventOrder.length) {
|
||||
runTests();
|
||||
return;
|
||||
}
|
||||
gCurrentTest = testsForEventOrder.shift();
|
||||
|
||||
synthesizeKey('a', {}, document.getElementById("embedded").contentWindow);
|
||||
// It take some time to propagate events to a remote iframe.
|
||||
|
||||
waitAndVerifyResult(0);
|
||||
}
|
||||
|
||||
function waitAndVerifyResult(aCount) {
|
||||
expectedEventLength = gCurrentTest.expectedEvents[0].length +
|
||||
gCurrentTest.expectedEvents[1].length;
|
||||
if (gCurrentTest.resultEvents.length >= expectedEventLength || aCount > 10) {
|
||||
classifyEvents(gCurrentTest);
|
||||
verifyResults(gCurrentTest);
|
||||
testEventOrder();
|
||||
}
|
||||
else {
|
||||
setTimeout(function () waitAndVerifyResult(aCount + 1),
|
||||
100);
|
||||
}
|
||||
}
|
||||
|
||||
var tests = [
|
||||
function addPermissions() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ type: "before-after-keyboard-event", allow: true, context: document },
|
||||
{ type: "browser", allow: true, context: document }],
|
||||
runTests);
|
||||
},
|
||||
function addPreferences() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.beforeAfterKeyboardEvent.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.tabs.disabled", false]] },
|
||||
runTests);
|
||||
},
|
||||
|
||||
// Tests for out-of-process iframe, i.el. <iframe mozbrowser remote>
|
||||
function () {
|
||||
prepareTest(true);
|
||||
},
|
||||
testEventOrder,
|
||||
cleanupTest
|
||||
];
|
||||
|
||||
function runTests()
|
||||
{
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -7,6 +7,10 @@
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
if (W3CTest.runner) {
|
||||
W3CTest.runner.requestLongerTimeout(2);
|
||||
}
|
||||
|
||||
function testCollapse(range, point) {
|
||||
selection.removeAllRanges();
|
||||
var addedRange;
|
||||
|
@ -9,6 +9,10 @@
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
if (W3CTest.runner) {
|
||||
W3CTest.runner.requestLongerTimeout(2);
|
||||
}
|
||||
|
||||
// Also test a selection with no ranges
|
||||
testRanges.unshift("[]");
|
||||
|
||||
|
@ -27,7 +27,10 @@ namespace {
|
||||
const char kPermissionString[] = IDB_PREFIX;
|
||||
|
||||
const char kPermissionPromptTopic[] = TOPIC_PREFIX "prompt";
|
||||
|
||||
#ifdef DEBUG
|
||||
const char kPermissionResponseTopic[] = TOPIC_PREFIX "response";
|
||||
#endif
|
||||
|
||||
#undef TOPIC_PREFIX
|
||||
#undef IDB_PREFIX
|
||||
|
@ -272,6 +272,13 @@ NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
mozilla::dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
mozilla::WidgetKeyboardEvent* aEvent);
|
||||
|
||||
nsresult
|
||||
NS_NewDOMBeforeAfterKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
mozilla::dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
mozilla::InternalBeforeAfterKeyboardEvent* aEvent);
|
||||
|
||||
nsresult
|
||||
NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
mozilla::dom::EventTarget* aOwner,
|
||||
|
@ -402,6 +402,8 @@ parent:
|
||||
|
||||
ReplyKeyEvent(WidgetKeyboardEvent event);
|
||||
|
||||
DispatchAfterKeyboardEvent(WidgetKeyboardEvent event);
|
||||
|
||||
sync RequestNativeKeyBindings(WidgetKeyboardEvent event)
|
||||
returns (MaybeNativeKeyBinding bindings);
|
||||
|
||||
|
@ -17,6 +17,10 @@
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
#include "ProcessUtils.h"
|
||||
#endif
|
||||
|
||||
// This number is fairly arbitrary ... the intention is to put off
|
||||
// launching another app process until the last one has finished
|
||||
// loading its content, to reduce CPU/memory/IO contention.
|
||||
@ -130,7 +134,14 @@ PreallocatedProcessManagerImpl::Init()
|
||||
os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
|
||||
/* weakRef = */ false);
|
||||
}
|
||||
RereadPrefs();
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
if (!mozilla::ipc::ProcLoaderIsInitialized()) {
|
||||
Disable();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
RereadPrefs();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -82,8 +82,8 @@
|
||||
#include "LayersLogging.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
|
||||
#include "nsColorPickerProxy.h"
|
||||
#include "nsPresShell.h"
|
||||
|
||||
#define BROWSER_ELEMENT_CHILD_SCRIPT \
|
||||
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
|
||||
@ -2387,6 +2387,10 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
|
||||
SendReplyKeyEvent(localEvent);
|
||||
}
|
||||
|
||||
if (PresShell::BeforeAfterKeyboardEventEnabled()) {
|
||||
SendDispatchAfterKeyboardEvent(localEvent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPIWindowWatcher.h"
|
||||
#include "nsPresShell.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -1475,6 +1476,29 @@ TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent)
|
||||
{
|
||||
NS_ENSURE_TRUE(mFrameElement, true);
|
||||
|
||||
WidgetKeyboardEvent localEvent(aEvent);
|
||||
localEvent.widget = GetWidget();
|
||||
|
||||
nsIDocument* doc = mFrameElement->OwnerDoc();
|
||||
nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
|
||||
NS_ENSURE_TRUE(presShell, true);
|
||||
|
||||
if (mFrameElement &&
|
||||
PresShell::BeforeAfterKeyboardEventEnabled() &&
|
||||
localEvent.message != NS_KEY_PRESS) {
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(mFrameElement));
|
||||
presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent,
|
||||
aEvent.mFlags.mDefaultPrevented);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to answer query event using cached text.
|
||||
*
|
||||
|
@ -127,6 +127,7 @@ public:
|
||||
virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE;
|
||||
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) MOZ_OVERRIDE;
|
||||
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& event);
|
||||
virtual bool RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& event);
|
||||
virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* aActor,
|
||||
ScrollingBehavior* aScrolling,
|
||||
TextureFactoryIdentifier* aFactoryIdentifier,
|
||||
|
@ -33,6 +33,7 @@ AudioSink::AudioSink(MediaDecoderStateMachine* aStateMachine,
|
||||
: mStateMachine(aStateMachine)
|
||||
, mStartTime(aStartTime)
|
||||
, mWritten(0)
|
||||
, mLastGoodPosition(0)
|
||||
, mInfo(aInfo)
|
||||
, mChannel(aChannel)
|
||||
, mVolume(1.0)
|
||||
@ -72,10 +73,16 @@ AudioSink::Init()
|
||||
int64_t
|
||||
AudioSink::GetPosition()
|
||||
{
|
||||
if (!mAudioStream) {
|
||||
return 0;
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
int64_t pos;
|
||||
if (mAudioStream &&
|
||||
(pos = mAudioStream->GetPosition()) >= 0) {
|
||||
// Update the last good position when we got a good one.
|
||||
mLastGoodPosition = pos;
|
||||
}
|
||||
return mAudioStream->GetPosition();
|
||||
|
||||
return mLastGoodPosition;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -116,6 +116,11 @@ private:
|
||||
// PCM frames written to the stream so far.
|
||||
int64_t mWritten;
|
||||
|
||||
// Keep the last good position returned from the audio stream. Used to ensure
|
||||
// position returned by GetPosition() is mono-increasing in spite of audio
|
||||
// stream error.
|
||||
int64_t mLastGoodPosition;
|
||||
|
||||
AudioInfo mInfo;
|
||||
|
||||
dom::AudioChannel mChannel;
|
||||
|
@ -1059,10 +1059,9 @@ MediaDecoderStateMachine::CheckIfDecodeComplete()
|
||||
((mState == DECODER_STATE_COMPLETED) ? "" : "NOT "));
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsPlaying()
|
||||
bool MediaDecoderStateMachine::IsPlaying() const
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
return !mPlayStartTime.IsNull();
|
||||
}
|
||||
|
||||
@ -1131,7 +1130,7 @@ void MediaDecoderStateMachine::SetSyncPointForMediaStream()
|
||||
mSyncPointInDecodedStream = mStartTime + mPlayDuration;
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetCurrentTimeViaMediaStreamSync()
|
||||
int64_t MediaDecoderStateMachine::GetCurrentTimeViaMediaStreamSync() const
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
NS_ASSERTION(mSyncPointInDecodedStream >= 0, "Should have set up sync point");
|
||||
@ -1814,6 +1813,9 @@ MediaDecoderStateMachine::StartAudioThread()
|
||||
|
||||
mStopAudioThread = false;
|
||||
if (HasAudio() && !mAudioSink) {
|
||||
// The audio end time should always be at least the audio start time.
|
||||
mAudioEndTime = mAudioStartTime;
|
||||
MOZ_ASSERT(mAudioStartTime == GetMediaTime());
|
||||
mAudioCompleted = false;
|
||||
mAudioSink = new AudioSink(this, mAudioStartTime,
|
||||
mInfo.mAudio, mDecoder->GetAudioChannel());
|
||||
@ -2564,24 +2566,28 @@ void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::ResyncAudioClock()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (IsPlaying()) {
|
||||
SetPlayStartTime(TimeStamp::Now());
|
||||
mPlayDuration = GetAudioClock() - mStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
MediaDecoderStateMachine::GetAudioClock()
|
||||
MediaDecoderStateMachine::GetAudioClock() const
|
||||
{
|
||||
// We must hold the decoder monitor while using the audio stream off the
|
||||
// audio sink to ensure that it doesn't get destroyed on the audio sink
|
||||
// while we're using it.
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (!HasAudio() || mAudioCaptured)
|
||||
return -1;
|
||||
if (!mAudioSink) {
|
||||
// Audio sink hasn't played any data yet.
|
||||
return mAudioStartTime;
|
||||
}
|
||||
int64_t t = mAudioSink->GetPosition();
|
||||
return (t == -1) ? -1 : t + mAudioStartTime;
|
||||
MOZ_ASSERT(HasAudio() && !mAudioCaptured);
|
||||
return mAudioStartTime +
|
||||
(mAudioSink ? mAudioSink->GetPosition() : 0);
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetVideoStreamPosition()
|
||||
int64_t MediaDecoderStateMachine::GetVideoStreamPosition() const
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
@ -2596,7 +2602,7 @@ int64_t MediaDecoderStateMachine::GetVideoStreamPosition()
|
||||
return mStartTime + mPlayDuration + delta;
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetClock()
|
||||
int64_t MediaDecoderStateMachine::GetClock() const
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
@ -2605,27 +2611,23 @@ int64_t MediaDecoderStateMachine::GetClock()
|
||||
// audio, or don't have audio, use the system clock. If our output is being
|
||||
// fed to a MediaStream, use that stream as the source of the clock.
|
||||
int64_t clock_time = -1;
|
||||
DecodedStreamData* stream = mDecoder->GetDecodedStream();
|
||||
if (!IsPlaying()) {
|
||||
clock_time = mPlayDuration + mStartTime;
|
||||
} else if (stream) {
|
||||
} else if (mDecoder->GetDecodedStream()) {
|
||||
clock_time = GetCurrentTimeViaMediaStreamSync();
|
||||
} else {
|
||||
int64_t audio_time = GetAudioClock();
|
||||
if (HasAudio() && !mAudioCompleted && audio_time != -1) {
|
||||
clock_time = audio_time;
|
||||
// Resync against the audio clock, while we're trusting the
|
||||
// audio clock. This ensures no "drift", particularly on Linux.
|
||||
mPlayDuration = clock_time - mStartTime;
|
||||
SetPlayStartTime(TimeStamp::Now());
|
||||
if (HasAudio() && !mAudioCompleted && !mAudioCaptured) {
|
||||
clock_time = GetAudioClock();
|
||||
} else {
|
||||
// Audio is disabled on this system. Sync to the system clock.
|
||||
clock_time = GetVideoStreamPosition();
|
||||
// Ensure the clock can never go backwards.
|
||||
NS_ASSERTION(mCurrentFrameTime <= clock_time || mPlaybackRate <= 0,
|
||||
"Clock should go forwards if the playback rate is > 0.");
|
||||
}
|
||||
// FIXME: This assertion should also apply the case of decoding to a stream.
|
||||
// Ensure the clock can never go backwards.
|
||||
NS_ASSERTION(GetMediaTime() <= clock_time || mPlaybackRate <= 0,
|
||||
"Clock should go forwards if the playback rate is > 0.");
|
||||
}
|
||||
|
||||
return clock_time;
|
||||
}
|
||||
|
||||
@ -2646,7 +2648,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t clock_time = GetClock();
|
||||
const int64_t clock_time = GetClock();
|
||||
TimeStamp nowTime = TimeStamp::Now();
|
||||
// Skip frames up to the frame at the playback position, and figure out
|
||||
// the time remaining until it's time to display the next frame.
|
||||
@ -2745,13 +2747,11 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
// advance the clock to after the media end time.
|
||||
if (mVideoFrameEndTime != -1 || mAudioEndTime != -1) {
|
||||
// These will be non -1 if we've displayed a video frame, or played an audio frame.
|
||||
clock_time = std::min(clock_time, std::max(mVideoFrameEndTime, mAudioEndTime));
|
||||
if (clock_time > GetMediaTime()) {
|
||||
// Only update the playback position if the clock time is greater
|
||||
// than the previous playback position. The audio clock can
|
||||
// sometimes report a time less than its previously reported in
|
||||
// some situations, and we need to gracefully handle that.
|
||||
UpdatePlaybackPosition(clock_time);
|
||||
int64_t t = std::min(clock_time, std::max(mVideoFrameEndTime, mAudioEndTime));
|
||||
// FIXME: Bug 1091422 - chained ogg files hit this assertion.
|
||||
//MOZ_ASSERT(t >= GetMediaTime());
|
||||
if (t > GetMediaTime()) {
|
||||
UpdatePlaybackPosition(t);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3141,6 +3141,7 @@ void MediaDecoderStateMachine::OnAudioSinkComplete()
|
||||
if (mAudioCaptured) {
|
||||
return;
|
||||
}
|
||||
ResyncAudioClock();
|
||||
mAudioCompleted = true;
|
||||
UpdateReadyState();
|
||||
// Kick the decode thread; it may be sleeping waiting for this to finish.
|
||||
@ -3155,6 +3156,7 @@ void MediaDecoderStateMachine::OnAudioSinkError()
|
||||
return;
|
||||
}
|
||||
|
||||
ResyncAudioClock();
|
||||
mAudioCompleted = true;
|
||||
|
||||
// Make the best effort to continue playback when there is video.
|
||||
|
@ -308,7 +308,7 @@ public:
|
||||
// call this while we're not playing (while the MediaStream is blocked). Can
|
||||
// be called on any thread with the decoder monitor held.
|
||||
void SetSyncPointForMediaStream();
|
||||
int64_t GetCurrentTimeViaMediaStreamSync();
|
||||
int64_t GetCurrentTimeViaMediaStreamSync() const;
|
||||
|
||||
// Copy queued audio/video data in the reader to any output MediaStreams that
|
||||
// need it.
|
||||
@ -325,7 +325,7 @@ public:
|
||||
|
||||
// Returns true if we're currently playing. The decoder monitor must
|
||||
// be held.
|
||||
bool IsPlaying();
|
||||
bool IsPlaying() const;
|
||||
|
||||
// Dispatch DoNotifyWaitingForResourcesStatusChanged task to mDecodeTaskQueue.
|
||||
// Called when the reader may have acquired the hardware resources required
|
||||
@ -450,19 +450,24 @@ protected:
|
||||
// ResetPlayback() to discard all enqueued data.
|
||||
void FlushDecoding();
|
||||
|
||||
// Called when AudioSink reaches the end. |mPlayStartTime| and
|
||||
// |mPlayDuration| are updated to provide a good base for calculating video
|
||||
// stream time.
|
||||
void ResyncAudioClock();
|
||||
|
||||
// Returns the audio clock, if we have audio, or -1 if we don't.
|
||||
// Called on the state machine thread.
|
||||
int64_t GetAudioClock();
|
||||
int64_t GetAudioClock() const;
|
||||
|
||||
// Get the video stream position, taking the |playbackRate| change into
|
||||
// account. This is a position in the media, not the duration of the playback
|
||||
// so far.
|
||||
int64_t GetVideoStreamPosition();
|
||||
int64_t GetVideoStreamPosition() const;
|
||||
|
||||
// Return the current time, either the audio clock if available (if the media
|
||||
// has audio, and the playback is possible), or a clock for the video.
|
||||
// Called on the state machine thread.
|
||||
int64_t GetClock();
|
||||
int64_t GetClock() const;
|
||||
|
||||
nsresult DropAudioUpToSeekTarget(AudioData* aSample);
|
||||
nsresult DropVideoUpToSeekTarget(VideoData* aSample);
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "MediaData.h"
|
||||
|
||||
#include "mp4_demuxer/Adts.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
|
||||
@ -21,6 +22,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include <jni.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gl;
|
||||
@ -111,6 +113,25 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
|
||||
if (!strcmp(mMimeType, "audio/mp4a-latm")) {
|
||||
uint32_t numChannels = mFormat->GetInteger(NS_LITERAL_STRING("channel-count"));
|
||||
uint32_t sampleRate = mFormat->GetInteger(NS_LITERAL_STRING("sample-rate"));
|
||||
uint8_t frequencyIndex =
|
||||
mp4_demuxer::Adts::GetFrequencyIndex(sampleRate);
|
||||
uint32_t aacProfile = mFormat->GetInteger(NS_LITERAL_STRING("aac-profile"));
|
||||
bool rv = mp4_demuxer::Adts::ConvertSample(numChannels,
|
||||
frequencyIndex,
|
||||
aacProfile,
|
||||
aSample);
|
||||
if (!rv) {
|
||||
printf_stderr("Failed to prepend ADTS header\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return MediaCodecDataDecoder::Input(aSample);
|
||||
}
|
||||
|
||||
nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) {
|
||||
// The output on Android is always 16-bit signed
|
||||
|
||||
@ -209,6 +230,7 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig&
|
||||
|
||||
if (mimeType.EqualsLiteral("audio/mp4a-latm")) {
|
||||
format->SetInteger(NS_LITERAL_STRING("is-adts"), 1);
|
||||
format->SetInteger(NS_LITERAL_STRING("aac-profile"), aConfig.aac_profile);
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "MP4Decoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mp4_demuxer/Adts.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "nsIThread.h"
|
||||
#include "AppleATDecoder.h"
|
||||
@ -355,6 +356,19 @@ AppleATDecoder::SetupDecoder()
|
||||
void
|
||||
AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
|
||||
{
|
||||
// Prepend ADTS header to AAC audio.
|
||||
if (!strcmp(mConfig.mime_type, "audio/mp4a-latm")) {
|
||||
bool rv = mp4_demuxer::Adts::ConvertSample(mConfig.channel_count,
|
||||
mConfig.frequency_index,
|
||||
mConfig.aac_profile,
|
||||
aSample);
|
||||
if (!rv) {
|
||||
NS_ERROR("Failed to apply ADTS header");
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Push the sample to the AudioFileStream for parsing.
|
||||
mSamplePosition = aSample->byte_offset;
|
||||
mCurrentAudioTimestamp = aSample->composition_timestamp;
|
||||
uint32_t flags = mFlushed ? kAudioFileStreamParseFlag_Discontinuity : 0;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "FFmpegRuntimeLinker.h"
|
||||
|
||||
#include "FFmpegAudioDecoder.h"
|
||||
#include "mp4_demuxer/Adts.h"
|
||||
|
||||
#define MAX_CHANNELS 16
|
||||
|
||||
@ -21,6 +22,7 @@ FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
|
||||
const mp4_demuxer::AudioDecoderConfig& aConfig)
|
||||
: FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
|
||||
, mCallback(aCallback)
|
||||
, mConfig(aConfig)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FFmpegAudioDecoder);
|
||||
}
|
||||
@ -83,6 +85,19 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames)
|
||||
void
|
||||
FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
|
||||
{
|
||||
// Prepend ADTS header to AAC audio.
|
||||
if (!strcmp(mConfig.mime_type, "audio/mp4a-latm")) {
|
||||
bool rv = mp4_demuxer::Adts::ConvertSample(mConfig.channel_count,
|
||||
mConfig.frequency_index,
|
||||
mConfig.aac_profile,
|
||||
aSample);
|
||||
if (!rv) {
|
||||
NS_ERROR("Failed to apply ADTS header");
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
|
@ -35,6 +35,7 @@ private:
|
||||
void DecodePacket(mp4_demuxer::MP4Sample* aSample);
|
||||
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
const mp4_demuxer::AudioDecoderConfig& mConfig;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <ICrypto.h>
|
||||
#include "GonkAudioDecoderManager.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "mp4_demuxer/Adts.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "prlog.h"
|
||||
@ -42,11 +43,16 @@ GonkAudioDecoderManager::GonkAudioDecoderManager(
|
||||
, mAudioRate(aConfig.samples_per_second)
|
||||
, mAudioProfile(aConfig.aac_profile)
|
||||
, mAudioBuffer(nullptr)
|
||||
, mUseAdts(true)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkAudioDecoderManager);
|
||||
MOZ_ASSERT(mAudioChannels);
|
||||
mUserData.AppendElements(&aConfig.audio_specific_config[0],
|
||||
aConfig.audio_specific_config.length());
|
||||
// Pass through mp3 without applying an ADTS header.
|
||||
if (strcmp(aConfig.mime_type, "audio/mp4a-latm") != 0) {
|
||||
mUseAdts = false;
|
||||
}
|
||||
}
|
||||
|
||||
GonkAudioDecoderManager::~GonkAudioDecoderManager()
|
||||
@ -215,6 +221,18 @@ GonkAudioDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
ALOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (aSample && mUseAdts) {
|
||||
int8_t frequency_index =
|
||||
mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate);
|
||||
bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels,
|
||||
frequency_index,
|
||||
mAudioProfile,
|
||||
aSample);
|
||||
if (!rv) {
|
||||
ALOG("Failed to apply ADTS header");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
status_t rv;
|
||||
if (aSample) {
|
||||
|
@ -45,6 +45,7 @@ private:
|
||||
const uint32_t mAudioRate;
|
||||
const uint32_t mAudioProfile;
|
||||
nsTArray<uint8_t> mUserData;
|
||||
bool mUseAdts;
|
||||
|
||||
MediaDataDecoderCallback* mReaderCallback;
|
||||
android::MediaBuffer* mAudioBuffer;
|
||||
|
@ -22,7 +22,8 @@ PRLogModuleInfo* GetDemuxerLog();
|
||||
namespace mozilla {
|
||||
|
||||
static void
|
||||
AACAudioSpecificConfigToUserData(const uint8_t* aAudioSpecConfig,
|
||||
AACAudioSpecificConfigToUserData(uint8_t aAACProfileLevelIndication,
|
||||
const uint8_t* aAudioSpecConfig,
|
||||
uint32_t aConfigLength,
|
||||
nsTArray<BYTE>& aOutUserData)
|
||||
{
|
||||
@ -59,8 +60,8 @@ AACAudioSpecificConfigToUserData(const uint8_t* aAudioSpecConfig,
|
||||
// the rest can be all 0x00.
|
||||
BYTE heeInfo[heeInfoLen] = {0};
|
||||
WORD* w = (WORD*)heeInfo;
|
||||
w[0] = 0x1; // Payload type ADTS
|
||||
w[1] = 0xFE; // Profile level indication, none specified.
|
||||
w[0] = 0x0; // Payload type raw AAC packet
|
||||
w[1] = aAACProfileLevelIndication;
|
||||
|
||||
aOutUserData.AppendElements(heeInfo, heeInfoLen);
|
||||
aOutUserData.AppendElements(aAudioSpecConfig, aConfigLength);
|
||||
@ -81,7 +82,8 @@ WMFAudioMFTManager::WMFAudioMFTManager(
|
||||
mStreamType = MP3;
|
||||
} else if (!strcmp(aConfig.mime_type, "audio/mp4a-latm")) {
|
||||
mStreamType = AAC;
|
||||
AACAudioSpecificConfigToUserData(&aConfig.audio_specific_config[0],
|
||||
AACAudioSpecificConfigToUserData(aConfig.aac_profile,
|
||||
&aConfig.audio_specific_config[0],
|
||||
aConfig.audio_specific_config.length(),
|
||||
mUserData);
|
||||
} else {
|
||||
@ -145,7 +147,7 @@ WMFAudioMFTManager::Init()
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
if (mStreamType == AAC) {
|
||||
hr = type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x1); // ADTS
|
||||
hr = type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x0); // Raw AAC packet
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
hr = type->SetBlob(MF_MT_USER_DATA,
|
||||
|
@ -45,7 +45,7 @@ template <>
|
||||
struct ParamTraits<GMPVideoFrameType>
|
||||
: public ContiguousEnumSerializer<GMPVideoFrameType,
|
||||
kGMPKeyFrame,
|
||||
kGMPSkipFrame>
|
||||
kGMPVideoFrameInvalid>
|
||||
{};
|
||||
|
||||
template<>
|
||||
@ -57,7 +57,7 @@ template <>
|
||||
struct ParamTraits<GMPSessionType>
|
||||
: public ContiguousEnumSerializer<GMPSessionType,
|
||||
kGMPTemporySession,
|
||||
kGMPPersistentSession>
|
||||
kGMPSessionInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
|
@ -202,7 +202,8 @@ public:
|
||||
|
||||
enum GMPSessionType {
|
||||
kGMPTemporySession = 0,
|
||||
kGMPPersistentSession = 1
|
||||
kGMPPersistentSession = 1,
|
||||
kGMPSessionInvalid = 2 // Must always be last.
|
||||
};
|
||||
|
||||
// API exposed by plugin library to manage decryption sessions.
|
||||
|
@ -45,7 +45,8 @@ enum GMPVideoFrameType
|
||||
kGMPDeltaFrame = 1,
|
||||
kGMPGoldenFrame = 2,
|
||||
kGMPAltRefFrame = 3,
|
||||
kGMPSkipFrame = 4
|
||||
kGMPSkipFrame = 4,
|
||||
kGMPVideoFrameInvalid = 5 // Must always be last.
|
||||
};
|
||||
|
||||
// The implementation backing this interface uses shared memory for the
|
||||
|
@ -446,7 +446,6 @@ skip-if = (toolkit == 'android' && processor == 'x86') #bug 845162
|
||||
[test_playback_rate_playpause.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_played.html]
|
||||
skip-if = true # bug 1021794
|
||||
[test_preload_actions.html]
|
||||
[test_preload_attribute.html]
|
||||
[test_preload_suspend.html]
|
||||
|
@ -10,15 +10,15 @@
|
||||
<body>
|
||||
<pre id='test'>
|
||||
<script class="testbody" type='application/javascript;version=1.8'>
|
||||
//longer timeout for sometimes B2G emulator runs very slowly
|
||||
if (SpecialPowers.Services.appinfo.name == "B2G") {
|
||||
SimpleTest.requestLongerTimeout(3);
|
||||
}
|
||||
|
||||
let manager = new MediaTestManager;
|
||||
|
||||
SimpleTest.expectAssertions(0, 2);
|
||||
|
||||
function finish_test(element) {
|
||||
if (element.parentNode)
|
||||
element.parentNode.removeChild(element);
|
||||
element.src="";
|
||||
removeNodeAndSource(element);
|
||||
manager.finished(element.token);
|
||||
}
|
||||
|
||||
@ -26,9 +26,9 @@ function finish_test(element) {
|
||||
function check_full_file_played(element) {
|
||||
element.addEventListener('ended', (function(e) {
|
||||
let interval_count = e.target.played.length;
|
||||
is(interval_count, 1, "normal play : a.played.length must be 1");
|
||||
is(element.played.start(0), 0, "start time shall be 0");
|
||||
is(element.played.end(0), e.target.duration, "end time shall be duration");
|
||||
is(interval_count, 1, element.token + ": played.length must be 1");
|
||||
is(element.played.start(0), 0, element.token + ": start time shall be 0");
|
||||
is(element.played.end(0), e.target.duration, element.token + ": end time shall be duration");
|
||||
finish_test(e.target);
|
||||
}), false);
|
||||
}
|
||||
@ -38,35 +38,39 @@ var tests = [
|
||||
{
|
||||
setup : function(element) {
|
||||
element.addEventListener("loadedmetadata", function() {
|
||||
is(element.played.length, 0, "audio : initial played.length equals zero");
|
||||
is(element.played.length, 0, element.token + ": initial played.length equals zero");
|
||||
finish_test(element);
|
||||
});
|
||||
}
|
||||
},
|
||||
name: "test1"
|
||||
},
|
||||
// Play the file, test the range we have.
|
||||
{
|
||||
setup : function(element) {
|
||||
check_full_file_played(element);
|
||||
element.play();
|
||||
}
|
||||
},
|
||||
name: "test2"
|
||||
},
|
||||
|
||||
// Play the second half of the file, pause, play
|
||||
// an check we have only one range.
|
||||
{
|
||||
setup : function (element) {
|
||||
element.addEventListener("ended", function (e) {
|
||||
element.onended = function (e) {
|
||||
var t = e.target;
|
||||
t.onended = null;
|
||||
check_full_file_played(t);
|
||||
t.pause();
|
||||
t.currentTime = 0;
|
||||
t.play();
|
||||
}, false);
|
||||
};
|
||||
element.addEventListener("loadedmetadata", function() {
|
||||
element.currentTime = element.duration / 2;
|
||||
element.play();
|
||||
}, false);
|
||||
}
|
||||
},
|
||||
name: "test3"
|
||||
},
|
||||
|
||||
// Play the first half of the file, seek back, while
|
||||
@ -74,31 +78,36 @@ var tests = [
|
||||
{
|
||||
setup : function (element) {
|
||||
let onTimeUpdate = function() {
|
||||
if (element.currentTime > element.duration/2) {
|
||||
if (element.currentTime > element.duration / 2) {
|
||||
element.removeEventListener("timeupdate", onTimeUpdate, false);
|
||||
element.pause();
|
||||
var oldEndRange = element.played.end(0);
|
||||
element.currentTime = element.duration / 4;
|
||||
is(element.played.end(0), oldEndRange,
|
||||
"When seeking back, |played| should not be changed");
|
||||
element.token + ": When seeking back, |played| should not be changed");
|
||||
element.play();
|
||||
}
|
||||
}
|
||||
element.addEventListener("timeupdate", onTimeUpdate, false);
|
||||
check_full_file_played(element);
|
||||
element.play();
|
||||
}
|
||||
},
|
||||
name: "test4"
|
||||
},
|
||||
|
||||
// Play and seek to have two ranges, and check that, as well a
|
||||
// boundaries.
|
||||
{
|
||||
setup : function (element) {
|
||||
let seekTarget = 0;
|
||||
let onTimeUpdate = function() {
|
||||
if (element.currentTime > element.duration / 2) {
|
||||
element.removeEventListener("timeupdate", onTimeUpdate, false);
|
||||
element.pause();
|
||||
element.currentTime += element.duration/10;
|
||||
// Remember seek target for later comparison since duration may change
|
||||
// during playback.
|
||||
seekTarget = element.currentTime = element.duration / 10;
|
||||
element.currentTime = seekTarget;
|
||||
element.play();
|
||||
}
|
||||
}
|
||||
@ -110,17 +119,17 @@ var tests = [
|
||||
|
||||
element.addEventListener("ended", (function() {
|
||||
if(element.played.length > 1) {
|
||||
is(element.played.length, 2, "element.played.length == 2");
|
||||
var guess = element.played.end(0) + element.duration/10.0;
|
||||
ok(rangeCheck(element.played.start(1), guess), "we should have seeked forward by one tenth of the duration");
|
||||
is(element.played.end(1), element.duration, "end of second range shall be the total duration");
|
||||
is(element.played.length, 2, element.token + ": element.played.length == 2");
|
||||
is(element.played.start(1), seekTarget, element.token + ": we should have seeked forward by one tenth of the duration");
|
||||
is(element.played.end(1), element.duration, element.token + ": end of second range shall be the total duration");
|
||||
}
|
||||
is(element.played.start(0), 0, "start of first range shall be 0");
|
||||
is(element.played.start(0), 0, element.token + ": start of first range shall be 0");
|
||||
finish_test(element);
|
||||
}), false);
|
||||
|
||||
element.play();
|
||||
}
|
||||
},
|
||||
name: "test5"
|
||||
},
|
||||
|
||||
// Play to create two ranges, in the reverse order. check that they are sorted.
|
||||
@ -129,20 +138,24 @@ var tests = [
|
||||
function end() {
|
||||
element.pause();
|
||||
let p = element.played;
|
||||
ok(p.length >= 1, "There should be at least one range");
|
||||
is(p.start(0), element.duration/6, "Start of first range should be the sixth of the duration");
|
||||
ok(p.end(p.length - 1) > 5*element.duration/6, "End of last range should be greater that five times the sixth of the duration");
|
||||
ok(p.length >= 1, element.token + ": There should be at least one range=" + p.length);
|
||||
is(p.start(0), seekTarget, element.token + ": Start of first range should be the sixth of the duration");
|
||||
ok(p.end(p.length - 1) > 5 * element.duration / 6, element.token + ": End of last range should be greater that five times the sixth of the duration");
|
||||
finish_test(element);
|
||||
}
|
||||
|
||||
let seekTarget = 0;
|
||||
function pauseseekrestart() {
|
||||
element.pause();
|
||||
element.currentTime = element.duration/6;
|
||||
// Remember seek target for later comparison since duration may change
|
||||
// during playback.
|
||||
seekTarget = element.duration / 6;
|
||||
element.currentTime = seekTarget;
|
||||
element.play();
|
||||
}
|
||||
|
||||
function onTimeUpdate_pauseseekrestart() {
|
||||
if (element.currentTime > 5*element.duration/6) {
|
||||
if (element.currentTime > 5 * element.duration / 6) {
|
||||
element.removeEventListener("timeupdate", onTimeUpdate_pauseseekrestart, false);
|
||||
pauseseekrestart();
|
||||
element.addEventListener("timeupdate", onTimeUpdate_end, false);
|
||||
@ -150,7 +163,7 @@ var tests = [
|
||||
}
|
||||
|
||||
function onTimeUpdate_end() {
|
||||
if (element.currentTime > 3 * element.duration/6) {
|
||||
if (element.currentTime > 3 * element.duration / 6) {
|
||||
element.removeEventListener("timeupdate", onTimeUpdate_end, false);
|
||||
end();
|
||||
}
|
||||
@ -159,10 +172,11 @@ var tests = [
|
||||
element.addEventListener("timeupdate", onTimeUpdate_pauseseekrestart, false);
|
||||
|
||||
element.addEventListener('loadedmetadata', function() {
|
||||
element.currentTime = 4 * element.duration/6;
|
||||
element.currentTime = 4 * element.duration / 6;
|
||||
element.play();
|
||||
}, false);
|
||||
}
|
||||
},
|
||||
name: "test6"
|
||||
},
|
||||
// Seek repeatedly without playing. No range should appear.
|
||||
{
|
||||
@ -172,7 +186,7 @@ var tests = [
|
||||
element.addEventListener('seeked', function() {
|
||||
index++;
|
||||
element.currentTime = index * element.duration / 5;
|
||||
is(element.played.length, 0, "element.played.length should be 0");
|
||||
is(element.played.length, 0, element.token + ": played.length should be 0");
|
||||
if (index == 5) {
|
||||
finish_test(element);
|
||||
}
|
||||
@ -181,7 +195,8 @@ var tests = [
|
||||
element.addEventListener('loadedmetadata', function() {
|
||||
element.currentTime = element.duration / 5;
|
||||
}, false);
|
||||
}
|
||||
},
|
||||
name: "test7"
|
||||
}
|
||||
];
|
||||
|
||||
@ -200,8 +215,9 @@ function createTestArray() {
|
||||
for (var k=0; k<gPlayedTests.length; k++) {
|
||||
var t = new Object();
|
||||
t.setup = tests[i].setup;
|
||||
t.name = gPlayedTests[k].name;
|
||||
t.name = tests[i].name + "-" + gPlayedTests[k].name;
|
||||
t.type = gPlayedTests[k].type;
|
||||
t.src = gPlayedTests[k].name;
|
||||
A.push(t);
|
||||
}
|
||||
}
|
||||
@ -211,9 +227,9 @@ function createTestArray() {
|
||||
function startTest(test, token) {
|
||||
var elemType = getMajorMimeType(test.type);
|
||||
var element = document.createElement(elemType);
|
||||
element.src = test.name;
|
||||
element.src = test.src;
|
||||
element.token = token;
|
||||
element.volume = 0;
|
||||
element.preload = "metadata";
|
||||
test.setup(element);
|
||||
manager.started(token);
|
||||
}
|
||||
|
@ -172,6 +172,10 @@ var interfaceNamesInGlobalScope =
|
||||
"BarProp",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"BatteryManager",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BeforeAfterKeyboardEvent", b2g: true,
|
||||
pref: "dom.beforeAfterKeyboardEvent.enabled",
|
||||
permission: ["embed-apps", "before-after-keyboard-event"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"BeforeUnloadEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -181,18 +185,18 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"BlobEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothAdapter", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothAdapter", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothDevice", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothDevice", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothDeviceEvent", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothDeviceEvent", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothDiscoveryStateChangedEvent", b2g: true,
|
||||
permission: "bluetooth"},
|
||||
permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothManager", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothManager", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothStatusChangedEvent", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothStatusChangedEvent", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BoxObject", xbl: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -756,7 +760,7 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MozSettingsEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozSettingsTransactionEvent", permission: "settings-api-read"},
|
||||
{name: "MozSettingsTransactionEvent", permission: ["settings-api-read"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MozSmsEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -776,23 +780,23 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWakeLock", b2g: true, pref: "dom.wakelock.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiCapabilities", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiCapabilities", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiConnectionInfoEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiStationInfoEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiManager", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiManager", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiNetwork", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiNetwork", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiStatusChangeEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiP2pGroupOwner", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiP2pGroupOwner", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiP2pManager", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiP2pManager", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiP2pStatusChangeEvent", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiP2pStatusChangeEvent", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MutationEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -850,9 +854,9 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"PeriodicWave",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "PermissionSettings", b2g: true, permission: "permissions"},
|
||||
{name: "PermissionSettings", b2g: true, permission: ["permissions"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "PhoneNumberService", permission: "phonenumberservice"},
|
||||
{name: "PhoneNumberService", permission: ["phonenumberservice"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Plugin",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -1236,25 +1240,31 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVChannel", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVCurrentChannelChangedEvent", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVCurrentChannelChangedEvent", b2g: true, pref: "dom.tv.enabled",
|
||||
permission: "tv"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVCurrentSourceChangedEvent", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVCurrentSourceChangedEvent", b2g: true, pref: "dom.tv.enabled",
|
||||
permission: "tv"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVEITBroadcastedEvent", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVEITBroadcastedEvent", b2g: true, pref: "dom.tv.enabled",
|
||||
permission: ["tv"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVManager", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVManager", b2g: true, pref: "dom.tv.enabled", permission: ["tv"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVProgram", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVProgram", b2g: true, pref: "dom.tv.enabled", permission: ["tv"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVScanningStateChangedEvent", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVScanningStateChangedEvent", b2g: true, pref: "dom.tv.enabled",
|
||||
permission: ["tv"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVSource", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVSource", b2g: true, pref: "dom.tv.enabled", permission: ["tv"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "TVTuner", b2g: true, pref: "dom.tv.enabled", permission: "tv"},
|
||||
{name: "TVTuner", b2g: true, pref: "dom.tv.enabled", permission: ["tv"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "UDPMessageEvent", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
|
||||
{name: "UDPMessageEvent", pref: "dom.udpsocket.enabled",
|
||||
permission: ["udp-socket"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "UDPSocket", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
|
||||
{name: "UDPSocket", pref: "dom.udpsocket.enabled",
|
||||
permission: ["udp-socket"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"UIEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -1360,8 +1370,12 @@ function createInterfaceMap(isXBLScope) {
|
||||
var isRelease = !version.contains("a");
|
||||
var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
|
||||
var isB2G = !isDesktop && !navigator.userAgent.contains("Android");
|
||||
var hasPermission = function (aPermission) {
|
||||
return SpecialPowers.hasPermission(aPermission, window.document);
|
||||
var hasPermission = function (aPermissions) {
|
||||
var result = false;
|
||||
for (var p of aPermissions) {
|
||||
result = result || SpecialPowers.hasPermission(p, window.document);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var interfaceMap = {};
|
||||
|
24
dom/webidl/BeforeAfterKeyboardEvent.webidl
Normal file
24
dom/webidl/BeforeAfterKeyboardEvent.webidl
Normal file
@ -0,0 +1,24 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[Constructor(DOMString typeArg,
|
||||
optional BeforeAfterKeyboardEventInit eventInitDict),
|
||||
CheckPermissions="embed-apps before-after-keyboard-event",
|
||||
Pref="dom.beforeAfterKeyboardEvent.enabled"]
|
||||
interface BeforeAfterKeyboardEvent : KeyboardEvent
|
||||
{
|
||||
// The valid value of embeddedCancelled is:
|
||||
// - "mozbrowserbeforekeydown": null
|
||||
// - "mozbrowserbeforekeyup": null
|
||||
// - "mozbrowserafterkeydown": true/false
|
||||
// - "mozbrowserafterkeyup": true/false
|
||||
readonly attribute boolean? embeddedCancelled;
|
||||
};
|
||||
|
||||
dictionary BeforeAfterKeyboardEventInit : KeyboardEventInit
|
||||
{
|
||||
boolean? embeddedCancelled = null;
|
||||
};
|
@ -50,6 +50,7 @@ WEBIDL_FILES = [
|
||||
'AutocompleteInfo.webidl',
|
||||
'BarProp.webidl',
|
||||
'BatteryManager.webidl',
|
||||
'BeforeAfterKeyboardEvent.webidl',
|
||||
'BeforeUnloadEvent.webidl',
|
||||
'BiquadFilterNode.webidl',
|
||||
'Blob.webidl',
|
||||
|
@ -100,13 +100,13 @@ needs-focus == spellcheck-superscript-1.html spellcheck-superscript-1-ref.html
|
||||
skip-if(B2G) fails-if(Android) needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html # bug 783658
|
||||
needs-focus == 824080-1.html 824080-1-ref.html
|
||||
needs-focus == 824080-2.html 824080-2-ref.html
|
||||
needs-focus == 824080-3.html 824080-3-ref.html
|
||||
needs-focus test-pref(selectioncaret.enabled,false) == 824080-3.html 824080-3-ref.html
|
||||
needs-focus != 824080-2.html 824080-3.html
|
||||
needs-focus == 824080-4.html 824080-4-ref.html
|
||||
needs-focus == 824080-5.html 824080-5-ref.html
|
||||
needs-focus test-pref(selectioncaret.enabled,false) == 824080-5.html 824080-5-ref.html
|
||||
needs-focus != 824080-4.html 824080-5.html
|
||||
needs-focus == 824080-6.html 824080-6-ref.html
|
||||
needs-focus == 824080-7.html 824080-7-ref.html
|
||||
needs-focus pref(selectioncaret.enabled,false) == 824080-7.html 824080-7-ref.html
|
||||
needs-focus != 824080-6.html 824080-7.html
|
||||
# Bug 674927: copy spellcheck-textarea tests to contenteditable
|
||||
== spellcheck-contenteditable-attr.html spellcheck-contenteditable-nofocus-ref.html
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
57241
|
||||
57242
|
||||
0/nm
|
||||
0th/pt
|
||||
1/n1
|
||||
@ -17983,6 +17983,7 @@ apathetic
|
||||
apathetically
|
||||
apathy/M
|
||||
apatite/M
|
||||
apatosaurus/M
|
||||
ape/DSMG
|
||||
apelike
|
||||
aperiodic
|
||||
|
@ -1078,85 +1078,6 @@ gfxContext::PopGroupToSource()
|
||||
CurrentState().surfTransform = mat;
|
||||
}
|
||||
|
||||
void
|
||||
gfxContext::RoundedRectangle(const gfxRect& rect,
|
||||
const RectCornerRadii& corners,
|
||||
bool draw_clockwise)
|
||||
{
|
||||
//
|
||||
// For CW drawing, this looks like:
|
||||
//
|
||||
// ...******0** 1 C
|
||||
// ****
|
||||
// *** 2
|
||||
// **
|
||||
// *
|
||||
// *
|
||||
// 3
|
||||
// *
|
||||
// *
|
||||
//
|
||||
// Where 0, 1, 2, 3 are the control points of the Bezier curve for
|
||||
// the corner, and C is the actual corner point.
|
||||
//
|
||||
// At the start of the loop, the current point is assumed to be
|
||||
// the point adjacent to the top left corner on the top
|
||||
// horizontal. Note that corner indices start at the top left and
|
||||
// continue clockwise, whereas in our loop i = 0 refers to the top
|
||||
// right corner.
|
||||
//
|
||||
// When going CCW, the control points are swapped, and the first
|
||||
// corner that's drawn is the top left (along with the top segment).
|
||||
//
|
||||
// There is considerable latitude in how one chooses the four
|
||||
// control points for a Bezier curve approximation to an ellipse.
|
||||
// For the overall path to be continuous and show no corner at the
|
||||
// endpoints of the arc, points 0 and 3 must be at the ends of the
|
||||
// straight segments of the rectangle; points 0, 1, and C must be
|
||||
// collinear; and points 3, 2, and C must also be collinear. This
|
||||
// leaves only two free parameters: the ratio of the line segments
|
||||
// 01 and 0C, and the ratio of the line segments 32 and 3C. See
|
||||
// the following papers for extensive discussion of how to choose
|
||||
// these ratios:
|
||||
//
|
||||
// Dokken, Tor, et al. "Good approximation of circles by
|
||||
// curvature-continuous Bezier curves." Computer-Aided
|
||||
// Geometric Design 7(1990) 33--41.
|
||||
// Goldapp, Michael. "Approximation of circular arcs by cubic
|
||||
// polynomials." Computer-Aided Geometric Design 8(1991) 227--238.
|
||||
// Maisonobe, Luc. "Drawing an elliptical arc using polylines,
|
||||
// quadratic, or cubic Bezier curves."
|
||||
// http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
|
||||
//
|
||||
// We follow the approach in section 2 of Goldapp (least-error,
|
||||
// Hermite-type approximation) and make both ratios equal to
|
||||
//
|
||||
// 2 2 + n - sqrt(2n + 28)
|
||||
// alpha = - * ---------------------
|
||||
// 3 n - 4
|
||||
//
|
||||
// where n = 3( cbrt(sqrt(2)+1) - cbrt(sqrt(2)-1) ).
|
||||
//
|
||||
// This is the result of Goldapp's equation (10b) when the angle
|
||||
// swept out by the arc is pi/2, and the parameter "a-bar" is the
|
||||
// expression given immediately below equation (21).
|
||||
//
|
||||
// Using this value, the maximum radial error for a circle, as a
|
||||
// fraction of the radius, is on the order of 0.2 x 10^-3.
|
||||
// Neither Dokken nor Goldapp discusses error for a general
|
||||
// ellipse; Maisonobe does, but his choice of control points
|
||||
// follows different constraints, and Goldapp's expression for
|
||||
// 'alpha' gives much smaller radial error, even for very flat
|
||||
// ellipses, than Maisonobe's equivalent.
|
||||
//
|
||||
// For the various corners and for each axis, the sign of this
|
||||
// constant changes, or it might be 0 -- it's multiplied by the
|
||||
// appropriate multiplier from the list before using.
|
||||
|
||||
EnsurePathBuilder();
|
||||
AppendRoundedRectToPath(mPathBuilder, ToRect(rect), corners, draw_clockwise);
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
void
|
||||
gfxContext::WriteAsPNG(const char* aFile)
|
||||
|
@ -191,18 +191,6 @@ public:
|
||||
*/
|
||||
void Polygon(const gfxPoint *points, uint32_t numPoints);
|
||||
|
||||
/*
|
||||
* Draw a rounded rectangle, with the given outer rect and
|
||||
* corners. The corners specify the radii of the two axes of an
|
||||
* ellipse (the horizontal and vertical directions given by the
|
||||
* width and height, respectively). By default the ellipse is
|
||||
* drawn in a clockwise direction; if draw_clockwise is false,
|
||||
* then it's drawn counterclockwise.
|
||||
*/
|
||||
void RoundedRectangle(const gfxRect& rect,
|
||||
const RectCornerRadii& corners,
|
||||
bool draw_clockwise = true);
|
||||
|
||||
/**
|
||||
** Transformation Matrix manipulation
|
||||
**/
|
||||
|
@ -35,12 +35,25 @@ struct RunnableMethodTraits<GonkDiskSpaceWatcher>
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
// NOTE: this should be unnecessary once we no longer support ICS.
|
||||
#ifndef __NR_fanotify_init
|
||||
#if defined(__ARM_EABI__)
|
||||
#define __NR_fanotify_init 367
|
||||
#define __NR_fanotify_mark 368
|
||||
#elif defined(__i386__)
|
||||
#define __NR_fanotify_init 338
|
||||
#define __NR_fanotify_mark 339
|
||||
#else
|
||||
#error "Unhandled architecture"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// fanotify_init and fanotify_mark functions are syscalls.
|
||||
// The user space bits are not part of bionic so we add them here
|
||||
// as well as fanotify.h
|
||||
int fanotify_init (unsigned int flags, unsigned int event_f_flags)
|
||||
{
|
||||
return syscall(367, flags, event_f_flags);
|
||||
return syscall(__NR_fanotify_init, flags, event_f_flags);
|
||||
}
|
||||
|
||||
// Add, remove, or modify an fanotify mark on a filesystem object.
|
||||
@ -56,11 +69,11 @@ int fanotify_mark (int fanotify_fd, unsigned int flags,
|
||||
uint32_t _32[2];
|
||||
} _mask;
|
||||
_mask._64 = mask;
|
||||
return syscall(368, fanotify_fd, flags, _mask._32[0], _mask._32[1],
|
||||
dfd, pathname);
|
||||
return syscall(__NR_fanotify_mark, fanotify_fd, flags,
|
||||
_mask._32[0], _mask._32[1], dfd, pathname);
|
||||
}
|
||||
|
||||
return syscall(368, fanotify_fd, flags, mask, dfd, pathname);
|
||||
return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname);
|
||||
}
|
||||
|
||||
class GonkDiskSpaceWatcher MOZ_FINAL : public MessageLoopForIO::Watcher
|
||||
@ -166,12 +179,13 @@ GonkDiskSpaceWatcher::DoStart()
|
||||
|
||||
mFd = fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC);
|
||||
if (mFd == -1) {
|
||||
NS_WARNING("Error calling inotify_init()");
|
||||
if (errno == ENOSYS) {
|
||||
NS_WARNING("Warning: No fanotify support in this device's kernel.\n");
|
||||
#if ANDROID_VERSION >= 19
|
||||
MOZ_CRASH("Fanotify support must be enabled in the kernel.");
|
||||
#endif
|
||||
} else {
|
||||
NS_WARNING("Error calling fanotify_init()");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ void SetThisProcessName(const char *aName);
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
// see ProcessUtils_linux.cpp for explaination.
|
||||
void ProcLoaderClientGeckoInit();
|
||||
|
||||
bool ProcLoaderIsInitialized();
|
||||
bool ProcLoaderLoad(const char *aArgv[],
|
||||
const char *aEnvp[],
|
||||
const base::file_handle_mapping_vector &aFdsRemap,
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "base/process_util.h"
|
||||
#include "base/eintr_wrapper.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "prenv.h"
|
||||
|
||||
@ -196,6 +197,14 @@ ProcLoaderClientGeckoInit()
|
||||
MOZ_ASSERT(!sProcLoaderClientGeckoInitialized,
|
||||
"call ProcLoaderClientGeckoInit() more than once");
|
||||
|
||||
if (!Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
|
||||
kill(sProcLoaderPid, SIGKILL);
|
||||
sProcLoaderPid = 0;
|
||||
close(sProcLoaderChannelFd);
|
||||
sProcLoaderChannelFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
sProcLoaderClientGeckoInitialized = true;
|
||||
|
||||
TransportDescriptor fd;
|
||||
@ -210,6 +219,11 @@ ProcLoaderClientGeckoInit()
|
||||
sProcLoaderLoop = MessageLoop::current();
|
||||
}
|
||||
|
||||
bool ProcLoaderIsInitialized()
|
||||
{
|
||||
return sProcLoaderPid != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown and destroy the client of B2G loader service.
|
||||
*/
|
||||
|
@ -4894,6 +4894,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
||||
actordecl = md.actorDecl()
|
||||
actorvar = actordecl.var()
|
||||
actorproto = actordecl.ipdltype.protocol
|
||||
actortype = ipdl.type.ActorType(actorproto)
|
||||
|
||||
if idexpr is None:
|
||||
idexpr = ExprCall(self.protocol.registerMethod(),
|
||||
@ -4903,7 +4904,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
||||
args=[ actorvar, idexpr ])
|
||||
|
||||
return [
|
||||
self.failIfNullActor(actorvar, errfn),
|
||||
self.failIfNullActor(actorvar, errfn, msg="Error constructing actor %s" % actortype.name() + self.side.capitalize()),
|
||||
StmtExpr(ExprAssn(_actorId(actorvar), idexpr)),
|
||||
StmtExpr(ExprAssn(_actorManager(actorvar), ExprVar.THIS)),
|
||||
StmtExpr(ExprAssn(_actorChannel(actorvar),
|
||||
@ -5136,8 +5137,10 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
||||
|
||||
# helper methods
|
||||
|
||||
def failIfNullActor(self, actorExpr, retOnNull=ExprLiteral.FALSE):
|
||||
def failIfNullActor(self, actorExpr, retOnNull=ExprLiteral.FALSE, msg=None):
|
||||
failif = StmtIf(ExprNot(actorExpr))
|
||||
if msg:
|
||||
failif.addifstmt(_printWarningMessage(msg))
|
||||
failif.addifstmt(StmtReturn(retOnNull))
|
||||
return failif
|
||||
|
||||
|
@ -479,8 +479,20 @@ BaselineInspector::templateCallObject()
|
||||
return &res->as<CallObject>();
|
||||
}
|
||||
|
||||
static Shape *GlobalShapeForGetPropFunction(ICStub *stub)
|
||||
{
|
||||
if (stub->isGetProp_CallNativePrototype()) {
|
||||
ICGetProp_CallNativePrototype *nstub =
|
||||
stub->toGetProp_CallNativePrototype();
|
||||
if (nstub->receiverShape()->getObjectClass()->flags & JSCLASS_IS_GLOBAL)
|
||||
return nstub->receiverShape();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
|
||||
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter,
|
||||
Shape **globalShape)
|
||||
{
|
||||
if (!hasBaselineScript())
|
||||
return nullptr;
|
||||
@ -489,6 +501,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
||||
JSObject* holder = nullptr;
|
||||
Shape *holderShape = nullptr;
|
||||
JSFunction *getter = nullptr;
|
||||
Shape *global = nullptr;
|
||||
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isGetProp_CallScripted() ||
|
||||
stub->isGetProp_CallNative() ||
|
||||
@ -499,7 +512,10 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
||||
holder = nstub->holder();
|
||||
holderShape = nstub->holderShape();
|
||||
getter = nstub->getter();
|
||||
} else if (nstub->holderShape() != holderShape) {
|
||||
global = GlobalShapeForGetPropFunction(nstub);
|
||||
} else if (nstub->holderShape() != holderShape ||
|
||||
GlobalShapeForGetPropFunction(nstub) != global)
|
||||
{
|
||||
return nullptr;
|
||||
} else {
|
||||
MOZ_ASSERT(getter == nstub->getter());
|
||||
@ -513,6 +529,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
||||
}
|
||||
*lastProperty = holderShape;
|
||||
*commonGetter = getter;
|
||||
*globalShape = global;
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,8 @@ class BaselineInspector
|
||||
DeclEnvObject *templateDeclEnvObject();
|
||||
CallObject *templateCallObject();
|
||||
|
||||
JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter);
|
||||
JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter,
|
||||
Shape **globalShape);
|
||||
JSObject *commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter);
|
||||
};
|
||||
|
||||
|
@ -8770,7 +8770,7 @@ IonBuilder::jsop_not()
|
||||
|
||||
bool
|
||||
IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
bool isGetter, JSObject *foundProto)
|
||||
bool isGetter, JSObject *foundProto, bool *guardGlobal)
|
||||
{
|
||||
// With foundProto a prototype with a getter or setter for name, return
|
||||
// whether looking up name on any object in |types| will go through
|
||||
@ -8780,6 +8780,7 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
// No sense looking if we don't know what's going on.
|
||||
if (!types || types->unknownObject())
|
||||
return false;
|
||||
*guardGlobal = false;
|
||||
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
if (types->getSingleObject(i) == foundProto)
|
||||
@ -8794,8 +8795,14 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
return false;
|
||||
|
||||
const Class *clasp = type->clasp();
|
||||
if (!ClassHasEffectlessLookup(clasp, name) || ClassHasResolveHook(compartment, clasp, name))
|
||||
if (!ClassHasEffectlessLookup(clasp, name))
|
||||
return false;
|
||||
JSObject *singleton = type->singleton();
|
||||
if (ClassHasResolveHook(compartment, clasp, name)) {
|
||||
if (!singleton || !singleton->is<GlobalObject>())
|
||||
return false;
|
||||
*guardGlobal = true;
|
||||
}
|
||||
|
||||
// Look for a getter/setter on the class itself which may need
|
||||
// to be called. Ignore the getGeneric hook for typed arrays, it
|
||||
@ -8813,9 +8820,11 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
if (!types->empty() || types->nonDataProperty())
|
||||
return false;
|
||||
}
|
||||
if (JSObject *obj = type->singleton()) {
|
||||
if (types::CanHaveEmptyPropertyTypesForOwnProperty(obj))
|
||||
return false;
|
||||
if (singleton) {
|
||||
if (types::CanHaveEmptyPropertyTypesForOwnProperty(singleton)) {
|
||||
MOZ_ASSERT(singleton->is<GlobalObject>());
|
||||
*guardGlobal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!type->hasTenuredProto())
|
||||
@ -8837,7 +8846,8 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
|
||||
void
|
||||
IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
JSObject *foundProto)
|
||||
JSObject *foundProto,
|
||||
bool allowEmptyTypesforGlobal/* = false*/)
|
||||
{
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
// If we found a Singleton object's own-property, there's nothing to
|
||||
@ -8851,7 +8861,7 @@ IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, P
|
||||
|
||||
while (true) {
|
||||
types::HeapTypeSetKey property = type->property(NameToId(name));
|
||||
JS_ALWAYS_TRUE(!property.isOwnProperty(constraints()));
|
||||
JS_ALWAYS_TRUE(!property.isOwnProperty(constraints(), allowEmptyTypesforGlobal));
|
||||
|
||||
// Don't mark the proto. It will be held down by the shape
|
||||
// guard. This allows us to use properties found on prototypes
|
||||
@ -8865,21 +8875,34 @@ IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, P
|
||||
|
||||
inline MDefinition *
|
||||
IonBuilder::testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
bool isGetter, JSObject *foundProto, Shape *lastProperty)
|
||||
bool isGetter, JSObject *foundProto, Shape *lastProperty,
|
||||
Shape *globalShape/* = nullptr*/)
|
||||
{
|
||||
bool guardGlobal;
|
||||
|
||||
// Check if all objects being accessed will lookup the name through foundProto.
|
||||
if (!objectsHaveCommonPrototype(types, name, isGetter, foundProto))
|
||||
if (!objectsHaveCommonPrototype(types, name, isGetter, foundProto, &guardGlobal) ||
|
||||
(guardGlobal && !globalShape))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We can optimize the getter/setter, so freeze all involved properties to
|
||||
// ensure there isn't a lower shadowing getter or setter installed in the
|
||||
// future.
|
||||
freezePropertiesForCommonPrototype(types, name, foundProto);
|
||||
freezePropertiesForCommonPrototype(types, name, foundProto, guardGlobal);
|
||||
|
||||
// Add a shape guard on the prototype we found the property on. The rest of
|
||||
// the prototype chain is guarded by TI freezes. Note that a shape guard is
|
||||
// good enough here, even in the proxy case, because we have ensured there
|
||||
// are no lookup hooks for this property.
|
||||
// the prototype chain is guarded by TI freezes, except when name is a global
|
||||
// name. In this case, we also have to guard on the globals shape to be able
|
||||
// to optimize. Note that a shape guard is good enough here, even in the proxy
|
||||
// case, because we have ensured there are no lookup hooks for this property.
|
||||
if (guardGlobal) {
|
||||
JSObject *obj = &script()->global();
|
||||
MDefinition *globalObj = constant(ObjectValue(*obj));
|
||||
addShapeGuard(globalObj, globalShape, Bailout_ShapeGuard);
|
||||
}
|
||||
|
||||
MInstruction *wrapper = constant(ObjectValue(*foundProto));
|
||||
return addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
|
||||
}
|
||||
@ -9407,13 +9430,14 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
||||
|
||||
Shape *lastProperty = nullptr;
|
||||
JSFunction *commonGetter = nullptr;
|
||||
JSObject *foundProto = inspector->commonGetPropFunction(pc, &lastProperty, &commonGetter);
|
||||
Shape *globalShape = nullptr;
|
||||
JSObject *foundProto = inspector->commonGetPropFunction(pc, &lastProperty, &commonGetter, &globalShape);
|
||||
if (!foundProto)
|
||||
return true;
|
||||
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
MDefinition *guard = testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
|
||||
foundProto, lastProperty);
|
||||
foundProto, lastProperty, globalShape);
|
||||
if (!guard)
|
||||
return true;
|
||||
|
||||
|
@ -807,11 +807,12 @@ class IonBuilder
|
||||
MBasicBlock *bottom);
|
||||
|
||||
bool objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
bool isGetter, JSObject *foundProto);
|
||||
bool isGetter, JSObject *foundProto, bool *guardGlobal);
|
||||
void freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
JSObject *foundProto);
|
||||
JSObject *foundProto, bool allowEmptyTypesForGlobal = false);
|
||||
MDefinition *testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
bool isGetter, JSObject *foundProto, Shape *lastProperty);
|
||||
bool isGetter, JSObject *foundProto, Shape *lastProperty,
|
||||
Shape *globalShape = nullptr);
|
||||
bool testShouldDOMCall(types::TypeSet *inTypes,
|
||||
JSFunction *func, JSJitInfo::OpType opType);
|
||||
|
||||
|
@ -1446,11 +1446,14 @@ HeapTypeSetKey::knownMIRType(CompilerConstraintList *constraints)
|
||||
}
|
||||
|
||||
bool
|
||||
HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints)
|
||||
HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints,
|
||||
bool allowEmptyTypesForGlobal/* = false*/)
|
||||
{
|
||||
if (maybeTypes() && (!maybeTypes()->empty() || maybeTypes()->nonDataProperty()))
|
||||
return true;
|
||||
if (JSObject *obj = object()->singleton()) {
|
||||
JSObject *obj = object()->singleton();
|
||||
MOZ_ASSERT_IF(obj, CanHaveEmptyPropertyTypesForOwnProperty(obj) == obj->is<GlobalObject>());
|
||||
if (obj && !allowEmptyTypesForGlobal) {
|
||||
if (CanHaveEmptyPropertyTypesForOwnProperty(obj))
|
||||
return true;
|
||||
}
|
||||
|
@ -1566,7 +1566,7 @@ class HeapTypeSetKey
|
||||
jit::MIRType knownMIRType(CompilerConstraintList *constraints);
|
||||
bool nonData(CompilerConstraintList *constraints);
|
||||
bool nonWritable(CompilerConstraintList *constraints);
|
||||
bool isOwnProperty(CompilerConstraintList *constraints);
|
||||
bool isOwnProperty(CompilerConstraintList *constraints, bool allowEmptyTypesForGlobal = false);
|
||||
bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
|
||||
JSObject *singleton(CompilerConstraintList *constraints);
|
||||
bool needsBarrier(CompilerConstraintList *constraints);
|
||||
|
@ -1529,6 +1529,12 @@ RestyleManager::ProcessPendingRestyles()
|
||||
NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
|
||||
"Missing a script blocker!");
|
||||
|
||||
if (mRebuildAllStyleData) {
|
||||
RebuildAllStyleData(nsChangeHint(0), nsRestyleHint(0));
|
||||
MOZ_ASSERT(mPendingRestyles.Count() == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// First do any queued-up frame creation. (We should really
|
||||
// merge this into the rest of the process, though; see bug 827239.)
|
||||
mPresContext->FrameConstructor()->CreateNeededFrames();
|
||||
|
37
layout/base/crashtests/403454.html
Normal file
37
layout/base/crashtests/403454.html
Normal file
@ -0,0 +1,37 @@
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
|
||||
<style>
|
||||
|
||||
.dddd:before {
|
||||
content: "generated";
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
function b()
|
||||
{
|
||||
document.getElementById("float").style.cssFloat = "";
|
||||
setTimeout(b2, 30);
|
||||
}
|
||||
|
||||
// This is just for visual effect, to make the timing clear.
|
||||
// It's not needed for the crash.
|
||||
function b2()
|
||||
{
|
||||
document.body.style.background = "#eee";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="document.body.offsetHeight; setTimeout(b, 0);">
|
||||
|
||||
<span class="dddd"><div></div><span id="float" style="float: left"></span></span>
|
||||
|
||||
</body>
|
||||
</html>
|
26
layout/base/crashtests/416107.xhtml
Normal file
26
layout/base/crashtests/416107.xhtml
Normal file
@ -0,0 +1,26 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
var z = document.getElementById("z");
|
||||
var c = document.getElementById("c");
|
||||
|
||||
z.removeChild(z.firstChild);
|
||||
document.body.offsetHeight;
|
||||
c.style.counterReset = "c";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="boom();" style="font-family: monospace; width: 7ch;">
|
||||
|
||||
<span style="margin: 8px;"></span>
|
||||
|
||||
<span style="position: relative;" id="z">OOO<span style="display: table-caption;">OOOOOO</span><span id="c" style="position: absolute;"></span></span>
|
||||
|
||||
</body>
|
||||
</html>
|
35
layout/base/crashtests/817219-iframe.html
Normal file
35
layout/base/crashtests/817219-iframe.html
Normal file
@ -0,0 +1,35 @@
|
||||
<html>
|
||||
<script>
|
||||
function start() {
|
||||
o3=document.createElement('input');
|
||||
tmp = o3.ownerDocument.createElement('iframe');
|
||||
document.body.appendChild(tmp);
|
||||
o4=tmp.contentDocument;
|
||||
cb_3=function() { var f = callback_3; callback_3 = null; return f(arguments); }
|
||||
o3.addEventListener('change', cb_3, false);
|
||||
o51=document.createElement('img');
|
||||
o94=document.createElement('input');
|
||||
o94.type='checkbox';
|
||||
o3.appendChild(o94);
|
||||
o192=document.createElement('input');
|
||||
o192.type='button';
|
||||
o94.appendChild(o192);
|
||||
o263=document.createEvent('MouseEvents');
|
||||
o263.initMouseEvent('click', true, true, window,0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
o192.dispatchEvent(o263)
|
||||
}
|
||||
function callback_3() {
|
||||
o192.addEventListener('DOMNodeRemoved', callback_21, true);
|
||||
o51.appendChild(o192);
|
||||
}
|
||||
function callback_21() {
|
||||
o4.documentElement.appendChild(o192);
|
||||
location.reload();
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<script>
|
||||
window.setTimeout("start();", 10);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
22
layout/base/crashtests/817219.html
Normal file
22
layout/base/crashtests/817219.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase for bug 817219</title>
|
||||
<script>
|
||||
function reload() {
|
||||
this.location.reload();
|
||||
}
|
||||
// Run the test for 2 seconds
|
||||
setTimeout(function() {
|
||||
document.documentElement.removeChild(document.body);
|
||||
document.documentElement.className = "";
|
||||
}, 2000);
|
||||
</script>
|
||||
</head>
|
||||
<body onload="document.body.getBoundingClientRect()">
|
||||
|
||||
<iframe onload="this.contentWindow.setTimeout(reload,1113)" src="817219-iframe.html"></iframe>
|
||||
<iframe onload="this.contentWindow.setTimeout(reload,1433)" src="817219-iframe.html"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
39
layout/base/crashtests/876221.html
Normal file
39
layout/base/crashtests/876221.html
Normal file
@ -0,0 +1,39 @@
|
||||
<html>
|
||||
<script>
|
||||
function start() {
|
||||
o0=tmp = document.createElement('iframe');
|
||||
document.getElementById('store_div').appendChild(tmp);
|
||||
o19=document.documentElement;
|
||||
tmp.id = 'id28'
|
||||
o119=tmp = document.createElement('iframe');
|
||||
tmp.id = 'id63'
|
||||
o19.appendChild(tmp)
|
||||
o152=document.getElementById('id63').contentDocument;
|
||||
o515=o152.createElement('xml');
|
||||
o547=document.createElementNS('http://www.w3.org/1999/xhtml','feFuncB');
|
||||
o552=document.createElementNS('http://www.w3.org/1999/xhtml','munder');
|
||||
o569=window.document.getElementById('id28').contentWindow.document;
|
||||
document.body.appendChild(o552);
|
||||
o552.appendChild(o547);
|
||||
o547.appendChild(o515);
|
||||
o582=o569.createElement('dl');
|
||||
o588=document.createElement('input');
|
||||
o552.style.cssText = 'overflow: -moz-hidden-unscrollable; '
|
||||
o552.style.position='absolute';
|
||||
o600=o515.offsetParent;
|
||||
o619=document.createElement('input');
|
||||
o635=o569.createElement('input');
|
||||
o635.type='image';
|
||||
o600.appendChild(o635);
|
||||
o588.style.position='absolute';
|
||||
o635.appendChild(o582);
|
||||
o588.appendChild(o619);
|
||||
o670=o619.parentNode;
|
||||
o552.style.position=null;
|
||||
o582.appendChild(o670);
|
||||
o635.style.position='relative';
|
||||
}
|
||||
</script>
|
||||
<body onload="start()"><div id="store_div"></div></body>
|
||||
</html>
|
||||
|
@ -206,6 +206,7 @@ load 401734-2.html
|
||||
needs-focus pref(accessibility.browsewithcaret,true) load 403048.html
|
||||
skip load 403175-1.html # times out occasionally, bug 473680
|
||||
load 403245-1.html
|
||||
load 403454.html
|
||||
load 403569-1.xhtml
|
||||
load 403569-2.xhtml
|
||||
load 403569-3.xhtml
|
||||
@ -229,6 +230,7 @@ load 413587-1.svg
|
||||
load 414058-1.html
|
||||
load 414175-1.xul
|
||||
load 415503.xhtml
|
||||
load 416107.xhtml
|
||||
load 420031-1.html
|
||||
load 420213-1.html
|
||||
load 420219-1.html
|
||||
@ -418,6 +420,7 @@ load 806056-1.html
|
||||
load 806056-2.html
|
||||
load 812665.html
|
||||
load 813372-1.html
|
||||
asserts(0-4) load 817219.html # bug 623436
|
||||
asserts-if(gtk2Widget,0-1) load 822865.html # bug 540078
|
||||
load 824862.html
|
||||
load 826163.html
|
||||
@ -432,6 +435,7 @@ pref(layers.force-active,true) load 859526-1.html
|
||||
pref(layers.force-active,true) load 859630-1.html
|
||||
load 866588.html
|
||||
load 876092.html
|
||||
load 876221.html
|
||||
load 897852.html
|
||||
asserts-if(Android,2) asserts-if(!Android,4-6) load 898913.html # bug 847368
|
||||
pref(layers.acceleration.disabled,true) pref(layers.force-active,true) load 919434.html
|
||||
|
@ -1535,56 +1535,57 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
|
||||
// rendered shadow (even after blurring), so those pixels must be completely
|
||||
// transparent in the shadow, so drawing them changes nothing.
|
||||
gfxContext* renderContext = aRenderingContext.ThebesContext();
|
||||
DrawTarget* drawTarget = renderContext->GetDrawTarget();
|
||||
nsContextBoxBlur blurringArea;
|
||||
gfxContext* shadowContext =
|
||||
blurringArea.Init(shadowPaintRect, 0, blurRadius, twipsPerPixel,
|
||||
renderContext, aDirtyRect, &skipGfxRect);
|
||||
if (!shadowContext)
|
||||
continue;
|
||||
DrawTarget* shadowDT = shadowContext->GetDrawTarget();
|
||||
|
||||
// shadowContext is owned by either blurringArea or aRenderingContext.
|
||||
MOZ_ASSERT(shadowContext == renderContext ||
|
||||
shadowContext == blurringArea.GetContext());
|
||||
|
||||
// Set the shadow color; if not specified, use the foreground color
|
||||
nscolor shadowColor;
|
||||
if (shadowItem->mHasColor)
|
||||
shadowColor = shadowItem->mColor;
|
||||
else
|
||||
shadowColor = aForFrame->StyleColor()->mColor;
|
||||
|
||||
Color shadowColor = Color::FromABGR(shadowItem->mHasColor ?
|
||||
shadowItem->mColor :
|
||||
aForFrame->StyleColor()->mColor);
|
||||
renderContext->Save();
|
||||
renderContext->SetColor(gfxRGBA(shadowColor));
|
||||
renderContext->SetColor(ThebesColor(shadowColor));
|
||||
|
||||
// Clip the context to the area of the frame's padding rect, so no part of the
|
||||
// shadow is painted outside. Also cut out anything beyond where the inset shadow
|
||||
// will be.
|
||||
gfxRect shadowGfxRect =
|
||||
nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
|
||||
Rect shadowGfxRect = NSRectToRect(paddingRect, twipsPerPixel);
|
||||
shadowGfxRect.Round();
|
||||
renderContext->NewPath();
|
||||
if (hasBorderRadius)
|
||||
renderContext->RoundedRectangle(shadowGfxRect, innerRadii, false);
|
||||
else
|
||||
renderContext->Rectangle(shadowGfxRect);
|
||||
renderContext->Clip();
|
||||
if (hasBorderRadius) {
|
||||
RefPtr<Path> roundedRect =
|
||||
MakePathForRoundedRect(*drawTarget, shadowGfxRect, innerRadii);
|
||||
renderContext->Clip(roundedRect);
|
||||
} else {
|
||||
renderContext->Clip(shadowGfxRect);
|
||||
}
|
||||
|
||||
// Fill the surface minus the area within the frame that we should
|
||||
// not paint in, and blur and apply it.
|
||||
gfxRect shadowPaintGfxRect =
|
||||
nsLayoutUtils::RectToGfxRect(shadowPaintRect, twipsPerPixel);
|
||||
Rect shadowPaintGfxRect = NSRectToRect(shadowPaintRect, twipsPerPixel);
|
||||
shadowPaintGfxRect.RoundOut();
|
||||
gfxRect shadowClipGfxRect =
|
||||
nsLayoutUtils::RectToGfxRect(shadowClipRect, twipsPerPixel);
|
||||
Rect shadowClipGfxRect = NSRectToRect(shadowClipRect, twipsPerPixel);
|
||||
shadowClipGfxRect.Round();
|
||||
shadowContext->NewPath();
|
||||
shadowContext->Rectangle(shadowPaintGfxRect);
|
||||
if (hasBorderRadius)
|
||||
shadowContext->RoundedRectangle(shadowClipGfxRect, clipRectRadii, false);
|
||||
else
|
||||
shadowContext->Rectangle(shadowClipGfxRect);
|
||||
shadowContext->SetFillRule(FillRule::FILL_EVEN_ODD);
|
||||
RefPtr<PathBuilder> builder =
|
||||
shadowDT->CreatePathBuilder(FillRule::FILL_EVEN_ODD);
|
||||
AppendRectToPath(builder, shadowPaintGfxRect, true);
|
||||
if (hasBorderRadius) {
|
||||
AppendRoundedRectToPath(builder, shadowClipGfxRect, clipRectRadii, false);
|
||||
} else {
|
||||
AppendRectToPath(builder, shadowClipGfxRect, false);
|
||||
}
|
||||
RefPtr<Path> path = builder->Finish();
|
||||
shadowContext->SetPath(path);
|
||||
shadowContext->Fill();
|
||||
shadowContext->NewPath();
|
||||
|
||||
blurringArea.DoPaint();
|
||||
renderContext->Restore();
|
||||
@ -1822,6 +1823,8 @@ SetupBackgroundClip(nsCSSRendering::BackgroundClipState& aClipState,
|
||||
return;
|
||||
}
|
||||
|
||||
DrawTarget* drawTarget = aCtx->GetDrawTarget();
|
||||
|
||||
// If we have rounded corners, clip all subsequent drawing to the
|
||||
// rounded rectangle defined by bgArea and bgRadii (we don't know
|
||||
// whether the rounded corners intrude on the dirtyRect or not).
|
||||
@ -1842,10 +1845,8 @@ SetupBackgroundClip(nsCSSRendering::BackgroundClipState& aClipState,
|
||||
}
|
||||
|
||||
if (aClipState.mHasRoundedCorners) {
|
||||
gfxRect bgAreaGfx =
|
||||
nsLayoutUtils::RectToGfxRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
|
||||
Rect bgAreaGfx = NSRectToRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
|
||||
bgAreaGfx.Round();
|
||||
bgAreaGfx.Condition();
|
||||
|
||||
if (bgAreaGfx.IsEmpty()) {
|
||||
// I think it's become possible to hit this since
|
||||
@ -1857,9 +1858,10 @@ SetupBackgroundClip(nsCSSRendering::BackgroundClipState& aClipState,
|
||||
}
|
||||
|
||||
aAutoSR->EnsureSaved(aCtx);
|
||||
aCtx->NewPath();
|
||||
aCtx->RoundedRectangle(bgAreaGfx, aClipState.mClippedRadii);
|
||||
aCtx->Clip();
|
||||
|
||||
RefPtr<Path> roundedRect =
|
||||
MakePathForRoundedRect(*drawTarget, bgAreaGfx, aClipState.mClippedRadii);
|
||||
aCtx->Clip(roundedRect);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1873,6 +1875,8 @@ DrawBackgroundColor(nsCSSRendering::BackgroundClipState& aClipState,
|
||||
return;
|
||||
}
|
||||
|
||||
DrawTarget* drawTarget = aCtx->GetDrawTarget();
|
||||
|
||||
// We don't support custom clips and rounded corners, arguably a bug, but
|
||||
// table painting seems to depend on it.
|
||||
if (!aClipState.mHasRoundedCorners || aClipState.mCustomClip) {
|
||||
@ -1882,10 +1886,8 @@ DrawBackgroundColor(nsCSSRendering::BackgroundClipState& aClipState,
|
||||
return;
|
||||
}
|
||||
|
||||
gfxRect bgAreaGfx =
|
||||
nsLayoutUtils::RectToGfxRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
|
||||
Rect bgAreaGfx = NSRectToRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
|
||||
bgAreaGfx.Round();
|
||||
bgAreaGfx.Condition();
|
||||
|
||||
if (bgAreaGfx.IsEmpty()) {
|
||||
// I think it's become possible to hit this since
|
||||
@ -1897,7 +1899,7 @@ DrawBackgroundColor(nsCSSRendering::BackgroundClipState& aClipState,
|
||||
}
|
||||
|
||||
aCtx->Save();
|
||||
gfxRect dirty = bgAreaGfx.Intersect(aClipState.mDirtyRectGfx);
|
||||
gfxRect dirty = ThebesRect(bgAreaGfx).Intersect(aClipState.mDirtyRectGfx);
|
||||
|
||||
aCtx->NewPath();
|
||||
aCtx->Rectangle(dirty, true);
|
||||
@ -1913,9 +1915,9 @@ DrawBackgroundColor(nsCSSRendering::BackgroundClipState& aClipState,
|
||||
aCtx->Clip();
|
||||
}
|
||||
|
||||
aCtx->NewPath();
|
||||
aCtx->RoundedRectangle(bgAreaGfx, aClipState.mClippedRadii);
|
||||
|
||||
RefPtr<Path> roundedRect =
|
||||
MakePathForRoundedRect(*drawTarget, bgAreaGfx, aClipState.mClippedRadii);
|
||||
aCtx->SetPath(roundedRect);
|
||||
aCtx->Fill();
|
||||
aCtx->Restore();
|
||||
}
|
||||
|
@ -60,22 +60,22 @@ static void ComputeBorderCornerDimensions(const Rect& aOuterRect,
|
||||
|
||||
// from the given base color and the background color, turn
|
||||
// color into a color for the given border pattern style
|
||||
static gfxRGBA MakeBorderColor(const gfxRGBA& aColor,
|
||||
const gfxRGBA& aBackgroundColor,
|
||||
BorderColorStyle aBorderColorStyle);
|
||||
static Color MakeBorderColor(nscolor aColor,
|
||||
nscolor aBackgroundColor,
|
||||
BorderColorStyle aBorderColorStyle);
|
||||
|
||||
|
||||
// Given a line index (an index starting from the outside of the
|
||||
// border going inwards) and an array of line styles, calculate the
|
||||
// color that that stripe of the border should be rendered in.
|
||||
static gfxRGBA ComputeColorForLine(uint32_t aLineIndex,
|
||||
static Color ComputeColorForLine(uint32_t aLineIndex,
|
||||
const BorderColorStyle* aBorderColorStyle,
|
||||
uint32_t aBorderColorStyleCount,
|
||||
nscolor aBorderColor,
|
||||
nscolor aBackgroundColor);
|
||||
|
||||
static gfxRGBA ComputeCompositeColorForLine(uint32_t aLineIndex,
|
||||
const nsBorderColors* aBorderColors);
|
||||
static Color ComputeCompositeColorForLine(uint32_t aLineIndex,
|
||||
const nsBorderColors* aBorderColors);
|
||||
|
||||
// little helper function to check if the array of 4 floats given are
|
||||
// equal to the given value
|
||||
@ -521,33 +521,36 @@ nsCSSBorderRenderer::DoSideClipSubPath(mozilla::css::Side aSide)
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSBorderRenderer::FillSolidBorder(const gfxRect& aOuterRect,
|
||||
const gfxRect& aInnerRect,
|
||||
nsCSSBorderRenderer::FillSolidBorder(const Rect& aOuterRect,
|
||||
const Rect& aInnerRect,
|
||||
const RectCornerRadii& aBorderRadii,
|
||||
const Float* aBorderSizes,
|
||||
int aSides,
|
||||
const gfxRGBA& aColor)
|
||||
const ColorPattern& aColor)
|
||||
{
|
||||
mContext->SetColor(aColor);
|
||||
DrawTarget* drawTarget = mContext->GetDrawTarget();
|
||||
|
||||
// Note that this function is allowed to draw more than just the
|
||||
// requested sides.
|
||||
|
||||
// If we have a border radius, do full rounded rectangles
|
||||
// and fill, regardless of what sides we're asked to draw.
|
||||
if (!AllCornersZeroSize(aBorderRadii)) {
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_EVEN_ODD);
|
||||
|
||||
RectCornerRadii innerRadii;
|
||||
ComputeInnerRadii(aBorderRadii, aBorderSizes, &innerRadii);
|
||||
|
||||
mContext->NewPath();
|
||||
|
||||
// do the outer border
|
||||
mContext->RoundedRectangle(aOuterRect, aBorderRadii, true);
|
||||
AppendRoundedRectToPath(builder, aOuterRect, aBorderRadii, true);
|
||||
|
||||
// then do the inner border CCW
|
||||
mContext->RoundedRectangle(aInnerRect, innerRadii, false);
|
||||
AppendRoundedRectToPath(builder, aInnerRect, innerRadii, false);
|
||||
|
||||
mContext->Fill();
|
||||
RefPtr<Path> path = builder->Finish();
|
||||
|
||||
drawTarget->Fill(path, aColor);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -560,14 +563,10 @@ nsCSSBorderRenderer::FillSolidBorder(const gfxRect& aOuterRect,
|
||||
CheckFourFloatsEqual(aBorderSizes, aBorderSizes[0]) &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
gfxRect r(aOuterRect);
|
||||
r.Deflate(aBorderSizes[0] / 2.0);
|
||||
mContext->SetLineWidth(aBorderSizes[0]);
|
||||
|
||||
mContext->NewPath();
|
||||
mContext->Rectangle(r);
|
||||
mContext->Stroke();
|
||||
|
||||
Float strokeWidth = aBorderSizes[0];
|
||||
Rect r(aOuterRect);
|
||||
r.Deflate(strokeWidth / 2.f);
|
||||
drawTarget->StrokeRect(r, aColor, StrokeOptions(strokeWidth));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -632,37 +631,37 @@ nsCSSBorderRenderer::FillSolidBorder(const gfxRect& aOuterRect,
|
||||
// Filling these one by one is faster than filling them all at once.
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
if (aSides & (1 << i)) {
|
||||
mContext->NewPath();
|
||||
mContext->Rectangle(ThebesRect(r[i]), true);
|
||||
mContext->Fill();
|
||||
MaybeSnapToDevicePixels(r[i], *drawTarget, true);
|
||||
drawTarget->FillRect(r[i], aColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfxRGBA
|
||||
MakeBorderColor(const gfxRGBA& aColor, const gfxRGBA& aBackgroundColor, BorderColorStyle aBorderColorStyle)
|
||||
Color
|
||||
MakeBorderColor(nscolor aColor, nscolor aBackgroundColor,
|
||||
BorderColorStyle aBorderColorStyle)
|
||||
{
|
||||
nscolor colors[2];
|
||||
int k = 0;
|
||||
|
||||
switch (aBorderColorStyle) {
|
||||
case BorderColorStyleNone:
|
||||
return gfxRGBA(0.0, 0.0, 0.0, 0.0);
|
||||
return Color(0.f, 0.f, 0.f, 0.f); // transparent black
|
||||
|
||||
case BorderColorStyleLight:
|
||||
k = 1;
|
||||
/* fall through */
|
||||
case BorderColorStyleDark:
|
||||
NS_GetSpecial3DColors(colors, aBackgroundColor.Packed(), aColor.Packed());
|
||||
return gfxRGBA(colors[k]);
|
||||
NS_GetSpecial3DColors(colors, aBackgroundColor, aColor);
|
||||
return Color::FromABGR(colors[k]);
|
||||
|
||||
case BorderColorStyleSolid:
|
||||
default:
|
||||
return aColor;
|
||||
return Color::FromABGR(aColor);
|
||||
}
|
||||
}
|
||||
|
||||
gfxRGBA
|
||||
Color
|
||||
ComputeColorForLine(uint32_t aLineIndex,
|
||||
const BorderColorStyle* aBorderColorStyle,
|
||||
uint32_t aBorderColorStyleCount,
|
||||
@ -671,17 +670,18 @@ ComputeColorForLine(uint32_t aLineIndex,
|
||||
{
|
||||
NS_ASSERTION(aLineIndex < aBorderColorStyleCount, "Invalid lineIndex given");
|
||||
|
||||
return MakeBorderColor(gfxRGBA(aBorderColor), gfxRGBA(aBackgroundColor), aBorderColorStyle[aLineIndex]);
|
||||
return MakeBorderColor(aBorderColor, aBackgroundColor,
|
||||
aBorderColorStyle[aLineIndex]);
|
||||
}
|
||||
|
||||
gfxRGBA
|
||||
Color
|
||||
ComputeCompositeColorForLine(uint32_t aLineIndex,
|
||||
const nsBorderColors* aBorderColors)
|
||||
{
|
||||
while (aLineIndex-- && aBorderColors->mNext)
|
||||
aBorderColors = aBorderColors->mNext;
|
||||
|
||||
return gfxRGBA(aBorderColors->mColor);
|
||||
return Color::FromABGR(aBorderColors->mColor);
|
||||
}
|
||||
|
||||
void
|
||||
@ -702,7 +702,8 @@ nsCSSBorderRenderer::DrawBorderSidesCompositeColors(int aSides, const nsBorderCo
|
||||
Point ibr = ToPoint(mInnerRect.BottomRight());
|
||||
|
||||
for (uint32_t i = 0; i < uint32_t(maxBorderWidth); i++) {
|
||||
gfxRGBA lineColor = ComputeCompositeColorForLine(i, aCompositeColors);
|
||||
ColorPattern color(ToDeviceColor(
|
||||
ComputeCompositeColorForLine(i, aCompositeColors)));
|
||||
|
||||
Rect siRect = soRect;
|
||||
siRect.Deflate(1.0);
|
||||
@ -724,7 +725,7 @@ nsCSSBorderRenderer::DrawBorderSidesCompositeColors(int aSides, const nsBorderCo
|
||||
fakeBorderSizes[NS_SIDE_BOTTOM] = soRect.BottomRight().y - siRect.BottomRight().y;
|
||||
fakeBorderSizes[NS_SIDE_LEFT] = siRect.BottomLeft().x - soRect.BottomLeft().x;
|
||||
|
||||
FillSolidBorder(ThebesRect(soRect), ThebesRect(siRect), radii, fakeBorderSizes, aSides, lineColor);
|
||||
FillSolidBorder(soRect, siRect, radii, fakeBorderSizes, aSides, color);
|
||||
|
||||
soRect = siRect;
|
||||
|
||||
@ -906,11 +907,11 @@ nsCSSBorderRenderer::DrawBorderSides(int aSides)
|
||||
borderWidths[i][2], borderWidths[i][3]));
|
||||
|
||||
if (borderColorStyle[i] != BorderColorStyleNone) {
|
||||
gfxRGBA color = ComputeColorForLine(i,
|
||||
borderColorStyle, borderColorStyleCount,
|
||||
borderRenderColor, mBackgroundColor);
|
||||
Color c = ComputeColorForLine(i, borderColorStyle, borderColorStyleCount,
|
||||
borderRenderColor, mBackgroundColor);
|
||||
ColorPattern color(ToDeviceColor(c));
|
||||
|
||||
FillSolidBorder(ThebesRect(soRect), ThebesRect(siRect), radii, borderWidths[i], aSides, color);
|
||||
FillSolidBorder(soRect, siRect, radii, borderWidths[i], aSides, color);
|
||||
}
|
||||
|
||||
ComputeInnerRadii(radii, borderWidths[i], &radii);
|
||||
@ -1055,8 +1056,8 @@ bool IsVisible(int aStyle)
|
||||
|
||||
TemporaryRef<GradientStops>
|
||||
nsCSSBorderRenderer::CreateCornerGradient(mozilla::css::Corner aCorner,
|
||||
const gfxRGBA &aFirstColor,
|
||||
const gfxRGBA &aSecondColor,
|
||||
nscolor aFirstColor,
|
||||
nscolor aSecondColor,
|
||||
DrawTarget *aDT,
|
||||
Point &aPoint1,
|
||||
Point &aPoint2)
|
||||
@ -1088,8 +1089,8 @@ nsCSSBorderRenderer::CreateCornerGradient(mozilla::css::Corner aCorner,
|
||||
aPoint1 = Point(pat1.x, pat1.y);
|
||||
aPoint2 = Point(pat2.x, pat2.y);
|
||||
|
||||
Color firstColor = ToColor(aFirstColor);
|
||||
Color secondColor = ToColor(aSecondColor);
|
||||
Color firstColor = Color::FromABGR(aFirstColor);
|
||||
Color secondColor = Color::FromABGR(aSecondColor);
|
||||
|
||||
nsTArray<gfx::GradientStop> rawStops(2);
|
||||
rawStops.SetLength(2);
|
||||
@ -1334,11 +1335,11 @@ nsCSSBorderRenderer::DrawRectangularCompositeColors()
|
||||
secondCorner.x -= cornerAdjusts[side].a;
|
||||
secondCorner.y -= cornerAdjusts[side].b;
|
||||
|
||||
gfxRGBA currentColor =
|
||||
currentColors[side] ? gfxRGBA(currentColors[side]->mColor)
|
||||
: gfxRGBA(mBorderColors[side]);
|
||||
Color currentColor = Color::FromABGR(
|
||||
currentColors[side] ? currentColors[side]->mColor
|
||||
: mBorderColors[side]);
|
||||
|
||||
mContext->SetColor(currentColor);
|
||||
mContext->SetColor(ThebesColor(currentColor));
|
||||
mContext->NewPath();
|
||||
mContext->MoveTo(firstCorner);
|
||||
mContext->LineTo(secondCorner);
|
||||
@ -1349,15 +1350,15 @@ nsCSSBorderRenderer::DrawRectangularCompositeColors()
|
||||
cornerTopLeft.x -= 0.5;
|
||||
cornerTopLeft.y -= 0.5;
|
||||
mContext->Rectangle(gfxRect(cornerTopLeft, gfxSize(1, 1)));
|
||||
gfxRGBA nextColor =
|
||||
currentColors[sideNext] ? gfxRGBA(currentColors[sideNext]->mColor)
|
||||
: gfxRGBA(mBorderColors[sideNext]);
|
||||
Color nextColor = Color::FromABGR(
|
||||
currentColors[sideNext] ? currentColors[sideNext]->mColor
|
||||
: mBorderColors[sideNext]);
|
||||
|
||||
gfxRGBA cornerColor((currentColor.r + nextColor.r) / 2.0,
|
||||
(currentColor.g + nextColor.g) / 2.0,
|
||||
(currentColor.b + nextColor.b) / 2.0,
|
||||
(currentColor.a + nextColor.a) / 2.0);
|
||||
mContext->SetColor(cornerColor);
|
||||
Color cornerColor((currentColor.r + nextColor.r) / 2.f,
|
||||
(currentColor.g + nextColor.g) / 2.f,
|
||||
(currentColor.b + nextColor.b) / 2.f,
|
||||
(currentColor.a + nextColor.a) / 2.f);
|
||||
mContext->SetColor(ThebesColor(cornerColor));
|
||||
mContext->Fill();
|
||||
|
||||
if (side != 0) {
|
||||
@ -1378,6 +1379,8 @@ nsCSSBorderRenderer::DrawRectangularCompositeColors()
|
||||
void
|
||||
nsCSSBorderRenderer::DrawBorders()
|
||||
{
|
||||
DrawTarget* drawTarget = mContext->GetDrawTarget();
|
||||
|
||||
bool forceSeparateCorners = false;
|
||||
|
||||
// Examine the border style to figure out if we can draw it in one
|
||||
@ -1435,6 +1438,9 @@ nsCSSBorderRenderer::DrawBorders()
|
||||
return;
|
||||
}
|
||||
|
||||
ColorPattern color(ToDeviceColor(mBorderColors[NS_SIDE_TOP]));
|
||||
StrokeOptions strokeOptions(mBorderWidths[NS_SIDE_TOP]); // stroke width
|
||||
|
||||
bool allBordersSolid;
|
||||
|
||||
// First there's a couple of 'special cases' that have specifically optimized
|
||||
@ -1488,8 +1494,6 @@ nsCSSBorderRenderer::DrawBorders()
|
||||
!mNoBorderRadius)
|
||||
{
|
||||
// Relatively simple case.
|
||||
SetupStrokeStyle(NS_SIDE_TOP);
|
||||
|
||||
RoundedRect borderInnerRect(mOuterRect, mBorderRadii);
|
||||
borderInnerRect.Deflate(mBorderWidths[NS_SIDE_TOP],
|
||||
mBorderWidths[NS_SIDE_BOTTOM],
|
||||
@ -1505,11 +1509,12 @@ nsCSSBorderRenderer::DrawBorders()
|
||||
// doesn't need to compute an offset curve to stroke the path. We know that
|
||||
// the rounded parts are elipses we can offset exactly and can just compute
|
||||
// a new cubic approximation.
|
||||
mContext->NewPath();
|
||||
mContext->RoundedRectangle(mOuterRect, mBorderRadii, true);
|
||||
mContext->RoundedRectangle(borderInnerRect.rect, borderInnerRect.corners, false);
|
||||
mContext->Fill();
|
||||
return;
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_EVEN_ODD);
|
||||
AppendRoundedRectToPath(builder, ToRect(mOuterRect), mBorderRadii, true);
|
||||
AppendRoundedRectToPath(builder, ToRect(borderInnerRect.rect), borderInnerRect.corners, false);
|
||||
RefPtr<Path> path = builder->Finish();
|
||||
drawTarget->Fill(path, color);
|
||||
}
|
||||
|
||||
bool hasCompositeColors;
|
||||
@ -1633,9 +1638,10 @@ nsCSSBorderRenderer::DrawBorders()
|
||||
{
|
||||
mContext->NewPath();
|
||||
DoCornerSubPath(corner);
|
||||
mContext->SetColor(MakeBorderColor(mBorderColors[sides[0]],
|
||||
mBackgroundColor,
|
||||
BorderColorStyleForSolidCorner(mBorderStyles[sides[0]], corner)));
|
||||
Color color = MakeBorderColor(mBorderColors[sides[0]],
|
||||
mBackgroundColor,
|
||||
BorderColorStyleForSolidCorner(mBorderStyles[sides[0]], corner));
|
||||
mContext->SetColor(ThebesColor(color));
|
||||
mContext->Fill();
|
||||
continue;
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
class gfxContext;
|
||||
struct gfxRGBA;
|
||||
struct nsBorderColors;
|
||||
|
||||
namespace mozilla {
|
||||
@ -77,7 +76,9 @@ typedef enum {
|
||||
} BorderColorStyle;
|
||||
|
||||
struct nsCSSBorderRenderer {
|
||||
typedef mozilla::gfx::ColorPattern ColorPattern;
|
||||
typedef mozilla::gfx::Float Float;
|
||||
typedef mozilla::gfx::Rect Rect;
|
||||
typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
|
||||
|
||||
nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
|
||||
@ -162,12 +163,12 @@ struct nsCSSBorderRenderer {
|
||||
//
|
||||
// Calling code is expected to only set up a clip as necessary; no
|
||||
// clip is needed if we can render the entire border in 1 or 2 passes.
|
||||
void FillSolidBorder(const gfxRect& aOuterRect,
|
||||
const gfxRect& aInnerRect,
|
||||
void FillSolidBorder(const Rect& aOuterRect,
|
||||
const Rect& aInnerRect,
|
||||
const RectCornerRadii& aBorderRadii,
|
||||
const Float *aBorderSizes,
|
||||
const Float* aBorderSizes,
|
||||
int aSides,
|
||||
const gfxRGBA& aColor);
|
||||
const ColorPattern& aColor);
|
||||
|
||||
//
|
||||
// core rendering
|
||||
@ -196,8 +197,8 @@ struct nsCSSBorderRenderer {
|
||||
|
||||
// Azure variant of CreateCornerGradient.
|
||||
mozilla::TemporaryRef<mozilla::gfx::GradientStops>
|
||||
CreateCornerGradient(mozilla::css::Corner aCorner, const gfxRGBA &aFirstColor,
|
||||
const gfxRGBA &aSecondColor, mozilla::gfx::DrawTarget *aDT,
|
||||
CreateCornerGradient(mozilla::css::Corner aCorner, nscolor aFirstColor,
|
||||
nscolor aSecondColor, mozilla::gfx::DrawTarget *aDT,
|
||||
mozilla::gfx::Point &aPoint1, mozilla::gfx::Point &aPoint2);
|
||||
|
||||
// Draw a solid color border that is uniformly the same width.
|
||||
|
@ -78,6 +78,7 @@ class nsDisplayList;
|
||||
class nsDisplayListBuilder;
|
||||
class nsPIDOMWindow;
|
||||
struct nsPoint;
|
||||
class nsINode;
|
||||
struct nsIntPoint;
|
||||
struct nsIntRect;
|
||||
struct nsRect;
|
||||
@ -140,8 +141,8 @@ typedef struct CapturingContentInfo {
|
||||
|
||||
// 79c0f49f-77f1-4cc5-80d1-6552e85ccb0c
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x79c0f49f, 0x77f1, 0x4cc5, \
|
||||
{ 0x80, 0xd1, 0x65, 0x52, 0xe8, 0x5c, 0xcb, 0x0c } }
|
||||
{ 0xa0a4b515, 0x0b91, 0x4f13, \
|
||||
{ 0xa0, 0x60, 0x4b, 0xfb, 0x35, 0x00, 0xdc, 0x00 } }
|
||||
|
||||
// debug VerifyReflow flags
|
||||
#define VERIFY_REFLOW_ON 0x01
|
||||
@ -881,6 +882,13 @@ public:
|
||||
nsIDOMEvent* aEvent,
|
||||
nsEventStatus* aStatus) = 0;
|
||||
|
||||
/**
|
||||
* Dispatch AfterKeyboardEvent with specific target.
|
||||
*/
|
||||
virtual void DispatchAfterKeyboardEvent(nsINode* aTarget,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current target event frame from the PresShell
|
||||
*/
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "nsPresShell.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEvent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
@ -72,6 +73,8 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIPageSequenceFrame.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIMozBrowserFrame.h"
|
||||
#include "nsCaret.h"
|
||||
#include "TouchCaret.h"
|
||||
#include "SelectionCarets.h"
|
||||
@ -81,6 +84,7 @@
|
||||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsILineIterator.h" // for ScrollContentIntoView
|
||||
#include "pldhash.h"
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEventBinding.h"
|
||||
#include "mozilla/dom/Touch.h"
|
||||
#include "mozilla/dom/PointerEventBinding.h"
|
||||
#include "nsIObserverService.h"
|
||||
@ -705,6 +709,7 @@ static uint32_t sNextPresShellId;
|
||||
static bool sPointerEventEnabled = true;
|
||||
static bool sTouchCaretEnabled = false;
|
||||
static bool sSelectionCaretEnabled = false;
|
||||
static bool sBeforeAfterKeyboardEventEnabled = false;
|
||||
|
||||
/* static */ bool
|
||||
PresShell::TouchCaretPrefEnabled()
|
||||
@ -728,6 +733,18 @@ PresShell::SelectionCaretPrefEnabled()
|
||||
return sSelectionCaretEnabled;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PresShell::BeforeAfterKeyboardEventEnabled()
|
||||
{
|
||||
static bool sInitialized = false;
|
||||
if (!sInitialized) {
|
||||
Preferences::AddBoolVarCache(&sBeforeAfterKeyboardEventEnabled,
|
||||
"dom.beforeAfterKeyboardEvent.enabled");
|
||||
sInitialized = true;
|
||||
}
|
||||
return sBeforeAfterKeyboardEventEnabled;
|
||||
}
|
||||
|
||||
PresShell::PresShell()
|
||||
: mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
|
||||
{
|
||||
@ -6940,6 +6957,229 @@ private:
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
};
|
||||
|
||||
static bool
|
||||
CheckPermissionForBeforeAfterKeyboardEvent(Element* aElement)
|
||||
{
|
||||
// An element which is chrome-privileged should be able to handle before
|
||||
// events and after events.
|
||||
nsIPrincipal* principal = aElement->NodePrincipal();
|
||||
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// An element which has "before-after-keyboard-event" permission should be
|
||||
// able to handle before events and after events.
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
if (permMgr) {
|
||||
permMgr->TestPermissionFromPrincipal(principal, "before-after-keyboard-event", &permission);
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check "embed-apps" permission for later use.
|
||||
permission = nsIPermissionManager::DENY_ACTION;
|
||||
permMgr->TestPermissionFromPrincipal(principal, "embed-apps", &permission);
|
||||
}
|
||||
|
||||
// An element can handle before events and after events if the following
|
||||
// conditions are met:
|
||||
// 1) <iframe mozbrowser mozapp>
|
||||
// 2) it has "embed-apps" permission.
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame(do_QueryInterface(aElement));
|
||||
if ((permission == nsIPermissionManager::ALLOW_ACTION) &&
|
||||
browserFrame && browserFrame->GetReallyIsApp()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
BuildTargetChainForBeforeAfterKeyboardEvent(nsINode* aTarget,
|
||||
nsTArray<nsCOMPtr<Element> >& aChain,
|
||||
bool& aTargetIsIframe)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget));
|
||||
aTargetIsIframe = content && content->IsHTML(nsGkAtoms::iframe);
|
||||
|
||||
Element* frameElement;
|
||||
// If event target is not an iframe, skip the event target and get its
|
||||
// parent frame.
|
||||
if (aTargetIsIframe) {
|
||||
frameElement = aTarget->AsElement();
|
||||
} else {
|
||||
nsPIDOMWindow* window = aTarget->OwnerDoc()->GetWindow();
|
||||
frameElement = window ? window->GetFrameElementInternal() : nullptr;
|
||||
}
|
||||
|
||||
// Check permission for all ancestors and add them into the target chain.
|
||||
while (frameElement) {
|
||||
if (CheckPermissionForBeforeAfterKeyboardEvent(frameElement)) {
|
||||
aChain.AppendElement(frameElement);
|
||||
}
|
||||
nsPIDOMWindow* window = frameElement->OwnerDoc()->GetWindow();
|
||||
frameElement = window ? window->GetFrameElementInternal() : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::DispatchBeforeKeyboardEventInternal(const nsTArray<nsCOMPtr<Element> >& aChain,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
size_t& aChainIndex,
|
||||
bool& aDefaultPrevented)
|
||||
{
|
||||
size_t length = aChain.Length();
|
||||
if (!CanDispatchEvent(&aEvent) || !length) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t message =
|
||||
(aEvent.message == NS_KEY_DOWN) ? NS_KEY_BEFORE_DOWN : NS_KEY_BEFORE_UP;
|
||||
nsCOMPtr<EventTarget> eventTarget;
|
||||
// Dispatch before events from the outermost element.
|
||||
for (int32_t i = length - 1; i >= 0; i--) {
|
||||
eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
|
||||
if (!eventTarget || !CanDispatchEvent(&aEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aChainIndex = i;
|
||||
InternalBeforeAfterKeyboardEvent beforeEvent(aEvent.mFlags.mIsTrusted,
|
||||
message, aEvent.widget);
|
||||
beforeEvent.AssignBeforeAfterKeyEventData(aEvent, false);
|
||||
EventDispatcher::Dispatch(eventTarget, mPresContext, &beforeEvent);
|
||||
|
||||
if (beforeEvent.mFlags.mDefaultPrevented) {
|
||||
aDefaultPrevented = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::DispatchAfterKeyboardEventInternal(const nsTArray<nsCOMPtr<Element> >& aChain,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
size_t aStartOffset)
|
||||
{
|
||||
size_t length = aChain.Length();
|
||||
if (!CanDispatchEvent(&aEvent) || !length) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t message =
|
||||
(aEvent.message == NS_KEY_DOWN) ? NS_KEY_AFTER_DOWN : NS_KEY_AFTER_UP;
|
||||
bool embeddedCancelled = aEmbeddedCancelled;
|
||||
nsCOMPtr<EventTarget> eventTarget;
|
||||
// Dispatch after events from the innermost element.
|
||||
for (uint32_t i = aStartOffset; i < length; i++) {
|
||||
eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
|
||||
if (!eventTarget || !CanDispatchEvent(&aEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
InternalBeforeAfterKeyboardEvent afterEvent(aEvent.mFlags.mIsTrusted,
|
||||
message, aEvent.widget);
|
||||
afterEvent.AssignBeforeAfterKeyEventData(aEvent, false);
|
||||
afterEvent.mEmbeddedCancelled.SetValue(embeddedCancelled);
|
||||
EventDispatcher::Dispatch(eventTarget, mPresContext, &afterEvent);
|
||||
embeddedCancelled = afterEvent.mFlags.mDefaultPrevented;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::DispatchAfterKeyboardEvent(nsINode* aTarget,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled)
|
||||
{
|
||||
MOZ_ASSERT(aTarget);
|
||||
MOZ_ASSERT(BeforeAfterKeyboardEventEnabled());
|
||||
|
||||
if (NS_WARN_IF(aEvent.message != NS_KEY_DOWN &&
|
||||
aEvent.message != NS_KEY_UP)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build up a target chain. Each item in the chain will receive an after event.
|
||||
nsAutoTArray<nsCOMPtr<Element>, 5> chain;
|
||||
bool targetIsIframe = false;
|
||||
BuildTargetChainForBeforeAfterKeyboardEvent(aTarget, chain, targetIsIframe);
|
||||
DispatchAfterKeyboardEventInternal(chain, aEvent, aEmbeddedCancelled);
|
||||
}
|
||||
|
||||
bool
|
||||
PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
|
||||
{
|
||||
bool rv =
|
||||
mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
|
||||
if (aEvent) {
|
||||
rv &= (aEvent && aEvent->widget && !aEvent->widget->Destroyed());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::HandleKeyboardEvent(nsINode* aTarget,
|
||||
WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
nsEventStatus* aStatus,
|
||||
EventDispatchingCallback* aEventCB)
|
||||
{
|
||||
if (aEvent.message == NS_KEY_PRESS ||
|
||||
!BeforeAfterKeyboardEventEnabled()) {
|
||||
EventDispatcher::Dispatch(aTarget, mPresContext,
|
||||
&aEvent, nullptr, aStatus, aEventCB);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aTarget);
|
||||
MOZ_ASSERT(aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_UP);
|
||||
|
||||
// Build up a target chain. Each item in the chain will receive a before event.
|
||||
nsAutoTArray<nsCOMPtr<Element>, 5> chain;
|
||||
bool targetIsIframe = false;
|
||||
BuildTargetChainForBeforeAfterKeyboardEvent(aTarget, chain, targetIsIframe);
|
||||
|
||||
// Dispatch before events. If each item in the chain consumes the before
|
||||
// event and doesn't prevent the default action, we will go further to
|
||||
// dispatch the actual key event and after events in the reverse order.
|
||||
// Otherwise, only items which has handled the before event will receive an
|
||||
// after event.
|
||||
size_t chainIndex;
|
||||
bool defaultPrevented = false;
|
||||
DispatchBeforeKeyboardEventInternal(chain, aEvent, chainIndex,
|
||||
defaultPrevented);
|
||||
|
||||
// Dispatch after events to partial items.
|
||||
if (defaultPrevented) {
|
||||
DispatchAfterKeyboardEventInternal(chain, aEvent,
|
||||
aEvent.mFlags.mDefaultPrevented, chainIndex);
|
||||
|
||||
// No need to forward the event to child process.
|
||||
aEvent.mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Event listeners may kill nsPresContext and nsPresShell.
|
||||
if (!CanDispatchEvent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch actual key event to event target.
|
||||
EventDispatcher::Dispatch(aTarget, mPresContext,
|
||||
&aEvent, nullptr, aStatus, aEventCB);
|
||||
|
||||
// Event listeners may kill nsPresContext and nsPresShell.
|
||||
if (targetIsIframe || !CanDispatchEvent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch after events to all items in the chain.
|
||||
DispatchAfterKeyboardEventInternal(chain, aEvent,
|
||||
aEvent.mFlags.mDefaultPrevented);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresShell::HandleEvent(nsIFrame* aFrame,
|
||||
WidgetGUIEvent* aEvent,
|
||||
@ -7946,6 +8186,9 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
|
||||
IMEStateManager::DispatchCompositionEvent(eventTarget,
|
||||
mPresContext, aEvent->AsCompositionEvent(), aStatus,
|
||||
eventCBPtr);
|
||||
} else if (aEvent->mClass == eKeyboardEventClass) {
|
||||
HandleKeyboardEvent(eventTarget, *(aEvent->AsKeyboardEvent()),
|
||||
false, aStatus, eventCBPtr);
|
||||
} else {
|
||||
EventDispatcher::Dispatch(eventTarget, mPresContext,
|
||||
aEvent, nullptr, aStatus, eventCBPtr);
|
||||
|
@ -50,6 +50,7 @@ class nsAutoCauseReflowNotifier;
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
class EventDispatchingCallback;
|
||||
} // namespace mozilla
|
||||
|
||||
// 250ms. This is actually pref-controlled, but we use this value if we fail
|
||||
@ -75,6 +76,9 @@ public:
|
||||
// Selection caret preference
|
||||
static bool SelectionCaretPrefEnabled();
|
||||
|
||||
// BeforeAfterKeyboardEvent preference
|
||||
static bool BeforeAfterKeyboardEventEnabled();
|
||||
|
||||
void Init(nsIDocument* aDocument, nsPresContext* aPresContext,
|
||||
nsViewManager* aViewManager, nsStyleSet* aStyleSet,
|
||||
nsCompatibility aCompatMode);
|
||||
@ -373,6 +377,10 @@ public:
|
||||
|
||||
virtual void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot);
|
||||
|
||||
virtual void DispatchAfterKeyboardEvent(nsINode* aTarget,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled) MOZ_OVERRIDE;
|
||||
|
||||
void SetNextPaintCompressed() { mNextPaintCompressed = true; }
|
||||
|
||||
protected:
|
||||
@ -723,6 +731,24 @@ protected:
|
||||
|
||||
void EvictTouches();
|
||||
|
||||
// Methods for dispatching KeyboardEvent and BeforeAfterKeyboardEvent.
|
||||
void HandleKeyboardEvent(nsINode* aTarget,
|
||||
mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
nsEventStatus* aStatus,
|
||||
mozilla::EventDispatchingCallback* aEventCB);
|
||||
void DispatchBeforeKeyboardEventInternal(
|
||||
const nsTArray<nsCOMPtr<mozilla::dom::Element> >& aChain,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
size_t& aChainIndex,
|
||||
bool& aDefaultPrevented);
|
||||
void DispatchAfterKeyboardEventInternal(
|
||||
const nsTArray<nsCOMPtr<mozilla::dom::Element> >& aChain,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
size_t aChainIndex = 0);
|
||||
bool CanDispatchEvent(const mozilla::WidgetGUIEvent* aEvent = nullptr) const;
|
||||
|
||||
// A list of images that are visible or almost visible.
|
||||
nsTHashtable< nsRefPtrHashKey<nsIImageLoadingContent> > mVisibleImages;
|
||||
|
||||
|
101
layout/base/tests/bug558663.html
Normal file
101
layout/base/tests/bug558663.html
Normal file
@ -0,0 +1,101 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=558663
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 558663</title>
|
||||
</head>
|
||||
<body>
|
||||
<p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=558663">Mozilla Bug 558663</a></p>
|
||||
|
||||
<!-- 20x20 of red -->
|
||||
<iframe id="iframe" src="data:text/html,<img id='image' border='0' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAG0lEQVR42mP8z0A%2BYKJA76jmUc2jmkc1U0EzACKcASfOgGoMAAAAAElFTkSuQmCC'>"></iframe>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 558663 **/
|
||||
var ok = parent.ok;
|
||||
var SimpleTest = parent.SimpleTest;
|
||||
var compareSnapshots = parent.compareSnapshots;
|
||||
var snapshotWindow = parent.snapshotWindow;
|
||||
var synthesizeMouse = parent.synthesizeMouse;
|
||||
|
||||
window.addEventListener("load", runTest, false);
|
||||
|
||||
function checkSnapshots(s1, s2, shouldBeEqual, testName) {
|
||||
var res = compareSnapshots(s1, s2, shouldBeEqual);
|
||||
if (res[0]) {
|
||||
ok(true, testName + " snapshots compare correctly");
|
||||
} else {
|
||||
ok(false, testName + " snapshots compare incorrectly. snapshot 1: " +
|
||||
res[1] + " snapshot 2: " + res[2]);
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
document.getElementById("iframe").contentWindow.document.designMode = "on";
|
||||
|
||||
// The editor requires the event loop to spin after you turn on design mode
|
||||
// before it takes effect.
|
||||
setTimeout(continueTest, 100);
|
||||
}
|
||||
|
||||
function continueTest() {
|
||||
var win = document.getElementById("iframe").contentWindow;
|
||||
var doc = win.document;
|
||||
var image = doc.getElementById("image");
|
||||
|
||||
// We want to test that clicking on the image and then clicking on one of the
|
||||
// draggers doesn't make the draggers disappear.
|
||||
|
||||
// clean snapshot
|
||||
var before = snapshotWindow(win);
|
||||
|
||||
// click to get the draggers
|
||||
synthesizeMouse(image, 1, 1, {type: "mousedown"}, win);
|
||||
synthesizeMouse(image, 1, 1, {type: "mouseup"}, win);
|
||||
|
||||
// mouse over a dragger will change its color, so move the mouse away
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mousemove"}, win);
|
||||
|
||||
// snapshot with hopefully draggers
|
||||
var middle = snapshotWindow(win);
|
||||
|
||||
// clicking on the top left dragger shouldn't change anything
|
||||
synthesizeMouse(image, 1, 1, {type: "mousedown"}, win);
|
||||
synthesizeMouse(image, 1, 1, {type: "mouseup"}, win);
|
||||
|
||||
// mouse over a dragger will change its color, so move the mouse away
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mousemove"}, win);
|
||||
|
||||
// snapshot with hopefully draggers again
|
||||
var middle2 = snapshotWindow(win);
|
||||
|
||||
// click outside the image (but inside the document) to unselect it
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mousedown"}, win);
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mouseup"}, win);
|
||||
|
||||
// and then click outside the document so we don't draw a caret
|
||||
synthesizeMouse(document.documentElement, 1, 1, {type: "mousedown"}, window);
|
||||
synthesizeMouse(document.documentElement, 1, 1, {type: "mouseup"}, window);
|
||||
|
||||
// hopefully clean snapshot
|
||||
var end = snapshotWindow(win);
|
||||
|
||||
// before == end && middle == middle2 && before/end != middle/middle2
|
||||
checkSnapshots(before, end, true, "before and after should be the same")
|
||||
checkSnapshots(middle, middle2, true, "middle two should be the same");
|
||||
checkSnapshots(before, middle, false, "before and middle should not be the same");
|
||||
checkSnapshots(before, middle2, false, "before and middle2 should not be the same");
|
||||
checkSnapshots(middle, end, false, "middle and end should not be the same");
|
||||
checkSnapshots(middle2, end, false, "middle2 and end should not be the same");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -30,6 +30,7 @@ support-files =
|
||||
bug467672-4-ref.html
|
||||
bug467672-5.html
|
||||
bug467672-5-ref.html
|
||||
bug558663.html
|
||||
bug570378-arabic-1.html
|
||||
bug570378-arabic-1-ref.html
|
||||
bug570378-arabic-2.html
|
||||
|
@ -1,101 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=558663
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 558663</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=558663">Mozilla Bug 514127</a></p>
|
||||
|
||||
<!-- 20x20 of red -->
|
||||
<iframe id="iframe" src="data:text/html,<img id='image' border='0' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAG0lEQVR42mP8z0A%2BYKJA76jmUc2jmkc1U0EzACKcASfOgGoMAAAAAElFTkSuQmCC'>"></iframe>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 558663 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.addEventListener("load", runTest, false);
|
||||
|
||||
function checkSnapshots(s1, s2, shouldBeEqual, testName) {
|
||||
var res = compareSnapshots(s1, s2, shouldBeEqual);
|
||||
if (res[0]) {
|
||||
ok(true, testName + " snapshots compare correctly");
|
||||
} else {
|
||||
ok(false, testName + " snapshots compare incorrectly. snapshot 1: " +
|
||||
res[1] + " snapshot 2: " + res[2]);
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
document.getElementById("iframe").contentWindow.document.designMode = "on";
|
||||
|
||||
// The editor requires the event loop to spin after you turn on design mode
|
||||
// before it takes effect.
|
||||
setTimeout(continueTest, 100);
|
||||
}
|
||||
|
||||
function continueTest() {
|
||||
var win = document.getElementById("iframe").contentWindow;
|
||||
var doc = win.document;
|
||||
var image = doc.getElementById("image");
|
||||
|
||||
// We want to test that clicking on the image and then clicking on one of the
|
||||
// draggers doesn't make the draggers disappear.
|
||||
|
||||
// clean snapshot
|
||||
var before = snapshotWindow(win);
|
||||
|
||||
// click to get the draggers
|
||||
synthesizeMouse(image, 1, 1, {type: "mousedown"}, win);
|
||||
synthesizeMouse(image, 1, 1, {type: "mouseup"}, win);
|
||||
|
||||
// mouse over a dragger will change its color, so move the mouse away
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mousemove"}, win);
|
||||
|
||||
// snapshot with hopefully draggers
|
||||
var middle = snapshotWindow(win);
|
||||
|
||||
// clicking on the top left dragger shouldn't change anything
|
||||
synthesizeMouse(image, 1, 1, {type: "mousedown"}, win);
|
||||
synthesizeMouse(image, 1, 1, {type: "mouseup"}, win);
|
||||
|
||||
// mouse over a dragger will change its color, so move the mouse away
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mousemove"}, win);
|
||||
|
||||
// snapshot with hopefully draggers again
|
||||
var middle2 = snapshotWindow(win);
|
||||
|
||||
// click outside the image (but inside the document) to unselect it
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mousedown"}, win);
|
||||
synthesizeMouse(doc.documentElement, 50, 50, {type: "mouseup"}, win);
|
||||
|
||||
// and then click outside the document so we don't draw a caret
|
||||
synthesizeMouse(document.documentElement, 1, 1, {type: "mousedown"}, window);
|
||||
synthesizeMouse(document.documentElement, 1, 1, {type: "mouseup"}, window);
|
||||
|
||||
// hopefully clean snapshot
|
||||
var end = snapshotWindow(win);
|
||||
|
||||
// before == end && middle == middle2 && before/end != middle/middle2
|
||||
checkSnapshots(before, end, true, "before and after should be the same")
|
||||
checkSnapshots(middle, middle2, true, "middle two should be the same");
|
||||
checkSnapshots(before, middle, false, "before and middle should not be the same");
|
||||
checkSnapshots(before, middle2, false, "before and middle2 should not be the same");
|
||||
checkSnapshots(middle, end, false, "middle and end should not be the same");
|
||||
checkSnapshots(middle2, end, false, "middle2 and end should not be the same");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
<head>
|
||||
<title>Bug 558663 test</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
iframe {
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
</body>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// Selection caret's pref is checked only when PresShell is initialized. To turn
|
||||
// off the pref, we test bug 558663 in an iframe.
|
||||
SpecialPowers.pushPrefEnv({"set": [['selectioncaret.enabled', false]]}, function() {
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "bug558663.html";
|
||||
document.getElementById('container').appendChild(iframe);
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
|
63
layout/generic/crashtests/400190.html
Normal file
63
layout/generic/crashtests/400190.html
Normal file
@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
|
||||
body {
|
||||
position: fixed;
|
||||
font-family: monospace;
|
||||
-moz-column-width: 10px;
|
||||
border: 2px solid #aaa;
|
||||
}
|
||||
|
||||
#padded {
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
#x {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="padded"></div>
|
||||
|
||||
<div id="x">
|
||||
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
x
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
7
layout/generic/crashtests/898871-iframe.xhtml
Normal file
7
layout/generic/crashtests/898871-iframe.xhtml
Normal file
@ -0,0 +1,7 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<style id="element1">
|
||||
iframe { width:300px; height:300px; border:none; }
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
44
layout/generic/crashtests/898871.html
Normal file
44
layout/generic/crashtests/898871.html
Normal file
@ -0,0 +1,44 @@
|
||||
<html><script>
|
||||
function start() {
|
||||
o0=tmp = document.createElement('iframe');
|
||||
tmp.id = 'id1';
|
||||
document.getElementById('store_div').appendChild(tmp);
|
||||
o3=tmp = document.createElement('iframe');
|
||||
document.getElementById('store_div').appendChild(tmp);
|
||||
o5=tmp = document.createElement('iframe');
|
||||
tmp.src='898871.jpg';
|
||||
document.getElementById('store_div').appendChild(tmp);
|
||||
o7=tmp = document.createElement('iframe');
|
||||
tmp.src='898871-iframe.xhtml';
|
||||
document.getElementById('store_div').appendChild(tmp);
|
||||
window.setTimeout('startrly()', 20);
|
||||
}
|
||||
function startrly() {
|
||||
o17=document.getElementById('fuzz_div');
|
||||
o22=document.createElement('input');
|
||||
o43=o5.contentDocument;
|
||||
o44=o43.documentElement;
|
||||
o50=document.createElement('div');
|
||||
o60=o7.contentDocument.getElementById('element1');
|
||||
o3.contentWindow.onresize=cb_frameresize_35_1;
|
||||
o43.dir = 'rtl'
|
||||
o43.documentElement.appendChild(o22);
|
||||
o17.appendChild(o50);
|
||||
o50.appendChild(o60);
|
||||
o22.contentEditable=true;
|
||||
o164=document.body;
|
||||
o164.removeChild(o17);
|
||||
}
|
||||
function cb_frameresize_35_1() {
|
||||
o44.innerHTML=unescape('<noframes> </noframes><plainText> </u></u></big></plainText></bdo></fieldset>');
|
||||
o135=o43.createElement('style');
|
||||
o43.head.appendChild(o135);
|
||||
o135.contentEditable=true;
|
||||
o5.contentWindow.onresize=cb_frameresize_103_1;
|
||||
}
|
||||
function cb_frameresize_103_1() {
|
||||
o257=document.documentElement;
|
||||
o257.removeChild(o164);
|
||||
}
|
||||
window.setTimeout("start()",10);
|
||||
</script><body><div id="store_div"></div><div id="fuzz_div"></div></body></html>
|
BIN
layout/generic/crashtests/898871.jpg
Normal file
BIN
layout/generic/crashtests/898871.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -182,6 +182,7 @@ load 399407-1.xhtml
|
||||
load 399412-1.html
|
||||
load 399843-1.html
|
||||
load 400078-1.html
|
||||
load 400190.html
|
||||
load 400223-1.html
|
||||
load 400232-1.html
|
||||
load 400244-1.html
|
||||
@ -535,6 +536,7 @@ asserts-if(Android,0-4) asserts-if(!Android,1-4) load 876074-1.html # bug 876749
|
||||
load 885009-1.html
|
||||
load 893496-1.html
|
||||
load 893523.html
|
||||
asserts(0-3) load 898871.html # bug 479160
|
||||
test-pref(layout.css.sticky.enabled,true) load 914891.html
|
||||
test-pref(layout.css.sticky.enabled,true) load 915475.xhtml
|
||||
load 927558.html
|
||||
|
@ -23,11 +23,11 @@
|
||||
== percent-3.html percent-3-ref.html
|
||||
|
||||
# more serious tests, using SVG reference
|
||||
== border-circle-2.html border-circle-2-ref.xhtml
|
||||
fuzzy(64,75) == border-circle-2.html border-circle-2-ref.xhtml
|
||||
fails == curved-stripe-border.html curved-stripe-border-ref.svg # bug 459945
|
||||
|
||||
# Corners
|
||||
== corner-1.html corner-1-ref.svg # bottom corners different radius than top corners
|
||||
fuzzy(64,58) == corner-1.html corner-1-ref.svg # bottom corners different radius than top corners
|
||||
random == corner-2.html corner-2-ref.svg # right corners different radius than left corners; see bug 500804
|
||||
|
||||
# Test that radii too long are reduced
|
||||
@ -37,7 +37,7 @@ random == corner-2.html corner-2-ref.svg # right corners different radius than l
|
||||
fails == clipping-1.html clipping-1-ref.html # background color should completely fill box; bug 466572
|
||||
!= clipping-2.html about:blank # background color clipped to inner/outer border, can't get
|
||||
# great tests for this due to antialiasing problems described in bug 466572
|
||||
fuzzy-if(Android&&AndroidVersion<15,9,73) fuzzy-if(Android&&AndroidVersion>=15,9,200) == clipping-3.html clipping-3-ref.xhtml # edge of border-radius clips an underlying object's background
|
||||
fuzzy(64,75) == clipping-3.html clipping-3-ref.xhtml # edge of border-radius clips an underlying object's background
|
||||
|
||||
# Tests for clipping the contents of replaced elements and overflow!=visible
|
||||
!= clipping-4-ref.html clipping-4-notref.html
|
||||
@ -85,6 +85,6 @@ skip-if(B2G) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(A
|
||||
== iframe-1.html iframe-1-ref.html
|
||||
|
||||
# Test for antialiasing gaps between background and border
|
||||
skip-if(B2G) fails-if(winWidget) fuzzy-if(Android,1,5) == curved-border-background-nogap.html curved-border-background-nogap-ref.html
|
||||
skip-if(B2G) fails-if(d2d) fuzzy-if(Android,1,5) == curved-border-background-nogap.html curved-border-background-nogap-ref.html
|
||||
|
||||
== color-layer-1a.html color-layer-1-ref.html
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user