Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-11-03 14:22:46 +01:00
commit bd9cd9ac32
140 changed files with 5228 additions and 1403 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

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

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

View File

@ -7,6 +7,10 @@
<script>
"use strict";
if (W3CTest.runner) {
W3CTest.runner.requestLongerTimeout(2);
}
function testCollapse(range, point) {
selection.removeAllRanges();
var addedRange;

View File

@ -9,6 +9,10 @@
<script>
"use strict";
if (W3CTest.runner) {
W3CTest.runner.requestLongerTimeout(2);
}
// Also test a selection with no ranges
testRanges.unshift("[]");

View File

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

View File

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

View File

@ -402,6 +402,8 @@ parent:
ReplyKeyEvent(WidgetKeyboardEvent event);
DispatchAfterKeyboardEvent(WidgetKeyboardEvent event);
sync RequestNativeKeyBindings(WidgetKeyboardEvent event)
returns (MaybeNativeKeyBinding bindings);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,6 +35,7 @@ private:
void DecodePacket(mp4_demuxer::MP4Sample* aSample);
MediaDataDecoderCallback* mCallback;
const mp4_demuxer::AudioDecoderConfig& mConfig;
};
} // namespace mozilla

View File

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

View File

@ -45,6 +45,7 @@ private:
const uint32_t mAudioRate;
const uint32_t mAudioProfile;
nsTArray<uint8_t> mUserData;
bool mUseAdts;
MediaDataDecoderCallback* mReaderCallback;
android::MediaBuffer* mAudioBuffer;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -50,6 +50,7 @@ WEBIDL_FILES = [
'AutocompleteInfo.webidl',
'BarProp.webidl',
'BatteryManager.webidl',
'BeforeAfterKeyboardEvent.webidl',
'BeforeUnloadEvent.webidl',
'BiquadFilterNode.webidl',
'Blob.webidl',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

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

View File

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