Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2013-11-22 15:37:51 -05:00
commit 95668dd697
292 changed files with 5151 additions and 1699 deletions

7
.lldbinit Normal file
View 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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
{
"revision": "32c72fb8d857627ed39e4e07e1a4efaa1d3caace",
"revision": "5cc15d1e291050f4e46c91b87a1af1353d1c5e46",
"repo_path": "/integration/gaia-central"
}

View File

@ -767,6 +767,8 @@ var gPluginHandler = {
if (aNewState != "block" && !pluginFound) {
browser.reload();
}
this._setPluginNotificationIcon(browser);
},
_showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aPlugin, aShowNow) {

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ EXPORTS.mozilla.chrome += [
'RegistryMessageUtils.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'nsChromeProtocolHandler.cpp',
'nsChromeRegistry.cpp',
'nsChromeRegistryChrome.cpp',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "mp4_demuxer/bit_reader.h"
#include <algorithm>
namespace mp4_demuxer {

View File

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

View File

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

View File

@ -68,7 +68,6 @@ private:
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
const bool mDXVAEnabled;
const bool mIsRunningOnVista;
bool mUseHwAccel;
};

View File

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

View File

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

View File

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

View File

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

View File

@ -125,6 +125,11 @@ protected:
return mMethod.GetJSFunction();
}
JSObject* GetCompiledMethodPreserveColor() const
{
return mMethod.GetJSFunctionPreserveColor();
}
JS::Heap<nsXBLMaybeCompiled<nsXBLUncompiledMethod> > mMethod;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -68,7 +68,7 @@ struct MmsMessageData
nsString smil;
MmsAttachmentData[] attachments;
uint64_t expiryDate;
bool isReadReportRequested;
bool readReportRequested;
};
union MobileMessageData

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -405,6 +405,7 @@ var interfaceNamesInGlobalScope =
"PhoneNumberService",
"Plugin",
"PluginArray",
{name: "PointerEvent", pref: "dom.w3c_pointer_events.enabled"},
"PopStateEvent",
"PopupBlockedEvent",
"ProcessingInstruction",

View File

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

View File

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

View File

@ -35,7 +35,7 @@ EXPORTS += [
'nsCTooltipTextProvider.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'nsCommandHandler.cpp',
'nsContextMenuInfo.cpp',
'nsDocShellTreeOwner.cpp',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -91,6 +91,9 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
RefPtr<TexturedEffect> effect =
CreateTexturedEffect(mDeprecatedTextureHost, mDeprecatedTextureHostOnWhite, aFilter);
if (!effect) {
return;
}
aEffectChain.mPrimaryEffect = effect;

View File

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