mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team.
This commit is contained in:
commit
95668dd697
7
.lldbinit
Normal file
7
.lldbinit
Normal file
@ -0,0 +1,7 @@
|
||||
# .lldbinit file for debugging Mozilla
|
||||
|
||||
# Mozilla's use of UNIFIED_SOURCES to include multiple source files into a
|
||||
# single compiled file breaks lldb breakpoint setting. This works around that.
|
||||
# See http://lldb.llvm.org/troubleshooting.html for more info.
|
||||
settings set target.inline-breakpoint-strategy always
|
||||
|
3
CLOBBER
3
CLOBBER
@ -18,4 +18,5 @@
|
||||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||
#
|
||||
|
||||
More Windows WebIDL changes.
|
||||
Bug 942184 - Landing and subsequent backout of bug 941450 increased the
|
||||
possibility of random build bustage.
|
||||
|
@ -600,6 +600,7 @@ pref("javascript.options.mem.gc_decommit_threshold_mb", 1);
|
||||
|
||||
// Show/Hide scrollbars when active/inactive
|
||||
pref("ui.showHideScrollbars", 1);
|
||||
pref("ui.useOverlayScrollbars", 1);
|
||||
|
||||
// Enable the ProcessPriorityManager, and give processes with no visible
|
||||
// documents a 1s grace period before they're eligible to be marked as
|
||||
@ -820,8 +821,10 @@ pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket");
|
||||
|
||||
// enable Skia/GL (OpenGL-accelerated 2D drawing) for large enough 2d canvases,
|
||||
// falling back to Skia/software for smaller canvases
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
pref("gfx.canvas.azure.backends", "skia");
|
||||
pref("gfx.canvas.azure.accelerated", true);
|
||||
#endif
|
||||
|
||||
// Turn on dynamic cache size for Skia
|
||||
pref("gfx.canvas.skiagl.dynamic-cache", true);
|
||||
|
@ -284,6 +284,10 @@ textarea:active {
|
||||
background-color: rgba(141, 184, 216, 0.5);
|
||||
}
|
||||
|
||||
input[type=number]::-moz-number-spin-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
%ifdef MOZ_WIDGET_GONK
|
||||
/* This binding only provide key shortcuts that we can't use on devices */
|
||||
input,
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "32c72fb8d857627ed39e4e07e1a4efaa1d3caace",
|
||||
"revision": "5cc15d1e291050f4e46c91b87a1af1353d1c5e46",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -767,6 +767,8 @@ var gPluginHandler = {
|
||||
if (aNewState != "block" && !pluginFound) {
|
||||
browser.reload();
|
||||
}
|
||||
|
||||
this._setPluginNotificationIcon(browser);
|
||||
},
|
||||
|
||||
_showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aPlugin, aShowNow) {
|
||||
|
@ -104,6 +104,7 @@ skip-if = toolkit == "gtk2" || toolkit == "gtk3" # browser_CTP_context_menu.js
|
||||
run-if = crashreporter
|
||||
[browser_CTP_data_urls.js]
|
||||
[browser_CTP_drag_drop.js]
|
||||
[browser_CTP_hideBar.js]
|
||||
[browser_CTP_nonplugins.js]
|
||||
[browser_CTP_resize.js]
|
||||
[browser_URLBarSetURI.js]
|
||||
|
98
browser/base/content/test/general/browser_CTP_hideBar.js
Normal file
98
browser/base/content/test/general/browser_CTP_hideBar.js
Normal file
@ -0,0 +1,98 @@
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
const gTestRoot = rootDir;
|
||||
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||
|
||||
var gTestBrowser = null;
|
||||
var gNextTest = null;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(function() {
|
||||
clearAllPluginPermissions();
|
||||
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||
});
|
||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||
|
||||
var newTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = newTab;
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
||||
|
||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
||||
|
||||
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_small.html");
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
||||
gBrowser.removeCurrentTab();
|
||||
window.focus();
|
||||
finish();
|
||||
}
|
||||
|
||||
function pageLoad() {
|
||||
// The plugin events are async dispatched and can come after the load event
|
||||
// This just allows the events to fire before we then go on to test the states
|
||||
executeSoon(gNextTest);
|
||||
}
|
||||
|
||||
function prepareTest(nextTest, url) {
|
||||
gNextTest = nextTest;
|
||||
gTestBrowser.contentWindow.location = url;
|
||||
}
|
||||
|
||||
// Due to layout being async, "PluginBindAttached" may trigger later.
|
||||
// This wraps a function to force a layout flush, thus triggering it,
|
||||
// and schedules the function execution so they're definitely executed
|
||||
// afterwards.
|
||||
function runAfterPluginBindingAttached(func) {
|
||||
return function() {
|
||||
let doc = gTestBrowser.contentDocument;
|
||||
let elems = doc.getElementsByTagName('embed');
|
||||
if (elems.length < 1) {
|
||||
elems = doc.getElementsByTagName('object');
|
||||
}
|
||||
elems[0].clientTop;
|
||||
executeSoon(func);
|
||||
};
|
||||
}
|
||||
|
||||
// Test that the notification bar is getting dismissed when directly activating plugins
|
||||
// via the doorhanger.
|
||||
|
||||
function test1() {
|
||||
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
|
||||
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") !== null,
|
||||
test2,
|
||||
"Test 1, expected a notification bar for hidden plugins");
|
||||
}
|
||||
|
||||
function test2() {
|
||||
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||
ok(notification, "Test 2, Should have a click-to-play notification");
|
||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
||||
ok(plugin, "Test 2, Found plugin in page");
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
|
||||
"Test 2, Plugin should be click-to-play");
|
||||
|
||||
// simulate "always allow"
|
||||
notification.reshow();
|
||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||
|
||||
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
|
||||
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
|
||||
test3,
|
||||
"Test 2, expected the notification bar for hidden plugins to get dismissed");
|
||||
}
|
||||
|
||||
function test3() {
|
||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
||||
ok(plugin, "Test 3, Found plugin in page");
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
waitForCondition(() => objLoadingContent.activated, finishTest,
|
||||
"Test 3, Waited too long for plugin to activate");
|
||||
}
|
@ -860,7 +860,7 @@ function test26() {
|
||||
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
|
||||
prepareTest(test27, gTestRoot + "plugin_small.html");
|
||||
},
|
||||
"Test 26, expected the plugin notification icon to be highlighted");
|
||||
"Test 26, expected to have a plugin notification bar");
|
||||
}
|
||||
|
||||
function test27() {
|
||||
@ -871,5 +871,5 @@ function test27() {
|
||||
|
||||
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
|
||||
finishTest,
|
||||
"Test 27, expected the plugin notification icon to not be highlighted");
|
||||
"Test 27, expected to not have a plugin notification bar");
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#include "windows.h"
|
||||
#include "shellapi.h"
|
||||
@ -53,6 +54,8 @@
|
||||
|
||||
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
|
||||
|
||||
using mozilla::IsWin8OrLater;
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsWindowsShellService, nsIWindowsShellService, nsIShellService)
|
||||
|
||||
static nsresult
|
||||
@ -314,16 +317,6 @@ nsWindowsShellService::ShortcutMaintenance()
|
||||
return LaunchHelper(appHelperPath);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsWin8OrLater()
|
||||
{
|
||||
OSVERSIONINFOW osInfo;
|
||||
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
|
||||
GetVersionExW(&osInfo);
|
||||
return osInfo.dwMajorVersion > 6 ||
|
||||
(osInfo.dwMajorVersion >= 6 && osInfo.dwMinorVersion >= 2);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsAARDefaultHTTP(IApplicationAssociationRegistration* pAAR,
|
||||
bool* aIsDefaultBrowser)
|
||||
|
@ -76,6 +76,15 @@ GDBINIT_FILES := $(topsrcdir)/.gdbinit
|
||||
GDBINIT_DEST = $(FINAL_TARGET)
|
||||
INSTALL_TARGETS += GDBINIT
|
||||
|
||||
# Put a useful .lldbinit in the bin directory, to be picked up automatically
|
||||
# by LLDB when we debug executables using that directory as the current working
|
||||
# directory.
|
||||
# NOTE: Keep .lldbinit in the topsrcdir for people who run LLDB from the
|
||||
# topsrcdir rather than the bin directory.
|
||||
LLDBINIT_FILES := $(topsrcdir)/.lldbinit
|
||||
LLDBINIT_DEST = $(FINAL_TARGET)
|
||||
INSTALL_TARGETS += LLDBINIT
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# we install to _leaktest/
|
||||
|
@ -292,7 +292,7 @@ case "$target" in
|
||||
# The build tools got moved around to different directories in
|
||||
# SDK Tools r22. Try to locate them.
|
||||
android_build_tools=""
|
||||
for suffix in android-4.3 18.1.0 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
for suffix in android-4.3 19.0.0 18.1.0 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
tools_directory="$android_sdk/../../build-tools/$suffix"
|
||||
if test -d "$tools_directory" ; then
|
||||
android_build_tools="$tools_directory"
|
||||
|
@ -471,24 +471,35 @@ class Automation(object):
|
||||
os.unlink(pwfilePath)
|
||||
return 0
|
||||
|
||||
def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False):
|
||||
def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False, dmdPath=None):
|
||||
if xrePath == None:
|
||||
xrePath = self.DIST_BIN
|
||||
if env == None:
|
||||
env = dict(os.environ)
|
||||
|
||||
ldLibraryPath = os.path.abspath(os.path.join(SCRIPT_DIR, xrePath))
|
||||
dmdLibrary = None
|
||||
preloadEnvVar = None
|
||||
if self.UNIXISH or self.IS_MAC:
|
||||
envVar = "LD_LIBRARY_PATH"
|
||||
preloadEnvVar = "LD_PRELOAD"
|
||||
if self.IS_MAC:
|
||||
envVar = "DYLD_LIBRARY_PATH"
|
||||
dmdLibrary = "libdmd.dylib"
|
||||
else: # unixish
|
||||
env['MOZILLA_FIVE_HOME'] = xrePath
|
||||
dmdLibrary = "libdmd.so"
|
||||
if envVar in env:
|
||||
ldLibraryPath = ldLibraryPath + ":" + env[envVar]
|
||||
env[envVar] = ldLibraryPath
|
||||
elif self.IS_WIN32:
|
||||
env["PATH"] = env["PATH"] + ";" + str(ldLibraryPath)
|
||||
dmdLibrary = "dmd.dll"
|
||||
preloadEnvVar = "MOZ_REPLACE_MALLOC_LIB"
|
||||
|
||||
if dmdPath and dmdLibrary and preloadEnvVar:
|
||||
env['DMD'] = '1'
|
||||
env[preloadEnvVar] = os.path.join(dmdPath, dmdLibrary)
|
||||
|
||||
if crashreporter and not debugger:
|
||||
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
|
||||
|
@ -400,7 +400,7 @@ def systemMemory():
|
||||
"""
|
||||
return int(os.popen("free").readlines()[1].split()[1])
|
||||
|
||||
def environment(xrePath, env=None, crashreporter=True, debugger=False):
|
||||
def environment(xrePath, env=None, crashreporter=True, debugger=False, dmdPath=None):
|
||||
"""populate OS environment variables for mochitest"""
|
||||
|
||||
env = os.environ.copy() if env is None else env
|
||||
@ -410,19 +410,31 @@ def environment(xrePath, env=None, crashreporter=True, debugger=False):
|
||||
ldLibraryPath = xrePath
|
||||
|
||||
envVar = None
|
||||
dmdLibrary = None
|
||||
preloadEnvVar = None
|
||||
if mozinfo.isUnix:
|
||||
envVar = "LD_LIBRARY_PATH"
|
||||
env['MOZILLA_FIVE_HOME'] = xrePath
|
||||
dmdLibrary = "libdmd.so"
|
||||
preloadEnvVar = "LD_PRELOAD"
|
||||
elif mozinfo.isMac:
|
||||
envVar = "DYLD_LIBRARY_PATH"
|
||||
dmdLibrary = "libdmd.dylib"
|
||||
preloadEnvVar = "DYLD_INSERT_LIBRARIES"
|
||||
elif mozinfo.isWin:
|
||||
envVar = "PATH"
|
||||
dmdLibrary = "dmd.dll"
|
||||
preloadEnvVar = "MOZ_REPLACE_MALLOC_LIB"
|
||||
if envVar:
|
||||
envValue = ((env.get(envVar), str(ldLibraryPath))
|
||||
if mozinfo.isWin
|
||||
else (ldLibraryPath, env.get(envVar)))
|
||||
else (ldLibraryPath, dmdPath, env.get(envVar)))
|
||||
env[envVar] = os.path.pathsep.join([path for path in envValue if path])
|
||||
|
||||
if dmdPath and dmdLibrary and preloadEnvVar:
|
||||
env['DMD'] = '1'
|
||||
env[preloadEnvVar] = os.path.join(dmdPath, dmdLibrary)
|
||||
|
||||
# crashreporter
|
||||
env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
|
||||
env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
|
||||
|
@ -48,12 +48,16 @@ class RemoteAutomation(Automation):
|
||||
self._remoteLog = logfile
|
||||
|
||||
# Set up what we need for the remote environment
|
||||
def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False):
|
||||
def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False, dmdPath=None):
|
||||
# Because we are running remote, we don't want to mimic the local env
|
||||
# so no copying of os.environ
|
||||
if env is None:
|
||||
env = {}
|
||||
|
||||
if dmdPath:
|
||||
env['DMD'] = '1'
|
||||
env['MOZ_REPLACE_MALLOC_LIB'] = os.path.join(dmdPath, 'libdmd.so')
|
||||
|
||||
# Except for the mochitest results table hiding option, which isn't
|
||||
# passed to runtestsremote.py as an actual option, but through the
|
||||
# MOZ_HIDE_RESULTS_TABLE environment variable.
|
||||
|
@ -8,7 +8,7 @@ EXPORTS.mozilla.chrome += [
|
||||
'RegistryMessageUtils.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsChromeProtocolHandler.cpp',
|
||||
'nsChromeRegistry.cpp',
|
||||
'nsChromeRegistryChrome.cpp',
|
||||
|
@ -1895,6 +1895,12 @@ public:
|
||||
*/
|
||||
static bool IsUserFocusIgnored(nsINode* aNode);
|
||||
|
||||
/**
|
||||
* Returns if aContent has the 'scrollgrab' property.
|
||||
* aContent may be null (in this case false is returned).
|
||||
*/
|
||||
static bool HasScrollgrab(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Flushes the layout tree (recursively)
|
||||
*
|
||||
|
@ -5919,6 +5919,13 @@ nsContentUtils::IsUserFocusIgnored(nsINode* aNode)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::HasScrollgrab(nsIContent* aContent)
|
||||
{
|
||||
nsGenericHTMLElement* element = nsGenericHTMLElement::FromContentOrNull(aContent);
|
||||
return element && element->Scrollgrab();
|
||||
}
|
||||
|
||||
void
|
||||
nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow)
|
||||
{
|
||||
|
@ -1826,6 +1826,7 @@ GK_ATOM(lineFrame, "LineFrame")
|
||||
GK_ATOM(listControlFrame,"ListControlFrame")
|
||||
GK_ATOM(menuFrame,"MenuFrame")
|
||||
GK_ATOM(menuPopupFrame,"MenuPopupFrame")
|
||||
GK_ATOM(numberControlFrame, "NumberControlFrame")
|
||||
GK_ATOM(objectFrame, "ObjectFrame")
|
||||
GK_ATOM(pageFrame, "PageFrame")
|
||||
GK_ATOM(pageBreakFrame, "PageBreakFrame")
|
||||
|
@ -154,6 +154,9 @@ WebGLContext::DepthMask(WebGLboolean b)
|
||||
void
|
||||
WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
const size_t buffersLength = buffers.Length();
|
||||
|
||||
if (buffersLength == 0) {
|
||||
|
@ -20,7 +20,14 @@ function IsD2DEnabled() {
|
||||
}
|
||||
|
||||
function IsLinux() {
|
||||
return navigator.platform.indexOf("Linux") == 0 &&
|
||||
var os = "";
|
||||
|
||||
try {
|
||||
os = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(SpecialPowers.Ci.nsIXULRuntime).OS;
|
||||
} catch (e) {}
|
||||
|
||||
return os.indexOf("Linux") == 0 &&
|
||||
navigator.appVersion.indexOf("Android") == -1;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ support-files =
|
||||
[test_bug493251.html]
|
||||
[test_bug502818.html]
|
||||
[test_bug508479.html]
|
||||
[test_bug822898.html]
|
||||
[test_bug517851.html]
|
||||
[test_bug534833.html]
|
||||
[test_bug545268.html]
|
||||
|
@ -298,6 +298,10 @@ const kEventConstructors = {
|
||||
return new PageTransitionEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
PointerEvent: { create: function (aName, aProps) {
|
||||
return new PointerEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
PopStateEvent: { create: function (aName, aProps) {
|
||||
return new PopStateEvent(aName, aProps);
|
||||
},
|
||||
|
359
content/events/test/test_bug822898.html
Normal file
359
content/events/test/test_bug822898.html
Normal file
@ -0,0 +1,359 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=822898
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 822898</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=822898">Mozilla Bug 822898</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe id="subFrame"></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.8">
|
||||
|
||||
/** Test for Bug 822898 - Pointer* Events **/
|
||||
|
||||
let tests = [], testTarget, parent, iframeBody, gOnPointerPropHandled;
|
||||
|
||||
function nextTest() {
|
||||
if (tests.length)
|
||||
SimpleTest.executeSoon(tests.shift());
|
||||
}
|
||||
|
||||
function random() {
|
||||
return Math.floor(Math.random() * 100);
|
||||
}
|
||||
|
||||
function createTestEventValue(name) {
|
||||
|
||||
let detail = random();
|
||||
let screenX = random();
|
||||
let screenY = random();
|
||||
let clientX = random();
|
||||
let clientY = random();
|
||||
let ctrlKey = random() % 2 ? true : false;
|
||||
let altKey = random() % 2 ? true : false;
|
||||
let shiftKey = random() % 2 ? true : false;
|
||||
let metaKey = random() % 2 ? true : false;
|
||||
let button = random();
|
||||
let pointerId = random();
|
||||
|
||||
return function() {
|
||||
let event = new PointerEvent("pointerdown", {
|
||||
bubbles: true, cancelable: true, view: window,
|
||||
detail: detail, screenX: screenX, screenY: screenY, clientX: clientX, clientY: clientY,
|
||||
ctrlKey: ctrlKey, altKey: altKey, shiftKey: shiftKey, metaKey: metaKey,
|
||||
button: button, relatedTarget: null, pointerId: pointerId
|
||||
});
|
||||
|
||||
|
||||
function check(ev) {
|
||||
is(ev.detail, detail, "Correct detail");
|
||||
is(ev.screenX, screenX, "Correct screenX");
|
||||
is(ev.screenY, screenY, "Correct screenY");
|
||||
is(ev.clientX, clientX, "Correct clientX");
|
||||
is(ev.clientY, clientY, "Correct clientY");
|
||||
is(ev.ctrlKey, ctrlKey, "Correct ctrlKey");
|
||||
is(ev.altKey, altKey, "Correct altKey");
|
||||
is(ev.shiftKey, shiftKey, "Correct shiftKey");
|
||||
is(ev.metaKey, metaKey, "Correct metaKey");
|
||||
is(ev.button, button, "Correct buttonArg");
|
||||
is(ev.pointerId, pointerId, "Correct pointerId");
|
||||
}
|
||||
|
||||
for each (let target in [document, window, testTarget, parent])
|
||||
target.addEventListener(name, check, false);
|
||||
|
||||
testTarget.dispatchEvent(event);
|
||||
|
||||
for each (let target in [document, window, testTarget, parent])
|
||||
target.removeEventListener(name, check, false);
|
||||
|
||||
|
||||
nextTest();
|
||||
}
|
||||
}
|
||||
|
||||
function getDefaultArgEvent(eventname) {
|
||||
return new PointerEvent(eventname, {
|
||||
bubbles: true, cancelable: true, view: window,
|
||||
detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
|
||||
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
||||
button: 0, relatedTarget: null, pointerId: 0
|
||||
});
|
||||
}
|
||||
|
||||
function testDefaultArg() {
|
||||
let event = getDefaultArgEvent("pointerdown");
|
||||
|
||||
testTarget.addEventListener("pointerdown", function(ev) {
|
||||
testTarget.removeEventListener("pointerdown", arguments.callee, false);
|
||||
is(ev.pointerId, 0, "Correct default pointerId");
|
||||
}, false);
|
||||
testTarget.dispatchEvent(event);
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function testStopPropagation() {
|
||||
let event = getDefaultArgEvent("pointerdown");
|
||||
|
||||
let unreachableListener = function () {
|
||||
ok(false, "Event should have been stopped");
|
||||
}
|
||||
|
||||
// Capturing phase
|
||||
let captured = false;
|
||||
parent.addEventListener("pointerdown", function() {
|
||||
parent.removeEventListener("pointerdown", arguments.callee, true);
|
||||
captured = true;
|
||||
}, true); // Capturing phase
|
||||
|
||||
// Bubbling phase
|
||||
parent.addEventListener("pointerdown", unreachableListener, false);
|
||||
|
||||
testTarget.addEventListener("pointerdown", function(ev) {
|
||||
testTarget.removeEventListener("pointerdown", arguments.callee, false);
|
||||
is(captured, true, "Event should have been captured");
|
||||
ev.stopPropagation();
|
||||
}, false);
|
||||
|
||||
testTarget.dispatchEvent(event);
|
||||
|
||||
parent.removeEventListener("pointerdown", unreachableListener, false);
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function testPreventDefault() {
|
||||
let event = getDefaultArgEvent("pointerdown");
|
||||
|
||||
parent.addEventListener("pointerdown", function(ev) {
|
||||
parent.removeEventListener("pointerdown", arguments.callee, false);
|
||||
is(ev.defaultPrevented, true, "preventDefault can be called");
|
||||
nextTest();
|
||||
}, false);
|
||||
|
||||
testTarget.addEventListener("pointerdown", function(ev) {
|
||||
testTarget.removeEventListener("pointerdown", arguments.callee, false);
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
|
||||
testTarget.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function testBlockPreventDefault() {
|
||||
let event = new PointerEvent("pointerdown", {
|
||||
bubbles: true, cancelable: false, view: window,
|
||||
detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
|
||||
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
||||
button: 0, relatedTarget: null, pointerId: 0, pointerType: "pen"
|
||||
});
|
||||
|
||||
parent.addEventListener("pointerdown", function(ev) {
|
||||
parent.removeEventListener("pointerdown", arguments.callee, false);
|
||||
is(ev.defaultPrevented, false, "aCancelableArg works");
|
||||
nextTest();
|
||||
}, false);
|
||||
|
||||
testTarget.addEventListener("pointerdown", function(ev) {
|
||||
testTarget.removeEventListener("pointerdown", arguments.callee, false);
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
|
||||
testTarget.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function testBlockBubbling() {
|
||||
let unreachableListener = function () {
|
||||
ok(false, "aCanBubble doesn't work");
|
||||
}
|
||||
|
||||
let event = new PointerEvent("pointerdown", {
|
||||
bubbles: false, cancelable: true, view: window,
|
||||
detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
|
||||
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
||||
button: 0, relatedTarget: null, pointerId: 0
|
||||
});
|
||||
|
||||
parent.addEventListener("pointerdown", unreachableListener, false);
|
||||
testTarget.dispatchEvent(event);
|
||||
parent.removeEventListener("pointerdown", unreachableListener, false);
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function testOnPointerProperty()
|
||||
{
|
||||
iframeBody.onpointerdown = function (e) { gOnPointerPropHandled["pointerdown"] = true; }
|
||||
iframeBody.onpointerup = function (e) { gOnPointerPropHandled["pointerup"] = true; }
|
||||
iframeBody.onpointermove = function (e) { gOnPointerPropHandled["pointermove"] = true; }
|
||||
iframeBody.onpointerout = function (e) { gOnPointerPropHandled["pointerout"] = true; }
|
||||
iframeBody.onpointerover = function (e) { gOnPointerPropHandled["pointerover"] = true; }
|
||||
iframeBody.onpointerenter = function (e) { gOnPointerPropHandled["pointerenter"] = true; }
|
||||
iframeBody.onpointerleave = function (e) { gOnPointerPropHandled["pointerleave"] = true; }
|
||||
|
||||
iframeBody.dispatchEvent(getDefaultArgEvent("pointerdown"));
|
||||
is(gOnPointerPropHandled['pointerdown'], true, "pointerdown property is performed");
|
||||
|
||||
iframeBody.dispatchEvent(getDefaultArgEvent("pointerup"));
|
||||
is(gOnPointerPropHandled['pointerup'], true, "pointerup property is performed");
|
||||
|
||||
iframeBody.dispatchEvent(getDefaultArgEvent("pointermove"));
|
||||
is(gOnPointerPropHandled['pointermove'], true, "pointermove property is performed");
|
||||
|
||||
iframeBody.dispatchEvent(getDefaultArgEvent("pointerout"));
|
||||
is(gOnPointerPropHandled['pointerout'], true, "pointerout property is performed");
|
||||
|
||||
iframeBody.dispatchEvent(getDefaultArgEvent("pointerover"));
|
||||
is(gOnPointerPropHandled['pointerover'], true, "pointerover property is performed");
|
||||
|
||||
iframeBody.dispatchEvent(getDefaultArgEvent("pointerenter"));
|
||||
is(gOnPointerPropHandled['pointerenter'], true, "pointerenter property is performed");
|
||||
|
||||
iframeBody.dispatchEvent(getDefaultArgEvent("pointerleave"));
|
||||
is(gOnPointerPropHandled['pointerleave'], true, "pointerleave property is performed");
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function testPointerEventCTORS()
|
||||
{
|
||||
// TODO: This should go to test_eventctors.html, when PointerEvents enabled by default
|
||||
var receivedEvent;
|
||||
iframeBody.addEventListener("hello", function(e) { receivedEvent = e; }, true);
|
||||
|
||||
var e;
|
||||
var ex = false;
|
||||
|
||||
try {
|
||||
e = new PointerEvent();
|
||||
} catch(exp) {
|
||||
ex = true;
|
||||
}
|
||||
ok(ex, "PointerEvent: First parameter is required!");
|
||||
ex = false;
|
||||
|
||||
e = new PointerEvent("hello");
|
||||
ok(e.type, "hello", "PointerEvent: Wrong event type!");
|
||||
ok(!e.isTrusted, "PointerEvent: Event shouldn't be trusted!");
|
||||
ok(!e.bubbles, "PointerEvent: Event shouldn't bubble!");
|
||||
ok(!e.cancelable, "PointerEvent: Event shouldn't be cancelable!");
|
||||
iframeBody.dispatchEvent(e);
|
||||
is(receivedEvent, e, "PointerEvent: Wrong event!");
|
||||
|
||||
var PointerEventProps =
|
||||
[ { screenX: 0 },
|
||||
{ screenY: 0 },
|
||||
{ clientX: 0 },
|
||||
{ clientY: 0 },
|
||||
{ ctrlKey: false },
|
||||
{ shiftKey: false },
|
||||
{ altKey: false },
|
||||
{ metaKey: false },
|
||||
{ button: 0 },
|
||||
{ buttons: 0 },
|
||||
{ relatedTarget: null },
|
||||
{ pointerId: 0 },
|
||||
{ pointerType: "" }
|
||||
];
|
||||
|
||||
var testPointerProps =
|
||||
[
|
||||
{ screenX: 1 },
|
||||
{ screenY: 2 },
|
||||
{ clientX: 3 },
|
||||
{ clientY: 4 },
|
||||
{ ctrlKey: true },
|
||||
{ shiftKey: true },
|
||||
{ altKey: true },
|
||||
{ metaKey: true },
|
||||
{ button: 5 },
|
||||
{ buttons: 6 },
|
||||
{ relatedTarget: window },
|
||||
{ pointerId: 5 },
|
||||
{ pointerType: "mouse" }
|
||||
];
|
||||
|
||||
var defaultPointerEventValues = {};
|
||||
for (var i = 0; i < PointerEventProps.length; ++i) {
|
||||
for (prop in PointerEventProps[i]) {
|
||||
ok(prop in e, "PointerEvent: PointerEvent doesn't have property " + prop + "!");
|
||||
defaultPointerEventValues[prop] = PointerEventProps[i][prop];
|
||||
}
|
||||
}
|
||||
|
||||
while (testPointerProps.length) {
|
||||
var p = testPointerProps.shift();
|
||||
e = new PointerEvent("foo", p);
|
||||
for (var def in defaultPointerEventValues) {
|
||||
if (!(def in p)) {
|
||||
is(e[def], defaultPointerEventValues[def],
|
||||
"PointerEvent: Wrong default value for " + def + "!");
|
||||
} else {
|
||||
is(e[def], p[def], "PointerEvent: Wrong event init value for " + def + "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
SpecialPowers.setBoolPref("dom.w3c_pointer_events.enabled", true); // Enable Pointer Events
|
||||
testTarget = document.getElementById("testTarget");
|
||||
parent = testTarget.parentNode;
|
||||
gOnPointerPropHandled = new Array;
|
||||
iframeBody = document.getElementById("subFrame").contentWindow.document.body;
|
||||
|
||||
tests.push(createTestEventValue("pointerdown"));
|
||||
tests.push(createTestEventValue("pointermove"));
|
||||
tests.push(createTestEventValue("pointerup"));
|
||||
|
||||
tests.push(testDefaultArg);
|
||||
tests.push(testStopPropagation);
|
||||
|
||||
tests.push(testPreventDefault);
|
||||
tests.push(testBlockPreventDefault);
|
||||
|
||||
tests.push(testBlockBubbling);
|
||||
tests.push(testOnPointerProperty());
|
||||
tests.push(testPointerEventCTORS());
|
||||
|
||||
tests.push(function() {
|
||||
clearPrefs();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function initPrefs()
|
||||
{
|
||||
SpecialPowers.setBoolPref("dom.w3c_pointer_events.enabled", true); // Enable Pointer Events
|
||||
}
|
||||
|
||||
function clearPrefs()
|
||||
{
|
||||
SpecialPowers.clearUserPref("dom.w3c_pointer_events.enabled"); // Disable Pointer Events
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
initPrefs();
|
||||
SimpleTest.executeSoon(runTests);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
<div id="parent">
|
||||
<span id="testTarget" style="border: 1px solid black;">testTarget</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -250,8 +250,6 @@ nsIFormControl::IsSingleLineTextControl(bool aExcludePassword, uint32_t aType)
|
||||
aType == NS_FORM_INPUT_SEARCH ||
|
||||
aType == NS_FORM_INPUT_TEL ||
|
||||
aType == NS_FORM_INPUT_URL ||
|
||||
// TODO: this is temporary until bug 635240 is fixed.
|
||||
aType == NS_FORM_INPUT_NUMBER ||
|
||||
// TODO: those are temporary until bug 773205 is fixed.
|
||||
aType == NS_FORM_INPUT_DATE ||
|
||||
aType == NS_FORM_INPUT_TIME ||
|
||||
|
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<!-- In this case we're using reftest-wait to make sure the test doesn't
|
||||
get snapshotted before it's been focused. We're not testing
|
||||
invalidation so we don't need to listen for MozReftestInvalidate.
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body onload="document.getElementsByTagName('input')[0].focus();">
|
||||
<input onfocus="document.documentElement.removeAttribute('class');"
|
||||
style="-moz-appearance: none;">
|
||||
<!-- div to cover spin box area for type=number to type=text comparison -->
|
||||
<div style="display:block; position:absolute; background-color:black; width:200px; height:100px; top:0px; left:100px;">
|
||||
</body>
|
||||
</html>
|
||||
|
26
content/html/content/reftests/autofocus/input-number.html
Normal file
26
content/html/content/reftests/autofocus/input-number.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<!-- In this case we're using reftest-wait to make sure the test doesn't
|
||||
get snapshotted before it's been focused. We're not testing
|
||||
invalidation so we don't need to listen for MozReftestInvalidate.
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
|
||||
function focusHandler() {
|
||||
setTimeout(function() {
|
||||
document.documentElement.removeAttribute('class');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<input type="number" autofocus onfocus="focusHandler();"
|
||||
style="-moz-appearance: none;">
|
||||
<!-- div to cover spin box area for type=number to type=text comparison -->
|
||||
<div style="display:block; position:absolute; background-color:black; width:200px; height:100px; top:0px; left:100px;">
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,5 +1,6 @@
|
||||
needs-focus == input-load.html input-ref.html
|
||||
needs-focus == input-create.html input-ref.html
|
||||
fails-if(Android) needs-focus == input-number.html input-number-ref.html # bug 940764
|
||||
needs-focus == button-load.html button-ref.html
|
||||
needs-focus == button-create.html button-ref.html
|
||||
needs-focus == textarea-load.html textarea-ref.html
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nsIControllers.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsNumberControlFrame.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsIComponentManager.h"
|
||||
@ -2142,6 +2143,14 @@ HTMLInputElement::StepUp(int32_t n, uint8_t optional_argc)
|
||||
return ApplyStep(optional_argc ? n : 1);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::FlushFrames()
|
||||
{
|
||||
if (GetCurrentDoc()) {
|
||||
GetCurrentDoc()->FlushPendingNotifications(Flush_Frames);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::MozGetFileNameArray(nsTArray< nsString >& aArray)
|
||||
{
|
||||
@ -2233,7 +2242,7 @@ HTMLInputElement::MozSetFileNameArray(const PRUnichar** aFileNames, uint32_t aLe
|
||||
bool
|
||||
HTMLInputElement::MozIsTextField(bool aExcludePassword)
|
||||
{
|
||||
// TODO: temporary until bug 635240 and 773205 are fixed.
|
||||
// TODO: temporary until bug 773205 is fixed.
|
||||
if (IsExperimentalMobileType(mType)) {
|
||||
return false;
|
||||
}
|
||||
@ -2687,6 +2696,14 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue,
|
||||
SetValueChanged(true);
|
||||
}
|
||||
OnValueChanged(!mParserCreating);
|
||||
|
||||
if (mType == NS_FORM_INPUT_NUMBER) {
|
||||
nsNumberControlFrame* numberControlFrame =
|
||||
do_QueryFrame(GetPrimaryFrame());
|
||||
if (numberControlFrame) {
|
||||
numberControlFrame->UpdateForValueChange(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent's SetAttr for color input so its control frame is notified
|
||||
@ -2952,9 +2969,41 @@ HTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify)
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::Blur(ErrorResult& aError)
|
||||
{
|
||||
if (mType == NS_FORM_INPUT_NUMBER) {
|
||||
// Blur our anonymous text control, if we have one. (DOM 'change' event
|
||||
// firing and other things depend on this.)
|
||||
nsNumberControlFrame* numberControlFrame =
|
||||
do_QueryFrame(GetPrimaryFrame());
|
||||
if (numberControlFrame) {
|
||||
HTMLInputElement* textControl = numberControlFrame->GetAnonTextControl();
|
||||
if (textControl) {
|
||||
textControl->Blur(aError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
nsGenericHTMLElement::Blur(aError);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::Focus(ErrorResult& aError)
|
||||
{
|
||||
if (mType == NS_FORM_INPUT_NUMBER) {
|
||||
// Focus our anonymous text control, if we have one.
|
||||
nsNumberControlFrame* numberControlFrame =
|
||||
do_QueryFrame(GetPrimaryFrame());
|
||||
if (numberControlFrame) {
|
||||
HTMLInputElement* textControl = numberControlFrame->GetAnonTextControl();
|
||||
if (textControl) {
|
||||
textControl->Focus(aError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mType != NS_FORM_INPUT_FILE) {
|
||||
nsGenericHTMLElement::Focus(aError);
|
||||
return;
|
||||
@ -3225,7 +3274,45 @@ HTMLInputElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
||||
nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
||||
|
||||
// We do this after calling the base class' PreHandleEvent so that
|
||||
// nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
|
||||
if (mType == NS_FORM_INPUT_NUMBER &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted &&
|
||||
aVisitor.mEvent->originalTarget != this) {
|
||||
// <input type=number> has an anonymous <input type=text> descendant. If
|
||||
// 'input' or 'change' events are fired at that text control then we need
|
||||
// to do some special handling here.
|
||||
HTMLInputElement* textControl = nullptr;
|
||||
nsNumberControlFrame* numberControlFrame =
|
||||
do_QueryFrame(GetPrimaryFrame());
|
||||
if (numberControlFrame) {
|
||||
textControl = numberControlFrame->GetAnonTextControl();
|
||||
}
|
||||
if (textControl && aVisitor.mEvent->originalTarget == textControl) {
|
||||
if (aVisitor.mEvent->message == NS_FORM_INPUT) {
|
||||
// Propogate the anon text control's new value to our HTMLInputElement:
|
||||
numberControlFrame->HandlingInputEvent(true);
|
||||
nsAutoString value;
|
||||
textControl->GetValue(value);
|
||||
SetValueInternal(value, false, true);
|
||||
numberControlFrame->HandlingInputEvent(false);
|
||||
}
|
||||
else if (aVisitor.mEvent->message == NS_FORM_CHANGE) {
|
||||
// We cancel the DOM 'change' event that is fired for any change to our
|
||||
// anonymous text control since we fire our own 'change' events and
|
||||
// content shouldn't be seeing two 'change' events. Besides that we
|
||||
// (as a number) control have tighter restrictions on when our internal
|
||||
// value changes than our anon text control does, so in some cases
|
||||
// (if our text control's value doesn't parse as a number) we don't
|
||||
// want to fire a 'change' event at all.
|
||||
aVisitor.mCanHandle = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
@ -3421,7 +3508,8 @@ HTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
||||
// the click event handling, and allow cancellation of DOMActivate to cancel
|
||||
// the click.
|
||||
if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault &&
|
||||
!IsSingleLineTextControl(true)) {
|
||||
!IsSingleLineTextControl(true) &&
|
||||
mType != NS_FORM_INPUT_NUMBER) {
|
||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||
if (mouseEvent && mouseEvent->IsLeftClickEvent() &&
|
||||
!ShouldPreventDOMActivateDispatch(aVisitor.mEvent->originalTarget)) {
|
||||
@ -5516,7 +5604,8 @@ HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t*
|
||||
}
|
||||
|
||||
if (IsSingleLineTextControl(false) ||
|
||||
mType == NS_FORM_INPUT_RANGE) {
|
||||
mType == NS_FORM_INPUT_RANGE ||
|
||||
mType == NS_FORM_INPUT_NUMBER) {
|
||||
*aIsFocusable = true;
|
||||
return false;
|
||||
}
|
||||
@ -5727,7 +5816,7 @@ HTMLInputElement::PlaceholderApplies() const
|
||||
bool
|
||||
HTMLInputElement::DoesPatternApply() const
|
||||
{
|
||||
// TODO: temporary until bug 635240 and bug 773205 are fixed.
|
||||
// TODO: temporary until bug 773205 is fixed.
|
||||
if (IsExperimentalMobileType(mType)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ public:
|
||||
|
||||
virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
|
||||
using nsGenericHTMLElement::Focus;
|
||||
virtual void Blur(ErrorResult& aError) MOZ_OVERRIDE;
|
||||
virtual void Focus(ErrorResult& aError) MOZ_OVERRIDE;
|
||||
|
||||
// nsIDOMHTMLInputElement
|
||||
@ -574,6 +575,13 @@ public:
|
||||
void SetType(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::type, aValue, aRv);
|
||||
if (aValue.Equals(NS_LITERAL_STRING("number"))) {
|
||||
// For NS_FORM_INPUT_NUMBER we rely on having frames to process key
|
||||
// events. Make sure we have them in case someone changes the type of
|
||||
// this element to "number" and then expects to be able to send key
|
||||
// events to it (type changes are rare, so not a big perf issue):
|
||||
FlushFrames();
|
||||
}
|
||||
}
|
||||
|
||||
// XPCOM GetDefaultValue() is OK
|
||||
@ -1088,10 +1096,14 @@ protected:
|
||||
*/
|
||||
static bool IsExperimentalMobileType(uint8_t aType)
|
||||
{
|
||||
return aType == NS_FORM_INPUT_NUMBER || aType == NS_FORM_INPUT_DATE ||
|
||||
aType == NS_FORM_INPUT_TIME;
|
||||
return aType == NS_FORM_INPUT_DATE || aType == NS_FORM_INPUT_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the layout frame tree to make sure we have up-to-date frames.
|
||||
*/
|
||||
void FlushFrames();
|
||||
|
||||
/**
|
||||
* Returns true if the element should prevent dispatching another DOMActivate.
|
||||
* This is used in situations where the anonymous subtree should already have
|
||||
@ -1243,7 +1255,8 @@ private:
|
||||
|
||||
static bool MayFireChangeOnBlur(uint8_t aType) {
|
||||
return IsSingleLineTextControl(false, aType) ||
|
||||
aType == NS_FORM_INPUT_RANGE;
|
||||
aType == NS_FORM_INPUT_RANGE ||
|
||||
aType == NS_FORM_INPUT_NUMBER;
|
||||
}
|
||||
|
||||
struct nsFilePickerFilter {
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "nsError.h"
|
||||
#include "nsScriptLoader.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
#include "nsPresState.h"
|
||||
#include "nsILayoutHistoryState.h"
|
||||
@ -1815,6 +1816,15 @@ nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsIURI** aU
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsGenericHTMLElement::IsScrollGrabAllowed(JSContext*, JSObject*)
|
||||
{
|
||||
// Only allow scroll grabbing in chrome and certified apps.
|
||||
nsIPrincipal* prin = nsContentUtils::GetSubjectPrincipal();
|
||||
return nsContentUtils::IsSystemPrincipal(prin) ||
|
||||
prin->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGenericHTMLElement::GetURIListAttr(nsIAtom* aAttr, nsAString& aResult)
|
||||
{
|
||||
|
@ -57,7 +57,8 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase,
|
||||
{
|
||||
public:
|
||||
nsGenericHTMLElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
: nsGenericHTMLElementBase(aNodeInfo)
|
||||
: nsGenericHTMLElementBase(aNodeInfo),
|
||||
mScrollgrab(false)
|
||||
{
|
||||
NS_ASSERTION(mNodeInfo->NamespaceID() == kNameSpaceID_XHTML,
|
||||
"Unexpected namespace");
|
||||
@ -158,7 +159,7 @@ public:
|
||||
SetHTMLIntAttr(nsGkAtoms::tabindex, aTabIndex, aError);
|
||||
}
|
||||
virtual void Focus(mozilla::ErrorResult& aError);
|
||||
void Blur(mozilla::ErrorResult& aError);
|
||||
virtual void Blur(mozilla::ErrorResult& aError);
|
||||
void GetAccessKey(nsString& aAccessKey)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::accesskey, aAccessKey);
|
||||
@ -226,6 +227,14 @@ public:
|
||||
: NS_LITERAL_STRING("false"),
|
||||
aError);
|
||||
}
|
||||
bool Scrollgrab() const
|
||||
{
|
||||
return mScrollgrab;
|
||||
}
|
||||
void SetScrollgrab(bool aValue)
|
||||
{
|
||||
mScrollgrab = aValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether an attribute is an event (onclick, etc.)
|
||||
@ -930,6 +939,9 @@ public:
|
||||
tag == nsGkAtoms::object;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsScrollGrabAllowed(JSContext*, JSObject*);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Add/remove this element to the documents name cache
|
||||
@ -1226,6 +1238,8 @@ protected:
|
||||
|
||||
private:
|
||||
void ChangeEditableState(int32_t aChange);
|
||||
|
||||
bool mScrollgrab;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -29,6 +29,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
|
||||
<input type="reset" id="input_reset" onchange="++NonTextInputChange[3];"></input>
|
||||
<input type="radio" id="input_radio" onchange="++NonTextInputChange[4];"></input>
|
||||
<input type="checkbox" id="input_checkbox" onchange="++NonTextInputChange[5];"></input>
|
||||
<input type="number" id="input_number" onchange="++numberChange;"></input>
|
||||
<input type="range" id="input_range" onchange="++rangeChange;"></input>
|
||||
|
||||
</div>
|
||||
@ -45,6 +46,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
|
||||
var NonTextInputTypes = ["button", "submit", "image", "reset", "radio", "checkbox"];
|
||||
var NonTextInputChange = [0, 0, 0, 0, 0, 0];
|
||||
|
||||
var numberChange = 0;
|
||||
var rangeChange = 0;
|
||||
|
||||
var blurTestCalled = false; //Sentinel to prevent infinite loop.
|
||||
@ -164,6 +166,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
|
||||
}
|
||||
}
|
||||
|
||||
// Special case type=number
|
||||
var number = document.getElementById("input_number");
|
||||
number.focus();
|
||||
synthesizeKey("a", {});
|
||||
number.blur();
|
||||
is(numberChange, 0, "Change event shouldn't be dispatched on number input element for key changes that don't change its value");
|
||||
number.value = "";
|
||||
number.focus();
|
||||
synthesizeKey("1", {});
|
||||
is(numberChange, 0, "Change event shouldn't be dispatched on number input element for keyboard input until it is looses focus");
|
||||
number.blur();
|
||||
is(numberChange, 1, "Change event should be dispatched on number input element on blur");
|
||||
|
||||
// Special case type=range
|
||||
var range = document.getElementById("input_range");
|
||||
range.focus();
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsMathMLElement.cpp',
|
||||
'nsMathMLElementFactory.cpp',
|
||||
]
|
||||
|
@ -8,9 +8,7 @@
|
||||
#include "DirectShowReader.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
using namespace mozilla::widget;
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -47,8 +45,8 @@ DirectShowDecoder::GetSupportedCodecs(const nsACString& aType,
|
||||
bool
|
||||
DirectShowDecoder::IsEnabled()
|
||||
{
|
||||
return (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION) &&
|
||||
Preferences::GetBool("media.directshow.enabled");
|
||||
return !IsVistaOrLater() &&
|
||||
Preferences::GetBool("media.directshow.enabled");
|
||||
}
|
||||
|
||||
DirectShowDecoder::DirectShowDecoder()
|
||||
|
@ -10,8 +10,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "WinUtils.h"
|
||||
using namespace mozilla::widget;
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
@ -72,7 +71,7 @@ HavePlatformMPEGDecoders()
|
||||
Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") ||
|
||||
#ifdef XP_WIN
|
||||
// We have H.264/AAC platform decoders on Windows Vista and up.
|
||||
WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ||
|
||||
IsVistaOrLater() ||
|
||||
#endif
|
||||
// TODO: Other platforms...
|
||||
false;
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "mp4_demuxer/bit_reader.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mp4_demuxer {
|
||||
|
||||
|
@ -8,10 +8,6 @@ EXPORTS += [
|
||||
'MP4Decoder.h',
|
||||
'MP4Reader.h',
|
||||
'PlatformDecoderModule.h',
|
||||
'wmf/MFTDecoder.h',
|
||||
'wmf/WMFAudioDecoder.h',
|
||||
'wmf/WMFDecoderModule.h',
|
||||
'wmf/WMFVideoDecoder.h',
|
||||
]
|
||||
|
||||
EXPORTS.mp4_demuxer += [
|
||||
@ -53,12 +49,22 @@ SOURCES += [
|
||||
'MP4Decoder.cpp',
|
||||
'MP4Reader.cpp',
|
||||
'PlatformDecoderModule.cpp',
|
||||
'wmf/MFTDecoder.cpp',
|
||||
'wmf/WMFAudioDecoder.cpp',
|
||||
'wmf/WMFDecoderModule.cpp',
|
||||
'wmf/WMFVideoDecoder.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WMF']:
|
||||
EXPORTS += [
|
||||
'wmf/MFTDecoder.h',
|
||||
'wmf/WMFAudioDecoder.h',
|
||||
'wmf/WMFDecoderModule.h',
|
||||
'wmf/WMFVideoDecoder.h',
|
||||
]
|
||||
SOURCES += [
|
||||
'wmf/MFTDecoder.cpp',
|
||||
'wmf/WMFAudioDecoder.cpp',
|
||||
'wmf/WMFDecoderModule.cpp',
|
||||
'wmf/WMFVideoDecoder.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'gklayout'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "VideoUtils.h"
|
||||
#include "DXVA2Manager.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "WinUtils.h"
|
||||
#include "Layers.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "prlog.h"
|
||||
@ -35,7 +34,6 @@ WMFVideoDecoder::WMFVideoDecoder(bool aDXVAEnabled)
|
||||
mVideoHeight(0),
|
||||
mLastStreamOffset(0),
|
||||
mDXVAEnabled(aDXVAEnabled),
|
||||
mIsRunningOnVista(widget::WinUtils::GetWindowsVersion() == widget::WinUtils::WIN7_VERSION),
|
||||
mUseHwAccel(false)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Must be on main thread.");
|
||||
|
@ -68,7 +68,6 @@ private:
|
||||
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
|
||||
|
||||
const bool mDXVAEnabled;
|
||||
const bool mIsRunningOnVista;
|
||||
bool mUseHwAccel;
|
||||
};
|
||||
|
||||
|
@ -10,15 +10,13 @@
|
||||
#include "WMFUtils.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "WinUtils.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
#include "DirectShowDecoder.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaDecoderStateMachine* WMFDecoder::CreateStateMachine()
|
||||
@ -38,21 +36,15 @@ WMFDecoder::IsMP3Supported()
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (!MediaDecoder::IsWMFEnabled()) {
|
||||
if (!MediaDecoder::IsWMFEnabled()) {
|
||||
return false;
|
||||
}
|
||||
if (WinUtils::GetWindowsVersion() != WinUtils::WIN7_VERSION) {
|
||||
if (!IsWin7OrLater()) {
|
||||
return true;
|
||||
}
|
||||
// We're on Windows 7. MP3 support is disabled if no service pack
|
||||
// MP3 support is disabled if we're on Windows 7 and no service pack
|
||||
// is installed, as it's crashy on Win7 SP0.
|
||||
UINT spMajorVer = 0, spMinorVer = 0;
|
||||
if (!WinUtils::GetWindowsServicePackVersion(spMajorVer, spMinorVer)) {
|
||||
// Um... We can't determine the service pack version... Just block
|
||||
// MP3 as a precaution...
|
||||
return false;
|
||||
}
|
||||
return spMajorVer != 0;
|
||||
return IsWin7SP1OrLater();
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -163,7 +155,7 @@ bool
|
||||
WMFDecoder::IsEnabled()
|
||||
{
|
||||
// We only use WMF on Windows Vista and up
|
||||
return WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION &&
|
||||
return IsVistaOrLater() &&
|
||||
Preferences::GetBool("media.windows-media-foundation.enabled");
|
||||
}
|
||||
|
||||
|
@ -7,15 +7,13 @@
|
||||
#include "WMFUtils.h"
|
||||
#include <stdint.h>
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "prlog.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "WinUtils.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
|
||||
// Some SDK versions don't define the AAC decoder CLSID.
|
||||
// {32D186A7-218F-4C75-8876-DD77273A8999}
|
||||
@ -510,7 +508,7 @@ MFStartup()
|
||||
|
||||
DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
|
||||
ENSURE_FUNCTION_PTR(MFStartup, Mfplat.dll)
|
||||
if (WinUtils::GetWindowsVersion() == WinUtils::VISTA_VERSION)
|
||||
if (!IsWin7OrLater())
|
||||
return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
|
||||
else
|
||||
return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#ifndef nsXBLMaybeCompiled_h__
|
||||
#define nsXBLMaybeCompiled_h__
|
||||
|
||||
#include "js/GCAPI.h"
|
||||
|
||||
/*
|
||||
* A union containing either a pointer representing uncompiled source or a
|
||||
* JSObject* representing the compiled result. The class is templated on the
|
||||
@ -39,6 +41,16 @@ public:
|
||||
}
|
||||
|
||||
JSObject* GetJSFunction() const
|
||||
{
|
||||
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
|
||||
if (mCompiled) {
|
||||
JS::ExposeObjectToActiveJS(mCompiled);
|
||||
}
|
||||
return mCompiled;
|
||||
}
|
||||
|
||||
// This is appropriate for use in tracing methods, etc.
|
||||
JSObject* GetJSFunctionPreserveColor() const
|
||||
{
|
||||
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
|
||||
return mCompiled;
|
||||
@ -122,6 +134,7 @@ public:
|
||||
bool IsCompiled() const { return extract()->IsCompiled(); }
|
||||
UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); }
|
||||
JSObject* GetJSFunction() const { return extract()->GetJSFunction(); }
|
||||
JSObject* GetJSFunctionPreserveColor() const { return extract()->GetJSFunctionPreserveColor(); }
|
||||
|
||||
void SetUncompiled(UncompiledT* source) {
|
||||
wrapper().set(nsXBLMaybeCompiled<UncompiledT>(source));
|
||||
|
@ -217,7 +217,7 @@ nsXBLProtoImplMethod::CompileMember(const nsCString& aClassStr,
|
||||
void
|
||||
nsXBLProtoImplMethod::Trace(const TraceCallbacks& aCallbacks, void *aClosure)
|
||||
{
|
||||
if (IsCompiled() && GetCompiledMethod()) {
|
||||
if (IsCompiled() && GetCompiledMethodPreserveColor()) {
|
||||
aCallbacks.Trace(&mMethod.AsHeapObject(), "mMethod", aClosure);
|
||||
}
|
||||
}
|
||||
@ -246,7 +246,7 @@ nsXBLProtoImplMethod::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
AssertInCompilationScope();
|
||||
MOZ_ASSERT(IsCompiled());
|
||||
if (GetCompiledMethod()) {
|
||||
if (GetCompiledMethodPreserveColor()) {
|
||||
nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -357,7 +357,7 @@ nsXBLProtoImplAnonymousMethod::Write(nsIObjectOutputStream* aStream,
|
||||
{
|
||||
AssertInCompilationScope();
|
||||
MOZ_ASSERT(IsCompiled());
|
||||
if (GetCompiledMethod()) {
|
||||
if (GetCompiledMethodPreserveColor()) {
|
||||
nsresult rv = aStream->Write8(aType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -125,6 +125,11 @@ protected:
|
||||
return mMethod.GetJSFunction();
|
||||
}
|
||||
|
||||
JSObject* GetCompiledMethodPreserveColor() const
|
||||
{
|
||||
return mMethod.GetJSFunctionPreserveColor();
|
||||
}
|
||||
|
||||
JS::Heap<nsXBLMaybeCompiled<nsXBLUncompiledMethod> > mMethod;
|
||||
};
|
||||
|
||||
|
@ -132,16 +132,16 @@ nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
|
||||
MOZ_ASSERT(xpc::IsInXBLScope(globalObject) ||
|
||||
globalObject == xpc::GetXBLScope(aCx, globalObject));
|
||||
|
||||
if (mGetter.GetJSFunction() || mSetter.GetJSFunction()) {
|
||||
JS::Rooted<JSObject*> getter(aCx, nullptr);
|
||||
if (mGetter.GetJSFunction()) {
|
||||
if (!(getter = ::JS_CloneFunctionObject(aCx, mGetter.GetJSFunction(), globalObject)))
|
||||
JS::Rooted<JSObject*> getter(aCx, mGetter.GetJSFunction());
|
||||
JS::Rooted<JSObject*> setter(aCx, mSetter.GetJSFunction());
|
||||
if (getter || setter) {
|
||||
if (getter) {
|
||||
if (!(getter = ::JS_CloneFunctionObject(aCx, getter, globalObject)))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> setter(aCx, nullptr);
|
||||
if (mSetter.GetJSFunction()) {
|
||||
if (!(setter = ::JS_CloneFunctionObject(aCx, mSetter.GetJSFunction(), globalObject)))
|
||||
if (setter) {
|
||||
if (!(setter = ::JS_CloneFunctionObject(aCx, setter, globalObject)))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -1779,7 +1779,7 @@ nsXULElement::GetWindowWidget()
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
|
||||
// only top level chrome documents can set the titlebar color
|
||||
if (doc->IsRootDisplayDocument()) {
|
||||
if (doc && doc->IsRootDisplayDocument()) {
|
||||
nsCOMPtr<nsISupports> container = doc->GetContainer();
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
|
||||
if (baseWindow) {
|
||||
|
@ -77,10 +77,12 @@ ActivityProxy.prototype = {
|
||||
debug("FireSuccess");
|
||||
Services.DOMRequest.fireSuccess(this.activity,
|
||||
ObjectWrapper.wrap(msg.result, this.window));
|
||||
Services.obs.notifyObservers(null, "Activity:Success", null);
|
||||
break;
|
||||
case "Activity:FireError":
|
||||
debug("FireError");
|
||||
Services.DOMRequest.fireError(this.activity, msg.error);
|
||||
Services.obs.notifyObservers(null, "Activity:Error", null);
|
||||
break;
|
||||
}
|
||||
// We can only get one FireSuccess / FireError message, so cleanup as soon as possible.
|
||||
|
@ -962,24 +962,24 @@ this.DOMApplicationRegistry = {
|
||||
mm: aMm,
|
||||
refCount: 1
|
||||
});
|
||||
}
|
||||
|
||||
// If it wasn't registered before, let's update its state
|
||||
if ((aMsgName === 'Webapps:FireEvent') ||
|
||||
(aMsgName === 'Webapps:UpdateState')) {
|
||||
if (man) {
|
||||
let app = this.getAppByManifestURL(aApp.manifestURL);
|
||||
if (app && ((aApp.installState !== app.installState) ||
|
||||
(aApp.downloading !== app.downloading))) {
|
||||
debug("Got a registration from an outdated app: " +
|
||||
aApp.manifestURL);
|
||||
let aEvent ={
|
||||
type: app.installState,
|
||||
app: app,
|
||||
manifestURL: app.manifestURL,
|
||||
manifest: app.manifest
|
||||
};
|
||||
aMm.sendAsyncMessage(aMsgName, aEvent);
|
||||
}
|
||||
// If the state reported by the registration is outdated, update it now.
|
||||
if ((aMsgName === 'Webapps:FireEvent') ||
|
||||
(aMsgName === 'Webapps:UpdateState')) {
|
||||
if (man) {
|
||||
let app = this.getAppByManifestURL(aApp.manifestURL);
|
||||
if (app && ((aApp.installState !== app.installState) ||
|
||||
(aApp.downloading !== app.downloading))) {
|
||||
debug("Got a registration from an outdated app: " +
|
||||
aApp.manifestURL);
|
||||
let aEvent ={
|
||||
type: app.installState,
|
||||
app: app,
|
||||
manifestURL: app.manifestURL,
|
||||
manifest: app.manifest
|
||||
};
|
||||
aMm.sendAsyncMessage(aMsgName, aEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMimeTypeArray)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsMimeTypeArray,
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsMimeTypeArray,
|
||||
mWindow,
|
||||
mMimeTypes)
|
||||
mMimeTypes,
|
||||
mHiddenMimeTypes)
|
||||
|
||||
nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow),
|
||||
mPluginMimeTypeCount(0)
|
||||
: mWindow(aWindow)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
@ -50,7 +50,7 @@ void
|
||||
nsMimeTypeArray::Refresh()
|
||||
{
|
||||
mMimeTypes.Clear();
|
||||
mPluginMimeTypeCount = 0;
|
||||
mHiddenMimeTypes.Clear();
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
@ -81,9 +81,7 @@ nsMimeTypeArray::IndexedGetter(uint32_t aIndex, bool &aFound)
|
||||
|
||||
EnsurePluginMimeTypes();
|
||||
|
||||
MOZ_ASSERT(mMimeTypes.Length() >= mPluginMimeTypeCount);
|
||||
|
||||
if (aIndex >= mPluginMimeTypeCount) {
|
||||
if (aIndex >= mMimeTypes.Length()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -92,6 +90,20 @@ nsMimeTypeArray::IndexedGetter(uint32_t aIndex, bool &aFound)
|
||||
return mMimeTypes[aIndex];
|
||||
}
|
||||
|
||||
static nsMimeType*
|
||||
FindMimeType(const nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
|
||||
const nsAString& aType)
|
||||
{
|
||||
for (uint32_t i = 0; i < aMimeTypes.Length(); ++i) {
|
||||
nsMimeType* mimeType = aMimeTypes[i];
|
||||
if (aType.Equals(mimeType->Type())) {
|
||||
return mimeType;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsMimeType*
|
||||
nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
{
|
||||
@ -99,12 +111,14 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
|
||||
EnsurePluginMimeTypes();
|
||||
|
||||
for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
|
||||
if (aName.Equals(mMimeTypes[i]->Type())) {
|
||||
aFound = true;
|
||||
nsMimeType* mimeType = FindMimeType(mMimeTypes, aName);
|
||||
if (!mimeType) {
|
||||
mimeType = FindMimeType(mHiddenMimeTypes, aName);
|
||||
}
|
||||
|
||||
return mMimeTypes[i];
|
||||
}
|
||||
if (mimeType) {
|
||||
aFound = true;
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
// Now let's check with the MIME service.
|
||||
@ -148,8 +162,10 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
// If we got here, we support this type! Say so.
|
||||
aFound = true;
|
||||
|
||||
// We don't want navigator.mimeTypes enumeration to expose MIME types with
|
||||
// application handlers, so add them to the list of hidden MIME types.
|
||||
nsMimeType *mt = new nsMimeType(mWindow, aName);
|
||||
mMimeTypes.AppendElement(mt);
|
||||
mHiddenMimeTypes.AppendElement(mt);
|
||||
|
||||
return mt;
|
||||
}
|
||||
@ -159,9 +175,7 @@ nsMimeTypeArray::Length()
|
||||
{
|
||||
EnsurePluginMimeTypes();
|
||||
|
||||
MOZ_ASSERT(mMimeTypes.Length() >= mPluginMimeTypeCount);
|
||||
|
||||
return mPluginMimeTypeCount;
|
||||
return mMimeTypes.Length();
|
||||
}
|
||||
|
||||
void
|
||||
@ -177,7 +191,7 @@ nsMimeTypeArray::GetSupportedNames(nsTArray< nsString >& aRetval)
|
||||
void
|
||||
nsMimeTypeArray::EnsurePluginMimeTypes()
|
||||
{
|
||||
if (!mMimeTypes.IsEmpty() || !mWindow) {
|
||||
if (!mMimeTypes.IsEmpty() || !mHiddenMimeTypes.IsEmpty() || !mWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -195,9 +209,7 @@ nsMimeTypeArray::EnsurePluginMimeTypes()
|
||||
return;
|
||||
}
|
||||
|
||||
pluginArray->GetMimeTypes(mMimeTypes);
|
||||
|
||||
mPluginMimeTypeCount = mMimeTypes.Length();
|
||||
pluginArray->GetMimeTypes(mMimeTypes, mHiddenMimeTypes);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef)
|
||||
|
@ -46,15 +46,16 @@ protected:
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
// mMimeTypes contains all mime types handled by plugins followed by
|
||||
// any other mime types that we handle internally and have been
|
||||
// looked up before.
|
||||
// mMimeTypes contains MIME types handled by non-hidden plugins, those
|
||||
// popular plugins that must be exposed in navigator.plugins enumeration to
|
||||
// avoid breaking web content. Likewise, mMimeTypes are exposed in
|
||||
// navigator.mimeTypes enumeration.
|
||||
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
|
||||
|
||||
// mPluginMimeTypeCount is the number of plugin mime types that we
|
||||
// have in mMimeTypes. The plugin mime types are always at the
|
||||
// beginning of the list.
|
||||
uint32_t mPluginMimeTypeCount;
|
||||
// mHiddenMimeTypes contains MIME types handled by plugins hidden from
|
||||
// navigator.plugins enumeration or by an OS PreferredApplicationHandler.
|
||||
// mHiddenMimeTypes are hidden from navigator.mimeTypes enumeration.
|
||||
nsTArray<nsRefPtr<nsMimeType> > mHiddenMimeTypes;
|
||||
};
|
||||
|
||||
class nsMimeType MOZ_FINAL : public nsWrapperCache
|
||||
|
@ -5,8 +5,11 @@
|
||||
|
||||
#include "nsPluginArray.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/PluginArrayBinding.h"
|
||||
#include "mozilla/dom/PluginBinding.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsMimeTypeArray.h"
|
||||
#include "Navigator.h"
|
||||
#include "nsIDocShell.h"
|
||||
@ -63,14 +66,27 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsPluginArray,
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsPluginArray,
|
||||
mWindow,
|
||||
mPlugins)
|
||||
mPlugins,
|
||||
mHiddenPlugins)
|
||||
|
||||
static void
|
||||
GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
|
||||
nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
|
||||
{
|
||||
for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
|
||||
nsPluginElement *plugin = aPlugins[i];
|
||||
aMimeTypes.AppendElements(plugin->MimeTypes());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
|
||||
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
|
||||
nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
|
||||
{
|
||||
aMimeTypes.Clear();
|
||||
aHiddenMimeTypes.Clear();
|
||||
|
||||
if (!AllowPlugins()) {
|
||||
return;
|
||||
@ -78,10 +94,8 @@ nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
|
||||
|
||||
EnsurePlugins();
|
||||
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
|
||||
nsPluginElement *plugin = mPlugins[i];
|
||||
aMimeTypes.AppendElements(plugin->MimeTypes());
|
||||
}
|
||||
GetPluginMimeTypes(mPlugins, aMimeTypes);
|
||||
GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
|
||||
}
|
||||
|
||||
nsPluginElement*
|
||||
@ -121,12 +135,14 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
||||
// happens, and therefore the lengths will be in sync only when
|
||||
// the both arrays contain the same plugin tags (though as
|
||||
// different types).
|
||||
if (newPluginTags.Length() == mPlugins.Length()) {
|
||||
uint32_t pluginCount = mPlugins.Length() + mHiddenPlugins.Length();
|
||||
if (newPluginTags.Length() == pluginCount) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mPlugins.Clear();
|
||||
mHiddenPlugins.Clear();
|
||||
|
||||
nsCOMPtr<nsIDOMNavigator> navigator;
|
||||
mWindow->GetNavigator(getter_AddRefs(navigator));
|
||||
@ -169,6 +185,23 @@ nsPluginArray::Invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
static nsPluginElement*
|
||||
FindPlugin(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
|
||||
const nsAString& aName)
|
||||
{
|
||||
for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
|
||||
nsAutoString pluginName;
|
||||
nsPluginElement* plugin = aPlugins[i];
|
||||
plugin->GetName(pluginName);
|
||||
|
||||
if (pluginName.Equals(aName)) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsPluginElement*
|
||||
nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
{
|
||||
@ -180,19 +213,13 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
|
||||
EnsurePlugins();
|
||||
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
|
||||
nsAutoString pluginName;
|
||||
nsPluginElement* plugin = mPlugins[i];
|
||||
plugin->GetName(pluginName);
|
||||
|
||||
if (pluginName.Equals(aName)) {
|
||||
aFound = true;
|
||||
|
||||
return plugin;
|
||||
}
|
||||
nsPluginElement* plugin = FindPlugin(mPlugins, aName);
|
||||
if (!plugin) {
|
||||
plugin = FindPlugin(mHiddenPlugins, aName);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
aFound = (plugin != nullptr);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@ -242,10 +269,32 @@ nsPluginArray::AllowPlugins() const
|
||||
return docShell && docShell->PluginsAllowedInCurrentDoc();
|
||||
}
|
||||
|
||||
static bool
|
||||
HasStringPrefix(const nsCString& str, const nsACString& prefix) {
|
||||
return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames,
|
||||
const nsPluginTag* pluginTag)
|
||||
{
|
||||
const nsCString& pluginName = pluginTag->mName;
|
||||
|
||||
const uint32_t length = enumerableNames.Length();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
const nsCString& name = enumerableNames[i];
|
||||
if (HasStringPrefix(pluginName, name)) {
|
||||
return true; // don't hide plugin
|
||||
}
|
||||
}
|
||||
|
||||
return false; // hide plugin!
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginArray::EnsurePlugins()
|
||||
{
|
||||
if (!mPlugins.IsEmpty()) {
|
||||
if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) {
|
||||
// We already have an array of plugin elements.
|
||||
return;
|
||||
}
|
||||
@ -259,10 +308,36 @@ nsPluginArray::EnsurePlugins()
|
||||
nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
|
||||
pluginHost->GetPlugins(pluginTags);
|
||||
|
||||
nsTArray<nsCString> enumerableNames;
|
||||
|
||||
const nsAdoptingCString& enumerableNamesPref =
|
||||
Preferences::GetCString("plugins.enumerable_names");
|
||||
|
||||
bool disablePluginHiding = !enumerableNamesPref ||
|
||||
enumerableNamesPref.EqualsLiteral("*");
|
||||
|
||||
if (!disablePluginHiding) {
|
||||
nsCCharSeparatedTokenizer tokens(enumerableNamesPref, ',');
|
||||
while (tokens.hasMoreTokens()) {
|
||||
const nsCSubstring& token = tokens.nextToken();
|
||||
if (!token.IsEmpty()) {
|
||||
enumerableNames.AppendElement(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// need to wrap each of these with a nsPluginElement, which is
|
||||
// scriptable.
|
||||
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
nsPluginTag* pluginTag = pluginTags[i];
|
||||
|
||||
// Add the plugin to the list of hidden plugins or non-hidden plugins?
|
||||
nsTArray<nsRefPtr<nsPluginElement> >& pluginArray =
|
||||
(disablePluginHiding || IsPluginEnumerable(enumerableNames, pluginTag))
|
||||
? mPlugins
|
||||
: mHiddenPlugins;
|
||||
|
||||
pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,8 @@ public:
|
||||
void Init();
|
||||
void Invalidate();
|
||||
|
||||
void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes);
|
||||
void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
|
||||
nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes);
|
||||
|
||||
// PluginArray WebIDL methods
|
||||
|
||||
@ -60,7 +61,18 @@ private:
|
||||
void EnsurePlugins();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
// Many sites check whether a particular plugin is installed by enumerating
|
||||
// all navigator.plugins, checking each plugin's name. These sites should
|
||||
// just check navigator.plugins["Popular Plugin Name"] instead. mPlugins
|
||||
// contains those popular plugins that must be exposed in navigator.plugins
|
||||
// enumeration to avoid breaking web content.
|
||||
nsTArray<nsRefPtr<nsPluginElement> > mPlugins;
|
||||
|
||||
// mHiddenPlugins contains plugins that can be queried by
|
||||
// navigator.plugins["Hidden Plugin Name"] but do not need to be exposed in
|
||||
// navigator.plugins enumeration.
|
||||
nsTArray<nsRefPtr<nsPluginElement> > mHiddenPlugins;
|
||||
};
|
||||
|
||||
class nsPluginElement MOZ_FINAL : public nsISupports,
|
||||
|
@ -10070,7 +10070,19 @@ class CGJSImplClass(CGBindingImplClass):
|
||||
descriptor.name)
|
||||
constructorBody = "SetIsDOMBinding();"
|
||||
extradefinitions= string.Template(
|
||||
"NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(${ifaceName}, mImpl, mParent)\n"
|
||||
"NS_IMPL_CYCLE_COLLECTION_CLASS(${ifaceName})\n"
|
||||
"NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})\n"
|
||||
" NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)\n"
|
||||
" NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)\n"
|
||||
" NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER\n"
|
||||
" tmp->ClearWeakReferences();\n"
|
||||
"NS_IMPL_CYCLE_COLLECTION_UNLINK_END\n"
|
||||
"NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})\n"
|
||||
" NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)\n"
|
||||
" NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)\n"
|
||||
" NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS\n"
|
||||
"NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END\n"
|
||||
"NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName})\n"
|
||||
"NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})\n"
|
||||
"NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})\n"
|
||||
"NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})\n"
|
||||
|
@ -174,9 +174,9 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
|
||||
, mRemoteConnectionFlags(0)
|
||||
, mRemoteMaxPacketLength(0)
|
||||
, mLastCommand(0)
|
||||
, mPacketLeftLength(0)
|
||||
, mPacketLength(0)
|
||||
, mPacketReceivedLength(0)
|
||||
, mBodySegmentLength(0)
|
||||
, mReceivedDataBufferOffset(0)
|
||||
, mAbortFlag(false)
|
||||
, mNewFileFlag(false)
|
||||
, mPutFinalFlag(false)
|
||||
@ -477,7 +477,7 @@ BluetoothOppManager::ConfirmReceivingFile(bool aConfirm)
|
||||
NS_ENSURE_TRUE(mConnected, false);
|
||||
NS_ENSURE_TRUE(mWaitingForConfirmationFlag, false);
|
||||
|
||||
MOZ_ASSERT(mPacketLeftLength == 0);
|
||||
MOZ_ASSERT(mPacketReceivedLength == 0);
|
||||
|
||||
mWaitingForConfirmationFlag = false;
|
||||
|
||||
@ -505,7 +505,7 @@ BluetoothOppManager::AfterFirstPut()
|
||||
{
|
||||
mUpdateProgressCounter = 1;
|
||||
mPutFinalFlag = false;
|
||||
mReceivedDataBufferOffset = 0;
|
||||
mPacketReceivedLength = 0;
|
||||
mSentFileLength = 0;
|
||||
mWaitingToSendPutFinal = false;
|
||||
mSuccessFlag = false;
|
||||
@ -541,7 +541,7 @@ BluetoothOppManager::AfterOppDisconnected()
|
||||
|
||||
mConnected = false;
|
||||
mLastCommand = 0;
|
||||
mPacketLeftLength = 0;
|
||||
mPacketReceivedLength = 0;
|
||||
mDsFile = nullptr;
|
||||
|
||||
// We can't reset mSuccessFlag here since this function may be called
|
||||
@ -586,7 +586,7 @@ BluetoothOppManager::DeleteReceivedFile()
|
||||
bool
|
||||
BluetoothOppManager::CreateFile()
|
||||
{
|
||||
MOZ_ASSERT(mPacketLeftLength == 0);
|
||||
MOZ_ASSERT(mPacketReceivedLength == mPacketLength);
|
||||
|
||||
nsString path;
|
||||
path.AssignLiteral(TARGET_SUBDIR);
|
||||
@ -759,21 +759,66 @@ BluetoothOppManager::ValidateFileName()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothOppManager::ComposePacket(uint8_t aOpCode, UnixSocketRawData* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aMessage);
|
||||
|
||||
int frameHeaderLength = 0;
|
||||
|
||||
// See if this is the first part of each Put packet
|
||||
if (mPacketReceivedLength == 0) {
|
||||
// Section 3.3.3 "Put", IrOBEX 1.2
|
||||
// [opcode:1][length:2][Headers:var]
|
||||
frameHeaderLength = 3;
|
||||
|
||||
mPacketLength = ((((int)aMessage->mData[1]) << 8) | aMessage->mData[2]) -
|
||||
frameHeaderLength;
|
||||
/**
|
||||
* A PUT request from remote devices may be divided into multiple parts.
|
||||
* In other words, one request may need to be received multiple times,
|
||||
* so here we keep a variable mPacketLeftLength to indicate if current
|
||||
* PUT request is done.
|
||||
*/
|
||||
mReceivedDataBuffer = new uint8_t[mPacketLength];
|
||||
mPutFinalFlag = (aOpCode == ObexRequestCode::PutFinal);
|
||||
}
|
||||
|
||||
int dataLength = aMessage->mSize - frameHeaderLength;
|
||||
|
||||
// Check length before memcpy to prevent from memory pollution
|
||||
if (dataLength < 0 ||
|
||||
mPacketReceivedLength + dataLength > mPacketLength) {
|
||||
BT_LOGR("%s: Received packet size is unreasonable", __FUNCTION__);
|
||||
|
||||
ReplyToPut(mPutFinalFlag, false);
|
||||
DeleteReceivedFile();
|
||||
FileTransferComplete();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(mReceivedDataBuffer.get() + mPacketReceivedLength,
|
||||
&aMessage->mData[frameHeaderLength], dataLength);
|
||||
|
||||
mPacketReceivedLength += dataLength;
|
||||
|
||||
return (mPacketReceivedLength == mPacketLength);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
uint8_t opCode;
|
||||
int packetLength;
|
||||
int receivedLength = aMessage->mSize;
|
||||
|
||||
if (mPacketLeftLength > 0) {
|
||||
if (mPacketReceivedLength > 0) {
|
||||
opCode = mPutFinalFlag ? ObexRequestCode::PutFinal : ObexRequestCode::Put;
|
||||
packetLength = mPacketLeftLength;
|
||||
} else {
|
||||
opCode = aMessage->mData[0];
|
||||
packetLength = (((int)aMessage->mData[1]) << 8) | aMessage->mData[2];
|
||||
|
||||
// When there's a Put packet right after a PutFinal packet,
|
||||
// which means it's the start point of a new file.
|
||||
@ -814,45 +859,16 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
|
||||
FileTransferComplete();
|
||||
} else if (opCode == ObexRequestCode::Put ||
|
||||
opCode == ObexRequestCode::PutFinal) {
|
||||
int headerStartIndex = 0;
|
||||
|
||||
// The first part of each Put packet
|
||||
if (mReceivedDataBufferOffset == 0) {
|
||||
// Section 3.3.3 "Put", IrOBEX 1.2
|
||||
// [opcode:1][length:2][Headers:var]
|
||||
headerStartIndex = 3;
|
||||
// The largest buffer size is 65535 because packetLength is a
|
||||
// 2-byte value (0 ~ 0xFFFF).
|
||||
mReceivedDataBuffer = new uint8_t[packetLength];
|
||||
mPacketLeftLength = packetLength;
|
||||
|
||||
/*
|
||||
* A PUT request from remote devices may be divided into multiple parts.
|
||||
* In other words, one request may need to be received multiple times,
|
||||
* so here we keep a variable mPacketLeftLength to indicate if current
|
||||
* PUT request is done.
|
||||
*/
|
||||
mPutFinalFlag = (opCode == ObexRequestCode::PutFinal);
|
||||
}
|
||||
|
||||
memcpy(mReceivedDataBuffer.get() + mReceivedDataBufferOffset,
|
||||
&aMessage->mData[headerStartIndex],
|
||||
receivedLength - headerStartIndex);
|
||||
|
||||
mPacketLeftLength -= receivedLength;
|
||||
mReceivedDataBufferOffset += receivedLength - headerStartIndex;
|
||||
if (mPacketLeftLength) {
|
||||
if (!ComposePacket(opCode, aMessage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A Put packet is received completely
|
||||
ParseHeaders(mReceivedDataBuffer.get(),
|
||||
mReceivedDataBufferOffset,
|
||||
&pktHeaders);
|
||||
ParseHeaders(mReceivedDataBuffer.get(), mPacketReceivedLength, &pktHeaders);
|
||||
ExtractPacketHeaders(pktHeaders);
|
||||
ValidateFileName();
|
||||
|
||||
mReceivedDataBufferOffset = 0;
|
||||
mPacketReceivedLength = 0;
|
||||
|
||||
// When we cancel the transfer, delete the file and notify completion
|
||||
if (mAbortFlag) {
|
||||
@ -917,16 +933,7 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
uint8_t opCode;
|
||||
int packetLength;
|
||||
|
||||
if (mPacketLeftLength > 0) {
|
||||
opCode = mPutFinalFlag ? ObexRequestCode::PutFinal : ObexRequestCode::Put;
|
||||
packetLength = mPacketLeftLength;
|
||||
} else {
|
||||
opCode = aMessage->mData[0];
|
||||
packetLength = (((int)aMessage->mData[1]) << 8) | aMessage->mData[2];
|
||||
}
|
||||
uint8_t opCode = aMessage->mData[0];
|
||||
|
||||
// Check response code and send out system message as finished if the response
|
||||
// code is somehow incorrect.
|
||||
|
@ -106,6 +106,17 @@ private:
|
||||
bool ProcessNextBatch();
|
||||
void ConnectInternal(const nsAString& aDeviceAddress);
|
||||
|
||||
/**
|
||||
* Usually we won't get a full PUT packet in one operation, which means that
|
||||
* a packet may be devided into several parts and BluetoothOppManager should
|
||||
* be in charge of assembling.
|
||||
*
|
||||
* @return true if a packet has been fully received.
|
||||
* false if the received length exceeds/not reaches the expected
|
||||
* length.
|
||||
*/
|
||||
bool ComposePacket(uint8_t aOpCode, UnixSocketRawData* aMessage);
|
||||
|
||||
/**
|
||||
* OBEX session status.
|
||||
* Set when OBEX session is established.
|
||||
@ -128,9 +139,9 @@ private:
|
||||
*/
|
||||
int mLastCommand;
|
||||
|
||||
int mPacketLeftLength;
|
||||
int mPacketLength;
|
||||
int mPacketReceivedLength;
|
||||
int mBodySegmentLength;
|
||||
int mReceivedDataBufferOffset;
|
||||
int mUpdateProgressCounter;
|
||||
|
||||
/**
|
||||
|
@ -63,8 +63,10 @@ const ContentPanning = {
|
||||
|
||||
addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
|
||||
addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
|
||||
addEventListener("visibilitychange", this._recvVisibilityChange.bind(this));
|
||||
addEventListener("visibilitychange", this._handleVisibilityChange.bind(this));
|
||||
Services.obs.addObserver(this, "BEC:ShownModalPrompt", false);
|
||||
Services.obs.addObserver(this, "Activity:Success", false);
|
||||
Services.obs.addObserver(this, "Activity:Error", false);
|
||||
},
|
||||
|
||||
handleEvent: function cp_handleEvent(evt) {
|
||||
@ -461,8 +463,10 @@ const ContentPanning = {
|
||||
|
||||
_resetHover: function cp_resetHover() {
|
||||
const kStateHover = 0x00000004;
|
||||
let element = content.document.createElement('foo');
|
||||
this._domUtils.setContentState(element, kStateHover);
|
||||
try {
|
||||
let element = content.document.createElement('foo');
|
||||
this._domUtils.setContentState(element, kStateHover);
|
||||
} catch(e) {}
|
||||
},
|
||||
|
||||
_setActive: function cp_setActive(elt) {
|
||||
@ -546,7 +550,7 @@ const ContentPanning = {
|
||||
}
|
||||
},
|
||||
|
||||
_recvVisibilityChange: function(evt) {
|
||||
_handleVisibilityChange: function(evt) {
|
||||
if (!evt.target.hidden)
|
||||
return;
|
||||
|
||||
|
@ -25,14 +25,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
|
||||
devicestorage_setup();
|
||||
|
||||
var oldFiles = ["a.png", "b.png", "c.png"];
|
||||
var timeFile = "t.png";
|
||||
var newFiles = ["d.png", "e.png", "f.png"];
|
||||
|
||||
var storage = navigator.getDeviceStorage('pictures');
|
||||
var prefix = "devicestorage/" + randomFilename(12);
|
||||
var callback;
|
||||
var files;
|
||||
var i;
|
||||
var timestamp;
|
||||
var lastFileAddedTimestamp;
|
||||
|
||||
function verifyAndDelete(prefix, files, e) {
|
||||
if (e.target.result == null) {
|
||||
@ -62,31 +62,56 @@ function verifyAndDelete(prefix, files, e) {
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
files.remove(index);
|
||||
files.splice(index, 1);
|
||||
|
||||
// clean up
|
||||
var cleanup = storage.delete(e.target.result.name);
|
||||
cleanup.onsuccess = function(e) {}
|
||||
}
|
||||
|
||||
function addSuccess(e) {
|
||||
i = i + 1;
|
||||
if (i == files.length) {
|
||||
callback();
|
||||
return;
|
||||
function addFile(filename, callback) {
|
||||
var addReq = storage.addNamed(createRandomBlob('image/png'), prefix + '/' + filename);
|
||||
addReq.onsuccess = function(e) {
|
||||
// After adding the file, we go ahead and grab the timestamp of the file
|
||||
// that we just added
|
||||
var getReq = storage.get(prefix + '/' + filename);
|
||||
getReq.onsuccess = function(e) {
|
||||
lastFileAddedTimestamp = e.target.result.lastModifiedDate;
|
||||
callback();
|
||||
}
|
||||
getReq.onerror = function(e) {
|
||||
ok(false, "getError was called : " + e.target.error.name);
|
||||
devicestorage_cleanup();
|
||||
};
|
||||
}
|
||||
addReq.onerror = function(e) {
|
||||
ok(false, "addError was called : " + e.target.error.name);
|
||||
devicestorage_cleanup();
|
||||
}
|
||||
addFile(files[i]);
|
||||
}
|
||||
|
||||
function addError(e) {
|
||||
ok(false, "addError was called : " + e.target.error.name);
|
||||
devicestorage_cleanup();
|
||||
function addFileArray(fileArray, callback) {
|
||||
var i = 0;
|
||||
function addNextFile() {
|
||||
i = i + 1;
|
||||
if (i == fileArray.length) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
addFile(fileArray[i], addNextFile);
|
||||
}
|
||||
addFile(fileArray[0], addNextFile);
|
||||
}
|
||||
|
||||
function addFile(filename){
|
||||
var req = storage.addNamed(createRandomBlob('image/png'), prefix + '/' + files[i]);
|
||||
req.onsuccess = addSuccess;
|
||||
req.onerror = addError;
|
||||
function delFile(filename, callback) {
|
||||
var req = storage.delete(prefix + '/' + filename);
|
||||
req.onsuccess = function(e) {
|
||||
callback();
|
||||
};
|
||||
req.onerror = function(e) {
|
||||
ok(false, "delError was called : " + e.target.error.name);
|
||||
devicestorage_cleanup();
|
||||
};
|
||||
}
|
||||
|
||||
function afterNewFiles() {
|
||||
@ -103,27 +128,36 @@ function afterNewFiles() {
|
||||
};
|
||||
}
|
||||
|
||||
function addNewFiles() {
|
||||
i = 0;
|
||||
files = newFiles;
|
||||
callback = afterNewFiles;
|
||||
addFile(files[0]);
|
||||
}
|
||||
|
||||
function beforeNewFiles() {
|
||||
timestamp = new Date();
|
||||
setTimeout(addNewFiles, 1000);
|
||||
function waitForTimestampChange() {
|
||||
// We've added a new file. See if the timestamp differs from
|
||||
// oldFileAddedTimestamp, and if it's the same wait for a bit
|
||||
// and try again.
|
||||
if (lastFileAddedTimestamp.valueOf() === timestamp.valueOf()) {
|
||||
delFile(timeFile, function() {
|
||||
setTimeout(function() {
|
||||
addFile(timeFile, waitForTimestampChange);
|
||||
}, 1000);
|
||||
});
|
||||
} else {
|
||||
timestamp = lastFileAddedTimestamp;
|
||||
// The timestamp has changed. Go ahead and add the rest of the new files
|
||||
delFile(timeFile, function() {
|
||||
addFileArray(newFiles, afterNewFiles);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function afterOldFiles() {
|
||||
setTimeout(beforeNewFiles, 1000);
|
||||
timestamp = lastFileAddedTimestamp;
|
||||
setTimeout(function() {
|
||||
// We've added our old files and waited for a second.
|
||||
// Add a new file until the timestamp changes
|
||||
addFile(timeFile, waitForTimestampChange);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function addOldFiles() {
|
||||
i = 0;
|
||||
files = oldFiles;
|
||||
callback = afterOldFiles;
|
||||
addFile(files[0]);
|
||||
addFileArray(oldFiles, afterOldFiles);
|
||||
}
|
||||
|
||||
addOldFiles();
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
#include "mozilla/dom/quota/FileStreams.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
@ -56,6 +57,8 @@ using namespace mozilla::dom::indexedDB::ipc;
|
||||
using mozilla::dom::quota::FileOutputStream;
|
||||
using mozilla::ErrorResult;
|
||||
using mozilla::fallible_t;
|
||||
using mozilla::LittleEndian;
|
||||
using mozilla::NativeEndian;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
@ -1372,36 +1375,6 @@ IDBObjectStore::SerializeValue(JSContext* aCx,
|
||||
return buffer.write(aCx, aValue, &callbacks, &aCloneWriteInfo);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
SwapBytes(uint32_t u)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
return ((u & 0x000000ffU) << 24) |
|
||||
((u & 0x0000ff00U) << 8) |
|
||||
((u & 0x00ff0000U) >> 8) |
|
||||
((u & 0xff000000U) >> 24);
|
||||
#else
|
||||
return u;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline double
|
||||
SwapBytes(uint64_t u)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
return ((u & 0x00000000000000ffLLU) << 56) |
|
||||
((u & 0x000000000000ff00LLU) << 40) |
|
||||
((u & 0x0000000000ff0000LLU) << 24) |
|
||||
((u & 0x00000000ff000000LLU) << 8) |
|
||||
((u & 0x000000ff00000000LLU) >> 8) |
|
||||
((u & 0x0000ff0000000000LLU) >> 24) |
|
||||
((u & 0x00ff000000000000LLU) >> 40) |
|
||||
((u & 0xff00000000000000LLU) >> 56);
|
||||
#else
|
||||
return double(u);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
StructuredCloneReadString(JSStructuredCloneReader* aReader,
|
||||
nsCString& aString)
|
||||
@ -1411,7 +1384,7 @@ StructuredCloneReadString(JSStructuredCloneReader* aReader,
|
||||
NS_WARNING("Failed to read length!");
|
||||
return false;
|
||||
}
|
||||
length = SwapBytes(length);
|
||||
length = NativeEndian::swapFromLittleEndian(length);
|
||||
|
||||
if (!aString.SetLength(length, fallible_t())) {
|
||||
NS_WARNING("Out of memory?");
|
||||
@ -1474,7 +1447,7 @@ IDBObjectStore::ReadBlobOrFile(JSStructuredCloneReader* aReader,
|
||||
NS_WARNING("Failed to read size!");
|
||||
return false;
|
||||
}
|
||||
aRetval->size = SwapBytes(size);
|
||||
aRetval->size = NativeEndian::swapFromLittleEndian(size);
|
||||
|
||||
nsCString type;
|
||||
if (!StructuredCloneReadString(aReader, type)) {
|
||||
@ -1490,11 +1463,16 @@ IDBObjectStore::ReadBlobOrFile(JSStructuredCloneReader* aReader,
|
||||
NS_ASSERTION(aTag == SCTAG_DOM_FILE ||
|
||||
aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE, "Huh?!");
|
||||
|
||||
uint64_t lastModifiedDate = UINT64_MAX;
|
||||
if (aTag != SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE &&
|
||||
!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) {
|
||||
NS_WARNING("Failed to read lastModifiedDate");
|
||||
return false;
|
||||
uint64_t lastModifiedDate;
|
||||
if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) {
|
||||
lastModifiedDate = UINT64_MAX;
|
||||
}
|
||||
else {
|
||||
if(!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) {
|
||||
NS_WARNING("Failed to read lastModifiedDate");
|
||||
return false;
|
||||
}
|
||||
lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate);
|
||||
}
|
||||
aRetval->lastModifiedDate = lastModifiedDate;
|
||||
|
||||
@ -1585,6 +1563,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
cloneWriteInfo->mOffsetToKeyProp = js_GetSCOffset(aWriter);
|
||||
|
||||
uint64_t value = 0;
|
||||
// Omit endian swap
|
||||
return JS_WriteBytes(aWriter, &value, sizeof(value));
|
||||
}
|
||||
|
||||
@ -1602,10 +1581,12 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 convType(fileHandle->Type());
|
||||
uint32_t convTypeLength = SwapBytes(convType.Length());
|
||||
uint32_t convTypeLength =
|
||||
NativeEndian::swapToLittleEndian(convType.Length());
|
||||
|
||||
NS_ConvertUTF16toUTF8 convName(fileHandle->Name());
|
||||
uint32_t convNameLength = SwapBytes(convName.Length());
|
||||
uint32_t convNameLength =
|
||||
NativeEndian::swapToLittleEndian(convName.Length());
|
||||
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILEHANDLE,
|
||||
cloneWriteInfo->mFiles.Length()) ||
|
||||
@ -1660,7 +1641,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
NS_WARNING("Failed to get size!");
|
||||
return false;
|
||||
}
|
||||
size = SwapBytes(size);
|
||||
size = NativeEndian::swapToLittleEndian(size);
|
||||
|
||||
nsString type;
|
||||
if (NS_FAILED(blob->GetType(type))) {
|
||||
@ -1668,7 +1649,8 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
return false;
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 convType(type);
|
||||
uint32_t convTypeLength = SwapBytes(convType.Length());
|
||||
uint32_t convTypeLength =
|
||||
NativeEndian::swapToLittleEndian(convType.Length());
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
|
||||
|
||||
@ -1687,7 +1669,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
return false;
|
||||
}
|
||||
|
||||
lastModifiedDate = SwapBytes(lastModifiedDate);
|
||||
lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
|
||||
|
||||
nsString name;
|
||||
if (NS_FAILED(file->GetName(name))) {
|
||||
@ -1695,7 +1677,8 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
return false;
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 convName(name);
|
||||
uint32_t convNameLength = SwapBytes(convName.Length());
|
||||
uint32_t convNameLength =
|
||||
NativeEndian::swapToLittleEndian(convName.Length());
|
||||
|
||||
if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) ||
|
||||
!JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
|
||||
@ -3134,6 +3117,18 @@ NoRequestObjectStoreHelper::OnError()
|
||||
mTransaction->Abort(GetResultCode());
|
||||
}
|
||||
|
||||
// This is a duplicate of the js engine's byte munging in StructuredClone.cpp
|
||||
uint64_t
|
||||
ReinterpretDoubleAsUInt64(double d)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u;
|
||||
} pun;
|
||||
pun.d = d;
|
||||
return pun.u;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
{
|
||||
@ -3180,9 +3175,14 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
if (mObjectStore->IsAutoIncrement()) {
|
||||
if (keyUnset) {
|
||||
autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId;
|
||||
|
||||
MOZ_ASSERT(autoIncrementNum > 0,
|
||||
"Generated key must always be a positive integer");
|
||||
|
||||
if (autoIncrementNum > (1LL << 53)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
mKey.SetFromInteger(autoIncrementNum);
|
||||
}
|
||||
else if (mKey.IsFloat() &&
|
||||
@ -3195,18 +3195,10 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
// objectStore with no key in its keyPath set. We needed to figure out
|
||||
// which row id we would get above before we could set that properly.
|
||||
|
||||
// This is a duplicate of the js engine's byte munging here
|
||||
union {
|
||||
double d;
|
||||
uint64_t u;
|
||||
} pun;
|
||||
|
||||
pun.d = SwapBytes(static_cast<uint64_t>(autoIncrementNum));
|
||||
|
||||
JSAutoStructuredCloneBuffer& buffer = mCloneWriteInfo.mCloneBuffer;
|
||||
uint64_t offsetToKeyProp = mCloneWriteInfo.mOffsetToKeyProp;
|
||||
|
||||
memcpy((char*)buffer.data() + offsetToKeyProp, &pun.u, sizeof(uint64_t));
|
||||
LittleEndian::writeUint64((char*)mCloneWriteInfo.mCloneBuffer.data() +
|
||||
mCloneWriteInfo.mOffsetToKeyProp,
|
||||
ReinterpretDoubleAsUInt64(static_cast<double>(
|
||||
autoIncrementNum)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,10 +121,6 @@ using namespace mozilla::system;
|
||||
#include "BluetoothService.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
|
||||
#include "JavaScriptParent.h"
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
@ -140,8 +136,6 @@ using namespace mozilla::system;
|
||||
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
|
||||
static const char* sClipboardTextFlavors[] = { kUnicodeMime };
|
||||
|
||||
#define NUWA_FORK_WAIT_DURATION_MS 2000 // 2 seconds.
|
||||
|
||||
using base::ChildPrivileges;
|
||||
using base::KillProcess;
|
||||
using namespace mozilla::dom::bluetooth;
|
||||
@ -273,32 +267,16 @@ static bool sCanLaunchSubprocesses;
|
||||
// The first content child has ID 1, so the chrome process can have ID 0.
|
||||
static uint64_t gContentChildID = 1;
|
||||
|
||||
|
||||
// sNuwaProcess points to the Nuwa process which is used for forking new
|
||||
// processes later.
|
||||
static StaticRefPtr<ContentParent> sNuwaProcess;
|
||||
// Nuwa process is ready for creating new process.
|
||||
static bool sNuwaReady = false;
|
||||
// The array containing the preallocated processes. 4 as the inline storage size
|
||||
// should be enough so we don't need to grow the nsAutoTArray.
|
||||
static StaticAutoPtr<nsAutoTArray<nsRefPtr<ContentParent>, 4> > sSpareProcesses;
|
||||
static StaticAutoPtr<nsTArray<CancelableTask*> > sNuwaForkWaitTasks;
|
||||
|
||||
// We want the prelaunched process to know that it's for apps, but not
|
||||
// actually for any app in particular. Use a magic manifest URL.
|
||||
// Can't be a static constant.
|
||||
#define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
|
||||
|
||||
void
|
||||
/* static */ already_AddRefed<ContentParent>
|
||||
ContentParent::RunNuwaProcess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sNuwaProcess) {
|
||||
NS_RUNTIMEABORT("sNuwaProcess is created twice.");
|
||||
}
|
||||
|
||||
sNuwaProcess =
|
||||
nsRefPtr<ContentParent> nuwaProcess =
|
||||
new ContentParent(/* aApp = */ nullptr,
|
||||
/* aIsForBrowser = */ false,
|
||||
/* aIsForPreallocated = */ true,
|
||||
@ -307,109 +285,10 @@ ContentParent::RunNuwaProcess()
|
||||
base::PRIVILEGES_INHERIT,
|
||||
PROCESS_PRIORITY_BACKGROUND,
|
||||
/* aIsNuwaProcess = */ true);
|
||||
sNuwaProcess->Init();
|
||||
nuwaProcess->Init();
|
||||
return nuwaProcess.forget();
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// initialization off the critical path of app startup.
|
||||
static CancelableTask* sPreallocateAppProcessTask;
|
||||
// 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.
|
||||
static int sPreallocateDelayMs = 1000;
|
||||
|
||||
static void
|
||||
DelayedNuwaFork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
sPreallocateAppProcessTask = nullptr;
|
||||
|
||||
if (!sNuwaReady) {
|
||||
if (!sNuwaProcess) {
|
||||
ContentParent::RunNuwaProcess();
|
||||
}
|
||||
// else sNuwaProcess is starting. It will SendNuwaFork() when ready.
|
||||
} else if (sSpareProcesses->IsEmpty()) {
|
||||
sNuwaProcess->SendNuwaFork();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ScheduleDelayedNuwaFork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sPreallocateAppProcessTask) {
|
||||
// Make sure there is only one request running.
|
||||
return;
|
||||
}
|
||||
|
||||
sPreallocateAppProcessTask = NewRunnableFunction(DelayedNuwaFork);
|
||||
MessageLoop::current()->
|
||||
PostDelayedTask(FROM_HERE,
|
||||
sPreallocateAppProcessTask,
|
||||
sPreallocateDelayMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a spare ContentParent from sSpareProcesses list.
|
||||
*/
|
||||
static already_AddRefed<ContentParent>
|
||||
GetSpareProcess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sSpareProcesses->IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<ContentParent> process = sSpareProcesses->LastElement();
|
||||
sSpareProcesses->RemoveElementAt(sSpareProcesses->Length() - 1);
|
||||
|
||||
if (sSpareProcesses->IsEmpty() && sNuwaReady) {
|
||||
NS_ASSERTION(sNuwaProcess != nullptr,
|
||||
"Nuwa process is not present!");
|
||||
ScheduleDelayedNuwaFork();
|
||||
}
|
||||
|
||||
return process.forget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a ContentParent to spare process list.
|
||||
*/
|
||||
static void
|
||||
PublishSpareProcess(ContentParent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sNuwaForkWaitTasks->IsEmpty()) {
|
||||
sNuwaForkWaitTasks->ElementAt(0)->Cancel();
|
||||
sNuwaForkWaitTasks->RemoveElementAt(0);
|
||||
}
|
||||
|
||||
sSpareProcesses->AppendElement(aContent);
|
||||
}
|
||||
|
||||
static void
|
||||
MaybeForgetSpare(ContentParent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sSpareProcesses->RemoveElement(aContent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aContent == sNuwaProcess) {
|
||||
sNuwaProcess = nullptr;
|
||||
sNuwaReady = false;
|
||||
ScheduleDelayedNuwaFork();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// PreallocateAppProcess is called by the PreallocatedProcessManager.
|
||||
// ContentParent then takes this process back within
|
||||
// MaybeTakePreallocatedAppProcess.
|
||||
@ -433,11 +312,7 @@ ContentParent::MaybeTakePreallocatedAppProcess(const nsAString& aAppManifestURL,
|
||||
ChildPrivileges aPrivs,
|
||||
ProcessPriority aInitialPriority)
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
nsRefPtr<ContentParent> process = GetSpareProcess();
|
||||
#else
|
||||
nsRefPtr<ContentParent> process = PreallocatedProcessManager::Take();
|
||||
#endif
|
||||
if (!process) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -464,17 +339,8 @@ ContentParent::StartUp()
|
||||
|
||||
sCanLaunchSubprocesses = true;
|
||||
|
||||
sSpareProcesses = new nsAutoTArray<nsRefPtr<ContentParent>, 4>();
|
||||
ClearOnShutdown(&sSpareProcesses);
|
||||
|
||||
sNuwaForkWaitTasks = new nsTArray<CancelableTask*>();
|
||||
ClearOnShutdown(&sNuwaForkWaitTasks);
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
ScheduleDelayedNuwaFork();
|
||||
#else
|
||||
// Try to preallocate a process that we can transform into an app later.
|
||||
PreallocatedProcessManager::AllocateAfterDelay();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
@ -1027,25 +893,13 @@ ContentParent::MarkAsDead()
|
||||
mIsAlive = false;
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::OnNuwaForkTimeout()
|
||||
{
|
||||
if (!sNuwaForkWaitTasks->IsEmpty()) {
|
||||
sNuwaForkWaitTasks->RemoveElementAt(0);
|
||||
}
|
||||
|
||||
// We haven't RecvAddNewProcess() after SendNuwaFork(). Maybe the main
|
||||
// thread of the Nuwa process is in deadlock.
|
||||
MOZ_ASSERT(false, "Can't fork from the nuwa process.");
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::OnChannelError()
|
||||
{
|
||||
nsRefPtr<ContentParent> content(this);
|
||||
PContentParent::OnChannelError();
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
MaybeForgetSpare(this);
|
||||
PreallocatedProcessManager::MaybeForgetSpare(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1801,19 +1655,12 @@ ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
|
||||
bool
|
||||
ContentParent::RecvFirstIdle()
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (sSpareProcesses->IsEmpty() && sNuwaReady) {
|
||||
ScheduleDelayedNuwaFork();
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
// When the ContentChild goes idle, it sends us a FirstIdle message
|
||||
// which we use as a good time to prelaunch another process. If we
|
||||
// prelaunch any sooner than this, then we'll be competing with the
|
||||
// child process and slowing it down.
|
||||
PreallocatedProcessManager::AllocateAfterDelay();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1897,34 +1744,16 @@ ContentParent::RecvBroadcastVolume(const nsString& aVolumeName)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::SendNuwaFork()
|
||||
{
|
||||
if (this != sNuwaProcess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CancelableTask* nuwaForkTimeoutTask = NewRunnableMethod(
|
||||
this, &ContentParent::OnNuwaForkTimeout);
|
||||
sNuwaForkWaitTasks->AppendElement(nuwaForkTimeoutTask);
|
||||
|
||||
MessageLoop::current()->
|
||||
PostDelayedTask(FROM_HERE,
|
||||
nuwaForkTimeoutTask,
|
||||
NUWA_FORK_WAIT_DURATION_MS);
|
||||
|
||||
return PContentParent::SendNuwaFork();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvNuwaReady()
|
||||
{
|
||||
NS_ASSERTION(!sNuwaReady, "Multiple Nuwa processes created!");
|
||||
ProcessPriorityManager::SetProcessPriority(sNuwaProcess,
|
||||
hal::PROCESS_PRIORITY_FOREGROUND);
|
||||
sNuwaReady = true;
|
||||
SendNuwaFork();
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
PreallocatedProcessManager::OnNuwaReady();
|
||||
return true;
|
||||
#else
|
||||
NS_ERROR("ContentParent::RecvNuwaReady() not implemented!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1939,7 +1768,7 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
aFds,
|
||||
base::PRIVILEGES_DEFAULT);
|
||||
content->Init();
|
||||
PublishSpareProcess(content);
|
||||
PreallocatedProcessManager::PublishSpareProcess(content);
|
||||
return true;
|
||||
#else
|
||||
NS_ERROR("ContentParent::RecvAddNewProcess() not implemented!");
|
||||
|
@ -92,7 +92,7 @@ public:
|
||||
*/
|
||||
static already_AddRefed<ContentParent> PreallocateAppProcess();
|
||||
|
||||
static void RunNuwaProcess();
|
||||
static already_AddRefed<ContentParent> RunNuwaProcess();
|
||||
|
||||
/**
|
||||
* Get or create a content process for the given TabContext. aFrameElement
|
||||
@ -209,8 +209,6 @@ public:
|
||||
return PContentParent::RecvPJavaScriptConstructor(aActor);
|
||||
}
|
||||
|
||||
virtual bool SendNuwaFork();
|
||||
|
||||
protected:
|
||||
void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
|
||||
virtual void ActorDestroy(ActorDestroyReason why);
|
||||
|
@ -9,6 +9,19 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "ProcessPriorityManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.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.
|
||||
#define DEFAULT_ALLOCATE_DELAY 1000
|
||||
#define NUWA_FORK_WAIT_DURATION_MS 2000 // 2 seconds.
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::hal;
|
||||
@ -35,6 +48,31 @@ public:
|
||||
void AllocateNow();
|
||||
already_AddRefed<ContentParent> Take();
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
public:
|
||||
void ScheduleDelayedNuwaFork();
|
||||
void DelayedNuwaFork();
|
||||
void PublishSpareProcess(ContentParent* aContent);
|
||||
void MaybeForgetSpare(ContentParent* aContent);
|
||||
void OnNuwaReady();
|
||||
already_AddRefed<ContentParent> GetSpareProcess();
|
||||
|
||||
private:
|
||||
void OnNuwaForkTimeout();
|
||||
void NuwaFork();
|
||||
|
||||
// initialization off the critical path of app startup.
|
||||
CancelableTask* mPreallocateAppProcessTask;
|
||||
|
||||
// The array containing the preallocated processes. 4 as the inline storage size
|
||||
// should be enough so we don't need to grow the nsAutoTArray.
|
||||
nsAutoTArray<nsRefPtr<ContentParent>, 4> mSpareProcesses;
|
||||
nsTArray<CancelableTask*> mNuwaForkWaitTasks;
|
||||
|
||||
// Nuwa process is ready for creating new process.
|
||||
bool mIsNuwaReady;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static mozilla::StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;
|
||||
|
||||
@ -72,6 +110,10 @@ NS_IMPL_ISUPPORTS1(PreallocatedProcessManagerImpl, nsIObserver)
|
||||
|
||||
PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
|
||||
: mEnabled(false)
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
, mPreallocateAppProcessTask(nullptr)
|
||||
, mIsNuwaReady(false)
|
||||
#endif
|
||||
{}
|
||||
|
||||
void
|
||||
@ -127,7 +169,11 @@ PreallocatedProcessManagerImpl::Enable()
|
||||
}
|
||||
|
||||
mEnabled = true;
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
ScheduleDelayedNuwaFork();
|
||||
#else
|
||||
AllocateAfterDelay();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -140,7 +186,8 @@ PreallocatedProcessManagerImpl::AllocateAfterDelay()
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateOnIdle),
|
||||
Preferences::GetUint("dom.ipc.processPrelaunch.delayMs", 1000));
|
||||
Preferences::GetUint("dom.ipc.processPrelaunch.delayMs",
|
||||
DEFAULT_ALLOCATE_DELAY));
|
||||
}
|
||||
|
||||
void
|
||||
@ -165,6 +212,135 @@ PreallocatedProcessManagerImpl::AllocateNow()
|
||||
mPreallocatedAppProcess = ContentParent::PreallocateAppProcess();
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::ScheduleDelayedNuwaFork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mPreallocateAppProcessTask) {
|
||||
// Make sure there is only one request running.
|
||||
return;
|
||||
}
|
||||
|
||||
mPreallocateAppProcessTask = NewRunnableMethod(
|
||||
this, &PreallocatedProcessManagerImpl::DelayedNuwaFork);
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE, mPreallocateAppProcessTask,
|
||||
Preferences::GetUint("dom.ipc.processPrelaunch.delayMs",
|
||||
DEFAULT_ALLOCATE_DELAY));
|
||||
}
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::DelayedNuwaFork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mPreallocateAppProcessTask = nullptr;
|
||||
|
||||
if (!mIsNuwaReady) {
|
||||
if (!mPreallocatedAppProcess) {
|
||||
mPreallocatedAppProcess = ContentParent::RunNuwaProcess();
|
||||
}
|
||||
// else mPreallocatedAppProcess is starting. It will NuwaFork() when ready.
|
||||
} else if (mSpareProcesses.IsEmpty()) {
|
||||
NuwaFork();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a spare ContentParent from mSpareProcesses list.
|
||||
*/
|
||||
already_AddRefed<ContentParent>
|
||||
PreallocatedProcessManagerImpl::GetSpareProcess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mSpareProcesses.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<ContentParent> process = mSpareProcesses.LastElement();
|
||||
mSpareProcesses.RemoveElementAt(mSpareProcesses.Length() - 1);
|
||||
|
||||
if (mSpareProcesses.IsEmpty() && mIsNuwaReady) {
|
||||
NS_ASSERTION(mPreallocatedAppProcess != nullptr,
|
||||
"Nuwa process is not present!");
|
||||
ScheduleDelayedNuwaFork();
|
||||
}
|
||||
|
||||
return process.forget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a ContentParent to spare process list.
|
||||
*/
|
||||
void
|
||||
PreallocatedProcessManagerImpl::PublishSpareProcess(ContentParent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mNuwaForkWaitTasks.IsEmpty()) {
|
||||
mNuwaForkWaitTasks.ElementAt(0)->Cancel();
|
||||
mNuwaForkWaitTasks.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
mSpareProcesses.AppendElement(aContent);
|
||||
}
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::MaybeForgetSpare(ContentParent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mSpareProcesses.RemoveElement(aContent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aContent == mPreallocatedAppProcess) {
|
||||
mPreallocatedAppProcess = nullptr;
|
||||
mIsNuwaReady = false;
|
||||
ScheduleDelayedNuwaFork();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::OnNuwaReady()
|
||||
{
|
||||
NS_ASSERTION(!mIsNuwaReady, "Multiple Nuwa processes created!");
|
||||
ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess,
|
||||
hal::PROCESS_PRIORITY_FOREGROUND);
|
||||
mIsNuwaReady = true;
|
||||
NuwaFork();
|
||||
}
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::OnNuwaForkTimeout()
|
||||
{
|
||||
if (!mNuwaForkWaitTasks.IsEmpty()) {
|
||||
mNuwaForkWaitTasks.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
// We haven't RecvAddNewProcess() after NuwaFork(). Maybe the main
|
||||
// thread of the Nuwa process is in deadlock.
|
||||
MOZ_ASSERT(false, "Can't fork from the nuwa process.");
|
||||
}
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::NuwaFork()
|
||||
{
|
||||
CancelableTask* nuwaForkTimeoutTask = NewRunnableMethod(
|
||||
this, &PreallocatedProcessManagerImpl::OnNuwaForkTimeout);
|
||||
mNuwaForkWaitTasks.AppendElement(nuwaForkTimeoutTask);
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
nuwaForkTimeoutTask,
|
||||
NUWA_FORK_WAIT_DURATION_MS);
|
||||
mPreallocatedAppProcess->SendNuwaFork();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::Disable()
|
||||
{
|
||||
@ -174,8 +350,24 @@ PreallocatedProcessManagerImpl::Disable()
|
||||
|
||||
mEnabled = false;
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// Cancel pending fork.
|
||||
if (mPreallocateAppProcessTask) {
|
||||
mPreallocateAppProcessTask->Cancel();
|
||||
mPreallocateAppProcessTask = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mPreallocatedAppProcess) {
|
||||
mPreallocatedAppProcess->ShutDown();
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
while (mSpareProcesses.Length() > 0){
|
||||
nsRefPtr<ContentParent> process = mSpareProcesses[0];
|
||||
process->Close();
|
||||
mSpareProcesses.RemoveElementAt(0);
|
||||
}
|
||||
mIsNuwaReady = false;
|
||||
#endif
|
||||
mPreallocatedAppProcess->Close();
|
||||
mPreallocatedAppProcess = nullptr;
|
||||
}
|
||||
}
|
||||
@ -199,6 +391,11 @@ PreallocatedProcessManagerImpl::ObserveProcessShutdown(nsISupports* aSubject)
|
||||
}
|
||||
}
|
||||
|
||||
inline PreallocatedProcessManagerImpl* GetPPMImpl()
|
||||
{
|
||||
return PreallocatedProcessManagerImpl::Singleton();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
@ -206,25 +403,53 @@ namespace mozilla {
|
||||
/* static */ void
|
||||
PreallocatedProcessManager::AllocateAfterDelay()
|
||||
{
|
||||
PreallocatedProcessManagerImpl::Singleton()->AllocateAfterDelay();
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
GetPPMImpl()->ScheduleDelayedNuwaFork();
|
||||
#else
|
||||
GetPPMImpl()->AllocateAfterDelay();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PreallocatedProcessManager::AllocateOnIdle()
|
||||
{
|
||||
PreallocatedProcessManagerImpl::Singleton()->AllocateOnIdle();
|
||||
GetPPMImpl()->AllocateOnIdle();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PreallocatedProcessManager::AllocateNow()
|
||||
{
|
||||
PreallocatedProcessManagerImpl::Singleton()->AllocateNow();
|
||||
GetPPMImpl()->AllocateNow();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<ContentParent>
|
||||
PreallocatedProcessManager::Take()
|
||||
{
|
||||
return PreallocatedProcessManagerImpl::Singleton()->Take();
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
return GetPPMImpl()->GetSpareProcess();
|
||||
#else
|
||||
return GetPPMImpl()->Take();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
/* static */ void
|
||||
PreallocatedProcessManager::PublishSpareProcess(ContentParent* aContent)
|
||||
{
|
||||
GetPPMImpl()->PublishSpareProcess(aContent);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PreallocatedProcessManager::MaybeForgetSpare(ContentParent* aContent)
|
||||
{
|
||||
GetPPMImpl()->MaybeForgetSpare(aContent);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PreallocatedProcessManager::OnNuwaReady()
|
||||
{
|
||||
GetPPMImpl()->OnNuwaReady();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -78,6 +78,12 @@ public:
|
||||
*/
|
||||
static already_AddRefed<ContentParent> Take();
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
static void PublishSpareProcess(ContentParent* aContent);
|
||||
static void MaybeForgetSpare(ContentParent* aContent);
|
||||
static void OnNuwaReady();
|
||||
#endif
|
||||
|
||||
private:
|
||||
PreallocatedProcessManager();
|
||||
DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManager);
|
||||
|
@ -829,7 +829,6 @@ RTCError.prototype = {
|
||||
// This is a separate object because we don't want to expose it to DOM.
|
||||
function PeerConnectionObserver() {
|
||||
this._dompc = null;
|
||||
this._guard = new WeakReferent(this);
|
||||
}
|
||||
PeerConnectionObserver.prototype = {
|
||||
classDescription: "PeerConnectionObserver",
|
||||
@ -1127,20 +1126,6 @@ PeerConnectionObserver.prototype = {
|
||||
getSupportedConstraints: function(dict) {
|
||||
return dict;
|
||||
},
|
||||
|
||||
get weakReferent() {
|
||||
return this._guard;
|
||||
}
|
||||
};
|
||||
|
||||
// A PeerConnectionObserver member that c++ can do weak references on
|
||||
|
||||
function WeakReferent(parent) {
|
||||
this._parent = parent; // prevents parent from going away without us
|
||||
}
|
||||
WeakReferent.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
|
@ -23,7 +23,7 @@ dictionary MmsDeliveryInfo
|
||||
// |delivery| = "received" or not yet delivered).
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(3593c914-420a-11e3-a297-a3bdd768257f)]
|
||||
[scriptable, builtinclass, uuid(82ca2465-f967-4107-a4da-65b7a15d5dba)]
|
||||
interface nsIDOMMozMmsMessage : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -71,5 +71,5 @@ interface nsIDOMMozMmsMessage : nsISupports
|
||||
// manually downloaded.
|
||||
|
||||
// Request read report from sender or not.
|
||||
readonly attribute boolean isReadReportRequested;
|
||||
readonly attribute boolean readReportRequested;
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ interface nsIDOMMozSmsSegmentInfo;
|
||||
#define MOBILE_MESSAGE_SERVICE_CONTRACTID "@mozilla.org/mobilemessage/mobilemessageservice;1"
|
||||
%}
|
||||
|
||||
[scriptable, builtinclass, uuid(c9a1aa14-7088-4f22-9d7f-b0c6ce9cf484)]
|
||||
[scriptable, builtinclass, uuid(7255f557-0dd1-42f9-82fa-031cebb76bb5)]
|
||||
interface nsIMobileMessageService : nsISupports
|
||||
{
|
||||
[implicit_jscontext]
|
||||
@ -45,7 +45,7 @@ interface nsIMobileMessageService : nsISupports
|
||||
in DOMString smil,
|
||||
in jsval attachments,
|
||||
in jsval expiryDate,
|
||||
in boolean isReadReportRequested);
|
||||
in boolean readReportRequested);
|
||||
|
||||
nsIDOMMozSmsSegmentInfo createSmsSegmentInfo(in long segments,
|
||||
in long charsPerSegment,
|
||||
|
@ -47,7 +47,7 @@ MmsMessage::MmsMessage(int32_t aId,
|
||||
const nsAString& aSmil,
|
||||
const nsTArray<MmsAttachment>& aAttachments,
|
||||
uint64_t aExpiryDate,
|
||||
bool aIsReadReportRequested)
|
||||
bool aReadReportRequested)
|
||||
: mId(aId),
|
||||
mThreadId(aThreadId),
|
||||
mIccId(aIccId),
|
||||
@ -61,7 +61,7 @@ MmsMessage::MmsMessage(int32_t aId,
|
||||
mSmil(aSmil),
|
||||
mAttachments(aAttachments),
|
||||
mExpiryDate(aExpiryDate),
|
||||
mIsReadReportRequested(aIsReadReportRequested)
|
||||
mReadReportRequested(aReadReportRequested)
|
||||
{
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData)
|
||||
, mSubject(aData.subject())
|
||||
, mSmil(aData.smil())
|
||||
, mExpiryDate(aData.expiryDate())
|
||||
, mIsReadReportRequested(aData.isReadReportRequested())
|
||||
, mReadReportRequested(aData.readReportRequested())
|
||||
{
|
||||
uint32_t len = aData.attachments().Length();
|
||||
mAttachments.SetCapacity(len);
|
||||
@ -339,7 +339,7 @@ MmsMessage::GetData(ContentParent* aParent,
|
||||
aData.subject() = mSubject;
|
||||
aData.smil() = mSmil;
|
||||
aData.expiryDate() = mExpiryDate;
|
||||
aData.isReadReportRequested() = mIsReadReportRequested;
|
||||
aData.readReportRequested() = mReadReportRequested;
|
||||
|
||||
aData.deliveryInfo().SetCapacity(mDeliveryInfo.Length());
|
||||
for (uint32_t i = 0; i < mDeliveryInfo.Length(); i++) {
|
||||
@ -658,9 +658,9 @@ MmsMessage::GetExpiryDate(JSContext* cx, JS::Value* aDate)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MmsMessage::GetIsReadReportRequested(bool* aIsReadReportRequested)
|
||||
MmsMessage::GetReadReportRequested(bool* aReadReportRequested)
|
||||
{
|
||||
*aIsReadReportRequested = mIsReadReportRequested;
|
||||
*aReadReportRequested = mReadReportRequested;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
const nsAString& aSmil,
|
||||
const nsTArray<idl::MmsAttachment>& aAttachments,
|
||||
uint64_t aExpiryDate,
|
||||
bool aIsReadReportRequested);
|
||||
bool aReadReportRequested);
|
||||
|
||||
MmsMessage(const mobilemessage::MmsMessageData& aData);
|
||||
|
||||
@ -57,7 +57,7 @@ public:
|
||||
const nsAString& aSmil,
|
||||
const JS::Value& aAttachments,
|
||||
const JS::Value& aExpiryDate,
|
||||
bool aIsReadReportRequested,
|
||||
bool aReadReportRequested,
|
||||
JSContext* aCx,
|
||||
nsIDOMMozMmsMessage** aMessage);
|
||||
|
||||
@ -79,7 +79,7 @@ private:
|
||||
nsString mSmil;
|
||||
nsTArray<idl::MmsAttachment> mAttachments;
|
||||
uint64_t mExpiryDate;
|
||||
bool mIsReadReportRequested;
|
||||
bool mReadReportRequested;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -74,7 +74,7 @@ MobileMessageService::CreateMmsMessage(int32_t aId,
|
||||
const nsAString& aSmil,
|
||||
const JS::Value& aAttachments,
|
||||
const JS::Value& aExpiryDate,
|
||||
bool aIsReadReportRequested,
|
||||
bool aReadReportRequested,
|
||||
JSContext* aCx,
|
||||
nsIDOMMozMmsMessage** aMessage)
|
||||
{
|
||||
@ -91,7 +91,7 @@ MobileMessageService::CreateMmsMessage(int32_t aId,
|
||||
aSmil,
|
||||
aAttachments,
|
||||
aExpiryDate,
|
||||
aIsReadReportRequested,
|
||||
aReadReportRequested,
|
||||
aCx,
|
||||
aMessage);
|
||||
}
|
||||
|
@ -1290,7 +1290,7 @@ MobileMessageDatabaseService.prototype = {
|
||||
if (headers["x-mms-expiry"] != undefined) {
|
||||
expiryDate = aMessageRecord.timestamp + headers["x-mms-expiry"] * 1000;
|
||||
}
|
||||
let isReadReportRequested = headers["x-mms-read-report"] || false;
|
||||
let readReportRequested = headers["x-mms-read-report"] || false;
|
||||
return gMobileMessageService.createMmsMessage(aMessageRecord.id,
|
||||
aMessageRecord.threadId,
|
||||
aMessageRecord.iccId,
|
||||
@ -1304,7 +1304,7 @@ MobileMessageDatabaseService.prototype = {
|
||||
smil,
|
||||
attachments,
|
||||
expiryDate,
|
||||
isReadReportRequested);
|
||||
readReportRequested);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -68,7 +68,7 @@ struct MmsMessageData
|
||||
nsString smil;
|
||||
MmsAttachmentData[] attachments;
|
||||
uint64_t expiryDate;
|
||||
bool isReadReportRequested;
|
||||
bool readReportRequested;
|
||||
};
|
||||
|
||||
union MobileMessageData
|
||||
|
@ -16,7 +16,7 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
const DB_NAME = "net_stats";
|
||||
const DB_VERSION = 3;
|
||||
const DB_VERSION = 4;
|
||||
const STORE_NAME = "net_stats";
|
||||
|
||||
// Constant defining the maximum values allowed per interface. If more, older
|
||||
@ -92,6 +92,34 @@ NetworkStatsDB.prototype = {
|
||||
if (DEBUG) {
|
||||
debug("Created object stores and indexes for version 3");
|
||||
}
|
||||
} else if (currVersion == 3) {
|
||||
// Delete redundent indexes (leave "network" only).
|
||||
objectStore = aTransaction.objectStore(STORE_NAME);
|
||||
if (objectStore.indexNames.contains("appId")) {
|
||||
objectStore.deleteIndex("appId");
|
||||
}
|
||||
if (objectStore.indexNames.contains("networkType")) {
|
||||
objectStore.deleteIndex("networkType");
|
||||
}
|
||||
if (objectStore.indexNames.contains("timestamp")) {
|
||||
objectStore.deleteIndex("timestamp");
|
||||
}
|
||||
if (objectStore.indexNames.contains("rxBytes")) {
|
||||
objectStore.deleteIndex("rxBytes");
|
||||
}
|
||||
if (objectStore.indexNames.contains("txBytes")) {
|
||||
objectStore.deleteIndex("txBytes");
|
||||
}
|
||||
if (objectStore.indexNames.contains("rxTotalBytes")) {
|
||||
objectStore.deleteIndex("rxTotalBytes");
|
||||
}
|
||||
if (objectStore.indexNames.contains("txTotalBytes")) {
|
||||
objectStore.deleteIndex("txTotalBytes");
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
debug("Deleted redundent indexes for version 4");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -9,24 +9,60 @@
|
||||
|
||||
<body onload="run()">
|
||||
<script class="testbody" type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
|
||||
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||
|
||||
function findPlugin(pluginName) {
|
||||
for (var i = 0; i < navigator.plugins.length; i++) {
|
||||
var plugin = navigator.plugins[i];
|
||||
if (plugin.name === pluginName) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findMimeType(mimeTypeType) {
|
||||
for (var i = 0; i < navigator.mimeTypes.length; i++) {
|
||||
var mimeType = navigator.mimeTypes[i];
|
||||
if (mimeType.type === mimeTypeType) {
|
||||
return mimeType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function run() {
|
||||
var foundFirstPlugin = false;
|
||||
var foundSecondPlugin = false;
|
||||
for (var index in navigator.plugins) {
|
||||
var plugin = navigator.plugins[index];
|
||||
if (plugin.name == "Test Plug-in") foundFirstPlugin = true;
|
||||
if (plugin.name == "Second Test Plug-in") foundSecondPlugin = true;
|
||||
}
|
||||
ok(foundFirstPlugin, "Should have a plugin named 'Test Plug-in'");
|
||||
ok(foundSecondPlugin, "Should have a plugin named 'Second Test Plug-in'");
|
||||
// Add "Test Plug-in" (but not "Second Test Plug-in") to the list of
|
||||
// unhidden plugins. This test must modify the "plugins.enumerable_names"
|
||||
// pref BEFORE accessing the navigator.plugins or navigator.mimeTypes
|
||||
// arrays because they only read the pref when they first initialize
|
||||
// their internal arrays!
|
||||
var prefs = SpecialPowers.Cc["@mozilla.org/preferences-service;1"].getService(SpecialPowers.Ci.nsIPrefBranch);
|
||||
var defaultEnumerableNamesPref = prefs.getCharPref("plugins.enumerable_names");
|
||||
prefs.setCharPref("plugins.enumerable_names", defaultEnumerableNamesPref + ",Test Plug-in");
|
||||
|
||||
var pluginElement = document.getElementById("plugin");
|
||||
is(pluginElement.identifierToStringTest("foo"), "foo", "Should be able to call a function provided by the plugin");
|
||||
|
||||
ok(navigator.plugins["Test Plug-in"], "Should have queried a non-hidden plugin named 'Test Plug-in'");
|
||||
ok(navigator.plugins["Second Test Plug-in"], "Should have queried a hidden plugin named 'Test Plug-in'");
|
||||
|
||||
ok(findPlugin("Test Plug-in"), "Should have found a non-hidden plugin named 'Test Plug-in'");
|
||||
ok(!findPlugin("Second Test Plug-in"), "Should NOT found a hidden plugin named 'Test Plug-in'");
|
||||
|
||||
ok(navigator.mimeTypes["application/x-test"], "Should have queried a non-hidden MIME type named 'application/x-test'");
|
||||
ok(navigator.mimeTypes["application/x-second-test"], "Should have queried a MIME type named 'application/x-second-test'");
|
||||
|
||||
ok(findMimeType("application/x-test"), "Should have found a non-hidden MIME type named 'application/x-test'");
|
||||
ok(!findMimeType("application/x-second-test"), "Should NOT have found a MIME type named 'application/x-second-test'");
|
||||
|
||||
// Restore original pref to hide "Test Plug-in" and "Second Test Plug-in".
|
||||
prefs.setCharPref("plugins.enumerable_names", defaultEnumerableNamesPref);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
|
@ -574,20 +574,23 @@ AudioManager::SetFmRadioAudioEnabled(bool aFmRadioAudioEnabled)
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::SetAudioChannelVolume(int32_t aChannel, int32_t aIndex) {
|
||||
status_t status;
|
||||
nsresult status;
|
||||
|
||||
switch (aChannel) {
|
||||
case AUDIO_CHANNEL_CONTENT:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_MUSIC, aIndex);
|
||||
status += SetStreamVolumeIndex(AUDIO_STREAM_SYSTEM, aIndex);
|
||||
// sync FMRadio's volume with content channel.
|
||||
if (IsDeviceOn(AUDIO_DEVICE_OUT_FM)) {
|
||||
status += SetStreamVolumeIndex(AUDIO_STREAM_FM, aIndex);
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_FM, aIndex);
|
||||
NS_ENSURE_SUCCESS(status, status);
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_MUSIC, aIndex);
|
||||
NS_ENSURE_SUCCESS(status, status);
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_SYSTEM, aIndex);
|
||||
break;
|
||||
case AUDIO_CHANNEL_NOTIFICATION:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_NOTIFICATION, aIndex);
|
||||
status += SetStreamVolumeIndex(AUDIO_STREAM_RING, aIndex);
|
||||
NS_ENSURE_SUCCESS(status, status);
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_RING, aIndex);
|
||||
break;
|
||||
case AUDIO_CHANNEL_ALARM:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_ALARM, aIndex);
|
||||
@ -599,7 +602,7 @@ AudioManager::SetAudioChannelVolume(int32_t aChannel, int32_t aIndex) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -664,17 +667,19 @@ AudioManager::GetMaxAudioChannelVolume(int32_t aChannel, int32_t* aMaxIndex) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
nsresult
|
||||
AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) {
|
||||
if (aIndex < 0 || aIndex > sMaxStreamVolumeTbl[aStream]) {
|
||||
return BAD_VALUE;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mCurrentStreamVolumeTbl[aStream] = aIndex;
|
||||
status_t status;
|
||||
#if ANDROID_VERSION < 17
|
||||
return AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex);
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex);
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
#else
|
||||
int device = 0;
|
||||
|
||||
@ -685,16 +690,21 @@ AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) {
|
||||
}
|
||||
|
||||
if (device != 0) {
|
||||
return AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
device);
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
device);
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
status_t status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_SPEAKER);
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_SPEAKER);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
@ -707,21 +717,21 @@ AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) {
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_EARPIECE);
|
||||
return status;
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
status_t
|
||||
nsresult
|
||||
AudioManager::GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex) {
|
||||
if (!aIndex) {
|
||||
return BAD_VALUE;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) {
|
||||
return BAD_VALUE;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aIndex = mCurrentStreamVolumeTbl[aStream];
|
||||
|
||||
return NO_ERROR;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -60,8 +60,8 @@ protected:
|
||||
int32_t mPhoneState;
|
||||
int mCurrentStreamVolumeTbl[AUDIO_STREAM_CNT];
|
||||
|
||||
android::status_t SetStreamVolumeIndex(int32_t aStream, int32_t aIndex);
|
||||
android::status_t GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex);
|
||||
nsresult SetStreamVolumeIndex(int32_t aStream, int32_t aIndex);
|
||||
nsresult GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex);
|
||||
|
||||
private:
|
||||
nsAutoPtr<mozilla::hal::SwitchObserver> mObserver;
|
||||
|
@ -935,6 +935,9 @@ function RadioInterface(options) {
|
||||
lock.get("ril.data.enabled", this);
|
||||
lock.get("ril.data.apnSettings", this);
|
||||
|
||||
// Read the default client id for data call.
|
||||
lock.get("ril.data.defaultServiceId", this);
|
||||
|
||||
// Read the "time.clock.automatic-update.enabled" setting to see if
|
||||
// we need to adjust the system clock time by NITZ or SNTP.
|
||||
lock.get(kSettingsClockAutoUpdateEnabled, this);
|
||||
@ -1742,6 +1745,34 @@ RadioInterface.prototype = {
|
||||
apnSetting.types.length);
|
||||
},
|
||||
|
||||
handleDataClientIdChange: function handleDataClientIdChange() {
|
||||
// Default data has been switched to the current RadioInterface.
|
||||
// If there is an active default data call, wait for it to get
|
||||
// disconnected, otherwise connect directly.
|
||||
if (this.clientId == this._dataDefaultClientId &&
|
||||
this._dataEnabled) {
|
||||
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
|
||||
this.dataCallSettings.enabled = true;
|
||||
if (gNetworkManager.active &&
|
||||
gNetworkManager.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
|
||||
if (DEBUG) this.debug("Default data active, wait for it to get disconnected.");
|
||||
this._dataCallSetupPending = true;
|
||||
return;
|
||||
}
|
||||
this.updateRILNetworkInterface();
|
||||
return;
|
||||
}
|
||||
|
||||
// Default data has been switched from this current RadioInterface,
|
||||
// disconnet data call if it is enabled.
|
||||
if (this.clientId != this._dataDefaultClientId &&
|
||||
this.dataCallSettings.enabled) {
|
||||
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
|
||||
this.dataCallSettings.enabled = false;
|
||||
this.updateRILNetworkInterface();
|
||||
}
|
||||
},
|
||||
|
||||
updateRILNetworkInterface: function updateRILNetworkInterface() {
|
||||
let apnSetting = this.apnSettings.byType.default;
|
||||
if (!this.validateApnSetting(apnSetting)) {
|
||||
@ -2359,6 +2390,18 @@ RadioInterface.prototype = {
|
||||
this._sntp.request();
|
||||
}
|
||||
}
|
||||
|
||||
// DSDS: setup pending data connection when switching the default id
|
||||
// for data call.
|
||||
// We can not use network.type to tell if it's NETWORK_TYPE_MOBILE,
|
||||
// since the type is removed from RILNetworkInterface.connectedTypes
|
||||
// on disconnect().
|
||||
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN &&
|
||||
this._dataCallSetupPending) {
|
||||
if (DEBUG) this.debug("Default data disconnected, setup pending data call.");
|
||||
this._dataCallSetupPending = false;
|
||||
this.updateRILNetworkInterface();
|
||||
}
|
||||
break;
|
||||
case kScreenStateChangedTopic:
|
||||
this.workerMessenger.send("setScreenState", { on: (data === "on") });
|
||||
@ -2371,6 +2414,17 @@ RadioInterface.prototype = {
|
||||
|
||||
apnSettings: null,
|
||||
|
||||
// Flag to determine the data state to start with when we boot up. It
|
||||
// corresponds to the 'ril.data.enabled' setting from the UI.
|
||||
_dataEnabled: null,
|
||||
|
||||
// Flag to record the default client id for data call.
|
||||
_dataDefaultClientId: null,
|
||||
|
||||
// Flag to determine if we need to setup data call when we are notified
|
||||
// that another data call has been disconnected.
|
||||
_dataCallSetupPending: false,
|
||||
|
||||
// Flag to determine whether to update system clock automatically. It
|
||||
// corresponds to the "time.clock.automatic-update.enabled" setting.
|
||||
_clockAutoUpdateEnabled: null,
|
||||
@ -2430,15 +2484,15 @@ RadioInterface.prototype = {
|
||||
break;
|
||||
case "ril.data.enabled":
|
||||
if (DEBUG) this.debug("'ril.data.enabled' is now " + aResult);
|
||||
let enabled;
|
||||
if (Array.isArray(aResult)) {
|
||||
enabled = aResult[this.clientId];
|
||||
} else {
|
||||
// Backward compability
|
||||
enabled = aResult;
|
||||
if (this._dataEnabled == aResult) {
|
||||
break;
|
||||
}
|
||||
this._dataEnabled = aResult;
|
||||
if (this.clientId != this._dataDefaultClientId) {
|
||||
break;
|
||||
}
|
||||
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
|
||||
this.dataCallSettings.enabled = enabled;
|
||||
this.dataCallSettings.enabled = aResult;
|
||||
this.updateRILNetworkInterface();
|
||||
break;
|
||||
case "ril.data.roaming_enabled":
|
||||
@ -2453,6 +2507,15 @@ RadioInterface.prototype = {
|
||||
this.updateRILNetworkInterface();
|
||||
}
|
||||
break;
|
||||
case "ril.data.defaultServiceId":
|
||||
aResult = aResult ? aResult : 0;
|
||||
if (DEBUG) this.debug("'ril.data.defaultServiceId' is now " + aResult);
|
||||
if (this._dataDefaultClientId == aResult) {
|
||||
break;
|
||||
}
|
||||
this._dataDefaultClientId = aResult;
|
||||
this.handleDataClientIdChange();
|
||||
break;
|
||||
case kSettingsClockAutoUpdateEnabled:
|
||||
this._clockAutoUpdateEnabled = aResult;
|
||||
if (!this._clockAutoUpdateEnabled) {
|
||||
@ -3682,18 +3745,17 @@ RILNetworkInterface.prototype = {
|
||||
this.radioInterface.updateRILNetworkInterface();
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(this,
|
||||
kNetworkInterfaceStateChangedTopic,
|
||||
null);
|
||||
|
||||
if (this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
||||
this.registeredAsNetworkInterface) {
|
||||
gNetworkManager.unregisterNetworkInterface(this);
|
||||
this.registeredAsNetworkInterface = false;
|
||||
this.cid = null;
|
||||
this.connectedTypes = [];
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(this,
|
||||
kNetworkInterfaceStateChangedTopic,
|
||||
null);
|
||||
},
|
||||
|
||||
receiveDataCallList: function receiveDataCallList(dataCalls, length) {
|
||||
|
@ -19,14 +19,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=427744
|
||||
|
||||
/** Test for Bug 427744 **/
|
||||
|
||||
var found = false;
|
||||
for (var i = 0; i < navigator.plugins.length; i++) {
|
||||
if (navigator.plugins[i].name == "Test Plug-in") {
|
||||
found = true;
|
||||
is(navigator.plugins[i].version, "1.0.0.0", "Should have seen the right version");
|
||||
}
|
||||
}
|
||||
ok(found, "Should have seen the test plugin");
|
||||
var firstPlugin = navigator.plugins["Test Plug-in"];
|
||||
ok(firstPlugin, "Should have seen the test plugin");
|
||||
is(firstPlugin.version, "1.0.0.0", "Should have seen the right test plugin version");
|
||||
|
||||
var secondPlugin = navigator.plugins["Second Test Plug-in"];
|
||||
ok(secondPlugin, "Should have seen the second test plugin");
|
||||
is(secondPlugin.version, "1.0.0.0", "Should have seen the right second test plugin version");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -405,6 +405,7 @@ var interfaceNamesInGlobalScope =
|
||||
"PhoneNumberService",
|
||||
"Plugin",
|
||||
"PluginArray",
|
||||
{name: "PointerEvent", pref: "dom.w3c_pointer_events.enabled"},
|
||||
"PopStateEvent",
|
||||
"PopupBlockedEvent",
|
||||
"ProcessingInstruction",
|
||||
|
@ -94,6 +94,13 @@ partial interface HTMLElement {
|
||||
readonly attribute long offsetHeight;
|
||||
};
|
||||
|
||||
// Extension for scroll-grabbing, used in the B2G dynamic toolbar.
|
||||
// This is likely to be revised.
|
||||
partial interface HTMLElement {
|
||||
[Func="nsGenericHTMLElement::IsScrollGrabAllowed"]
|
||||
attribute boolean scrollgrab;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface TouchEventHandlers {
|
||||
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
|
||||
|
@ -42,9 +42,6 @@ interface PeerConnectionObserver
|
||||
void onAddTrack();
|
||||
void onRemoveTrack();
|
||||
|
||||
/* Used by c++ to know when Observer goes away */
|
||||
readonly attribute nsISupports weakReferent;
|
||||
|
||||
/* Helper function to access supported constraints defined in webidl. Needs to
|
||||
* be in a separate webidl object we hold, so putting it here was convenient.
|
||||
*/
|
||||
|
@ -35,7 +35,7 @@ EXPORTS += [
|
||||
'nsCTooltipTextProvider.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsCommandHandler.cpp',
|
||||
'nsContextMenuInfo.cpp',
|
||||
'nsDocShellTreeOwner.cpp',
|
||||
|
@ -3,6 +3,9 @@
|
||||
* 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 nsEmbedStream_h__
|
||||
#define nsEmbedStream_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIURI.h"
|
||||
@ -27,5 +30,6 @@ class nsEmbedStream : public nsISupports
|
||||
private:
|
||||
nsIWebBrowser *mOwner;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
|
||||
};
|
||||
|
||||
#endif // nsEmbedStream_h__
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsBaseCommandController.cpp',
|
||||
'nsCommandGroup.cpp',
|
||||
'nsCommandManager.cpp',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsFind.cpp',
|
||||
'nsWebBrowserFind.cpp',
|
||||
]
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsPrintProgress.cpp',
|
||||
'nsPrintProgressParams.cpp',
|
||||
]
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsPrintingPromptService.cpp',
|
||||
'nsPrintProgress.cpp',
|
||||
'nsPrintProgressParams.cpp',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsPrintDialogUtil.cpp',
|
||||
'nsPrintingPromptService.cpp',
|
||||
'nsPrintProgress.cpp',
|
||||
|
@ -4,13 +4,13 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsAutoWindowStateHelper.cpp',
|
||||
'nsWindowWatcher.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_XUL']:
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsDialogParamBlock.cpp',
|
||||
]
|
||||
|
||||
|
@ -585,6 +585,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
|
||||
WriteParam(aMsg, aParam.mPresShellId);
|
||||
WriteParam(aMsg, aParam.mIsRoot);
|
||||
WriteParam(aMsg, aParam.mHasScrollgrab);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
@ -602,7 +603,8 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mIsRoot));
|
||||
ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasScrollgrab));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -122,6 +122,8 @@ class ISurfaceAllocator;
|
||||
class NewTextureSource;
|
||||
class DataTextureSource;
|
||||
class CompositingRenderTarget;
|
||||
class PCompositorParent;
|
||||
class LayerManagerComposite;
|
||||
|
||||
enum SurfaceInitMode
|
||||
{
|
||||
@ -176,9 +178,10 @@ enum SurfaceInitMode
|
||||
class Compositor : public RefCounted<Compositor>
|
||||
{
|
||||
public:
|
||||
Compositor()
|
||||
Compositor(PCompositorParent* aParent = nullptr)
|
||||
: mCompositorID(0)
|
||||
, mDiagnosticTypes(DIAGNOSTIC_NONE)
|
||||
, mParent(aParent)
|
||||
{
|
||||
MOZ_COUNT_CTOR(Compositor);
|
||||
}
|
||||
@ -306,7 +309,8 @@ public:
|
||||
* for the clip rect).
|
||||
*
|
||||
* If aRenderBoundsOut is non-null, it will be set to the render bounds
|
||||
* actually used by the compositor in window space.
|
||||
* actually used by the compositor in window space. If aRenderBoundsOut
|
||||
* is returned empty, composition should be aborted.
|
||||
*/
|
||||
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::Rect* aClipRectIn,
|
||||
@ -408,6 +412,12 @@ public:
|
||||
*/
|
||||
virtual bool Resume() { return true; }
|
||||
|
||||
/**
|
||||
* Call before rendering begins to ensure the compositor is ready to
|
||||
* composite. Returns false if rendering should be aborted.
|
||||
*/
|
||||
virtual bool Ready() { return true; }
|
||||
|
||||
// XXX I expect we will want to move mWidget into this class and implement
|
||||
// these methods properly.
|
||||
virtual nsIWidget* GetWidget() const { return nullptr; }
|
||||
@ -446,6 +456,7 @@ protected:
|
||||
uint32_t mCompositorID;
|
||||
static LayersBackend sBackend;
|
||||
DiagnosticTypes mDiagnosticTypes;
|
||||
PCompositorParent* mParent;
|
||||
|
||||
/**
|
||||
* We keep track of the total number of pixels filled as we composite the
|
||||
|
@ -229,7 +229,8 @@ CreateTexturedEffect(gfx::SurfaceFormat aFormat,
|
||||
result = new EffectYCbCr(aSource, aFilter);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unhandled program type");
|
||||
NS_WARNING("unhandled program type");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
, mMayHaveTouchListeners(false)
|
||||
, mPresShellId(-1)
|
||||
, mIsRoot(false)
|
||||
, mHasScrollgrab(false)
|
||||
{}
|
||||
|
||||
// Default copy ctor and operator= are fine
|
||||
@ -256,6 +257,9 @@ public:
|
||||
|
||||
// Whether or not this is the root scroll frame for the root content document.
|
||||
bool mIsRoot;
|
||||
|
||||
// Whether or not this frame is for an element marked 'scrollgrab'.
|
||||
bool mHasScrollgrab;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -107,7 +107,8 @@ RotatedBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
||||
} else if (mDTBuffer) {
|
||||
source = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDTBuffer);
|
||||
} else {
|
||||
NS_RUNTIMEABORT("Can't draw a RotatedBuffer without any buffer!");
|
||||
NS_WARNING("Can't draw a RotatedBuffer without any buffer!");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(aSource == BUFFER_WHITE);
|
||||
@ -116,7 +117,8 @@ RotatedBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
||||
} else if (mDTBufferOnWhite) {
|
||||
source = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDTBufferOnWhite);
|
||||
} else {
|
||||
NS_RUNTIMEABORT("Can't draw a RotatedBuffer without any buffer!");
|
||||
NS_WARNING("Can't draw a RotatedBuffer without any buffer!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,7 +312,9 @@ ThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
|
||||
gfxASurface* aMask,
|
||||
const gfxMatrix* aMaskTransform)
|
||||
{
|
||||
EnsureBuffer();
|
||||
if (!EnsureBuffer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTarget->IsCairo()) {
|
||||
aTarget->Save();
|
||||
@ -385,11 +389,15 @@ FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
||||
already_AddRefed<gfxContext>
|
||||
ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds, ContextSource aSource, nsIntPoint *aTopLeft)
|
||||
{
|
||||
EnsureBuffer();
|
||||
if (!EnsureBuffer()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
|
||||
EnsureBufferOnWhite();
|
||||
if (!EnsureBufferOnWhite()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mBuffer) {
|
||||
MOZ_ASSERT(mBufferOnWhite);
|
||||
gfxASurface* surfaces[2] = { mBuffer, mBufferOnWhite };
|
||||
@ -410,7 +418,9 @@ ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds, Context
|
||||
ctx = new gfxContext(dualDT);
|
||||
}
|
||||
} else if (aSource == BUFFER_WHITE) {
|
||||
EnsureBufferOnWhite();
|
||||
if (!EnsureBufferOnWhite()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mBufferOnWhite) {
|
||||
ctx = new gfxContext(mBufferOnWhite);
|
||||
} else {
|
||||
@ -489,7 +499,7 @@ ThebesLayerBuffer::IsAzureBuffer()
|
||||
return SupportsAzureContent();
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
ThebesLayerBuffer::EnsureBuffer()
|
||||
{
|
||||
if ((!mBuffer && !mDTBuffer) && mBufferProvider) {
|
||||
@ -501,9 +511,12 @@ ThebesLayerBuffer::EnsureBuffer()
|
||||
mDTBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(mBuffer || mDTBuffer, "no buffer");
|
||||
return mBuffer || mDTBuffer;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
ThebesLayerBuffer::EnsureBufferOnWhite()
|
||||
{
|
||||
if ((!mBufferOnWhite && !mDTBufferOnWhite) && mBufferProviderOnWhite) {
|
||||
@ -515,6 +528,9 @@ ThebesLayerBuffer::EnsureBufferOnWhite()
|
||||
mDTBufferOnWhite = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(mBufferOnWhite || mDTBufferOnWhite, "no buffer");
|
||||
return mBufferOnWhite || mDTBufferOnWhite;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -673,7 +689,9 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
bufferFlags |= BUFFER_COMPONENT_ALPHA;
|
||||
}
|
||||
if (canReuseBuffer) {
|
||||
EnsureBuffer();
|
||||
if (!EnsureBuffer()) {
|
||||
return result;
|
||||
}
|
||||
nsIntRect keepArea;
|
||||
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
|
||||
// Set mBufferRotation so that the pixels currently in mBuffer
|
||||
@ -701,7 +719,9 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
mDTBuffer->CopyRect(IntRect(srcRect.x, srcRect.y, srcRect.width, srcRect.height),
|
||||
IntPoint(dest.x, dest.y));
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
EnsureBufferOnWhite();
|
||||
if (!EnsureBufferOnWhite()) {
|
||||
return result;
|
||||
}
|
||||
MOZ_ASSERT(mDTBufferOnWhite);
|
||||
mDTBufferOnWhite->CopyRect(IntRect(srcRect.x, srcRect.y, srcRect.width, srcRect.height),
|
||||
IntPoint(dest.x, dest.y));
|
||||
@ -710,7 +730,9 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
MOZ_ASSERT(mBuffer);
|
||||
mBuffer->MovePixels(srcRect, dest);
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
EnsureBufferOnWhite();
|
||||
if (!EnsureBufferOnWhite()) {
|
||||
return result;
|
||||
}
|
||||
MOZ_ASSERT(mBufferOnWhite);
|
||||
mBufferOnWhite->MovePixels(srcRect, dest);
|
||||
}
|
||||
@ -738,7 +760,9 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
mDTBuffer->ReleaseBits(data);
|
||||
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
EnsureBufferOnWhite();
|
||||
if (!EnsureBufferOnWhite()) {
|
||||
return result;
|
||||
}
|
||||
MOZ_ASSERT(mDTBufferOnWhite);
|
||||
mDTBufferOnWhite->LockBits(&data, &size, &stride, &format);
|
||||
uint8_t bytesPerPixel = BytesPerPixel(format);
|
||||
@ -801,11 +825,15 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
nsIntPoint offset = -destBufferRect.TopLeft();
|
||||
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
tmpCtx->Translate(gfxPoint(offset.x, offset.y));
|
||||
EnsureBuffer();
|
||||
if (!EnsureBuffer()) {
|
||||
return result;
|
||||
}
|
||||
DrawBufferWithRotation(tmpCtx, BUFFER_BLACK);
|
||||
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
EnsureBufferOnWhite();
|
||||
if (!EnsureBufferOnWhite()) {
|
||||
return result;
|
||||
}
|
||||
NS_ASSERTION(destBufferOnWhite, "Must have a white buffer!");
|
||||
nsRefPtr<gfxContext> tmpCtx = new gfxContext(destBufferOnWhite);
|
||||
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
@ -827,15 +855,19 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
Matrix mat;
|
||||
mat.Translate(offset.x, offset.y);
|
||||
destDTBuffer->SetTransform(mat);
|
||||
EnsureBuffer();
|
||||
MOZ_ASSERT(mDTBuffer, "Have we got a Thebes buffer for some reason?");
|
||||
if (!EnsureBuffer()) {
|
||||
return result;
|
||||
}
|
||||
MOZ_ASSERT(mDTBuffer, "Have we got a Thebes buffer for some reason?");
|
||||
DrawBufferWithRotation(destDTBuffer, BUFFER_BLACK, 1.0, OP_SOURCE);
|
||||
destDTBuffer->SetTransform(Matrix());
|
||||
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
NS_ASSERTION(destDTBufferOnWhite, "Must have a white buffer!");
|
||||
destDTBufferOnWhite->SetTransform(mat);
|
||||
EnsureBufferOnWhite();
|
||||
if (!EnsureBufferOnWhite()) {
|
||||
return result;
|
||||
}
|
||||
MOZ_ASSERT(mDTBufferOnWhite, "Have we got a Thebes buffer for some reason?");
|
||||
DrawBufferWithRotation(destDTBufferOnWhite, BUFFER_WHITE, 1.0, OP_SOURCE);
|
||||
destDTBufferOnWhite->SetTransform(Matrix());
|
||||
|
@ -394,8 +394,8 @@ protected:
|
||||
/**
|
||||
* If the buffer hasn't been mapped, map it.
|
||||
*/
|
||||
void EnsureBuffer();
|
||||
void EnsureBufferOnWhite();
|
||||
bool EnsureBuffer();
|
||||
bool EnsureBufferOnWhite();
|
||||
/**
|
||||
* True if we have a buffer where we can get it (but not necessarily
|
||||
* mapped currently).
|
||||
|
@ -147,7 +147,14 @@ CompositableClient::CreateDeprecatedTextureClient(DeprecatedTextureClientType aD
|
||||
}
|
||||
if (parentBackend == LAYERS_D3D9 &&
|
||||
!GetForwarder()->ForwardsToDifferentProcess()) {
|
||||
if (aContentType == GFX_CONTENT_COLOR_ALPHA) {
|
||||
// We can't use a d3d9 texture for an RGBA surface because we cannot get a DC for
|
||||
// for a gfxWindowsSurface.
|
||||
// We have to wait for the compositor thread to create a d3d9 device before we
|
||||
// can create d3d9 textures on the main thread (because we need to reset on the
|
||||
// compositor thread, and the d3d9 device must be reset on the same thread it was
|
||||
// created on).
|
||||
if (aContentType == GFX_CONTENT_COLOR_ALPHA ||
|
||||
!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
|
||||
result = new DeprecatedTextureClientDIB(GetForwarder(), GetTextureInfo());
|
||||
} else {
|
||||
result = new DeprecatedTextureClientD3D9(GetForwarder(), GetTextureInfo());
|
||||
|
@ -190,8 +190,6 @@ ContentClientRemoteBuffer::BuildDeprecatedTextureClients(ContentType aType,
|
||||
NS_ABORT_IF_FALSE(!mIsNewBuffer,
|
||||
"Bad! Did we create a buffer twice without painting?");
|
||||
|
||||
mIsNewBuffer = true;
|
||||
|
||||
if (mDeprecatedTextureClient) {
|
||||
mOldTextures.AppendElement(mDeprecatedTextureClient);
|
||||
if (mDeprecatedTextureClientOnWhite) {
|
||||
@ -218,6 +216,7 @@ ContentClientRemoteBuffer::BuildDeprecatedTextureClients(ContentType aType,
|
||||
}
|
||||
|
||||
CreateFrontBufferAndNotify(aRect);
|
||||
mIsNewBuffer = true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -497,6 +496,8 @@ private:
|
||||
void
|
||||
ContentClientDoubleBuffered::SyncFrontBufferToBackBuffer()
|
||||
{
|
||||
mIsNewBuffer = false;
|
||||
|
||||
if (!mFrontAndBackBufferDiffer) {
|
||||
return;
|
||||
}
|
||||
@ -555,7 +556,6 @@ ContentClientDoubleBuffered::SyncFrontBufferToBackBuffer()
|
||||
UpdateDestinationFrom(frontBuffer, updateRegion);
|
||||
}
|
||||
|
||||
mIsNewBuffer = false;
|
||||
mFrontAndBackBufferDiffer = false;
|
||||
}
|
||||
|
||||
@ -565,6 +565,9 @@ ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
|
||||
{
|
||||
nsRefPtr<gfxContext> destCtx =
|
||||
GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK);
|
||||
if (!destCtx) {
|
||||
return;
|
||||
}
|
||||
destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
|
||||
bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
|
||||
@ -621,15 +624,21 @@ ContentClientSingleBuffered::CreateFrontBufferAndNotify(const nsIntRect& aBuffer
|
||||
void
|
||||
ContentClientSingleBuffered::SyncFrontBufferToBackBuffer()
|
||||
{
|
||||
mIsNewBuffer = false;
|
||||
if (!mFrontAndBackBufferDiffer) {
|
||||
return;
|
||||
}
|
||||
mFrontAndBackBufferDiffer = false;
|
||||
|
||||
if (SupportsAzureContent()) {
|
||||
DrawTarget* backBuffer = GetDTBuffer();
|
||||
if (!backBuffer && mDeprecatedTextureClient) {
|
||||
backBuffer = mDeprecatedTextureClient->LockDrawTarget();
|
||||
}
|
||||
if (!backBuffer) {
|
||||
NS_WARNING("Could not lock texture client");
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> oldBuffer;
|
||||
oldBuffer = SetDTBuffer(backBuffer,
|
||||
@ -640,6 +649,10 @@ ContentClientSingleBuffered::SyncFrontBufferToBackBuffer()
|
||||
if (!backBuffer && mDeprecatedTextureClientOnWhite) {
|
||||
backBuffer = mDeprecatedTextureClientOnWhite->LockDrawTarget();
|
||||
}
|
||||
if (!backBuffer) {
|
||||
NS_WARNING("Could not lock texture client (on white)");
|
||||
return;
|
||||
}
|
||||
|
||||
oldBuffer = SetDTBufferOnWhite(backBuffer);
|
||||
} else {
|
||||
@ -647,6 +660,10 @@ ContentClientSingleBuffered::SyncFrontBufferToBackBuffer()
|
||||
if (!backBuffer && mDeprecatedTextureClient) {
|
||||
backBuffer = mDeprecatedTextureClient->LockSurface();
|
||||
}
|
||||
if (!backBuffer) {
|
||||
NS_WARNING("Could not lock texture client");
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxASurface> oldBuffer;
|
||||
oldBuffer = SetBuffer(backBuffer,
|
||||
@ -657,12 +674,13 @@ ContentClientSingleBuffered::SyncFrontBufferToBackBuffer()
|
||||
if (!backBuffer && mDeprecatedTextureClientOnWhite) {
|
||||
backBuffer = mDeprecatedTextureClientOnWhite->LockSurface();
|
||||
}
|
||||
if (!backBuffer) {
|
||||
NS_WARNING("Could not lock texture client (on white)");
|
||||
return;
|
||||
}
|
||||
|
||||
oldBuffer = SetBufferOnWhite(backBuffer);
|
||||
}
|
||||
|
||||
mIsNewBuffer = false;
|
||||
mFrontAndBackBufferDiffer = false;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
|
||||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
|
||||
#include <algorithm> // for std::stable_sort
|
||||
|
||||
#define APZC_LOG(...)
|
||||
// #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
|
||||
|
||||
@ -271,6 +273,8 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
|
||||
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
mTouchCount++;
|
||||
mApzcForInputBlock = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint));
|
||||
if (multiTouchInput.mTouches.Length() == 1) // pan, not pinch
|
||||
mApzcForInputBlock = AdjustForScrollGrab(mApzcForInputBlock);
|
||||
for (size_t i = 1; i < multiTouchInput.mTouches.Length(); i++) {
|
||||
nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[i].mScreenPoint));
|
||||
mApzcForInputBlock = CommonAncestor(mApzcForInputBlock.get(), apzc2.get());
|
||||
@ -313,6 +317,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
|
||||
// then null it out so we don't keep a dangling reference and leak things.
|
||||
if (mTouchCount == 0) {
|
||||
mApzcForInputBlock = nullptr;
|
||||
mOverscrollHandoffChain.clear();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -348,6 +353,8 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
|
||||
ScreenPoint aPoint)
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aPoint);
|
||||
if (aEvent.touches.Length() == 1) // pan, not pinch
|
||||
apzc = AdjustForScrollGrab(apzc);
|
||||
gfx3DMatrix transformToApzc, transformToGecko;
|
||||
// Reset the cached apz transform
|
||||
mCachedTransformToApzcForInputBlock = transformToApzc;
|
||||
@ -423,6 +430,7 @@ APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
}
|
||||
if (mTouchCount == 0) {
|
||||
mApzcForInputBlock = nullptr;
|
||||
mOverscrollHandoffChain.clear();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -612,34 +620,37 @@ APZCTreeManager::ClearTree()
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::HandleOverscroll(AsyncPanZoomController* aChild, ScreenPoint aStartPoint, ScreenPoint aEndPoint)
|
||||
APZCTreeManager::HandleOverscroll(AsyncPanZoomController* aPrev, ScreenPoint aStartPoint, ScreenPoint aEndPoint,
|
||||
int aOverscrollHandoffChainIndex)
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> parent;
|
||||
{
|
||||
// The tree lock needs to be held while navigating from an apzc to its
|
||||
// parent. We don't hold it any longer though because GetInputTransforms()
|
||||
// does its own locking, and AttemptScroll() can call HandleOverscroll()
|
||||
// recursively.
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
parent = aChild->GetParent();
|
||||
// Increment the current index into the chain of APZCs that handle overscroll
|
||||
// for the current pan gesture. Since we are in overscroll, we have scrolled
|
||||
// the previous APZC as far as possible, and will now hand off the remaining
|
||||
// scroll to the next one.
|
||||
++aOverscrollHandoffChainIndex;
|
||||
if (aOverscrollHandoffChainIndex >= mOverscrollHandoffChain.length()) {
|
||||
// Nothing more to scroll - ignore the rest of the pan gesture.
|
||||
return;
|
||||
}
|
||||
if (parent == nullptr)
|
||||
|
||||
nsRefPtr<AsyncPanZoomController> next = mOverscrollHandoffChain[aOverscrollHandoffChainIndex];
|
||||
if (next == nullptr)
|
||||
return;
|
||||
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko; // ignored
|
||||
|
||||
// Convert start and end points to untransformed screen coordinates.
|
||||
GetInputTransforms(aChild, transformToApzc, transformToGecko);
|
||||
GetInputTransforms(aPrev, transformToApzc, transformToGecko);
|
||||
ApplyTransform(&aStartPoint, transformToApzc.Inverse());
|
||||
ApplyTransform(&aEndPoint, transformToApzc.Inverse());
|
||||
|
||||
// Convert start and end points to parent's transformed screen coordinates.
|
||||
GetInputTransforms(parent.get(), transformToApzc, transformToGecko);
|
||||
// Convert start and end points to next's transformed screen coordinates.
|
||||
GetInputTransforms(next, transformToApzc, transformToGecko);
|
||||
ApplyTransform(&aStartPoint, transformToApzc);
|
||||
ApplyTransform(&aEndPoint, transformToApzc);
|
||||
|
||||
parent->AttemptScroll(aStartPoint, aEndPoint);
|
||||
next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffChainIndex);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -673,6 +684,13 @@ APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
struct CompareByScrollPriority
|
||||
{
|
||||
bool operator()(const nsRefPtr<AsyncPanZoomController>& a, const nsRefPtr<AsyncPanZoomController>& b) {
|
||||
return a->HasScrollgrab() && !b->HasScrollgrab();
|
||||
}
|
||||
};
|
||||
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
|
||||
{
|
||||
@ -689,6 +707,46 @@ APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::AdjustForScrollGrab(const nsRefPtr<AsyncPanZoomController>& aInitialTarget)
|
||||
{
|
||||
// Scroll grabbing is a mechanism that allows content to specify that
|
||||
// the initial target of a pan should be not the innermost scrollable
|
||||
// frame at the touch point (which is what GetTargetAPZC finds), but
|
||||
// something higher up in the tree.
|
||||
// It's not sufficient to just find the initial target, however, as
|
||||
// overscroll can be handed off to another APZC. Without scroll grabbing,
|
||||
// handoff just occurs from child to parent. With scroll grabbing, the
|
||||
// handoff order can be different, so we build a chain of APZCs in the
|
||||
// order in which scroll will be handed off to them.
|
||||
|
||||
mOverscrollHandoffChain.clear();
|
||||
|
||||
// Start with the child -> parent chain.
|
||||
for (AsyncPanZoomController* apzc = aInitialTarget; apzc; apzc = apzc->GetParent()) {
|
||||
if (!mOverscrollHandoffChain.append(apzc)) {
|
||||
NS_WARNING("Vector::append failed");
|
||||
mOverscrollHandoffChain.clear();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Now adjust the chain to account for scroll grabbing. Sorting is a bit
|
||||
// of an overkill here, but scroll grabbing will likely be generalized
|
||||
// to scroll priorities, so we might as well do it this way.
|
||||
// The sorting being stable ensures that the relative order between
|
||||
// non-scrollgrabbing APZCs remains child -> parent.
|
||||
// (The relative order between scrollgrabbing APZCs will also remain
|
||||
// child -> parent, though that's just an artefact of the implementation
|
||||
// and users of 'scrollgrab' should not rely on this.)
|
||||
std::stable_sort(mOverscrollHandoffChain.begin(), mOverscrollHandoffChain.end(),
|
||||
CompareByScrollPriority());
|
||||
|
||||
// The initial target is the first APZC in the handoff chain.
|
||||
nsRefPtr<AsyncPanZoomController> result = mOverscrollHandoffChain.length() > 0 ? mOverscrollHandoffChain[0] : nullptr;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::GetRootAPZCsFor(const uint64_t& aLayersId,
|
||||
nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "mozilla/Vector.h" // for mozilla::Vector
|
||||
|
||||
class gfx3DMatrix;
|
||||
template <class E> class nsTArray;
|
||||
@ -213,15 +214,21 @@ public:
|
||||
|
||||
/**
|
||||
* This is a callback for AsyncPanZoomController to call when a touch-move
|
||||
* event causes overscroll. The overscroll will be passed on to the parent
|
||||
* APZC. |aStartPoint| and |aEndPoint| are in |aAPZC|'s transformed screen
|
||||
* event causes overscroll. The overscroll will be passed on to the next
|
||||
* APZC in the overscroll handoff chain, which was determined in the
|
||||
* GetTargetAPZC() call for the first touch event of the touch block (usually
|
||||
* the handoff chain is child -> parent, but scroll grabbing can change this).
|
||||
* |aStartPoint| and |aEndPoint| are in |aAPZC|'s transformed screen
|
||||
* coordinates (i.e. the same coordinates in which touch points are given to
|
||||
* APZCs). The amount of the overscroll is represented by two points rather
|
||||
* than a displacement because with certain 3D transforms, the same
|
||||
* displacement between different points in transformed coordinates can
|
||||
* represent different displacements in untransformed coordinates.
|
||||
* |aOverscrollHandoffChainIndex| is |aAPZC|'s current position in the
|
||||
* overscroll handoff chain.
|
||||
*/
|
||||
void HandleOverscroll(AsyncPanZoomController* aAPZC, ScreenPoint aStartPoint, ScreenPoint aEndPoint);
|
||||
void HandleOverscroll(AsyncPanZoomController* aAPZC, ScreenPoint aStartPoint, ScreenPoint aEndPoint,
|
||||
int aOverscrollHandoffChainIndex);
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -239,6 +246,10 @@ public:
|
||||
*/
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
|
||||
/*
|
||||
* Adjust the target APZC of an input event to account for scroll grabbing.
|
||||
*/
|
||||
already_AddRefed<AsyncPanZoomController> AdjustForScrollGrab(const nsRefPtr<AsyncPanZoomController>& aInitialTarget);
|
||||
void GetRootAPZCsFor(const uint64_t& aLayersId,
|
||||
nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs);
|
||||
void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
|
||||
@ -295,10 +306,16 @@ private:
|
||||
* screen coordinates, as returned through the 'aTransformToApzcOut' parameter
|
||||
* of GetInputTransform(), at the start of the input block. This is cached
|
||||
* because this transform can change over the course of the input block,
|
||||
* but for some operations we need to use the initial tranform.
|
||||
* but for some operations we need to use the initial transform.
|
||||
* Meaningless if mApzcForInputBlock is nullptr.
|
||||
*/
|
||||
gfx3DMatrix mCachedTransformToApzcForInputBlock;
|
||||
/* The chain of APZCs that will handle pans for the current touch input
|
||||
* block, in the order in which they will be scrolled. When one APZC has
|
||||
* been scrolled as far as it can, any overscroll will be handed off to
|
||||
* the next APZC in the chain.
|
||||
*/
|
||||
Vector< nsRefPtr<AsyncPanZoomController> > mOverscrollHandoffChain;
|
||||
|
||||
static float sDPI;
|
||||
};
|
||||
|
@ -91,6 +91,9 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
|
||||
|
||||
RefPtr<TexturedEffect> effect =
|
||||
CreateTexturedEffect(mDeprecatedTextureHost, mDeprecatedTextureHostOnWhite, aFilter);
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
aEffectChain.mPrimaryEffect = effect;
|
||||
|
||||
|
@ -86,6 +86,10 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mFrontBuffer->GetFormat(),
|
||||
source,
|
||||
aFilter);
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
aEffectChain.mPrimaryEffect = effect;
|
||||
IntSize textureSize = source->GetSize();
|
||||
gfx::Rect gfxPictureRect
|
||||
@ -288,6 +292,9 @@ DeprecatedImageHostSingle::Composite(EffectChain& aEffectChain,
|
||||
|
||||
RefPtr<TexturedEffect> effect =
|
||||
CreateTexturedEffect(mDeprecatedTextureHost, aFilter);
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
aEffectChain.mPrimaryEffect = effect;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user