Merge mozilla-central into services-central

This commit is contained in:
Gregory Szorc 2012-08-13 10:30:29 -07:00
commit 6ecc3ed030
631 changed files with 34239 additions and 7647 deletions

View File

@ -7,11 +7,12 @@
#include "nsARIAMap.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "Role.h"
#include "States.h"
#include "nsIContent.h"
#include "nsAttrName.h"
#include "nsWhitespaceTokenizer.h"
using namespace mozilla;
@ -684,3 +685,39 @@ aria::UniversalStatesFor(mozilla::dom::Element* aElement)
return state;
}
////////////////////////////////////////////////////////////////////////////////
// AttrIterator class
bool
AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue)
{
while (mAttrIdx < mAttrCount) {
const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx);
mAttrIdx++;
if (attr->NamespaceEquals(kNameSpaceID_None)) {
nsIAtom* attrAtom = attr->Atom();
nsDependentAtomString attrStr(attrAtom);
if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
continue; // Not ARIA
PRUint8 attrFlags = nsAccUtils::GetAttributeCharacteristics(attrAtom);
if (attrFlags & ATTR_BYPASSOBJ)
continue; // No need to handle exposing as obj attribute here
if ((attrFlags & ATTR_VALTOKEN) &&
!nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
continue; // only expose token based attributes if they are defined
nsAutoString value;
if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
aAttrName.Assign(Substring(attrStr, 5));
aAttrValue.Assign(value);
return true;
}
}
}
return false;
}

View File

@ -12,8 +12,8 @@
#include "mozilla/a11y/Role.h"
#include "nsIAtom.h"
#include "nsIContent.h"
class nsIContent;
class nsINode;
////////////////////////////////////////////////////////////////////////////////
@ -226,6 +226,31 @@ nsRoleMapEntry* GetRoleMap(nsINode* aNode);
*/
PRUint64 UniversalStatesFor(mozilla::dom::Element* aElement);
/**
* Represents a simple enumerator for iterating through ARIA attributes
* exposed as object attributes on a given accessible.
*/
class AttrIterator
{
public:
AttrIterator(nsIContent* aContent) :
mContent(aContent), mAttrIdx(0)
{
mAttrCount = mContent->GetAttrCount();
}
bool Next(nsAString& aAttrName, nsAString& aAttrValue);
private:
AttrIterator() MOZ_DELETE;
AttrIterator(const AttrIterator&) MOZ_DELETE;
AttrIterator& operator= (const AttrIterator&) MOZ_DELETE;
nsIContent* mContent;
PRUint32 mAttrIdx;
PRUint32 mAttrCount;
};
} // namespace aria
} // namespace a11y
} // namespace mozilla

View File

@ -1225,25 +1225,11 @@ Accessible::GetAttributes(nsIPersistentProperties **aAttributes)
groupPos.setSize, groupPos.posInSet);
// Expose object attributes from ARIA attributes.
PRUint32 numAttrs = mContent->GetAttrCount();
for (PRUint32 count = 0; count < numAttrs; count ++) {
const nsAttrName *attr = mContent->GetAttrNameAt(count);
if (attr && attr->NamespaceEquals(kNameSpaceID_None)) {
nsIAtom *attrAtom = attr->Atom();
nsDependentAtomString attrStr(attrAtom);
if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
continue; // Not ARIA
PRUint8 attrFlags = nsAccUtils::GetAttributeCharacteristics(attrAtom);
if (attrFlags & ATTR_BYPASSOBJ)
continue; // No need to handle exposing as obj attribute here
if ((attrFlags & ATTR_VALTOKEN) &&
!nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
continue; // only expose token based attributes if they are defined
nsAutoString value;
if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
attributes->SetStringProperty(NS_ConvertUTF16toUTF8(Substring(attrStr, 5)), value, oldValueUnused);
}
}
aria::AttrIterator attribIter(mContent);
nsAutoString name, value;
while(attribIter.Next(name, value)) {
attributes->SetStringProperty(NS_ConvertUTF16toUTF8(name), value,
oldValueUnused);
}
// If there is no aria-live attribute then expose default value of 'live'
@ -3258,3 +3244,4 @@ KeyBinding::ToAtkFormat(nsAString& aValue) const
aValue.Append(mKey);
}

View File

@ -8,6 +8,7 @@
#include "AccessibleWrap.h"
#include "nsIPersistentProperties2.h"
#include "nsARIAMap.h"
using namespace mozilla;
using namespace mozilla::a11y;
@ -199,6 +200,30 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
break;
}
//ARIA Properties
case UIA_AriaPropertiesPropertyId: {
nsAutoString ariaProperties;
aria::AttrIterator attribIter(mAcc->GetContent());
nsAutoString attribName, attribValue;
while (attribIter.Next(attribName, attribValue)) {
ariaProperties.Append(attribName);
ariaProperties.Append('=');
ariaProperties.Append(attribValue);
ariaProperties.Append(';');
}
if (!ariaProperties.IsEmpty()) {
//remove last delimiter:
ariaProperties.Truncate(ariaProperties.Length()-1);
aPropertyValue->vt = VT_BSTR;
aPropertyValue->bstrVal = ::SysAllocString(ariaProperties.get());
return S_OK;
}
break;
}
}
return S_OK;

View File

@ -472,6 +472,9 @@ pref("dom.disable_window_print", true);
// Disable window.showModalDialog
pref("dom.disable_window_showModalDialog", true);
// Enable new experimental html forms
pref("dom.experimental_forms", true);
// Turns on gralloc-based direct texturing for Gonk
pref("gfx.gralloc.enabled", false);

View File

@ -180,15 +180,15 @@ FormAssistant.init();
function getJSON(element) {
let type = element.type || "";
// FIXME/bug 344616 is input type="number"
// Until then, let's return 'number' even if the platform returns 'text'
// Until the input type=date/datetime/time have been implemented
// let's return their real type even if the platform returns 'text'
// Related to Bug 769352 - Implement <input type=date>
// Related to Bug 777279 - Implement <input type=time>
let attributeType = element.getAttribute("type") || "";
if (attributeType) {
var typeLowerCase = attributeType.toLowerCase();
switch (typeLowerCase) {
case "number":
case "date":
case "time":
case "datetime":

View File

@ -48,29 +48,6 @@ function getContentWindow() {
return shell.contentBrowser.contentWindow;
}
// FIXME Bug 707625
// Please don't add more permissions here.
// XXX never grant 'content-camera' to non-gaia apps
function addPermissions(urls) {
let permissions = [
'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'pin-app',
'content-camera', 'wifi-manage', 'desktop-notification',
'geolocation', 'device-storage', 'alarms'
];
urls.forEach(function(url) {
url = url.trim();
if (url) {
let uri = Services.io.newURI(url, null, null);
let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
permissions.forEach(function(permission) {
Services.perms.add(uri, permission, allow);
});
}
});
}
var shell = {
get CrashSubmit() {
@ -160,13 +137,6 @@ var shell = {
dump('Error setting master volume: ' + e + '\n');
}
let domains = "";
try {
domains = Services.prefs.getCharPref('b2g.privileged.domains');
} catch(e) {}
addPermissions(domains.split(","));
CustomEventManager.init();
WebappsHelper.init();

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1343854380000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1344613852000">
<emItems>
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
<versionRange minVersion="0" maxVersion="*">
@ -120,6 +120,10 @@
</emItem>
<emItem blockID="i13" id="{E8E88AB0-7182-11DF-904E-6045E0D72085}">
</emItem>
<emItem blockID="i117" id="{ce7e73df-6a44-4028-8079-5927a588c948}">
<versionRange minVersion="0" maxVersion="1.0.8" severity="1">
</versionRange>
</emItem>
<emItem blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
<versionRange minVersion="0.1" maxVersion="1.3.328.4" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">

View File

@ -510,34 +510,23 @@ pref("browser.gesture.twist.right", "");
pref("browser.gesture.twist.left", "");
pref("browser.gesture.tap", "cmd_fullZoomReset");
// 0=lines, 1=pages, 2=history , 3=text size
// 0: Nothing happens
// 1: Scrolling contents
// 2: Go back or go forward, in your history
// 3: Zoom in or out.
#ifdef XP_MACOSX
// On OS X, if the wheel has one axis only, shift+wheel comes through as a
// horizontal scroll event. Thus, we can't assign anything other than normal
// scrolling to shift+wheel.
pref("mousewheel.withshiftkey.action",0);
pref("mousewheel.withshiftkey.sysnumlines",true);
pref("mousewheel.withshiftkey.numlines",1);
pref("mousewheel.withaltkey.action",2);
pref("mousewheel.withaltkey.sysnumlines",false);
pref("mousewheel.withaltkey.numlines",1);
pref("mousewheel.withmetakey.action",0);
pref("mousewheel.withmetakey.sysnumlines",false);
pref("mousewheel.withmetakey.numlines",1);
pref("mousewheel.with_alt.action", 2);
pref("mousewheel.with_shift.action", 1);
#else
pref("mousewheel.withshiftkey.action",2);
pref("mousewheel.withshiftkey.sysnumlines",false);
pref("mousewheel.withshiftkey.numlines",1);
pref("mousewheel.withaltkey.action",0);
pref("mousewheel.withaltkey.sysnumlines",false);
pref("mousewheel.withaltkey.numlines",1);
pref("mousewheel.withmetakey.action",0);
pref("mousewheel.withmetakey.sysnumlines",true);
pref("mousewheel.withmetakey.numlines",1);
pref("mousewheel.with_alt.action", 1);
pref("mousewheel.with_shift.action", 2);
#endif
pref("mousewheel.withcontrolkey.action",3);
pref("mousewheel.withcontrolkey.sysnumlines",false);
pref("mousewheel.withcontrolkey.numlines",1);
pref("mousewheel.with_control.action",3);
pref("mousewheel.with_meta.action", 1); // command key on Mac
pref("mousewheel.with_win.action", 1);
// pref to control the alert notification
pref("alerts.slideIncrement", 1);

View File

@ -156,7 +156,7 @@ _BROWSER_FILES = \
browser_bug749738.js \
browser_bug763468.js \
browser_bug767836.js \
browser_shareButton.js \
browser_social_shareButton.js \
browser_canonizeURL.js \
browser_customize.js \
browser_findbarClose.js \
@ -232,6 +232,7 @@ _BROWSER_FILES = \
plugin_clickToPlayAllow.html \
plugin_clickToPlayDeny.html \
plugin_bug749455.html \
plugin_hidden_to_visible.html \
alltabslistener.html \
zoom_test.html \
dummy_page.html \

View File

@ -72,11 +72,11 @@ function runOverflowTests(aEvent) {
"(" + left(scrollbox) + " <= " + firstScrollableLeft + ")");
for (var i = 2; i; i--)
EventUtils.synthesizeMouseScroll(scrollbox, 1, 1, {axis: "horizontal", delta: -1});
EventUtils.synthesizeWheel(scrollbox, 1, 1, { deltaX: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE });
is(left(firstScrollable()), firstScrollableLeft, "Remained at the start with the mouse wheel");
element = nextRightElement();
EventUtils.synthesizeMouseScroll(scrollbox, 1, 1, {axis: "horizontal", delta: 1});
EventUtils.synthesizeWheel(scrollbox, 1, 1, { deltaX: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE});
isRight(element, "Scrolled one tab to the right with the mouse wheel");
while (tabs.length > 1)

View File

@ -689,5 +689,56 @@ function test19f() {
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 19f, Plugin should be activated");
prepareTest(test20a, gTestRoot + "plugin_hidden_to_visible.html");
}
// Tests that a plugin in a div that goes from style="display: none" to
// "display: block" can be clicked to activate.
function test20a() {
var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(clickToPlayNotification, "Test 20a, Should have a click-to-play notification");
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("plugin");
var mainBox = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
ok(mainBox, "Test 20a, plugin overlay should not be null");
var pluginRect = mainBox.getBoundingClientRect();
ok(pluginRect.width == 0, "Test 20a, plugin should have an overlay with 0px width");
ok(pluginRect.height == 0, "Test 20a, plugin should have an overlay with 0px height");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 20a, plugin should not be activated");
var div = doc.getElementById("container");
ok(div.style.display == "none", "Test 20a, container div should be display: none");
div.style.display = "block";
var condition = function() {
var pluginRect = mainBox.getBoundingClientRect();
return (pluginRect.width == 200);
}
waitForCondition(condition, test20b, "Test 20a, Waited too long for plugin to become visible");
}
function test20b() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("plugin");
var pluginRect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
ok(pluginRect.width == 200, "Test 20b, plugin should have an overlay with 200px width");
ok(pluginRect.height == 200, "Test 20b, plugin should have an overlay with 200px height");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 20b, plugin should not be activated");
EventUtils.synthesizeMouseAtCenter(plugin, {}, gTestBrowser.contentWindow);
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test20c, "Test 20b, Waited too long for plugin to activate");
}
function test20c() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("plugin");
var pluginRect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
ok(pluginRect.width == 0, "Test 20c, plugin should have click-to-play overlay with zero width");
ok(pluginRect.height == 0, "Test 20c, plugin should have click-to-play overlay with zero height");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 20c, plugin should be activated");
finishTest();
}

View File

@ -2,14 +2,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/. */
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
function test() {
// XXX Bug 775779
if (Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2).isDebugBuild) {
ok(true, "can't run social sidebar test in debug builds because they falsely report leaks");
return;
}
waitForExplicitFinish();
let manifest = { // normal provider
@ -19,10 +12,8 @@ function test() {
workerURL: "http://example.com/browser/browser/base/content/test/social_worker.js",
iconURL: "chrome://branding/content/icon48.png"
};
runSocialTestWithProvider(manifest, function () {
runSocialTests(tests, undefined, undefined, function () {
SocialService.removeProvider(Social.provider.origin, finish);
});
runSocialTestWithProvider(manifest, function (finishcb) {
runSocialTests(tests, undefined, undefined, finishcb);
});
}

View File

@ -6,7 +6,8 @@ let prefName = "social.enabled",
shareButton,
sharePopup,
okButton,
undoButton;
undoButton,
gFinishCB;
function test() {
waitForExplicitFinish();
@ -18,9 +19,6 @@ function test() {
executeSoon(tabLoaded);
}, true);
// Enable the service to start
Services.prefs.setBoolPref(prefName, true);
registerCleanupFunction(function() {
Services.prefs.clearUserPref(prefName);
gBrowser.removeTab(tab);
@ -30,19 +28,20 @@ function test() {
function tabLoaded() {
ok(Social, "Social module loaded");
// If the UI is already active, run the test immediately, otherwise wait
// for initialization.
if (Social.provider) {
executeSoon(testInitial);
} else {
Services.obs.addObserver(function obs() {
Services.obs.removeObserver(obs, "test-social-ui-ready");
executeSoon(testInitial);
}, "test-social-ui-ready", false);
}
let manifest = { // normal provider
name: "provider 1",
origin: "https://example.com",
sidebarURL: "https://example.com/browser/browser/base/content/test/social_sidebar.html",
workerURL: "https://example.com/browser/browser/base/content/test/social_worker.js",
iconURL: "chrome://branding/content/icon48.png"
};
runSocialTestWithProvider(manifest, function (finishcb) {
gFinishCB = finishcb;
testInitial();
});
}
function testInitial() {
function testInitial(finishcb) {
ok(Social.provider, "Social provider is active");
ok(Social.provider.enabled, "Social provider is enabled");
ok(Social.provider.port, "Social provider has a port to its FrameWorker");
@ -116,19 +115,33 @@ function checkShortcutWorked(keyTarget) {
function checkOKButton() {
is(document.activeElement, okButton, "ok button should be focused by default");
checkNextInTabOrder(undoButton, function () {
checkNextInTabOrder(okButton, testCloseBySpace);
});
}
function checkNextInTabOrder(element, next) {
// This particular test doesn't really apply on Mac, since buttons aren't
// focusable by default.
// This rest of particular test doesn't really apply on Mac, since buttons
// aren't focusable by default.
if (navigator.platform.indexOf("Mac") != -1) {
executeSoon(next);
executeSoon(testCloseBySpace);
return;
}
let displayName = document.getElementById("socialUserDisplayName");
// Linux has the buttons in the [unshare] [ok] order, so displayName will come first.
if (navigator.platform.indexOf("Linux") != -1) {
checkNextInTabOrder(displayName, function () {
checkNextInTabOrder(undoButton, function () {
checkNextInTabOrder(okButton, testCloseBySpace);
});
});
} else {
checkNextInTabOrder(undoButton, function () {
checkNextInTabOrder(displayName, function () {
checkNextInTabOrder(okButton, testCloseBySpace);
});
});
}
}
function checkNextInTabOrder(element, next) {
function listener() {
element.removeEventListener("focus", listener);
is(document.activeElement, element, element.id + " should be next in tab order");
@ -155,5 +168,5 @@ function testCloseBySpace() {
function testDisable() {
Services.prefs.setBoolPref(prefName, false);
is(shareButton.hidden, true, "Share button should be hidden when pref is disabled");
finish();
gFinishCB();
}

View File

@ -2,15 +2,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/. */
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
function test() {
// XXX Bug 775779
if (Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2).isDebugBuild) {
ok(true, "can't run social sidebar test in debug builds because they falsely report leaks");
return;
}
waitForExplicitFinish();
let manifest = { // normal provider
@ -23,7 +15,7 @@ function test() {
runSocialTestWithProvider(manifest, doTest);
}
function doTest() {
function doTest(finishcb) {
ok(SocialSidebar.canShow, "social sidebar should be able to be shown");
ok(SocialSidebar.enabled, "social sidebar should be on by default");
@ -56,8 +48,8 @@ function doTest() {
checkShown(true);
// Remove the test provider
SocialService.removeProvider(Social.provider.origin, finish);
// Finish the test
finishcb();
});
// Toggle it back on

View File

@ -2,8 +2,6 @@
* 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/. */
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
function test() {
waitForExplicitFinish();
@ -13,10 +11,8 @@ function test() {
workerURL: "https://example1.com/worker.js",
iconURL: "chrome://branding/content/icon48.png"
};
runSocialTestWithProvider(manifest, function () {
runSocialTests(tests, undefined, undefined, function () {
SocialService.removeProvider(Social.provider.origin, finish);
});
runSocialTestWithProvider(manifest, function (finishcb) {
runSocialTests(tests, undefined, undefined, finishcb);
});
}

View File

@ -89,8 +89,13 @@ function waitForCondition(condition, nextTest, errorMsg) {
}
function runSocialTestWithProvider(manifest, callback) {
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
info("runSocialTestWithProvider: " + manifest.toSource());
let oldProvider;
function saveOldProviderAndStartTestWith(provider) {
SocialService.addProvider(manifest, function(provider) {
info("runSocialTestWithProvider: provider added");
oldProvider = Social.provider;
Social.provider = provider;
@ -102,20 +107,10 @@ function runSocialTestWithProvider(manifest, callback) {
Services.prefs.clearUserPref("social.enabled");
});
callback();
}
SocialService.addProvider(manifest, function(provider) {
// If the UI is already active, run the test immediately, otherwise wait
// for initialization.
if (Social.provider) {
saveOldProviderAndStartTestWith(provider);
} else {
Services.obs.addObserver(function obs() {
Services.obs.removeObserver(obs, "test-social-ui-ready");
saveOldProviderAndStartTestWith(provider);
}, "test-social-ui-ready", false);
function finishSocialTest() {
SocialService.removeProvider(provider.origin, finish);
}
callback(finishSocialTest);
});
}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="container" style="display: none">
<object id="plugin" type="application/x-test" style="width: 200px; height: 200px;"></object>
</div>
</body>
</html>

View File

@ -51,8 +51,8 @@ function performScrollingTest()
InspectorUI.highlighter.removeListener("nodeselected", performScrollingTest);
executeSoon(function() {
EventUtils.synthesizeMouseScroll(div, 10, 10,
{axis:"vertical", delta:50, type:"MozMousePixelScroll"},
EventUtils.synthesizeWheel(div, 10, 10,
{ deltaY: 50.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL },
iframe.contentWindow);
});

View File

@ -40,9 +40,6 @@ SUBMAKEFILES += \
# This makefile uses variable overrides from the libs-% target to
# build non-default locales to non-default dist/ locations. Be aware!
# XXXCallek Unused?
APP_VERSION := $(shell cat $(srcdir)/../config/version.txt)
PWD := $(CURDIR)
# These are defaulted to be compatible with the files the wget-en-US target

View File

@ -31,7 +31,6 @@ let Social = {
if (providers.length)
this.provider = providers[0];
callback();
Services.obs.notifyObservers(null, "test-social-ui-ready", "");
}.bind(this));
},

View File

@ -356,6 +356,7 @@ class Automation(object):
{'allowXULXBL':[(l.host, 'noxul' not in l.options) for l in locations]});
part = """\
user_pref("social.skipLoadingProviders", true);
user_pref("browser.console.showInPanel", true);
user_pref("browser.dom.window.dump.enabled", true);
user_pref("browser.firstrun.show.localepicker", false);

View File

@ -6,6 +6,11 @@ elif [ -d "$topsrcdir/../clang" ]; then
# comm-central based build
export CC=$topsrcdir/../clang/bin/clang
export CXX=$topsrcdir/../clang/bin/clang++
else
# SeaMonkey does not have clang installed so need
# to set CC and CXX here.
export CC=/usr/bin/gcc-4.2
export CXX=/usr/bin/g++-4.2
fi
ac_add_options --enable-stdcxx-compat

View File

@ -35,16 +35,19 @@ class B2GRemoteAutomation(Automation):
_devicemanager = None
def __init__(self, deviceManager, appName='', remoteLog=None,
marionette=None):
marionette=None, context_chrome=True):
self._devicemanager = deviceManager
self._appName = appName
self._remoteProfile = None
self._remoteLog = remoteLog
self.marionette = marionette
self.context_chrome = context_chrome
self._is_emulator = False
# Default our product to b2g
self._product = "b2g"
# Default log finish to mochitest standard
self.logFinish = 'INFO SimpleTest FINISHED'
Automation.__init__(self)
def setEmulator(self, is_emulator):
@ -121,7 +124,7 @@ class B2GRemoteAutomation(Automation):
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime,
debuggerInfo, symbolsPath):
""" Wait for mochitest to finish (as evidenced by a signature string
""" Wait for tests to finish (as evidenced by a signature string
in logcat), or for a given amount of time to elapse with no
output.
"""
@ -135,7 +138,7 @@ class B2GRemoteAutomation(Automation):
if currentlog:
done = time.time() + timeout
print currentlog
if 'INFO SimpleTest FINISHED' in currentlog:
if hasattr(self, 'logFinish') and self.logFinish in currentlog:
return 0
else:
if time.time() > done:
@ -162,6 +165,8 @@ class B2GRemoteAutomation(Automation):
return (serial, status)
def restartB2G(self):
# TODO hangs in subprocess.Popen without this delay
time.sleep(5)
self._devicemanager.checkCmd(['shell', 'stop', 'b2g'])
# Wait for a bit to make sure B2G has completely shut down.
time.sleep(10)
@ -194,7 +199,7 @@ class B2GRemoteAutomation(Automation):
def Process(self, cmd, stdout=None, stderr=None, env=None, cwd=None):
# On a desktop or fennec run, the Process method invokes a gecko
# process in which to run mochitests. For B2G, we simply
# process in which to the tests. For B2G, we simply
# reboot the device (which was configured with a test profile
# already), wait for B2G to start up, and then navigate to the
# test url using Marionette. There doesn't seem to be any way
@ -239,11 +244,27 @@ class B2GRemoteAutomation(Automation):
if 'b2g' not in session:
raise Exception("bad session value %s returned by start_session" % session)
if self.context_chrome:
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
# start the tests
if hasattr(self, 'testURL'):
# Start the tests by navigating to the mochitest url, by setting it
# as the 'src' attribute to the homescreen mozbrowser element
# provided by B2G's shell.js.
self.marionette.set_context("chrome")
self.marionette.execute_script("document.getElementById('homescreen').src='%s';" % self.testURL)
# run the script that starts the tests
elif hasattr(self, 'testScript'):
if os.path.isfile(self.testScript):
script = open(self.testScript, 'r')
self.marionette.execute_script(script.read())
script.close()
else:
# assume testScript is a string
self.marionette.execute_script(self.testScript)
else:
# assumes the tests are started on startup automatically
pass
return instance

View File

@ -43,7 +43,7 @@ public interface Actions {
*
* @param geckoEvent The geckoEvent JSONObject's type
*/
EventExpecter expectGeckoEvent(String geckoEvent);
RepeatedEventExpecter expectGeckoEvent(String geckoEvent);
/**
* Listens for a paint event. Note that calling expectPaint() will

View File

@ -10,8 +10,8 @@ public interface Assert {
void dumpLog(String message, Throwable t);
void setLogFile(String filename);
void setTestName(String testName);
void endTest();
void finalize();
void ok(boolean condition, String name, String diag);
void is(Object a, Object b, String name);
void isnot(Object a, Object b, String name);

View File

@ -108,8 +108,7 @@ public class FennecMochitestAssert implements Assert {
}
}
public void finalize() {
// It appears that we call finalize during cleanup, this might be an invalid assertion.
public void endTest() {
String message;
if (mLogTestName != "") {

View File

@ -65,8 +65,8 @@ public class FennecNativeActions implements Actions {
Class [] parameters = new Class[2];
parameters[0] = String.class;
parameters[1] = mGel;
mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
mRegisterGEL = mGas.getMethod("registerEventListener", parameters);
mUnregisterGEL = mGas.getMethod("unregisterEventListener", parameters);
parameters = new Class[1];
parameters[0] = mGe;
mSendGE = mGas.getMethod("sendEventToGecko", parameters);
@ -115,7 +115,7 @@ public class FennecNativeActions implements Actions {
}
}
class GeckoEventExpecter implements EventExpecter {
class GeckoEventExpecter implements RepeatedEventExpecter {
private final String mGeckoEvent;
private final Object[] mRegistrationParams;
private boolean mEventReceived;
@ -143,6 +143,61 @@ public class FennecNativeActions implements Actions {
return;
}
}
try {
mUnregisterGEL.invoke(null, mRegistrationParams);
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"unblocked on expecter for " + mGeckoEvent);
}
public synchronized void blockUntilClear(long millis) {
if (millis <= 0) {
throw new IllegalArgumentException("millis must be > 0");
}
// wait for at least one event
long startTime = SystemClock.uptimeMillis();
long endTime = 0;
while (!mEventReceived) {
try {
this.wait(MAX_WAIT_MS);
} catch (InterruptedException ie) {
FennecNativeDriver.log(LogLevel.ERROR, ie);
break;
}
endTime = SystemClock.uptimeMillis();
if (!mEventReceived && (endTime - startTime >= MAX_WAIT_MS)) {
mAsserter.ok(false, "GeckoEventExpecter", "blockUtilClear timeout");
return;
}
}
// now wait for a period of millis where we don't get an event
startTime = SystemClock.uptimeMillis();
while (true) {
try {
this.wait(millis);
} catch (InterruptedException ie) {
FennecNativeDriver.log(LogLevel.ERROR, ie);
break;
}
endTime = SystemClock.uptimeMillis();
if (endTime - startTime >= millis) {
// success
break;
}
// we got a notify() before we could wait long enough, so we need to start over
startTime = endTime;
}
try {
mUnregisterGEL.invoke(null, mRegistrationParams);
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"unblocked on expecter for " + mGeckoEvent);
}
@ -152,13 +207,6 @@ public class FennecNativeActions implements Actions {
}
void notifyOfEvent() {
try {
mUnregisterGEL.invoke(null, mRegistrationParams);
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"received event " + mGeckoEvent);
synchronized (this) {
@ -168,7 +216,7 @@ public class FennecNativeActions implements Actions {
}
}
public EventExpecter expectGeckoEvent(String geckoEvent) {
public RepeatedEventExpecter expectGeckoEvent(String geckoEvent) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"waiting for "+geckoEvent);
try {

View File

@ -94,8 +94,8 @@ public class FennecNativeDriver implements Driver {
Class [] parameters = new Class[2];
parameters[0] = String.class;
parameters[1] = mGel;
mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
mRegisterGEL = mGas.getMethod("registerEventListener", parameters);
mUnregisterGEL = mGas.getMethod("unregisterEventListener", parameters);
parameters = new Class[1];
parameters[0] = mGe;
mSendGE = mGas.getMethod("sendEventToGecko", parameters);

View File

@ -31,7 +31,7 @@ public class FennecTalosAssert implements Assert {
public void setTestName(String testName) { }
public void finalize() { }
public void endTest() { }
public void ok(boolean condition, String name, String diag) {
if (!condition) {

View File

@ -789,9 +789,12 @@ public class SUTAgentAndroid extends Activity
Log.e("SUTAgentAndroid", "exception with file writer on: " + logFile);
}
finally
{
if (pw != null)
{
pw.close();
}
}
}
}

View File

@ -38,7 +38,8 @@ endif
CSRCS := \
inject/$(CPU).c \
inject/$(CPU)-noinit.c \
test.c \
test-ctors.c \
test-array.c \
$(NULL)
ifndef CROSS_COMPILE
@ -53,33 +54,39 @@ OS_CXXFLAGS := $(filter-out -pedantic,$(OS_CXXFLAGS))
include $(topsrcdir)/config/rules.mk
test$(DLL_SUFFIX): test.$(OBJ_SUFFIX) elfhack $(CSRCS:.c=.$(OBJ_SUFFIX))
$(MKSHLIB) $(LDFLAGS) $<
test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack $(filter inject/%,$(CSRCS:.c=.$(OBJ_SUFFIX)))
$(MKSHLIB) $(LDFLAGS) $< -nostartfiles
@echo ===
@echo === If you get failures below, please file a bug describing the error
@echo === and your environment \(compiler and linker versions\), and use
@echo === --disable-elf-hack until this is fixed.
@echo ===
# Fail if the library doesn't have $(DT_TYPE) .dynamic info
$(TOOLCHAIN_PREFIX)readelf -d $@ | grep '($(DT_TYPE))'
@rm -f $@.bak
$(CURDIR)/elfhack -b -f $@
# Fail if the backup file doesn't exist
[ -f "$@.bak" ]
# Fail if the new library doesn't contain less relocations
[ $$(objdump -R $@.bak | wc -l) -gt $$(objdump -R $@ | wc -l) ]
[ $$($(TOOLCHAIN_PREFIX)objdump -R $@.bak | wc -l) -gt $$(objdump -R $@ | wc -l) ]
.PRECIOUS: test$(DLL_SUFFIX)
test-array$(DLL_SUFFIX): DT_TYPE=INIT_ARRAY
test-ctors$(DLL_SUFFIX): DT_TYPE=INIT
GARBAGE += test$(DLL_SUFFIX) test$(DLL_SUFFIX).bak
.PRECIOUS: test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX)
libs:: test$(DLL_SUFFIX)
GARBAGE += test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX) test-array$(DLL_SUFFIX).bak test-ctors$(DLL_SUFFIX).bak
libs:: test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX)
ifndef CROSS_COMPILE
dummy: dummy.$(OBJ_SUFFIX) test$(DLL_SUFFIX)
dummy: dummy.$(OBJ_SUFFIX)
$(CC) -o $@ $^ $(LDFLAGS)
libs:: dummy
# Will either crash or return exit code 1 if elfhack is broken
LD_LIBRARY_PATH=$(CURDIR) $(CURDIR)/dummy
LD_PRELOAD=$(CURDIR)/test-array$(DLL_SUFFIX) $(CURDIR)/dummy
LD_PRELOAD=$(CURDIR)/test-ctors$(DLL_SUFFIX) $(CURDIR)/dummy
GARBAGE += dummy
endif
@ -87,7 +94,7 @@ endif
inject:
$(NSINSTALL) -D $@
inject/%.c: inject.c | inject
inject/%.c: inject.c $(call mkdir_deps,inject)
cp $< $@
GARBAGE_DIRS += inject

View File

@ -2,7 +2,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/. */
extern __attribute__((visibility("default"))) int print_status();
extern __attribute__((visibility("default"), weak)) int print_status();
int main() {
return print_status();

View File

@ -347,7 +347,7 @@ ElfDynamic_Section *Elf::getDynSection()
return NULL;
}
void Elf::write(std::ofstream &file)
void Elf::normalize()
{
// fixup section headers sh_name; TODO: that should be done by sections
// themselves
@ -387,6 +387,11 @@ void Elf::write(std::ofstream &file)
ehdr->e_shoff = shdr_section->getOffset();
ehdr->e_entry = eh_entry.getValue();
ehdr->e_shstrndx = eh_shstrndx->getIndex();
}
void Elf::write(std::ofstream &file)
{
normalize();
for (ElfSection *section = ehdr;
section != NULL; section = section->getNext()) {
file.seekp(section->getOffset());
@ -642,34 +647,25 @@ ElfSection *ElfDynamic_Section::getSectionForType(unsigned int tag)
return value ? value->getSection() : NULL;
}
void ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val)
bool ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val)
{
unsigned int i;
for (i = 0; (i < shdr.sh_size / shdr.sh_entsize) && (dyns[i].tag != DT_NULL); i++)
unsigned int shnum = shdr.sh_size / shdr.sh_entsize;
for (i = 0; (i < shnum) && (dyns[i].tag != DT_NULL); i++)
if (dyns[i].tag == tag) {
delete dyns[i].value;
dyns[i].value = val;
return;
return true;
}
// This should never happen, as the last entry is always tagged DT_NULL
assert(i < shdr.sh_size / shdr.sh_entsize);
// If we get here, this means we didn't match for the given tag
// Most of the time, there are a few DT_NULL entries, that we can
// use to add our value, but if we are on the last entry, we can't.
if (i >= shnum - 1)
return false;
dyns[i].tag = tag;
dyns[i++].value = val;
// If we were on the last entry, we need to grow the section.
// Most of the time, though, there are a few DT_NULL entries.
if (i < shdr.sh_size / shdr.sh_entsize)
return;
Elf_DynValue value;
value.tag = DT_NULL;
value.value = NULL;
dyns.push_back(value);
// Resize the section accordingly
shdr.sh_size += shdr.sh_entsize;
if (getNext() != NULL)
getNext()->markDirty();
dyns[i].value = val;
return true;
}
ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)

View File

@ -38,6 +38,8 @@ public:
}
};
typedef serializable<Elf_Addr_Traits> Elf_Addr;
class Elf_RelHack_Traits {
public:
typedef Elf32_Rel Type32;
@ -81,10 +83,9 @@ private:
class ElfRelHackCode_Section: public ElfSection {
public:
ElfRelHackCode_Section(Elf_Shdr &s, Elf &e)
: ElfSection(s, NULL, NULL), parent(e) {
ElfRelHackCode_Section(Elf_Shdr &s, Elf &e, unsigned int init)
: ElfSection(s, NULL, NULL), parent(e), init(init) {
std::string file(rundir);
init = parent.getDynSection()->getSectionForType(DT_INIT);
file += "/inject/";
switch (parent.getMachine()) {
case EM_386:
@ -99,7 +100,7 @@ public:
default:
throw std::runtime_error("unsupported architecture");
}
if (init == NULL)
if (!init)
file += "-noinit";
file += ".o";
std::ifstream inject(file.c_str(), std::ios::in|std::ios::binary);
@ -224,17 +225,17 @@ private:
Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
Elf32_Word addend, unsigned int addr)
{
/* Follows description of b.w instructions as per
/* Follows description of b.w and bl instructions as per
ARM Architecture Reference Manual ARM® v7-A and ARM® v7-R edition, A8.6.16
We limit ourselves to Encoding T3.
We limit ourselves to Encoding T4 of b.w and Encoding T1 of bl.
We don't care about sign_extend because the only case where this is
going to be used only jumps forward. */
Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr);
unsigned int word0 = addend & 0xffff,
word1 = addend >> 16;
if (((word0 & 0xf800) != 0xf000) || ((word1 & 0xd000) != 0x9000))
throw std::runtime_error("R_ARM_THM_JUMP24 relocation only supported for B.W <label>");
if (((word0 & 0xf800) != 0xf000) || ((word1 & 0x9000) != 0x9000))
throw std::runtime_error("R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for B.W <label> and BL <label>");
unsigned int s = (word0 & (1 << 10)) >> 10;
unsigned int j1 = (word1 & (1 << 13)) >> 13;
@ -249,7 +250,7 @@ private:
j2 = ((tmp & (1 << 22)) >> 22) ^ !s;
return 0xf000 | (s << 10) | ((tmp & (0x3ff << 12)) >> 12) |
(0x9000 << 16) | (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
((word1 & 0xd000) << 16) | (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
}
};
@ -299,7 +300,7 @@ private:
ElfSection *ehdr = parent.getSection(1)->getPrevious()->getPrevious();
addr = ehdr->getAddr();
} else if (strcmp(name, "original_init") == 0) {
addr = init->getAddr();
addr = init;
} else if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0) {
// We actually don't need a GOT, but need it as a reference for
// GOTOFF relocations. We'll just use the start of the ELF file
@ -328,6 +329,7 @@ private:
case REL(ARM, PLT32):
apply_relocation<arm_plt32_relocation>(the_code, buf, &*r, addr);
break;
case REL(ARM, THM_PC22 /* THM_CALL */):
case REL(ARM, THM_JUMP24):
apply_relocation<arm_thm_jump24_relocation>(the_code, buf, &*r, addr);
break;
@ -346,12 +348,36 @@ private:
Elf *elf, &parent;
std::vector<ElfSection *> code;
ElfSection *init;
unsigned int init;
int entry_point;
};
unsigned int get_addend(Elf_Rel *rel, Elf *elf) {
ElfLocation loc(rel->r_offset, elf);
Elf_Addr addr(loc.getBuffer(), Elf_Addr::size(elf->getClass()), elf->getClass(), elf->getData());
return addr.value;
}
unsigned int get_addend(Elf_Rela *rel, Elf *elf) {
return rel->r_addend;
}
void set_relative_reloc(Elf_Rel *rel, Elf *elf, unsigned int value) {
ElfLocation loc(rel->r_offset, elf);
Elf_Addr addr;
addr.value = value;
addr.serialize(const_cast<char *>(loc.getBuffer()), Elf_Addr::size(elf->getClass()), elf->getClass(), elf->getData());
}
void set_relative_reloc(Elf_Rela *rel, Elf *elf, unsigned int value) {
// ld puts the value of relocated relocations both in the addend and
// at r_offset. For consistency, keep it that way.
set_relative_reloc((Elf_Rel *)rel, elf, value);
rel->r_addend = value;
}
template <typename Rel_Type>
int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2)
int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2, bool force)
{
ElfDynamic_Section *dyn = elf->getDynSection();
if (dyn ==NULL) {
@ -370,10 +396,35 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
Elf32_Shdr relhackcode32_section =
{ 0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, (Elf32_Off)-1, 0,
SHN_UNDEF, 0, 1, 0 };
unsigned int entry_sz = Elf_Addr::size(elf->getClass());
// The injected code needs to be executed before any init code in the
// binary. There are three possible cases:
// - The binary has no init code at all. In this case, we will add a
// DT_INIT entry pointing to the injected code.
// - The binary has a DT_INIT entry. In this case, we will interpose:
// we change DT_INIT to point to the injected code, and have the
// injected code call the original DT_INIT entry point.
// - The binary has no DT_INIT entry, but has a DT_INIT_ARRAY. In this
// case, we interpose as well, by replacing the first entry in the
// array to point to the injected code, and have the injected code
// call the original first entry.
// The binary may have .ctors instead of DT_INIT_ARRAY, for its init
// functions, but this falls into the second case above, since .ctors
// are actually run by DT_INIT code.
ElfValue *value = dyn->getValueForType(DT_INIT);
unsigned int original_init = value ? value->getValue() : 0;
ElfSection *init_array = NULL;
if (!value || !value->getValue()) {
value = dyn->getValueForType(DT_INIT_ARRAYSZ);
if (value && value->getValue() >= entry_sz)
init_array = dyn->getSectionForType(DT_INIT_ARRAY);
}
Elf_Shdr relhack_section(relhack32_section);
Elf_Shdr relhackcode_section(relhackcode32_section);
ElfRelHack_Section *relhack = new ElfRelHack_Section(relhack_section);
ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf);
ElfSymtab_Section *symtab = (ElfSymtab_Section *) section->getLink();
Elf_SymValue *sym = symtab->lookup("__cxa_pure_virtual");
@ -381,13 +432,13 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
std::vector<Rel_Type> new_rels;
Elf_RelHack relhack_entry;
relhack_entry.r_offset = relhack_entry.r_info = 0;
int entry_sz = (elf->getClass() == ELFCLASS32) ? 4 : 8;
size_t init_array_reloc = 0;
for (typename std::vector<Rel_Type>::iterator i = section->rels.begin();
i != section->rels.end(); i++) {
// We don't need to keep R_*_NONE relocations
if (!ELF32_R_TYPE(i->r_info))
continue;
ElfSection *section = elf->getSectionAt(i->r_offset);
ElfLocation loc(i->r_offset, elf);
// __cxa_pure_virtual is a function used in vtables to point at pure
// virtual methods. The __cxa_pure_virtual function usually abort()s.
// These functions are however normally never called. In the case
@ -401,9 +452,9 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
// __cxa_pure_virtual symbol is defined in our lib, and we
// have relative relocations (rel_type) for it.
if (ELF32_R_TYPE(i->r_info) == rel_type) {
serializable<Elf_Addr_Traits> addr(&section->getData()[i->r_offset - section->getAddr()], entry_sz, elf->getClass(), elf->getData());
Elf_Addr addr(loc.getBuffer(), entry_sz, elf->getClass(), elf->getData());
if (addr.value == sym->value.getValue()) {
memset((char *)&section->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
memset((char *)loc.getBuffer(), 0, entry_sz);
continue;
}
}
@ -413,18 +464,26 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
// have absolute relocations (rel_type2) for it.
if ((ELF32_R_TYPE(i->r_info) == rel_type2) &&
(sym == &symtab->syms[ELF32_R_SYM(i->r_info)])) {
memset((char *)&section->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
memset((char *)loc.getBuffer(), 0, entry_sz);
continue;
}
}
}
// Keep track of the relocation associated with the first init_array entry.
if (init_array && i->r_offset == init_array->getAddr()) {
if (init_array_reloc) {
fprintf(stderr, "Found multiple relocations for the first init_array entry. Skipping\n");
return -1;
}
new_rels.push_back(*i);
init_array_reloc = new_rels.size();
} else if (!(loc.getSection()->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type) ||
(relro && (i->r_offset >= relro->getAddr()) &&
(i->r_offset < relro->getAddr() + relro->getMemSize()))) {
// Don't pack relocations happening in non writable sections.
// Our injected code is likely not to be allowed to write there.
if (!(section->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type) ||
(relro && (i->r_offset >= relro->getAddr()) &&
(i->r_offset < relro->getAddr() + relro->getMemSize())))
new_rels.push_back(*i);
else {
} else {
// TODO: check that i->r_addend == *i->r_offset
if (i->r_offset == relhack_entry.r_offset + relhack_entry.r_info * entry_sz) {
relhack_entry.r_info++;
@ -444,21 +503,54 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
unsigned int old_end = section->getOffset() + section->getSize();
if (init_array) {
if (! init_array_reloc) {
fprintf(stderr, "Didn't find relocation for DT_INIT_ARRAY's first entry. Skipping\n");
return -1;
}
Rel_Type *rel = &new_rels[init_array_reloc - 1];
unsigned int addend = get_addend(rel, elf);
// Use relocated value of DT_INIT_ARRAY's first entry for the
// function to be called by the injected code.
if (ELF32_R_TYPE(rel->r_info) == rel_type) {
original_init = addend;
} else if (ELF32_R_TYPE(rel->r_info) == rel_type2) {
ElfSymtab_Section *symtab = (ElfSymtab_Section *)section->getLink();
original_init = symtab->syms[ELF32_R_SYM(rel->r_info)].value.getValue() + addend;
} else {
fprintf(stderr, "Unsupported relocation type for DT_INIT_ARRAY's first entry. Skipping\n");
return -1;
}
}
ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf, original_init);
relhackcode->insertBefore(section);
relhack->insertAfter(relhackcode);
section->rels.assign(new_rels.begin(), new_rels.end());
section->shrink(new_rels.size() * section->getEntSize());
ElfLocation *init = new ElfLocation(relhackcode, relhackcode->getEntryPoint());
dyn->setValueForType(DT_INIT, init);
// TODO: adjust the value according to the remaining number of relative relocations
if (dyn->getValueForType(Rel_Type::d_tag_count))
dyn->setValueForType(Rel_Type::d_tag_count, new ElfPlainValue(0));
if (section->getOffset() + section->getSize() >= old_end) {
fprintf(stderr, "No gain. Skipping\n");
return -1;
}
// Ensure Elf sections will be at their final location.
elf->normalize();
ElfLocation *init = new ElfLocation(relhackcode, relhackcode->getEntryPoint());
if (init_array) {
// Adjust the first DT_INIT_ARRAY entry to point at the injected code
// by transforming its relocation into a relative one pointing to the
// address of the injected code.
Rel_Type *rel = &section->rels[init_array_reloc - 1];
rel->r_info = ELF32_R_INFO(0, rel_type); // Set as a relative relocation
set_relative_reloc(&section->rels[init_array_reloc - 1], elf, init->getValue());
} else if (!dyn->setValueForType(DT_INIT, init)) {
fprintf(stderr, "Can't grow .dynamic section to set DT_INIT. Skipping\n");
return -1;
}
// TODO: adjust the value according to the remaining number of relative relocations
if (dyn->getValueForType(Rel_Type::d_tag_count))
dyn->setValueForType(Rel_Type::d_tag_count, new ElfPlainValue(0));
return 0;
}
@ -494,13 +586,13 @@ void do_file(const char *name, bool backup = false, bool force = false)
int exit = -1;
switch (elf->getMachine()) {
case EM_386:
exit = do_relocation_section<Elf_Rel>(elf, R_386_RELATIVE, R_386_32);
exit = do_relocation_section<Elf_Rel>(elf, R_386_RELATIVE, R_386_32, force);
break;
case EM_X86_64:
exit = do_relocation_section<Elf_Rela>(elf, R_X86_64_RELATIVE, R_X86_64_64);
exit = do_relocation_section<Elf_Rela>(elf, R_X86_64_RELATIVE, R_X86_64_64, force);
break;
case EM_ARM:
exit = do_relocation_section<Elf_Rel>(elf, R_ARM_RELATIVE, R_ARM_ABS32);
exit = do_relocation_section<Elf_Rel>(elf, R_ARM_RELATIVE, R_ARM_ABS32, force);
break;
}
if (exit == 0) {

View File

@ -135,6 +135,7 @@ public:
ElfLocation(unsigned int location, Elf *elf);
unsigned int getValue();
ElfSection *getSection() { return section; }
const char *getBuffer();
};
class ElfSize: public ElfValue {
@ -164,7 +165,7 @@ private:
void init(const char *buf, size_t len, char ei_data)
{
R e;
assert(len <= sizeof(e));
assert(len >= sizeof(e));
memcpy(&e, buf, sizeof(e));
if (ei_data == ELFDATA2LSB) {
T::template swap<little_endian>(e, *this);
@ -176,6 +177,20 @@ private:
throw std::runtime_error("Unsupported ELF data encoding");
}
template <typename R>
void serialize(const char *buf, size_t len, char ei_data)
{
assert(len >= sizeof(R));
if (ei_data == ELFDATA2LSB) {
T::template swap<little_endian>(*this, *(R *)buf);
return;
} else if (ei_data == ELFDATA2MSB) {
T::template swap<big_endian>(*this, *(R *)buf);
return;
}
throw std::runtime_error("Unsupported ELF data encoding");
}
public:
serializable(const char *buf, size_t len, char ei_class, char ei_data)
{
@ -194,23 +209,13 @@ public:
if (ei_class == ELFCLASS32) {
typename T::Type32 e;
file.read((char *)&e, sizeof(e));
if (ei_data == ELFDATA2LSB) {
T::template swap<little_endian>(e, *this);
init<typename T::Type32>((char *)&e, sizeof(e), ei_data);
return;
} else if (ei_data == ELFDATA2MSB) {
T::template swap<big_endian>(e, *this);
return;
}
} else if (ei_class == ELFCLASS64) {
typename T::Type64 e;
file.read((char *)&e, sizeof(e));
if (ei_data == ELFDATA2LSB) {
T::template swap<little_endian>(e, *this);
init<typename T::Type64>((char *)&e, sizeof(e), ei_data);
return;
} else if (ei_data == ELFDATA2MSB) {
T::template swap<big_endian>(e, *this);
return;
}
}
throw std::runtime_error("Unsupported ELF class or data encoding");
}
@ -219,30 +224,30 @@ public:
{
if (ei_class == ELFCLASS32) {
typename T::Type32 e;
if (ei_data == ELFDATA2LSB) {
T::template swap<little_endian>(*this, e);
serialize<typename T::Type32>((char *)&e, sizeof(e), ei_data);
file.write((char *)&e, sizeof(e));
return;
} else if (ei_data == ELFDATA2MSB) {
T::template swap<big_endian>(*this, e);
file.write((char *)&e, sizeof(e));
return;
}
} else if (ei_class == ELFCLASS64) {
typename T::Type64 e;
if (ei_data == ELFDATA2LSB) {
T::template swap<little_endian>(*this, e);
serialize<typename T::Type64>((char *)&e, sizeof(e), ei_data);
file.write((char *)&e, sizeof(e));
return;
} else if (ei_data == ELFDATA2MSB) {
T::template swap<big_endian>(*this, e);
file.write((char *)&e, sizeof(e));
return;
}
}
throw std::runtime_error("Unsupported ELF class or data encoding");
}
void serialize(char *buf, size_t len, char ei_class, char ei_data)
{
if (ei_class == ELFCLASS32) {
serialize<typename T::Type32>(buf, len, ei_data);
return;
} else if (ei_class == ELFCLASS64) {
serialize<typename T::Type64>(buf, len, ei_data);
return;
}
throw std::runtime_error("Unsupported ELF class");
}
static inline unsigned int size(char ei_class)
{
if (ei_class == ELFCLASS32)
@ -269,6 +274,7 @@ public:
ElfDynamic_Section *getDynSection();
void normalize();
void write(std::ofstream &file);
char getClass();
@ -505,7 +511,7 @@ public:
ElfValue *getValueForType(unsigned int tag);
ElfSection *getSectionForType(unsigned int tag);
void setValueForType(unsigned int tag, ElfValue *val);
bool setValueForType(unsigned int tag, ElfValue *val);
private:
std::vector<Elf_DynValue> dyns;
};
@ -661,6 +667,10 @@ inline unsigned int ElfLocation::getValue() {
return (section ? section->getAddr() : 0) + offset;
}
inline const char *ElfLocation::getBuffer() {
return section ? section->getData() + offset : NULL;
}
inline unsigned int ElfSize::getValue() {
return section->getSize();
}

View File

@ -0,0 +1,8 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "test.c"
__attribute__((section(".init_array"), used))
static void (*init_array[])() = { end_test, test };

View File

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "test.c"
/* Recent binutils would put .ctors content into a .init_array section */
__attribute__((section(".manual_ctors"), used))
static void (*ctors[])() = { (void (*)())-1, end_test, test, NULL };
__attribute__((section(".init")))
void _init() {
void (**func)() = &ctors[sizeof(ctors) / sizeof(void (*)()) - 1];
while (*(--func) != (void (*)())-1) {
(*func)();
}
}

View File

@ -125,14 +125,14 @@ int print_status() {
* following sections as part of the PT_TLS segment. */
__thread int foo[1024];
__attribute__((constructor)) void end_test() {
void end_test() {
static int count = 0;
/* Only exit when both constructors have been called */
if (++count == 2)
ret = 0;
}
__attribute__((constructor)) void test() {
void test() {
int i = 0, j = 0;
#define DEF_(a,i,w) \
if (a[i++] != str_ ## w) return;

View File

@ -4150,7 +4150,6 @@ MOZ_SPEEX_RESAMPLER=1
MOZ_CUBEB=
MOZ_VORBIS=
MOZ_TREMOR=
MOZ_FLOATING_POINT_AUDIO=
MOZ_WAVE=1
MOZ_MEDIA=
MOZ_OPUS=1
@ -5200,24 +5199,6 @@ fi
AC_SUBST(MOZ_WEBRTC)
dnl ========================================================
dnl = Disable floating point audio.
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(floating-point,
[ --disable-floating-point Disable floating point audio],
MOZ_FLOATING_POINT_AUDIO=,
MOZ_FLOATING_POINT_AUDIO=1)
case "$target_cpu" in
arm*)
;;
*)
AC_DEFINE(MOZ_FLOATING_POINT_AUDIO)
MOZ_FLOATING_POINT_AUDIO=1
;;
esac
dnl ========================================================
dnl = Enable Raw Codecs
dnl ========================================================
@ -5246,6 +5227,14 @@ if test -n "$MOZ_OGG"; then
MOZ_SYDNEYAUDIO=1
MOZ_CUBEB=1
MOZ_MEDIA=1
case "$target_cpu" in
arm*)
MOZ_TREMOR=1
;;
*)
MOZ_VORBIS=1
;;
esac
dnl Checks for __attribute__(aligned()) directive
AC_CACHE_CHECK([__attribute__ ((aligned ())) support],
@ -5315,7 +5304,7 @@ if test -n "$MOZ_MEDIA_NAVIGATOR"; then
fi
dnl ========================================================
dnl = Enable building OMX media plugin (B2G)
dnl = Enable building OMX media plugin (B2G or Android)
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(omx-plugin,
[ --enable-omx-plugin Enable building OMX plugin (B2G)],
@ -5323,12 +5312,12 @@ MOZ_ARG_ENABLE_BOOL(omx-plugin,
MOZ_OMX_PLUGIN=)
if test -n "$MOZ_OMX_PLUGIN"; then
if test "$OS_TARGET" = "Android" -a -n "$gonkdir"; then
dnl Only allow building OMX plugin on Gonk (B2G)
if test "$OS_TARGET" = "Android"; then
dnl Only allow building OMX plugin on Gonk (B2G) or Android
AC_DEFINE(MOZ_OMX_PLUGIN)
else
dnl fail if we're not building on Gonk
AC_MSG_ERROR([OMX media plugin can only be built on B2G])
dnl fail if we're not building on Gonk or Android
AC_MSG_ERROR([OMX media plugin can only be built on B2G or Android])
fi
fi
@ -5375,11 +5364,14 @@ if test "$MOZ_WEBM"; then
MOZ_SYDNEYAUDIO=1
MOZ_CUBEB=1
MOZ_MEDIA=1
if test -n "$MOZ_FLOATING_POINT_AUDIO"; then
MOZ_VORBIS=1
else
case "$target_cpu" in
arm*)
MOZ_TREMOR=1
fi
;;
*)
MOZ_VORBIS=1
;;
esac
fi
if test -n "$MOZ_VP8" -a -z "$MOZ_NATIVE_LIBVPX"; then

View File

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DirectionalityUtils_h___
#define DirectionalityUtils_h___
class nsIContent;
class nsIDocument;
class nsINode;
namespace mozilla {
namespace dom {
class Element;
} // namespace dom
} // namespace mozilla
namespace mozilla {
namespace directionality {
enum Directionality {
eDir_NotSet = 0,
eDir_RTL = 1,
eDir_LTR = 2
};
/**
* Set the directionality of an element according to the algorithm defined at
* http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#the-directionality,
* not including elements with auto direction.
*
* @return the directionality that the element was set to
*/
Directionality RecomputeDirectionality(mozilla::dom::Element* aElement,
bool aNotify = true);
/**
* Set the directionality of any descendants of a node that do not themselves
* have a dir attribute.
* For performance reasons we walk down the descendant tree in the rare case
* of setting the dir attribute, rather than walking up the ancestor tree in
* the much more common case of getting the element's directionality.
*/
void SetDirectionalityOnDescendants(mozilla::dom::Element* aElement,
Directionality aDir,
bool aNotify = true);
} // end namespace directionality
} // end namespace mozilla
#endif /* DirectionalityUtils_h___ */

View File

@ -10,6 +10,7 @@
#include "mozilla/dom/FragmentOrElement.h" // for base class
#include "nsChangeHint.h" // for enum
#include "nsEventStates.h" // for member
#include "mozilla/dom/DirectionalityUtils.h"
class nsEventStateManager;
class nsFocusManager;
@ -216,6 +217,54 @@ public:
*/
virtual nsIAtom *GetClassAttributeName() const = 0;
inline mozilla::directionality::Directionality GetDirectionality() const {
if (HasFlag(NODE_HAS_DIRECTION_RTL)) {
return mozilla::directionality::eDir_RTL;
}
if (HasFlag(NODE_HAS_DIRECTION_LTR)) {
return mozilla::directionality::eDir_LTR;
}
return mozilla::directionality::eDir_NotSet;
}
inline void SetDirectionality(mozilla::directionality::Directionality aDir,
bool aNotify) {
UnsetFlags(NODE_ALL_DIRECTION_FLAGS);
if (!aNotify) {
RemoveStatesSilently(DIRECTION_STATES);
}
switch (aDir) {
case (mozilla::directionality::eDir_RTL):
SetFlags(NODE_HAS_DIRECTION_RTL);
if (!aNotify) {
AddStatesSilently(NS_EVENT_STATE_RTL);
}
break;
case(mozilla::directionality::eDir_LTR):
SetFlags(NODE_HAS_DIRECTION_LTR);
if (!aNotify) {
AddStatesSilently(NS_EVENT_STATE_LTR);
}
break;
default:
break;
}
/*
* Only call UpdateState if we need to notify, because we call
* SetDirectionality for every element, and UpdateState is very very slow
* for some elements.
*/
if (aNotify) {
UpdateState(true);
}
}
protected:
/**
* Method to get the _intrinsic_ content state of this element. This is the

View File

@ -48,6 +48,7 @@ $(NULL)
EXPORTS_NAMESPACES = mozilla/dom mozilla
EXPORTS_mozilla/dom = \
DirectionalityUtils.h \
Element.h \
FragmentOrElement.h \
FromParser.h \

View File

@ -21,7 +21,7 @@
//A trick to handle IEEE floating point exceptions on FreeBSD - E.D.
#ifdef __FreeBSD__
#include <ieeefp.h>
#ifdef __alpha__
#if !defined(__i386__) && !defined(__x86_64__)
static fp_except_t allmask = FP_X_INV|FP_X_OFL|FP_X_UFL|FP_X_DZ|FP_X_IMP;
#else
static fp_except_t allmask = FP_X_INV|FP_X_OFL|FP_X_UFL|FP_X_DZ|FP_X_IMP|FP_X_DNML;

View File

@ -23,6 +23,7 @@
#include "nsPIDOMWindow.h" // for use in inline functions
#include "nsPropertyTable.h" // for member
#include "nsTHashtable.h" // for member
#include "mozilla/dom/DirectionalityUtils.h"
class imgIRequest;
class nsAString;
@ -398,6 +399,10 @@ public:
mBidiOptions = aBidiOptions;
}
inline mozilla::directionality::Directionality GetDocumentDirectionality() {
return mDirectionality;
}
/**
* Access HTTP header data (this may also get set from other
* sources, like HTML META tags).
@ -1853,6 +1858,9 @@ protected:
// defined in nsBidiUtils.h
PRUint32 mBidiOptions;
// The root directionality of this document.
mozilla::directionality::Directionality mDirectionality;
nsCString mContentLanguage;
private:
nsCString mContentType;

View File

@ -145,8 +145,16 @@ enum {
// Set if the node has had :hover selectors matched against it
NODE_HAS_RELEVANT_HOVER_RULES = 0x00080000U,
// Set if the node has right-to-left directionality
NODE_HAS_DIRECTION_RTL = 0x00100000U,
// Set if the node has left-to-right directionality
NODE_HAS_DIRECTION_LTR = 0x00200000U,
NODE_ALL_DIRECTION_FLAGS = NODE_HAS_DIRECTION_LTR | NODE_HAS_DIRECTION_RTL,
// Remaining bits are node type specific.
NODE_TYPE_SPECIFIC_BITS_OFFSET = 20
NODE_TYPE_SPECIFIC_BITS_OFFSET = 22
};
/**
@ -1279,6 +1287,8 @@ private:
NodeIsContent,
// Set if the node has animations or transitions
ElementHasAnimations,
// Set if node has a dir attribute with a valid value (ltr or rtl)
NodeHasValidDirAttribute,
// Guard value
BooleanFlagCount
};
@ -1346,6 +1356,9 @@ public:
void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
bool MayHaveAnimations() { return GetBoolFlag(ElementHasAnimations); }
void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
protected:
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
void SetInDocument() { SetBoolFlag(IsInDocument); }

View File

@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=78: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/DirectionalityUtils.h"
#include "nsINode.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "mozilla/dom/Element.h"
#include "nsIDOMNodeFilter.h"
#include "nsTreeWalker.h"
#include "nsIDOMHTMLDocument.h"
namespace mozilla {
namespace directionality {
typedef mozilla::dom::Element Element;
Directionality
RecomputeDirectionality(Element* aElement, bool aNotify)
{
Directionality dir = eDir_LTR;
if (aElement->HasValidDir()) {
dir = aElement->GetDirectionality();
} else {
Element* parent = aElement->GetElementParent();
if (parent) {
// If the element doesn't have an explicit dir attribute with a valid
// value, the directionality is the same as the parent element (but
// don't propagate the parent directionality if it isn't set yet).
Directionality parentDir = parent->GetDirectionality();
if (parentDir != eDir_NotSet) {
dir = parentDir;
}
} else {
// If there is no parent element, the directionality is the same as the
// document direction.
Directionality documentDir =
aElement->OwnerDoc()->GetDocumentDirectionality();
if (documentDir != eDir_NotSet) {
dir = documentDir;
}
}
aElement->SetDirectionality(dir, aNotify);
}
return dir;
}
void
SetDirectionalityOnDescendants(Element* aElement, Directionality aDir,
bool aNotify)
{
for (nsIContent* child = aElement->GetFirstChild(); child; ) {
if (!child->IsElement()) {
child = child->GetNextNode(aElement);
continue;
}
Element* element = child->AsElement();
if (element->HasValidDir()) {
child = child->GetNextNonChildNode(aElement);
continue;
}
element->SetDirectionality(aDir, aNotify);
child = child->GetNextNode(aElement);
}
}
} // end namespace directionality
} // end namespace mozilla

View File

@ -15,7 +15,6 @@ LIBRARY_NAME = gkconbase_s
LIBXUL_LIBRARY = 1
EXPORTS = \
nsAtomListUtils.h \
nsAttrName.h \
@ -53,6 +52,7 @@ LOCAL_INCLUDES = \
$(NULL)
CPPSRCS = \
DirectionalityUtils.cpp \
nsAtomListUtils.cpp \
nsAttrAndChildArray.cpp \
nsAttrValue.cpp \

View File

@ -1199,8 +1199,8 @@ nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
PRInt32 endOffset = mRange->EndOffset();
MOZ_ASSERT(mCommonParent && startParent && endParent);
// Bug 767169
MOZ_ASSERT(startOffset <= startParent->Length() &&
endOffset <= endParent->Length());
MOZ_ASSERT(PRUint32(startOffset) <= startParent->Length() &&
PRUint32(endOffset) <= endParent->Length());
// short circuit when start node == end node
if (startParent == endParent) {

View File

@ -57,7 +57,6 @@ private:
nsCOMPtr<nsIURI> mBaseURI;
nsWeakPtr mScriptHandlingObject;
bool mLoopingForSyncLoad;
bool mAttemptedInit;
};

View File

@ -91,6 +91,7 @@
#include "nsXMLEventsManager.h"
#include "nsBidiUtils.h"
#include "mozilla/dom/DirectionalityUtils.h"
#include "nsIDOMUserDataHandler.h"
#include "nsIDOMXPathEvaluator.h"
@ -170,6 +171,7 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::directionality;
typedef nsTArray<Link*> LinkArray;
@ -1510,6 +1512,7 @@ nsIDocument::nsIDocument()
mAllowDNSPrefetch(true),
mIsBeingUsedAsImage(false),
mHasLinksToUpdate(false),
mDirectionality(eDir_LTR),
mPartID(0)
{
SetInDocument();
@ -5583,6 +5586,15 @@ nsDocument::SetDir(const nsAString& aDirection)
// No presentation; just set it on ourselves
SetBidiOptions(options);
}
Directionality dir = elt->mValue == IBMBIDI_TEXTDIRECTION_RTL ?
eDir_RTL : eDir_LTR;
SetDocumentDirectionality(dir);
// Set the directionality of the root element and its descendants, if any
Element* rootElement = GetRootElement();
if (rootElement) {
rootElement->SetDirectionality(dir, true);
SetDirectionalityOnDescendants(rootElement, dir);
}
}
break;

View File

@ -1048,6 +1048,12 @@ protected:
nsIContent* GetFirstBaseNodeWithHref();
nsresult SetFirstBaseNodeWithHref(nsIContent *node);
inline void
SetDocumentDirectionality(mozilla::directionality::Directionality aDir)
{
mDirectionality = aDir;
}
// Get the first <title> element with the given IsNodeOfType type, or
// return null if there isn't one
nsIContent* GetTitleContent(PRUint32 aNodeType);

View File

@ -808,9 +808,13 @@ nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
nsCOMPtr<nsIInputStream> input;
channel->Open(getter_AddRefs(input));
nsString dataString;
PRUint32 avail = 0;
if (input && NS_SUCCEEDED(input->Available(&avail)) && avail) {
PRUint64 avail64 = 0;
if (input && NS_SUCCEEDED(input->Available(&avail64)) && avail64) {
if (avail64 > PR_UINT32_MAX) {
return;
}
nsCString buffer;
PRUint32 avail = (PRUint32)NS_MIN(avail64, (PRUint64)PR_UINT32_MAX);
if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, avail))) {
return;
}

View File

@ -51,6 +51,7 @@
#include "nsIDOMMutationEvent.h"
#include "nsMutationEvent.h"
#include "nsNodeUtils.h"
#include "mozilla/dom/DirectionalityUtils.h"
#include "nsDocument.h"
#include "nsAttrValueOrString.h"
#ifdef MOZ_XUL
@ -128,6 +129,7 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::directionality;
nsEventStates
Element::IntrinsicState() const
@ -1358,6 +1360,13 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
SetSubtreeRootPointer(aParent->SubtreeRoot());
}
// This has to be here, rather than in nsGenericHTMLElement::BindToTree,
// because it has to happen after updating the parent pointer, but before
// recursively binding the kids.
if (IsHTML()) {
RecomputeDirectionality(this, false);
}
// If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
// that also need to be told that they are moving.
nsresult rv;
@ -1543,6 +1552,13 @@ nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
}
// This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,
// because it has to happen after unsetting the parent pointer, but before
// recursively unbinding the kids.
if (IsHTML()) {
RecomputeDirectionality(this, false);
}
if (aDeep) {
// Do the kids. Don't call GetChildCount() here since that'll force
// XUL to generate template children, which there is no need for since

View File

@ -270,6 +270,7 @@ GK_ATOM(dialog, "dialog")
GK_ATOM(difference, "difference")
GK_ATOM(digit, "digit")
GK_ATOM(dir, "dir")
GK_ATOM(directionality, "directionality")
GK_ATOM(disableOutputEscaping, "disable-output-escaping")
GK_ATOM(disabled, "disabled")
GK_ATOM(display, "display")
@ -719,6 +720,7 @@ GK_ATOM(ontransitionend, "ontransitionend")
GK_ATOM(onunderflow, "onunderflow")
GK_ATOM(onunload, "onunload")
GK_ATOM(onupgradeneeded, "onupgradeneeded")
GK_ATOM(onwheel, "onwheel")
GK_ATOM(open, "open")
GK_ATOM(optgroup, "optgroup")
GK_ATOM(optimum, "optimum")

View File

@ -81,6 +81,16 @@ static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc");
#define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gObjectLog, PR_LOG_DEBUG)
static bool
InActiveDocument(nsIContent *aContent)
{
if (!aContent->IsInDoc()) {
return false;
}
nsIDocument *doc = aContent->OwnerDoc();
return (doc && doc->IsActive());
}
///
/// Runnables and helper classes
///
@ -137,7 +147,7 @@ InDocCheckEvent::Run()
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent *>(objLC));
if (!content->IsInDoc()) {
if (!InActiveDocument(content)) {
nsObjectLoadingContent *objLC =
static_cast<nsObjectLoadingContent *>(mContent.get());
objLC->UnloadObject();
@ -556,21 +566,30 @@ nsObjectLoadingContent::IsSupportedDocument(const nsCString& aMimeType)
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
NS_ASSERTION(thisContent, "must be a content");
nsresult rv;
nsCOMPtr<nsIWebNavigationInfo> info(
do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID, &rv));
PRUint32 supported;
if (info) {
do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID));
if (!info) {
return false;
}
nsCOMPtr<nsIWebNavigation> webNav;
nsIDocument* currentDoc = thisContent->GetCurrentDoc();
if (currentDoc) {
webNav = do_GetInterface(currentDoc->GetScriptGlobalObject());
}
rv = info->IsTypeSupported(aMimeType, webNav, &supported);
PRUint32 supported;
nsresult rv = info->IsTypeSupported(aMimeType, webNav, &supported);
if (NS_FAILED(rv)) {
return false;
}
if (supported != nsIWebNavigationInfo::UNSUPPORTED) {
// Don't want to support plugins as documents
return supported != nsIWebNavigationInfo::PLUGIN;
}
if (NS_SUCCEEDED(rv)) {
if (supported == nsIWebNavigationInfo::UNSUPPORTED) {
// Try a stream converter
// NOTE: We treat any type we can convert from as a supported type. If a
// type is not actually supported, the URI loader will detect that and
@ -584,13 +603,6 @@ nsObjectLoadingContent::IsSupportedDocument(const nsCString& aMimeType)
return NS_SUCCEEDED(rv) && canConvert;
}
// Don't want to support plugins as documents
return supported != nsIWebNavigationInfo::PLUGIN;
}
return false;
}
nsresult
nsObjectLoadingContent::BindToTree(nsIDocument* aDocument,
nsIContent* /*aParent*/,
@ -612,7 +624,7 @@ nsObjectLoadingContent::UnbindFromTree(bool /*aDeep*/, bool /*aNullParent*/)
nsIDocument* ownerDoc = thisContent->OwnerDoc();
ownerDoc->RemovePlugin(this);
if (mType == eType_Plugin) {
if (mType == eType_Plugin && mInstanceOwner) {
// we'll let the plugin continue to run at least until we get back to
// the event loop. If we get back to the event loop and the node
// has still not been added back to the document then we tear down the
@ -624,6 +636,7 @@ nsObjectLoadingContent::UnbindFromTree(bool /*aDeep*/, bool /*aNullParent*/)
appShell->RunInStableState(event);
}
} else {
// Reset state and clear pending events
/// XXX(johns): The implementation for GenericFrame notes that ideally we
/// would keep the docshell around, but trash the frameloader
UnloadObject();
@ -694,7 +707,7 @@ nsObjectLoadingContent::InstantiatePluginInstance()
if (!doc) {
return NS_ERROR_FAILURE;
}
if (!doc->IsActive()) {
if (!InActiveDocument(thisContent)) {
NS_ERROR("Shouldn't be calling "
"InstantiatePluginInstance in an inactive document");
return NS_ERROR_FAILURE;
@ -1471,6 +1484,12 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
nsIDocument* doc = thisContent->OwnerDoc();
nsresult rv = NS_OK;
// Sanity check
if (!InActiveDocument(thisContent)) {
NS_NOTREACHED("LoadObject called while not bound to an active document");
return NS_ERROR_UNEXPECTED;
}
// XXX(johns): In these cases, we refuse to touch our content and just
// remain unloaded, as per legacy behavior. It would make more sense to
// load fallback content initially and refuse to ever change state again.
@ -1478,12 +1497,6 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
return NS_OK;
}
// Sanity check
if (!thisContent->IsInDoc()) {
NS_NOTREACHED("LoadObject called while not bound to a document");
return NS_ERROR_UNEXPECTED;
}
LOG(("OBJLC [%p]: LoadObject called, notify %u, forceload %u, channel %p",
this, aNotify, aForceLoad, aLoadingChannel));
@ -1970,7 +1983,7 @@ nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
if (newState != aOldState) {
// This will trigger frame construction
NS_ASSERTION(thisContent->IsInDoc(), "Something is confused");
NS_ASSERTION(InActiveDocument(thisContent), "Something is confused");
nsEventStates changedBits = aOldState ^ newState;
{
@ -2151,10 +2164,10 @@ nsObjectLoadingContent::SyncStartPluginInstance()
"Must be able to run script in order to instantiate a plugin instance!");
// Don't even attempt to start an instance unless the content is in
// the document.
// the document and active
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
if (!thisContent->IsInDoc()) {
if (!InActiveDocument(thisContent)) {
return NS_ERROR_FAILURE;
}

View File

@ -352,9 +352,9 @@ nsSyncLoadService::PushSyncStreamToListener(nsIInputStream* aIn,
// Load
rv = aListener->OnStartRequest(aChannel, nullptr);
if (NS_SUCCEEDED(rv)) {
PRUint32 sourceOffset = 0;
PRUint64 sourceOffset = 0;
while (1) {
PRUint32 readCount = 0;
PRUint64 readCount = 0;
rv = aIn->Available(&readCount);
if (NS_FAILED(rv) || !readCount) {
if (rv == NS_BASE_STREAM_CLOSED) {
@ -364,8 +364,12 @@ nsSyncLoadService::PushSyncStreamToListener(nsIInputStream* aIn,
break;
}
if (readCount > PR_UINT32_MAX)
readCount = PR_UINT32_MAX;
rv = aListener->OnDataAvailable(aChannel, nullptr, aIn,
sourceOffset, readCount);
(PRUint32)NS_MIN(sourceOffset, (PRUint64)PR_UINT32_MAX),
(PRUint32)readCount);
if (NS_FAILED(rv)) {
break;
}

View File

@ -2962,7 +2962,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
}
mUploadComplete = false;
PRUint32 uploadTotal = 0;
PRUint64 uploadTotal = 0;
postDataStream->Available(&uploadTotal);
mUploadTotal = uploadTotal;

View File

@ -381,6 +381,8 @@ MOCHITEST_FILES_B = \
test_bug562652.html \
test_bug562137.html \
file_bug562137.txt \
test_bug562169-1.html \
test_bug562169-2.html \
test_bug548193.html \
file_bug548193.sjs \
test_html_colors_quirks.html \

View File

@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=562169
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 562169</title>
<script type="application/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=562169">Mozilla Bug 562169</a>
<p id="display"></p>
<div id="content" style="display: none">
<div dir="rtl" id="z"></div>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 562169 **/
/** Test that adding an child to an element with dir="rtl" makes the
child have rtl directionality, and removing the child makes it
go back to ltr directionality **/
function checkSelector(element, expectedDir, expectedChild)
{
ok(element.querySelector(":dir("+expectedDir+")") == expectedChild,
"direction should be " + expectedDir);
}
var x = document.createElement("div");
var y = document.createElement("div");
x.appendChild(y);
checkSelector(x, "ltr", y);
$(z).appendChild(x);
checkSelector(x, "rtl", y);
$(z).removeChild(x);
checkSelector(x, "ltr", y);
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=562169
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 562169</title>
<script type="application/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=562169">Mozilla Bug 562169</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 562169 **/
/** Test that a newly created element has ltr directionality **/
ok(document.createElement("div").mozMatchesSelector(":dir(ltr)"),
"Element should be ltr on creation");
</script>
</pre>
</body>
</html>

View File

@ -1099,6 +1099,7 @@ protected:
bool mMinCapability;
bool mDisableExtensions;
bool mHasRobustness;
bool mIsMesa;
template<typename WebGLObjectType>
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
@ -2324,6 +2325,24 @@ public:
return false;
}
size_t UpperBoundNumSamplerUniforms() {
size_t numSamplerUniforms = 0;
for (size_t i = 0; i < mAttachedShaders.Length(); ++i) {
const WebGLShader *shader = mAttachedShaders[i];
if (!shader)
continue;
for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) {
WebGLUniformInfo u = shader->mUniformInfos[j];
if (u.type == SH_SAMPLER_2D ||
u.type == SH_SAMPLER_CUBE)
{
numSamplerUniforms += u.arraySize;
}
}
}
return numSamplerUniforms;
}
bool NextGeneration()
{
if (!(mGeneration + 1).isValid())

View File

@ -3706,6 +3706,17 @@ WebGLContext::LinkProgram(WebGLProgram *program, ErrorResult& rv)
return;
}
// bug 777028
// Mesa can't handle more than 16 samplers per program, counting each array entry.
if (mIsMesa) {
if (program->UpperBoundNumSamplerUniforms() > 16) {
GenerateWarning("Programs with more than 16 samplers are disallowed on Mesa drivers "
"to avoid a Mesa crasher.");
program->SetLinkStatus(false);
return;
}
}
GLint ok;
if (gl->WorkAroundDriverBugs() &&
program->HasBadShaderAttached())
@ -5029,7 +5040,6 @@ WebGLContext::CompileShader(WebGLShader *shader)
nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
for (int i = 0; i < num_uniforms; i++) {
int length, size;
ShDataType type;

View File

@ -771,6 +771,9 @@ WebGLContext::InitAndValidateGL()
}
#endif
// Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
mIsMesa = strstr((const char *)(gl->fGetString(LOCAL_GL_VERSION)), "Mesa");
// notice that the point of calling GetAndClearError here is not only to check for error,
// it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
error = gl->GetAndClearError();

View File

@ -4316,8 +4316,11 @@ nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
CanvasLayer *aOldLayer,
LayerManager *aManager)
{
if (!EnsureSurface())
// If we don't have anything to draw, don't bother.
if (!mValid || !mSurface || mSurface->CairoStatus() || !mThebes ||
!mSurfaceCreated) {
return nullptr;
}
if (!mResetLayer && aOldLayer) {
CanvasRenderingContext2DUserData* userData =

View File

@ -20,7 +20,8 @@ function IsD2DEnabled() {
}
function IsLinux() {
return navigator.platform.indexOf("Linux") == 0;
return navigator.platform.indexOf("Linux") == 0 &&
navigator.appVersion.indexOf("Android") == -1;
}
function IsMacOSX10_5orOlder() {

View File

@ -600,6 +600,10 @@ NON_IDL_EVENT(underflow,
NS_SCROLLPORT_UNDERFLOW,
EventNameType_XUL,
NS_EVENT_NULL)
NON_IDL_EVENT(wheel,
NS_WHEEL_WHEEL,
EventNameType_XUL,
NS_WHEEL_EVENT)
// Various SVG events
NON_IDL_EVENT(SVGLoad,

View File

@ -248,11 +248,17 @@ private:
#define NS_EVENT_STATE_VULNERABLE_NO_UPDATE NS_DEFINE_EVENT_STATE_MACRO(41)
// Platform does not support plugin content (some mobile platforms)
#define NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM NS_DEFINE_EVENT_STATE_MACRO(42)
// Element is ltr (for :dir pseudo-class)
#define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(43)
// Element is rtl (for :dir pseudo-class)
#define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(44)
/**
* NOTE: do not go over 63 without updating nsEventStates::InternalType!
*/
#define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \

View File

@ -0,0 +1,176 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DOMWheelEvent.h"
#include "nsGUIEvent.h"
#include "nsIContent.h"
#include "nsContentUtils.h"
#include "DictionaryHelpers.h"
#include "nsDOMClassInfoID.h"
DOMCI_DATA(WheelEvent, mozilla::dom::DOMWheelEvent)
namespace mozilla {
namespace dom {
DOMWheelEvent::DOMWheelEvent(nsPresContext* aPresContext,
widget::WheelEvent* aWheelEvent)
: nsDOMMouseEvent(aPresContext, aWheelEvent ? aWheelEvent :
new widget::WheelEvent(false, 0, nullptr))
{
if (aWheelEvent) {
mEventIsInternal = false;
} else {
mEventIsInternal = true;
mEvent->time = PR_Now();
mEvent->refPoint.x = mEvent->refPoint.y = 0;
static_cast<widget::WheelEvent*>(mEvent)->inputSource =
nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
}
}
DOMWheelEvent::~DOMWheelEvent()
{
if (mEventIsInternal && mEvent) {
MOZ_ASSERT(mEvent->eventStructType == NS_WHEEL_EVENT,
"The mEvent must be WheelEvent");
delete static_cast<widget::WheelEvent*>(mEvent);
mEvent = nullptr;
}
}
NS_IMPL_ADDREF_INHERITED(DOMWheelEvent, nsDOMMouseEvent)
NS_IMPL_RELEASE_INHERITED(DOMWheelEvent, nsDOMMouseEvent)
NS_INTERFACE_MAP_BEGIN(DOMWheelEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMWheelEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WheelEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMMouseEvent)
NS_IMETHODIMP
DOMWheelEvent::InitWheelEvent(const nsAString & aType,
bool aCanBubble,
bool aCancelable,
nsIDOMWindow *aView,
PRInt32 aDetail,
PRInt32 aScreenX,
PRInt32 aScreenY,
PRInt32 aClientX,
PRInt32 aClientY,
PRUint16 aButton,
nsIDOMEventTarget *aRelatedTarget,
const nsAString& aModifiersList,
double aDeltaX,
double aDeltaY,
double aDeltaZ,
PRUint32 aDeltaMode)
{
nsresult rv =
nsDOMMouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView,
aDetail, aScreenX, aScreenY,
aClientX, aClientY, aButton,
aRelatedTarget, aModifiersList);
NS_ENSURE_SUCCESS(rv, rv);
widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(mEvent);
wheelEvent->deltaX = aDeltaX;
wheelEvent->deltaY = aDeltaY;
wheelEvent->deltaZ = aDeltaZ;
wheelEvent->deltaMode = aDeltaMode;
return NS_OK;
}
NS_IMETHODIMP
DOMWheelEvent::GetDeltaX(double* aDeltaX)
{
NS_ENSURE_ARG_POINTER(aDeltaX);
*aDeltaX = static_cast<widget::WheelEvent*>(mEvent)->deltaX;
return NS_OK;
}
NS_IMETHODIMP
DOMWheelEvent::GetDeltaY(double* aDeltaY)
{
NS_ENSURE_ARG_POINTER(aDeltaY);
*aDeltaY = static_cast<widget::WheelEvent*>(mEvent)->deltaY;
return NS_OK;
}
NS_IMETHODIMP
DOMWheelEvent::GetDeltaZ(double* aDeltaZ)
{
NS_ENSURE_ARG_POINTER(aDeltaZ);
*aDeltaZ = static_cast<widget::WheelEvent*>(mEvent)->deltaZ;
return NS_OK;
}
NS_IMETHODIMP
DOMWheelEvent::GetDeltaMode(PRUint32* aDeltaMode)
{
NS_ENSURE_ARG_POINTER(aDeltaMode);
*aDeltaMode = static_cast<widget::WheelEvent*>(mEvent)->deltaMode;
return NS_OK;
}
nsresult
DOMWheelEvent::InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal)
{
WheelEventInit d;
nsresult rv = d.Init(aCx, aVal);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString modifierList;
if (d.ctrlKey) {
modifierList.AppendLiteral(NS_DOM_KEYNAME_CONTROL);
}
if (d.shiftKey) {
if (!modifierList.IsEmpty()) {
modifierList.AppendLiteral(" ");
}
modifierList.AppendLiteral(NS_DOM_KEYNAME_SHIFT);
}
if (d.altKey) {
if (!modifierList.IsEmpty()) {
modifierList.AppendLiteral(" ");
}
modifierList.AppendLiteral(NS_DOM_KEYNAME_ALT);
}
if (d.metaKey) {
if (!modifierList.IsEmpty()) {
modifierList.AppendLiteral(" ");
}
modifierList.AppendLiteral(NS_DOM_KEYNAME_META);
}
rv = InitWheelEvent(aType, d.bubbles, d.cancelable,
d.view, d.detail, d.screenX, d.screenY,
d.clientX, d.clientY, d.button, d.relatedTarget,
modifierList, d.deltaX, d.deltaY, d.deltaZ, d.deltaMode);
NS_ENSURE_SUCCESS(rv, rv);
static_cast<widget::WheelEvent*>(mEvent)->buttons = d.buttons;
return NS_OK;
}
} // namespace dom
} // namespace mozilla
using namespace mozilla;
nsresult NS_NewDOMWheelEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
widget::WheelEvent *aEvent)
{
dom::DOMWheelEvent* it = new dom::DOMWheelEvent(aPresContext, aEvent);
return CallQueryInterface(it, aInstancePtrResult);
}

View File

@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_DOMWheelEvent_h__
#define mozilla_dom_DOMWheelEvent_h__
#include "nsIDOMWheelEvent.h"
#include "nsDOMMouseEvent.h"
namespace mozilla {
namespace dom {
class DOMWheelEvent : public nsDOMMouseEvent,
public nsIDOMWheelEvent
{
public:
DOMWheelEvent(nsPresContext* aPresContext,
widget::WheelEvent* aWheelEvent);
virtual ~DOMWheelEvent();
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMWheelEvent Interface
NS_DECL_NSIDOMWHEELEVENT
// Forward to base class
NS_FORWARD_TO_NSDOMMOUSEEVENT
virtual nsresult InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_DOMWheelEvent_h__

View File

@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk
MODULE = content
LIBRARY_NAME = gkconevents_s
LIBXUL_LIBRARY = 1
FAIL_ON_WARNINGS = 1
EXPORTS = \
nsEventStateManager.h \
@ -62,6 +63,7 @@ CPPSRCS = \
nsDOMAnimationEvent.cpp \
nsDOMTouchEvent.cpp \
nsDOMCompositionEvent.cpp \
DOMWheelEvent.cpp \
$(NULL)
ifdef MOZ_B2G_RIL

View File

@ -52,7 +52,7 @@ static const char* const sEventNames[] = {
"DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument",
"DOMAttrModified", "DOMCharacterDataModified",
"DOMActivate", "DOMFocusIn", "DOMFocusOut",
"pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll",
"pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll", "wheel",
"offline", "online", "copy", "cut", "paste", "open", "message", "show",
"SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
"SVGZoom",
@ -191,6 +191,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEvent)
switch (tmp->mEvent->eventStructType) {
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:
static_cast<nsMouseEvent_base*>(tmp->mEvent)->relatedTarget = nullptr;
@ -218,6 +219,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent)
switch (tmp->mEvent->eventStructType) {
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
@ -718,11 +720,10 @@ nsDOMEvent::DuplicatePrivateData()
{
nsMouseScrollEvent* mouseScrollEvent =
new nsMouseScrollEvent(false, msg, nullptr);
NS_ENSURE_TRUE(mouseScrollEvent, NS_ERROR_OUT_OF_MEMORY);
isInputEvent = true;
nsMouseScrollEvent* oldMouseScrollEvent =
static_cast<nsMouseScrollEvent*>(mEvent);
mouseScrollEvent->scrollFlags = oldMouseScrollEvent->scrollFlags;
mouseScrollEvent->isHorizontal = oldMouseScrollEvent->isHorizontal;
mouseScrollEvent->delta = oldMouseScrollEvent->delta;
mouseScrollEvent->relatedTarget = oldMouseScrollEvent->relatedTarget;
mouseScrollEvent->button = oldMouseScrollEvent->button;
@ -732,6 +733,33 @@ nsDOMEvent::DuplicatePrivateData()
newEvent = mouseScrollEvent;
break;
}
case NS_WHEEL_EVENT:
{
widget::WheelEvent* wheelEvent =
new widget::WheelEvent(false, msg, nullptr);
isInputEvent = true;
widget::WheelEvent* oldWheelEvent =
static_cast<widget::WheelEvent*>(mEvent);
wheelEvent->deltaX = oldWheelEvent->deltaX;
wheelEvent->deltaY = oldWheelEvent->deltaY;
wheelEvent->deltaZ = oldWheelEvent->deltaZ;
wheelEvent->deltaMode = oldWheelEvent->deltaMode;
wheelEvent->relatedTarget = oldWheelEvent->relatedTarget;
wheelEvent->button = oldWheelEvent->button;
wheelEvent->buttons = oldWheelEvent->buttons;
wheelEvent->modifiers = oldWheelEvent->modifiers;
wheelEvent->inputSource = oldWheelEvent->inputSource;
wheelEvent->customizedByUserPrefs = oldWheelEvent->customizedByUserPrefs;
wheelEvent->isMomentum = oldWheelEvent->isMomentum;
wheelEvent->isPixelOnlyDevice = oldWheelEvent->isPixelOnlyDevice;
wheelEvent->lineOrPageDeltaX = oldWheelEvent->lineOrPageDeltaX;
wheelEvent->lineOrPageDeltaY = oldWheelEvent->lineOrPageDeltaY;
wheelEvent->scrollType = oldWheelEvent->scrollType;
wheelEvent->overflowDeltaX = oldWheelEvent->overflowDeltaX;
wheelEvent->overflowDeltaY = oldWheelEvent->overflowDeltaY;
newEvent = wheelEvent;
break;
}
case NS_SCROLLPORT_EVENT:
{
newEvent = new nsScrollPortEvent(false, msg, nullptr);
@ -1157,6 +1185,7 @@ nsDOMEvent::GetScreenCoords(nsPresContext* aPresContext,
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_WHEEL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_TOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
@ -1216,6 +1245,7 @@ nsDOMEvent::GetClientCoords(nsPresContext* aPresContext,
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_WHEEL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_TOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
@ -1390,6 +1420,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_DOMMouseScroll];
case NS_MOUSE_PIXEL_SCROLL:
return sEventNames[eDOMEvents_MozMousePixelScroll];
case NS_WHEEL_WHEEL:
return sEventNames[eDOMEvents_wheel];
case NS_OFFLINE:
return sEventNames[eDOMEvents_offline];
case NS_ONLINE:

View File

@ -102,6 +102,7 @@ public:
eDOMEvents_pagehide,
eDOMEvents_DOMMouseScroll,
eDOMEvents_MozMousePixelScroll,
eDOMEvents_wheel,
eDOMEvents_offline,
eDOMEvents_online,
eDOMEvents_copy,

View File

@ -85,6 +85,7 @@ nsDOMMouseEvent::InitMouseEvent(const nsAString & aType, bool aCanBubble, bool a
{
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_DRAG_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:
@ -139,6 +140,7 @@ nsDOMMouseEvent::InitMouseEvent(const nsAString& aType,
switch(mEvent->eventStructType) {
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_DRAG_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:
@ -167,6 +169,7 @@ nsDOMMouseEvent::InitFromCtor(const nsAString& aType,
switch(mEvent->eventStructType) {
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_DRAG_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:
@ -206,6 +209,7 @@ nsDOMMouseEvent::GetButton(PRUint16* aButton)
{
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_DRAG_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:
@ -227,6 +231,7 @@ nsDOMMouseEvent::GetButtons(PRUint16* aButtons)
{
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_DRAG_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:
@ -250,6 +255,7 @@ nsDOMMouseEvent::GetRelatedTarget(nsIDOMEventTarget** aRelatedTarget)
{
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_WHEEL_EVENT:
case NS_DRAG_EVENT:
case NS_SIMPLE_GESTURE_EVENT:
case NS_MOZTOUCH_EVENT:

View File

@ -21,8 +21,7 @@ nsDOMMouseScrollEvent::nsDOMMouseScrollEvent(nsPresContext* aPresContext,
}
if(mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
nsMouseScrollEvent* mouseEvent = static_cast<nsMouseScrollEvent*>(mEvent);
mDetail = mouseEvent->delta;
mDetail = static_cast<nsMouseScrollEvent*>(mEvent)->delta;
}
}
@ -66,9 +65,8 @@ nsDOMMouseScrollEvent::InitMouseScrollEvent(const nsAString & aType, bool aCanBu
NS_ENSURE_SUCCESS(rv, rv);
if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
static_cast<nsMouseScrollEvent*>(mEvent)->scrollFlags =
(aAxis == HORIZONTAL_AXIS) ? nsMouseScrollEvent::kIsHorizontal
: nsMouseScrollEvent::kIsVertical;
static_cast<nsMouseScrollEvent*>(mEvent)->isHorizontal =
(aAxis == HORIZONTAL_AXIS);
}
return NS_OK;
@ -81,9 +79,9 @@ nsDOMMouseScrollEvent::GetAxis(PRInt32* aResult)
NS_ENSURE_ARG_POINTER(aResult);
if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
PRUint32 flags = static_cast<nsMouseScrollEvent*>(mEvent)->scrollFlags;
*aResult = (flags & nsMouseScrollEvent::kIsHorizontal)
? PRInt32(HORIZONTAL_AXIS) : PRInt32(VERTICAL_AXIS);
*aResult = static_cast<nsMouseScrollEvent*>(mEvent)->isHorizontal ?
static_cast<PRInt32>(HORIZONTAL_AXIS) :
static_cast<PRInt32>(VERTICAL_AXIS);
} else {
*aResult = 0;
}

View File

@ -97,7 +97,7 @@ protected:
bool mPointsInitialized;
};
class nsDOMTouchList : public nsIDOMTouchList
class nsDOMTouchList MOZ_FINAL : public nsIDOMTouchList
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View File

@ -114,6 +114,7 @@ nsDOMUIEvent::GetMovementPoint()
(mEvent->eventStructType != NS_MOUSE_EVENT &&
mEvent->eventStructType != NS_POPUP_EVENT &&
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
mEvent->eventStructType != NS_WHEEL_EVENT &&
mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
mEvent->eventStructType != NS_DRAG_EVENT &&
mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
@ -312,6 +313,7 @@ nsDOMUIEvent::GetLayerPoint()
(mEvent->eventStructType != NS_MOUSE_EVENT &&
mEvent->eventStructType != NS_POPUP_EVENT &&
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
mEvent->eventStructType != NS_WHEEL_EVENT &&
mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
mEvent->eventStructType != NS_TOUCH_EVENT &&
mEvent->eventStructType != NS_DRAG_EVENT &&

View File

@ -39,6 +39,7 @@ public:
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_WHEEL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
@ -64,6 +65,7 @@ public:
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_WHEEL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||

View File

@ -22,6 +22,8 @@
#include "sampler.h"
#include "GeneratedEvents.h"
using namespace mozilla;
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
@ -734,6 +736,9 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
case NS_MOUSE_SCROLL_EVENT:
return NS_NewDOMMouseScrollEvent(aDOMEvent, aPresContext,
static_cast<nsInputEvent*>(aEvent));
case NS_WHEEL_EVENT:
return NS_NewDOMWheelEvent(aDOMEvent, aPresContext,
static_cast<widget::WheelEvent*>(aEvent));
case NS_DRAG_EVENT:
return NS_NewDOMDragEvent(aDOMEvent, aPresContext,
static_cast<nsDragEvent*>(aEvent));

File diff suppressed because it is too large Load Diff

View File

@ -86,6 +86,14 @@ public:
nsIFrame* aTargetFrame,
nsEventStatus* aStatus);
/**
* DispatchLegacyMouseScrollEvents() dispatches NS_MOUSE_SCROLL event and
* NS_MOUSE_PIXEL_SCROLL event for compatiblity with old Gecko.
*/
void DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
mozilla::widget::WheelEvent* aEvent,
nsEventStatus* aStatus);
void NotifyDestroyPresContext(nsPresContext* aPresContext);
void SetPresContext(nsPresContext* aPresContext);
void ClearFrameRefs(nsIFrame* aFrame);
@ -317,67 +325,241 @@ protected:
bool IsShellVisible(nsIDocShell* aShell);
// These functions are for mousewheel and pixel scrolling
void SendLineScrollEvent(nsIFrame* aTargetFrame,
nsMouseScrollEvent* aEvent,
nsPresContext* aPresContext,
nsEventStatus* aStatus,
PRInt32 aNumLines);
void SendPixelScrollEvent(nsIFrame* aTargetFrame,
nsMouseScrollEvent* aEvent,
nsPresContext* aPresContext,
nsEventStatus* aStatus);
class WheelPrefs
{
public:
static WheelPrefs* GetInstance();
static void Shutdown();
/**
* @param aQueryEvent If you set vailid pointer for this, DoScrollText()
* computes the line-height and page size of current
* mouse wheel scroll target and sets it to the event.
* And then, this method does NOT scroll any scrollable
* elements. I.e., you can just query the scroll target
* information.
* ApplyUserPrefsToDelta() overrides the wheel event's delta values with
* user prefs.
*/
nsresult DoScrollText(nsIFrame* aTargetFrame,
nsMouseScrollEvent* aMouseEvent,
nsIScrollableFrame::ScrollUnit aScrollQuantity,
bool aAllowScrollSpeedOverride,
nsQueryContentEvent* aQueryEvent = nullptr,
nsIAtom *aOrigin = nullptr);
void ApplyUserPrefsToDelta(mozilla::widget::WheelEvent* aEvent);
/**
* If ApplyUserPrefsToDelta() changed the delta values with customized
* prefs, the overflowDelta values would be inflated.
* CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation.
*/
void CancelApplyingUserPrefsFromOverflowDelta(
mozilla::widget::WheelEvent* aEvent);
/**
* Computes the default action for the aEvent with the prefs.
*/
enum Action
{
ACTION_NONE = 0,
ACTION_SCROLL,
ACTION_HISTORY,
ACTION_ZOOM,
ACTION_LAST = ACTION_ZOOM
};
Action ComputeActionFor(mozilla::widget::WheelEvent* aEvent);
/**
* NeedToComputeLineOrPageDelta() returns if the aEvent needs to be
* computed the lineOrPageDelta values.
*/
bool NeedToComputeLineOrPageDelta(mozilla::widget::WheelEvent* aEvent);
private:
WheelPrefs();
~WheelPrefs();
static int OnPrefChanged(const char* aPrefName, void* aClosure);
enum Index
{
INDEX_DEFAULT = 0,
INDEX_ALT,
INDEX_CONTROL,
INDEX_META,
INDEX_SHIFT,
INDEX_OS,
COUNT_OF_MULTIPLIERS
};
/**
* GetIndexFor() returns the index of the members which should be used for
* the aEvent. When only one modifier key of MODIFIER_ALT,
* MODIFIER_CONTROL, MODIFIER_META, MODIFIER_SHIFT or MODIFIER_OS is
* pressed, returns the index for the modifier. Otherwise, this return the
* default index which is used at either no modifier key is pressed or
* two or modifier keys are pressed.
*/
Index GetIndexFor(mozilla::widget::WheelEvent* aEvent);
/**
* GetPrefNameBase() returns the base pref name for aEvent.
* It's decided by GetModifierForPref() which modifier should be used for
* the aEvent.
*
* @param aBasePrefName The result, must be "mousewheel.with_*." or
* "mousewheel.default.".
*/
void GetBasePrefName(Index aIndex, nsACString& aBasePrefName);
void Init(Index aIndex);
void Reset();
bool mInit[COUNT_OF_MULTIPLIERS];
double mMultiplierX[COUNT_OF_MULTIPLIERS];
double mMultiplierY[COUNT_OF_MULTIPLIERS];
double mMultiplierZ[COUNT_OF_MULTIPLIERS];
Action mActions[COUNT_OF_MULTIPLIERS];
static WheelPrefs* sInstance;
};
/**
* DeltaDirection is used for specifying whether the called method should
* handle vertical delta or horizontal delta.
* This is clearer than using bool.
*/
enum DeltaDirection
{
DELTA_DIRECTION_X = 0,
DELTA_DIRECTION_Y
};
/**
* SendLineScrollEvent() dispatches a DOMMouseScroll event for the
* widget::WheelEvent. This method shouldn't be called for non-trusted
* wheel event because it's not necessary for compatiblity.
*
* @param aTargetFrame The event target of wheel event.
* @param aEvent The original Wheel event.
* @param aStatus The event status, must not be
* nsEventStatus_eConsumeNoDefault.
* @param aDelta The delta value of the event.
* @param aDeltaDirection The X/Y direction of dispatching event.
*/
void SendLineScrollEvent(nsIFrame* aTargetFrame,
mozilla::widget::WheelEvent* aEvent,
nsEventStatus* aStatus,
PRInt32 aDelta,
DeltaDirection aDeltaDirection);
/**
* SendPixelScrollEvent() dispatches a MozMousePixelScroll event for the
* widget::WheelEvent. This method shouldn't be called for non-trusted
* wheel event because it's not necessary for compatiblity.
*
* @param aTargetFrame The event target of wheel event.
* @param aEvent The original Wheel event.
* @param aStatus The event status, must not be
* nsEventStatus_eConsumeNoDefault.
* @param aPixelDelta The delta value of the event.
* @param aDeltaDirection The X/Y direction of dispatching event.
*/
void SendPixelScrollEvent(nsIFrame* aTargetFrame,
mozilla::widget::WheelEvent* aEvent,
nsEventStatus* aStatus,
PRInt32 aPixelDelta,
DeltaDirection aDeltaDirection);
/**
* ComputeScrollTarget() returns the scrollable frame which should be
* scrolled.
*
* @param aTargetFrame The event target of the wheel event.
* @param aEvent The handling mouse wheel event.
* @param aForDefaultAction Whether this uses wheel transaction or not.
* If true, returns the latest scrolled frame if
* there is it. Otherwise, the nearest ancestor
* scrollable frame from aTargetFrame.
* @return The scrollable frame which should be scrolled.
*/
nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
mozilla::widget::WheelEvent* aEvent,
bool aForDefaultAction);
/**
* GetScrollAmount() returns the scroll amount in app uints of one line or
* one page. If the wheel event scrolls a page, returns the page width and
* height. Otherwise, returns line height for both its width and height.
*
* @param aScrollableFrame A frame which will be scrolled by the event.
* The result of ComputeScrollTarget() is
* expected for this value.
* This can be NULL if there is no scrollable
* frame. Then, this method uses root frame's
* line height or visible area's width and height.
*/
nsSize GetScrollAmount(nsPresContext* aPresContext,
mozilla::widget::WheelEvent* aEvent,
nsIScrollableFrame* aScrollableFrame);
/**
* DoScrollText() scrolls the scrollable frame for aEvent.
*/
void DoScrollText(nsIScrollableFrame* aScrollableFrame,
mozilla::widget::WheelEvent* aEvent);
void DoScrollHistory(PRInt32 direction);
void DoScrollZoom(nsIFrame *aTargetFrame, PRInt32 adjustment);
nsresult GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv);
nsresult ChangeTextSize(PRInt32 change);
nsresult ChangeFullZoom(PRInt32 change);
/**
* Computes actual delta value used for scrolling. If user customized the
* scrolling speed and/or direction, this would return the customized value.
* Otherwise, it would return the original delta value of aMouseEvent.
* DeltaAccumulator class manages delta values for dispatching DOMMouseScroll
* event. If wheel events are caused by pixel scroll only devices or
* the delta values are customized by prefs, this class stores the delta
* values and set lineOrPageDelta values.
*/
PRInt32 ComputeWheelDeltaFor(nsMouseScrollEvent* aMouseEvent);
class DeltaAccumulator
{
public:
static DeltaAccumulator* GetInstance()
{
if (!sInstance) {
sInstance = new DeltaAccumulator;
}
return sInstance;
}
static void Shutdown()
{
delete sInstance;
sInstance = nullptr;
}
/**
* Computes the action for the aMouseEvent with prefs. The result is
* MOUSE_SCROLL_N_LINES, MOUSE_SCROLL_PAGE, MOUSE_SCROLL_HISTORY,
* MOUSE_SCROLL_ZOOM, MOUSE_SCROLL_PIXELS or -1.
* When the result is -1, nothing happens for the event.
*
* @param aUseSystemSettings Set the result of UseSystemScrollSettingFor().
* InitLineOrPageDelta() stores pixel delta values of WheelEvents which are
* caused if it's needed. And if the accumulated delta becomes a
* line height, sets lineOrPageDeltaX and lineOrPageDeltaY automatically.
*/
PRInt32 ComputeWheelActionFor(nsMouseScrollEvent* aMouseEvent,
bool aUseSystemSettings);
void InitLineOrPageDelta(nsIFrame* aTargetFrame,
nsEventStateManager* aESM,
mozilla::widget::WheelEvent* aEvent);
/**
* Gets the wheel action for the aMouseEvent ONLY with the pref.
* When you actually do something for the event, probably you should use
* ComputeWheelActionFor().
* Reset() resets both delta values.
*/
PRInt32 GetWheelActionFor(nsMouseScrollEvent* aMouseEvent);
/**
* Gets the pref value for line scroll amount for the aMouseEvent.
* Note that this method doesn't check whether the aMouseEvent is line scroll
* event and doesn't use system settings.
*/
PRInt32 GetScrollLinesFor(nsMouseScrollEvent* aMouseEvent);
/**
* Whether use system scroll settings or settings in our prefs for the event.
* TRUE, if use system scroll settings. Otherwise, FALSE.
*/
bool UseSystemScrollSettingFor(nsMouseScrollEvent* aMouseEvent);
void Reset();
private:
DeltaAccumulator() :
mX(0.0), mY(0.0), mHandlingDeltaMode(PR_UINT32_MAX),
mHandlingPixelOnlyDevice(false)
{
}
double mX;
double mY;
TimeStamp mLastTime;
PRUint32 mHandlingDeltaMode;
bool mHandlingPixelOnlyDevice;
static DeltaAccumulator* sInstance;
};
// end mousewheel functions
/*
@ -440,8 +622,6 @@ protected:
nsresult DoContentCommandEvent(nsContentCommandEvent* aEvent);
nsresult DoContentCommandScrollEvent(nsContentCommandEvent* aEvent);
void DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
nsIFrame* aTargetFrame);
void DoQuerySelectedText(nsQueryContentEvent* aEvent);
bool RemoteQueryContentEvent(nsEvent *aEvent);
@ -530,10 +710,6 @@ public:
// Array for accesskey support
nsCOMArray<nsIContent> mAccessKeys;
// Unlocks pixel scrolling
bool mLastLineScrollConsumedX;
bool mLastLineScrollConsumedY;
static PRInt32 sUserInputEventDepth;
static bool sNormalLMouseEventInProcess;

View File

@ -84,6 +84,11 @@ MOCHITEST_FILES = \
test_bug741666.html \
test_dom_keyboard_event.html \
test_dom_mouse_event.html \
test_dom_wheel_event.html \
test_continuous_wheel_events.html \
test_moz_mouse_pixel_scroll_event.html \
test_wheel_default_action.html \
window_wheel_default_action.html \
test_bug603008.html \
test_bug716822.html \
test_bug742376.html \
@ -106,7 +111,6 @@ endif
MOCHITEST_CHROME_FILES = \
test_bug336682_2.xul \
test_bug336682.js \
test_bug350471.xul \
test_bug586961.xul \
test_bug415498.xul \
bug415498-doc1.html \

View File

@ -1,264 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=350471
-->
<window title="Mozilla Bug 350471"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<title>Test for Bug 350471</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=350471">Mozilla Bug 350471</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
</body>
<script class="testbody" type="application/javascript;version=1.7"><![CDATA[
/** Test for Bug 350471 **/
const minLineHeight = 10, maxLineHeight = 20;
function between(x, min, max) (min <= max) ? (min <= x && x <= max) : (max <= x && x <= min);
function isbetween(x, min, max, msg) ok(between(x, min, max), msg + " - Expected " + min + " to " + max + ", got " + x);
function testEventDispatching(aWin) {
function helper(aAxis, aDelta, aKind, aShiftKey, aCtrlKey, aAltKey, aMetaKey) {
let expectedEvents = [];
let deltaUnit = "";
function listener(e) {
if (!expectedEvents.length) {
ok(false, "Received an event that I didn't expect. type: " + e.type +
", axis: " + e.axis + ", delta: " + e.delta);
return;
}
let expected = expectedEvents.shift();
["type", "shiftKey", "ctrlKey", "altKey", "metaKey"].forEach(function(field) {
is(e[field], expected[field],
"e." + field + " (" + e[field] + ") does not match expected value (" + expected[field] + ")");
});
let expectedAxis = expected.axis == "horizontal" ? e.HORIZONTAL_AXIS : e.VERTICAL_AXIS;
is(e.axis, expectedAxis,
"e.axis (" + e.axis + ") does not match expected value (" + expectedAxis + ")");
// When modifier keys are pressed, cancel the event.
// We don't want to zoom or navigate back / forward (history scroll).
if (aShiftKey || aCtrlKey || aAltKey || aMetaKey) {
e.preventDefault();
// Note: If this is a DOMMouseScroll event without hasPixels, we still
// expect a follow-up MozMousePixelScroll event.
} else {
// Only check the delta if no modifiers are pressed.
// History scroll and zoom change the deltas in nsESM::PreHandleEvent.
if (deltaUnit == (e.type == "DOMMouseScroll" ? "lines" : "pixels")) {
// no unit conversion necessary
is(e.detail, expected.delta,
"e.detail (" + e.detail + ") does not match expected value (" + expected.delta + ")");
} else if (e.type == "MozMousePixelScroll") {
// We sent a line scroll event but are receiving a pixel scroll event,
// so we need to convert the delta.
let minDelta = expected.delta * minLineHeight;
let maxDelta = expected.delta * maxLineHeight;
isbetween(e.detail, minDelta, maxDelta, "wrong pixel scroll event delta");
}
}
e.stopPropagation();
}
// Set up the expected values.
if (aKind == 0 || aKind == 1) {
expectedEvents.push({
type: "DOMMouseScroll",
axis: aAxis,
delta: aDelta,
hasPixels: (aKind == 1),
shiftKey: aShiftKey,
ctrlKey: aCtrlKey,
altKey: aAltKey,
metaKey: aMetaKey
});
}
if (aKind == 0 || aKind == 2) {
expectedEvents.push({
type: "MozMousePixelScroll",
axis: aAxis,
delta: aDelta,
shiftKey: aShiftKey,
ctrlKey: aCtrlKey,
altKey: aAltKey,
metaKey: aMetaKey
});
}
deltaUnit = aKind == 2 ? "pixels" : "lines";
aWin.document.addEventListener("DOMMouseScroll", listener, true);
aWin.document.addEventListener("MozMousePixelScroll", listener, true);
// Send the event to the documentElement.
synthesizeMouseScroll(aWin.document.documentElement, 10, 10, expectedEvents[0], aWin);
aWin.document.removeEventListener("DOMMouseScroll", listener, true);
aWin.document.removeEventListener("MozMousePixelScroll", listener, true);
// expectedEvents should be empty now. If it's not, print errors.
expectedEvents.forEach(function(e) {
ok(false, "Didn't receive expected event: " + JSON.stringify(e));
});
};
let i = 0;
[0, 1, 2].forEach(function(aKind) {
["horizontal", "vertical"].forEach(function(aAxis) {
[false, true].forEach(function(aShift) {
[false, true].forEach(function(aCtrl) {
[false, true].forEach(function(aAlt) {
[false, true].forEach(function(aMeta) {
helper(aAxis, [-5, -1, 0, 1, 5][i++ % 5], aKind, aShift, aCtrl, aAlt, aMeta);
});
});
});
});
});
});
}
function testDefaultHandling(aWin, andThen) {
let scrollbox = aWin.document.getElementById("scrollbox");
function scrollWithPreventDefault(aEvent, aDoConsume) {
function listener(e) {
if (aDoConsume[e.type])
e.preventDefault();
}
scrollbox.addEventListener("DOMMouseScroll", listener, true);
scrollbox.addEventListener("MozMousePixelScroll", listener, true);
synthesizeMouseScroll(scrollbox, 10, 10, aEvent, aWin);
scrollbox.removeEventListener("DOMMouseScroll", listener, true);
scrollbox.removeEventListener("MozMousePixelScroll", listener, true);
}
let tests = [];
function helper(aType, aHasPixels, aAxis, aStart, aDelta, aConsumeLine, aConsumePixel, aPositionShouldChange, aCurrentTest) {
tests.push([aType, aHasPixels, aAxis, aStart, aDelta, aConsumeLine, aConsumePixel, aPositionShouldChange, aCurrentTest]);
}
function exec() {
let [aType, aHasPixels, aAxis, aStart, aDelta, aConsumeLine, aConsumePixel, aPositionShouldChange, currentTest] = tests[0];
tests.shift();
scrollbox.scrollLeft = aStart;
scrollbox.scrollTop = aStart;
scrollWithPreventDefault({
type: aType,
axis: aAxis,
hasPixels: aHasPixels,
delta: aDelta
}, {
"DOMMouseScroll": aConsumeLine,
"MozMousePixelScroll": aConsumePixel
});
setTimeout(function() {
let newPos = scrollbox[aAxis == "horizontal" ? "scrollLeft" : "scrollTop"];
let newPosWrongAxis = scrollbox[aAxis == "horizontal" ? "scrollTop" : "scrollLeft"];
is(newPosWrongAxis, aStart, currentTest + " wrong axis scrolled - type: " + aType);
if (aPositionShouldChange) {
if (aType == "MozMousePixelScroll") {
// aDelta is in pixels, no conversion necessary
is(newPos, aStart + aDelta, currentTest + " wrong scroll position - type: " + aType);
} else {
// Use minLineHeight and maxLineHeight as an estimate for the conversion factor.
isbetween(newPos, aStart + aDelta * minLineHeight, aStart + aDelta * maxLineHeight,
currentTest + " wrong scroll position - type: " + aType);
}
} else {
is(newPos, aStart, currentTest + " The scroll position shouldn't have changed. - type: " + aType);
}
if (tests.length)
exec();
else
andThen();
}, 20);
}
["horizontal", "vertical"].forEach(function(aAxis) {
[-5, 5].forEach(function(aDelta) {
[false, true].forEach(function(aConsumeLine) {
[false, true].forEach(function(aConsumePixel) {
let shouldScroll = !aConsumeLine && !aConsumePixel;
let currentTest = "";
currentTest = "normal DOMMouseScroll: only scroll if neither line nor pixel scroll are consumed.";
helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, aConsumePixel, shouldScroll, currentTest);
currentTest = "DOMMouseScroll with hasPixels: never scroll.";
helper("DOMMouseScroll", true, aAxis, 4000, aDelta, aConsumeLine, aConsumePixel, false, currentTest);
currentTest = "MozMousePixelScroll (consumed: " + aConsumePixel +
") with preceding DOMMouseScroll (consumed: " + aConsumeLine +
"): " + (shouldScroll ? "scroll." : "don't scroll.");
// It shouldn't matter:
// 1. whether hasPixels is set on the preceding DOMMouseScroll event or
// 2. whether the preceding DOMMouseScroll event's MozMousePixelScroll event is consumed.
helper("DOMMouseScroll", true, aAxis, 4000, aDelta, aConsumeLine, false, false, currentTest);
helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll, currentTest);
helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, false, !aConsumeLine, currentTest);
helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll, currentTest);
helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, true, false, currentTest);
helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll, currentTest);
});
});
});
});
exec();
}
function initPrefs()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
// Disables the app level scroll acceleration
prefSvc.setIntPref("mousewheel.acceleration.start", -1);
prefSvc.setBoolPref("mousewheel.system_scroll_override_on_root_content.enabled", false);
prefSvc.setBoolPref("general.smoothScroll", false);
}
function clearPrefs()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
prefSvc.clearUserPref("mousewheel.acceleration.start");
prefSvc.clearUserPref("mousewheel.system_scroll_override_on_root_content.enabled");
prefSvc.clearUserPref("general.smoothScroll");
}
window.onload = function () {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
let win = window.open('data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?><?xml-stylesheet href="chrome://global/skin" type="text/css"?><window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><vbox style="height: 150px; background: cyan; overflow: auto;" id="scrollbox"><hbox style="height: 8000px;"><vbox style="width: 8000px;"/></hbox></vbox></window>', '_blank', 'chrome,width=400,height=200');
win.onload = function() {
setTimeout(function() {
initPrefs();
testEventDispatching(win);
testDefaultHandling(win, function() {
clearPrefs();
win.close();
SimpleTest.finish();
});
}, 20);
}
}
SimpleTest.waitForExplicitFinish();
]]></script>
</window>

View File

@ -23,25 +23,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=574663
function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum) {
var win = scrollbox.ownerDocument.defaultView;
let event = {
'type': "DOMMouseScroll",
'axis': "vertical",
'delta': direction,
'hasPixels': true,
'ctrlKey': ctrl,
'isMomentum': momentum,
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaY: direction * 3,
lineOrPageDeltaY: direction,
ctrlKey: ctrl,
isMomentum: momentum
};
// first a line scroll
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
// Then a line scroll with hasPixels set to false
event.hasPixels = false;
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
// then 5 pixel scrolls
event.hasPixels = true;
event.delta *= 3;
event.type = "MozMousePixelScroll";
event.hasPixels = false;
synthesizeWheel(scrollbox, 10, 10, event, win);
// then 5 additional pixel scrolls
event.lineOrPageDeltaY = 0;
for (let i = 0; i < 5; ++i) {
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
synthesizeWheel(scrollbox, 10, 10, event, win);
}
}
@ -110,7 +102,7 @@ function initPrefs()
prefSvc.setIntPref("mousewheel.acceleration.start", -1);
prefSvc.setBoolPref("mousewheel.system_scroll_override_on_root_content.enabled", false);
// Enable zooming for ctrl-scrolling
prefSvc.setIntPref("mousewheel.withcontrolkey.action", 3);
prefSvc.setIntPref("mousewheel.with_control.action", 3);
}
function clearPrefs()
@ -122,7 +114,7 @@ function clearPrefs()
prefSvc.clearUserPref("general.smoothScroll");
prefSvc.clearUserPref("mousewheel.acceleration.start");
prefSvc.clearUserPref("mousewheel.system_scroll_override_on_root_content.enabled");
prefSvc.clearUserPref("mousewheel.withcontrolkey.action");
prefSvc.clearUserPref("mousewheel.with_control.action");
}
window.onload = function () {

View File

@ -26,19 +26,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=607464
function scrollDown15PxWithPixelScrolling(scrollbox) {
var win = scrollbox.ownerDocument.defaultView;
let event = {
'type': "DOMMouseScroll",
'axis': "vertical",
'delta': 1,
'hasPixels': true,
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaY: 3.0,
lineOrPageDeltaY: 1
};
// first a line scroll
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
// then 5 pixel scrolls with 3px each
event.delta *= 3;
event.type = "MozMousePixelScroll";
event.hasPixels = false;
for (let i = 0; i < 5; ++i) {
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
// A pixel scroll with lineOrPageDeltaY.
synthesizeWheel(scrollbox, 10, 10, event, win);
// then 4 pixel scrolls without lineOrPageDeltaY.
event.lineOrPageDeltaY = 0;
for (let i = 0; i < 4; ++i) {
synthesizeWheel(scrollbox, 10, 10, event, win);
}
// Note: the line scroll shouldn't have any effect because it has

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,707 @@
<!DOCTYPE HTML>
<html style="font-size: 32px;">
<head>
<title>Test for D3E WheelEvent</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="scrollable" style="font-size: 16px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
<div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
</div>
</div>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests, window);
var gScrollableElement = document.getElementById("scrollable");
var gScrolledElement = document.getElementById("scrolled");
var gLineHeight = 0;
var gPageHeight = 0;
var gPageWidth = 0;
function prepareScrollUnits()
{
var result = -1;
function handler(aEvent)
{
result = aEvent.detail;
aEvent.preventDefault();
}
window.addEventListener("MozMousePixelScroll", handler, true);
synthesizeWheel(gScrollableElement, 10, 10,
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaY: 1.0, lineOrPageDeltaY: 1 });
gLineHeight = result;
ok(gLineHeight > 10 && gLineHeight < 25, "prepareScrollUnits: gLineHeight may be illegal value, got " + gLineHeight);
result = -1;
synthesizeWheel(gScrollableElement, 10, 10,
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaY: 1.0, lineOrPageDeltaY: 1 });
gPageHeight = result;
// XXX Cannot we know the actual scroll port size?
ok(gPageHeight >= 150 && gPageHeight <= 200,
"prepareScrollUnits: gPageHeight is strange value, got " + gPageHeight);
result = -1;
synthesizeWheel(gScrollableElement, 10, 10,
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 1.0, lineOrPageDeltaX: 1 });
gPageWidth = result;
ok(gPageWidth >= 150 && gPageWidth <= 200,
"prepareScrollUnits: gPageWidth is strange value, got " + gPageWidth);
window.removeEventListener("MozMousePixelScroll", handler, true);
}
function testMakingUntrustedEvent()
{
const kCreateEventArgs = [
"WheelEvent", "wheelevent", "wheelEvent", "Wheelevent"
];
for (var i = 0; i < kCreateEventArgs.length; i++) {
try {
// We never support WheelEvent construction with document.createEvent().
var event = document.createEvent(kCreateEventArgs[i]);
ok(false, "document.createEvent(" + kCreateEventArgs[i] + ") should throw an error");
} catch (e) {
ok(true, "document.createEvent(" + kCreateEventArgs[i] + ") threw an error");
}
}
var wheelEvent = new WheelEvent("wheel");
ok(wheelEvent instanceof WheelEvent,
"new WheelEvent() should create an instance of WheelEvent");
ok(typeof(wheelEvent.initWheelEvent) != "function",
"WheelEvent must not have initWheelEvent()");
}
// delta_multiplier prefs should cause changing delta values of trusted events only.
// And also legacy events' detail value should be changed too.
function testDeltaMultiplierPrefs()
{
const kModifierAlt = 0x01;
const kModifierControl = 0x02;
const kModifierMeta = 0x04;
const kModifierShift = 0x08;
const kModifierWin = 0x10;
const kTests = [
{ name: "default",
expected: [ 0, kModifierShift | kModifierAlt, kModifierShift | kModifierControl,
kModifierShift | kModifierMeta, kModifierShift | kModifierWin,
kModifierControl | kModifierAlt, kModifierMeta | kModifierAlt ],
unexpected: [ kModifierAlt, kModifierControl, kModifierMeta, kModifierShift, kModifierWin ] },
{ name: "with_alt",
expected: [ kModifierAlt ],
unexpected: [0, kModifierControl, kModifierMeta, kModifierShift, kModifierWin,
kModifierShift | kModifierAlt, kModifierControl | kModifierAlt,
kModifierMeta | kModifierAlt ] },
{ name: "with_control",
expected: [ kModifierControl ],
unexpected: [0, kModifierAlt, kModifierMeta, kModifierShift, kModifierWin,
kModifierShift | kModifierControl, kModifierControl | kModifierAlt,
kModifierMeta | kModifierControl ] },
{ name: "with_meta",
expected: [ kModifierMeta ],
unexpected: [0, kModifierAlt, kModifierControl, kModifierShift, kModifierWin,
kModifierShift | kModifierMeta, kModifierControl | kModifierMeta,
kModifierMeta | kModifierAlt ] },
{ name: "with_shift",
expected: [ kModifierShift ],
unexpected: [0, kModifierAlt, kModifierControl, kModifierMeta, kModifierWin,
kModifierShift | kModifierAlt, kModifierControl | kModifierShift,
kModifierMeta | kModifierShift ] },
{ name: "with_win",
expected: [ kModifierWin ],
unexpected: [0, kModifierAlt, kModifierControl, kModifierMeta, kModifierShift,
kModifierShift | kModifierWin ] },
];
// Note that this test doesn't support complicated lineOrPageDelta values which are computed with
// accumulated delta values by the prefs. If you need to test the lineOrPageDelta accumulation,
// use test_continuous_dom_wheel_event.html.
const kEvents = [
{ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: gLineHeight, deltaY: gLineHeight, deltaZ: gLineHeight, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
{ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: -gLineHeight, deltaY: -gLineHeight, deltaZ: -gLineHeight, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: -1.0, deltaY: -1.0, deltaZ: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: -1.0, deltaY: -1.0, deltaZ: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
];
const kDeltaMultiplierPrefs = [
"delta_multiplier_x", "delta_multiplier_y", "delta_multiplier_z"
];
const kPrefValues = [
200, 50, 0, -50, -150
];
var currentTest, currentModifiers, currentEvent, currentPref, currentMultiplier, testingExpected;
var description;
var calledHandlers = { wheel: false,
DOMMouseScroll: { horizontal: false, vertical: false },
MozMousePixelScroll: { horizontal: false, vertical: false } };
function wheelEventHandler(aEvent) {
calledHandlers.wheel = true;
var expectedDeltaX = currentEvent.deltaX;
var expectedDeltaY = currentEvent.deltaY;
var expectedDeltaZ = currentEvent.deltaZ;
if (testingExpected) {
switch (currentPref.charAt(currentPref.length - 1)) {
case "x":
expectedDeltaX *= currentMultiplier;
break;
case "y":
expectedDeltaY *= currentMultiplier;
break;
case "z":
expectedDeltaZ *= currentMultiplier;
break;
}
}
is(aEvent.deltaX, expectedDeltaX, description + "deltaX (" + currentEvent.deltaX + ") was invaild");
is(aEvent.deltaY, expectedDeltaY, description + "deltaY (" + currentEvent.deltaY + ") was invaild");
is(aEvent.deltaZ, expectedDeltaZ, description + "deltaZ (" + currentEvent.deltaZ + ") was invaild");
}
function legacyEventHandler(aEvent) {
var isHorizontal = (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS);
var isScrollEvent = (aEvent.type == "DOMMouseScroll");
if (isScrollEvent) {
if (isHorizontal) {
calledHandlers.DOMMouseScroll.horizontal = true;
} else {
calledHandlers.DOMMouseScroll.vertical = true;
}
} else {
if (isHorizontal) {
calledHandlers.MozMousePixelScroll.horizontal = true;
} else {
calledHandlers.MozMousePixelScroll.vertical = true;
}
}
var eventName = (isHorizontal ? "Horizontal " : "Vertical ") + aEvent.type + " ";
var expectedDetail;
if (isScrollEvent) {
expectedDetail = isHorizontal ? currentEvent.lineOrPageDeltaX : currentEvent.lineOrPageDeltaY;
if (currentEvent.deltaMode == WheelEvent.DOM_DELTA_PAGE && expectedDetail) {
expectedDetail = ((expectedDetail > 0) ? UIEvent.SCROLL_PAGE_DOWN : UIEvent.SCROLL_PAGE_UP);
}
} else {
expectedDetail = isHorizontal ? currentEvent.deltaX : currentEvent.deltaY;
if (expectedDetail) {
if (currentEvent.deltaMode == WheelEvent.DOM_DELTA_LINE) {
expectedDetail *= gLineHeight;
} else if (currentEvent.deltaMode == WheelEvent.DOM_DELTA_PAGE) {
if (expectedDetail > 0) {
expectedDetail = (isHorizontal ? gPageWidth : gPageHeight);
} else {
expectedDetail = (isHorizontal ? -gPageWidth : -gPageHeight);
}
}
}
}
if (testingExpected) {
if ((isHorizontal && currentPref.charAt(currentPref.length - 1) == "x") ||
(!isHorizontal && currentPref.charAt(currentPref.length - 1) == "y")) {
// If it's a page scroll event, the detail value is UIEvent.SCROLL_PAGE_DOWN or
// UIEvent.SCROLL_PAGE_UP. If the delta value sign is reverted, we need to
// revert the expected detail value too. Otherwise, don't touch it.
if (isScrollEvent && currentEvent.deltaMode == WheelEvent.DOM_DELTA_PAGE) {
if (currentMultiplier < 0) {
expectedDetail = ((expectedDetail == UIEvent.SCROLL_PAGE_UP) ? UIEvent.SCROLL_PAGE_DOWN : UIEvent.SCROLL_PAGE_UP);
}
} else {
expectedDetail *= currentMultiplier;
expectedDetail = expectedDetail < 0 ? Math.ceil(expectedDetail) : Math.floor(expectedDetail);
}
}
}
is(aEvent.detail, expectedDetail, description + eventName + "detail was invalid");
aEvent.preventDefault();
}
window.addEventListener("wheel", wheelEventHandler, true);
window.addEventListener("DOMMouseScroll", legacyEventHandler, true);
window.addEventListener("MozMousePixelScroll", legacyEventHandler, true);
function dispatchEvent(aIsExpected) {
for (var i = 0; i < kEvents.length; i++) {
currentEvent = kEvents[i];
currentEvent.shiftKey = (currentModifiers & kModifierShift) != 0;
currentEvent.ctrlKey = (currentModifiers & kModifierControl) != 0;
currentEvent.altKey = (currentModifiers & kModifierAlt) != 0;
currentEvent.metaKey = (currentModifiers & kModifierMeta) != 0;
currentEvent.osKey = (currentModifiers & kModifierWin) != 0;
var modifierList = "";
if (currentEvent.shiftKey) {
modifierList += "Shift ";
}
if (currentEvent.ctrlKey) {
modifierList += "Control ";
}
if (currentEvent.altKey) {
modifierList += "Alt ";
}
if (currentEvent.metaKey) {
modifierList += "Meta ";
}
if (currentEvent.osKey) {
modifierList += "Win ";
}
for (var j = 0; j < kPrefValues.length; j++) {
currentMultiplier = kPrefValues[j] / 100;
if (currentMultiplier > -1.0 && currentMultiplier < 1.0) {
currentMultiplier = currentMultiplier < 0 ? -1.0 : 1.0;
}
for (var k = 0; k < kDeltaMultiplierPrefs.length; k++) {
currentPref = "mousewheel." + currentTest.name + "." + kDeltaMultiplierPrefs[k];
SpecialPowers.setIntPref(currentPref, kPrefValues[j]);
gScrollableElement.scrollTop = gScrollableElement.scrollBottom = 1000;
// trusted event's delta valuses should be reverted by the pref.
testingExpected = aIsExpected;
description = "testDeltaMultiplierPrefs, pref: " + currentPref + "=" + kPrefValues[j] +
", deltaMode: " + currentEvent.deltaMode + ", modifiers: \"" + modifierList + "\", (trusted event): ";
synthesizeWheel(gScrollableElement, 10, 10, currentEvent);
ok(calledHandlers.wheel, description + "wheel event was not fired");
ok(calledHandlers.DOMMouseScroll.horizontal,
description + "Horizontal DOMMouseScroll event was not fired");
ok(calledHandlers.DOMMouseScroll.vertical,
description + "Vertical DOMMouseScroll event was not fired");
ok(calledHandlers.MozMousePixelScroll.horizontal,
description + "Horizontal MozMousePixelScroll event was not fired");
ok(calledHandlers.MozMousePixelScroll.vertical,
description + "Vertical MozMousePixelScroll event was not fired");
calledHandlers = { wheel: false,
DOMMouseScroll: { horizontal: false, vertical: false },
MozMousePixelScroll: { horizontal: false, vertical: false } };
// untrusted event's delta values shouldn't be reverted by the pref.
testingExpected = false;
var props = {
bubbles: true,
cancelable: true,
shiftKey: currentEvent.shiftKey,
ctrlKey: currentEvent.ctrlKey,
altKey: currentEvent.altKey,
metaKey: currentEvent.metaKey,
deltaX: currentEvent.deltaX,
deltaY: currentEvent.deltaY,
deltaZ: currentEvent.deltaZ,
deltaMode: currentEvent.deltaMode,
};
var untrustedEvent = new WheelEvent("wheel", props);
description = "testDeltaMultiplierPrefs, pref: " + currentPref + "=" + kPrefValues[j] +
", deltaMode: " + currentEvent.deltaMode + ", modifiers: \"" + modifierList + "\", (untrusted event): ";
gScrollableElement.dispatchEvent(untrustedEvent);
ok(calledHandlers.wheel, description + "wheel event was not fired for untrusted event");
ok(!calledHandlers.DOMMouseScroll.horizontal,
description + "Horizontal DOMMouseScroll event was fired for untrusted event");
ok(!calledHandlers.DOMMouseScroll.vertical,
description + "Vertical DOMMouseScroll event was fired for untrusted event");
ok(!calledHandlers.MozMousePixelScroll.horizontal,
description + "Horizontal MozMousePixelScroll event was fired for untrusted event");
ok(!calledHandlers.MozMousePixelScroll.vertical,
description + "Vertical MozMousePixelScroll event was fired for untrusted event");
SpecialPowers.setIntPref(currentPref, 100);
calledHandlers = { wheel: false,
DOMMouseScroll: { horizontal: false, vertical: false },
MozMousePixelScroll: { horizontal: false, vertical: false } };
}
// We should skip other value tests if testing with modifier key.
// If we didn't do so, it would test too many times, but we don't need to do so.
if (kTests.name != "default") {
break;
}
}
}
}
for (var i = 0; i < kTests.length; i++) {
currentTest = kTests[i];
for (var j = 0; j < currentTest.expected.length; j++) {
currentModifiers = currentTest.expected[j];
dispatchEvent(true);
}
for (var k = 0; k < currentTest.unexpected.length; k++) {
currentModifiers = currentTest.unexpected[k];
dispatchEvent(false);
}
}
window.removeEventListener("wheel", wheelEventHandler, true);
window.removeEventListener("DOMMouseScroll", legacyEventHandler, true);
window.removeEventListener("MozMousePixelScroll", legacyEventHandler, true);
}
// Untrusted wheel events shouldn't cause legacy mouse scroll events.
function testDispatchingUntrustEvent()
{
var descriptionBase = "testDispatchingUntrustEvent, ";
var description, wheelEventFired;
function wheelEventHandler(aEvent)
{
wheelEventFired = true;
}
function legacyEventHandler(aEvent)
{
ok(false, aEvent.type + " must not be fired");
}
window.addEventListener("wheel", wheelEventHandler, true);
window.addEventListener("DOMMouseScroll", legacyEventHandler, true);
window.addEventListener("MozMousePixelScroll", legacyEventHandler, true);
description = descriptionBase + "dispatching a pixel wheel event: ";
wheelEventFired = false;
var untrustedPixelEvent = new WheelEvent("wheel", {
bubbles: true, cancelable: true,
deltaX: 24.0, deltaY: 24.0,
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
});
gScrolledElement.dispatchEvent(untrustedPixelEvent);
ok(wheelEventFired, description + "wheel event wasn't fired");
description = descriptionBase + "dispatching a line wheel event: ";
wheelEventFired = false;
var untrustedLineEvent = new WheelEvent("wheel", {
bubbles: true, cancelable: true,
deltaX: 3.0, deltaY: 3.0,
deltaMode: WheelEvent.DOM_DELTA_LINE,
});
gScrolledElement.dispatchEvent(untrustedLineEvent);
ok(wheelEventFired, description + "wheel event wasn't fired");
description = descriptionBase + "dispatching a page wheel event: ";
wheelEventFired = false;
var untrustedPageEvent = new WheelEvent("wheel", {
bubbles: true, cancelable: true,
deltaX: 1.0, deltaY: 1.0,
deltaMode: WheelEvent.DOM_DELTA_PAGE,
});
gScrolledElement.dispatchEvent(untrustedPageEvent);
ok(wheelEventFired, description + "wheel event wasn't fired");
window.removeEventListener("wheel", wheelEventHandler, true);
window.removeEventListener("DOMMouseScroll", legacyEventHandler, true);
window.removeEventListener("MozMousePixelScroll", legacyEventHandler, true);
}
function testEventOrder()
{
const kWheelEvent = 0x0001;
const kDOMMouseScrollEvent = 0x0002;
const kMozMousePixelScrollEvent = 0x0004;
const kVerticalScrollEvent = 0x0010;
const kHorizontalScrollEvent = 0x0020;
const kInSystemGroup = 0x0100;
const kDefaultPrevented = 0x1000;
var currentTest;
const kTests = [
{
description: "Testing the order of the events without preventDefault()",
expectedEvents: [ kWheelEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kVerticalScrollEvent,
kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup,
kDOMMouseScrollEvent | kHorizontalScrollEvent,
kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kHorizontalScrollEvent,
kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kWheelEvent | kInSystemGroup],
resultEvents: [],
doPreventDefaultAt: 0,
},
{
description: "Testing the order of the events, calling preventDefault() at default group wheel event",
expectedEvents: [ kWheelEvent,
kWheelEvent | kInSystemGroup | kDefaultPrevented],
resultEvents: [],
doPreventDefaultAt: kWheelEvent,
},
{
description: "Testing the order of the events, calling preventDefault() at default group DOMMouseScroll event",
expectedEvents: [ kWheelEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
kMozMousePixelScrollEvent | kVerticalScrollEvent | kDefaultPrevented,
kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
kDOMMouseScrollEvent | kHorizontalScrollEvent,
kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kHorizontalScrollEvent,
kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kWheelEvent | kInSystemGroup | kDefaultPrevented],
resultEvents: [],
doPreventDefaultAt: kDOMMouseScrollEvent | kVerticalScrollEvent,
},
{
description: "Testing the order of the events, calling preventDefault() at default group MozMousePixelScroll event",
expectedEvents: [ kWheelEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kVerticalScrollEvent,
kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
kDOMMouseScrollEvent | kHorizontalScrollEvent,
kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kHorizontalScrollEvent,
kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kWheelEvent | kInSystemGroup | kDefaultPrevented],
resultEvents: [],
doPreventDefaultAt: kMozMousePixelScrollEvent | kVerticalScrollEvent,
},
{
description: "Testing the order of the events, calling preventDefault() at system group DOMMouseScroll event",
expectedEvents: [ kWheelEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kVerticalScrollEvent | kDefaultPrevented,
kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
kDOMMouseScrollEvent | kHorizontalScrollEvent,
kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kHorizontalScrollEvent,
kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kWheelEvent | kInSystemGroup | kDefaultPrevented],
resultEvents: [],
doPreventDefaultAt: kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
},
{
description: "Testing the order of the events, calling preventDefault() at system group MozMousePixelScroll event",
expectedEvents: [ kWheelEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent,
kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kVerticalScrollEvent,
kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup,
kDOMMouseScrollEvent | kHorizontalScrollEvent,
kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kMozMousePixelScrollEvent | kHorizontalScrollEvent,
kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
kWheelEvent | kInSystemGroup | kDefaultPrevented],
resultEvents: [],
doPreventDefaultAt: kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup,
},
];
function getEventDescription(aEvent)
{
var result = "";
if (aEvent & kWheelEvent) {
result = "wheel"
} else {
if (aEvent & kDOMMouseScrollEvent) {
result = "DOMMouseScroll";
} else if (aEvent & kMozMousePixelScrollEvent) {
result = "MozMousePixelScroll";
}
if (aEvent & kVerticalScrollEvent) {
result += ", vertical";
} else {
result += ", horizontal";
}
}
if (aEvent & kInSystemGroup) {
result += ", system group";
}
if (aEvent & kDefaultPrevented) {
result += ", defaultPrevented";
}
return result;
}
function pushEvent(aEvent, aIsSystemGroup)
{
var event = 0;
if (aEvent.type == "wheel") {
event = kWheelEvent;
} else {
if (aEvent.type == "DOMMouseScroll") {
event = kDOMMouseScrollEvent;
} else if (aEvent.type == "MozMousePixelScroll") {
event = kMozMousePixelScrollEvent;
}
if (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS) {
event |= kHorizontalScrollEvent;
} else {
event |= kVerticalScrollEvent;
}
}
if (aIsSystemGroup) {
event |= kInSystemGroup;
}
if (aEvent.defaultPrevented) {
event |= kDefaultPrevented;
}
currentTest.resultEvents.push(event);
return event;
}
function handler(aEvent)
{
if (pushEvent(aEvent, false) == currentTest.doPreventDefaultAt) {
aEvent.preventDefault();
}
}
function systemHandler(aEvent)
{
if (pushEvent(aEvent, true) == currentTest.doPreventDefaultAt) {
aEvent.preventDefault();
}
}
window.addEventListener("wheel", handler, true);
window.addEventListener("DOMMouseScroll", handler, true);
window.addEventListener("MozMousePixelScroll", handler, true);
SpecialPowers.addSystemEventListener(window, "wheel", systemHandler, true);
SpecialPowers.addSystemEventListener(window, "DOMMouseScroll", systemHandler, true);
SpecialPowers.addSystemEventListener(window, "MozMousePixelScroll", systemHandler, true);
for (var i = 0; i < kTests.length; i++) {
currentTest = kTests[i];
synthesizeWheel(gScrollableElement, 10, 10,
{ deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0 });
for (var j = 0; j < currentTest.expectedEvents.length; j++) {
if (currentTest.resultEvents.length == j) {
ok(false, currentTest.description + ": " +
getEventDescription(currentTest.expectedEvents[j]) + " wasn't fired");
break;
}
is(getEventDescription(currentTest.resultEvents[j]),
getEventDescription(currentTest.expectedEvents[j]),
currentTest.description + ": " + (j + 1) + "th event is mismatched");
}
if (currentTest.expectedEvents.length < currentTest.resultEvents.length) {
ok(false, currentTest.description + ": " +
getEventDescription(currentTest.resultEvents[currentTest.expectedEvents.length]) +
" was fired unexpectedly");
}
}
window.removeEventListener("wheel", handler, true);
window.removeEventListener("DOMMouseScroll", handler, true);
window.removeEventListener("MozMousePixelScroll", handler, true);
SpecialPowers.removeSystemEventListener(window, "wheel", systemHandler, true);
SpecialPowers.removeSystemEventListener(window, "DOMMouseScroll", systemHandler, true);
SpecialPowers.removeSystemEventListener(window, "MozMousePixelScroll", systemHandler, true);
}
function runTests()
{
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_z", 100);
SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_x", 100);
SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_y", 100);
SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_z", 100);
SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_x", 100);
SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_y", 100);
SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_z", 100);
SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_x", 100);
SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_y", 100);
SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_z", 100);
SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_x", 100);
SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_y", 100);
SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_z", 100);
SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_x", 100);
SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_y", 100);
SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_z", 100);
prepareScrollUnits();
testMakingUntrustedEvent();
testDeltaMultiplierPrefs();
testDispatchingUntrustEvent();
testEventOrder();
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_x");
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_y");
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_z");
SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_x");
SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_y");
SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_z");
SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_x");
SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_y");
SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_z");
SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_x");
SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_y");
SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_z");
SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_x");
SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_y");
SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_z");
SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_x");
SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_y");
SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_z");
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -451,16 +451,16 @@ try {
} catch(exp) {
ex = true;
}
ok(ex, "First parameter is required!");
ok(ex, "MouseEvent: First parameter is required!");
ex = false;
e = new MouseEvent("hello");
ok(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event shouldn't be trusted!");
ok(!e.bubbles, "Event shouldn't bubble!");
ok(!e.cancelable, "Event shouldn't be cancelable!");
ok(e.type, "hello", "MouseEvent: Wrong event type!");
ok(!e.isTrusted, "MouseEvent: Event shouldn't be trusted!");
ok(!e.bubbles, "MouseEvent: Event shouldn't bubble!");
ok(!e.cancelable, "MouseEvent: Event shouldn't be cancelable!");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
is(receivedEvent, e, "MouseEvent: Wrong event!");
var mouseEventProps =
[ { screenX: 0 },
@ -494,7 +494,7 @@ var testProps =
var defaultMouseEventValues = {};
for (var i = 0; i < mouseEventProps.length; ++i) {
for (prop in mouseEventProps[i]) {
ok(prop in e, "MouseEvent doesn't have property " + prop + "!");
ok(prop in e, "MouseEvent: MouseEvent doesn't have property " + prop + "!");
defaultMouseEventValues[prop] = mouseEventProps[i][prop];
}
}
@ -504,9 +504,86 @@ while (testProps.length) {
e = new MouseEvent("foo", p);
for (var def in defaultMouseEventValues) {
if (!(def in p)) {
is(e[def], defaultMouseEventValues[def], "Wrong default value for " + def + "!");
is(e[def], defaultMouseEventValues[def],
"MouseEvent: Wrong default value for " + def + "!");
} else {
is(e[def], p[def], "Wrong event init value for " + def + "!");
is(e[def], p[def], "MouseEvent: Wrong event init value for " + def + "!");
}
}
}
// WheelEvent
try {
e = new WheelEvent();
} catch(exp) {
ex = true;
}
ok(ex, "WheelEvent: First parameter is required!");
ex = false;
e = new WheelEvent("hello");
ok(e.type, "hello", "WheelEvent: Wrong event type!");
ok(!e.isTrusted, "WheelEvent: Event shouldn't be trusted!");
ok(!e.bubbles, "WheelEvent: Event shouldn't bubble!");
ok(!e.cancelable, "WheelEvent: Event shouldn't be cancelable!");
document.dispatchEvent(e);
is(receivedEvent, e, "WheelEvent: Wrong event!");
var wheelEventProps =
[ { screenX: 0 },
{ screenY: 0 },
{ clientX: 0 },
{ clientY: 0 },
{ ctrlKey: false },
{ shiftKey: false },
{ altKey: false },
{ metaKey: false },
{ button: 0 },
{ buttons: 0 },
{ relatedTarget: null },
{ deltaX: 0.0 },
{ deltaY: 0.0 },
{ deltaZ: 0.0 },
{ deltaMode: 0 }
];
var testWheelProps =
[
{ screenX: 1 },
{ screenY: 2 },
{ clientX: 3 },
{ clientY: 4 },
{ ctrlKey: true },
{ shiftKey: true },
{ altKey: true },
{ metaKey: true },
{ button: 5 },
{ buttons: 6 },
{ relatedTarget: window },
{ deltaX: 7.8 },
{ deltaY: 9.1 },
{ deltaZ: 2.3 },
{ deltaMode: 4 }
];
var defaultWheelEventValues = {};
for (var i = 0; i < wheelEventProps.length; ++i) {
for (prop in wheelEventProps[i]) {
ok(prop in e, "WheelEvent: WheelEvent doesn't have property " + prop + "!");
defaultWheelEventValues[prop] = wheelEventProps[i][prop];
}
}
while (testWheelProps.length) {
var p = testWheelProps.shift();
e = new WheelEvent("foo", p);
for (var def in defaultWheelEventValues) {
if (!(def in p)) {
is(e[def], defaultWheelEventValues[def],
"WheelEvent: Wrong default value for " + def + "!");
} else {
is(e[def], p[def], "WheelEvent: Wrong event init value for " + def + "!");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for default action of WheelEvent</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
var subWin = window.open("window_wheel_default_action.html", "_blank",
"width=500,height=500,scrollbars=yes");
function finish()
{
subWin.close();
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -53,6 +53,7 @@
#include "nsHTMLParts.h"
#include "nsContentUtils.h"
#include "mozilla/dom/DirectionalityUtils.h"
#include "nsString.h"
#include "nsUnicharUtils.h"
#include "nsGkAtoms.h"
@ -96,6 +97,7 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::directionality;
class nsINodeInfo;
class nsIDOMNodeList;
@ -1687,6 +1689,24 @@ nsGenericHTMLElement::UpdateEditableState(bool aNotify)
nsStyledElement::UpdateEditableState(aNotify);
}
nsEventStates
nsGenericHTMLElement::IntrinsicState() const
{
nsEventStates state = nsGenericHTMLElementBase::IntrinsicState();
if (GetDirectionality() == eDir_RTL) {
state |= NS_EVENT_STATE_RTL;
state &= ~NS_EVENT_STATE_LTR;
} else { // at least for HTML, directionality is exclusively LTR or RTL
NS_ASSERTION(GetDirectionality() == eDir_LTR,
"HTML element's directionality must be either RTL or LTR");
state |= NS_EVENT_STATE_LTR;
state &= ~NS_EVENT_STATE_RTL;
}
return state;
}
nsresult
nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@ -1889,6 +1909,20 @@ nsGenericHTMLElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
else if (aNotify && aName == nsGkAtoms::spellcheck) {
SyncEditorsOnSubtree(this);
}
else if (aName == nsGkAtoms::dir) {
Directionality dir;
if (aValue &&
(aValue->Equals(nsGkAtoms::ltr, eIgnoreCase) ||
aValue->Equals(nsGkAtoms::rtl, eIgnoreCase))) {
SetHasValidDir();
dir = aValue->Equals(nsGkAtoms::rtl, eIgnoreCase) ? eDir_RTL : eDir_LTR;
SetDirectionality(dir, aNotify);
} else {
ClearHasValidDir();
dir = RecomputeDirectionality(this, aNotify);
}
SetDirectionalityOnDescendants(this, dir, aNotify);
}
}
return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,

View File

@ -49,6 +49,8 @@ public:
{
NS_ASSERTION(mNodeInfo->NamespaceID() == kNameSpaceID_XHTML,
"Unexpected namespace");
AddStatesSilently(NS_EVENT_STATE_LTR);
SetFlags(NODE_HAS_DIRECTION_LTR);
}
/** Typesafe, non-refcounting cast from nsIContent. Cheaper than QI. **/
@ -202,6 +204,8 @@ public:
virtual void UpdateEditableState(bool aNotify);
virtual nsEventStates IntrinsicState() const;
// Helper for setting our editable flag and notifying
void DoSetEditableFlag(bool aEditable, bool aNotify) {
SetEditableFlag(aEditable);

View File

@ -116,7 +116,8 @@ nsHTMLAudioElement::MozSetup(PRUint32 aChannels, PRUint32 aRate)
}
mAudioStream = nsAudioStream::AllocateStream();
nsresult rv = mAudioStream->Init(aChannels, aRate);
nsresult rv = mAudioStream->Init(aChannels, aRate,
nsAudioStream::FORMAT_FLOAT32);
if (NS_FAILED(rv)) {
mAudioStream->Shutdown();
mAudioStream = nullptr;

View File

@ -359,11 +359,12 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
aDataURL = NS_LITERAL_STRING("data:") + type +
NS_LITERAL_STRING(";base64,");
PRUint32 count;
PRUint64 count;
rv = stream->Available(&count);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(count <= PR_UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
return Base64EncodeInputStream(stream, aDataURL, count, aDataURL.Length());
return Base64EncodeInputStream(stream, aDataURL, (PRUint32)count, aDataURL.Length());
}
NS_IMETHODIMP
@ -398,17 +399,18 @@ nsHTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
type.AssignLiteral("image/png");
}
PRUint32 imgSize;
PRUint64 imgSize;
rv = stream->Available(&imgSize);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(imgSize <= PR_UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
void* imgData = nullptr;
rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
rv = NS_ReadInputStreamToBuffer(stream, &imgData, (PRUint32)imgSize);
NS_ENSURE_SUCCESS(rv, rv);
// The DOMFile takes ownership of the buffer
nsRefPtr<nsDOMMemoryFile> file =
new nsDOMMemoryFile(imgData, imgSize, aName, type);
new nsDOMMemoryFile(imgData, (PRUint32)imgSize, aName, type);
file.forget(aResult);
return NS_OK;

View File

@ -2204,7 +2204,7 @@ nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType,
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), aCodecList))
if (IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), aCodecList))
return CANPLAY_MAYBE;
#endif
return CANPLAY_NO;
@ -2230,7 +2230,7 @@ bool nsHTMLMediaElement::ShouldHandleMediaType(const char* aMIMEType)
return true;
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), NULL))
if (IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), NULL))
return true;
#endif
// We should not return true for Wave types, since there are some
@ -2346,7 +2346,7 @@ nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (GetMediaPluginHost()->FindDecoder(aType, NULL)) {
if (IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(aType, NULL)) {
nsRefPtr<nsMediaPluginDecoder> decoder = new nsMediaPluginDecoder(aType);
if (decoder->Init(this)) {
return decoder.forget();

View File

@ -517,6 +517,12 @@ nsHTMLObjectElement::GetAttributeMappingFunction() const
void
nsHTMLObjectElement::StartObjectLoad(bool aNotify)
{
// BindToTree can call us asynchronously, and we may be removed from the tree
// in the interim
if (!IsInDoc() || !OwnerDoc()->IsActive()) {
return;
}
LoadObject(aNotify);
SetIsNetworkCreated(false);
}

View File

@ -465,6 +465,12 @@ nsHTMLSharedObjectElement::GetAttributeMappingFunction() const
void
nsHTMLSharedObjectElement::StartObjectLoad(bool aNotify)
{
// BindToTree can call us asynchronously, and we may be removed from the tree
// in the interim
if (!IsInDoc() || !OwnerDoc()->IsActive()) {
return;
}
LoadObject(aNotify);
SetIsNetworkCreated(false);
}

View File

@ -13,7 +13,7 @@ include $(DEPTH)/config/autoconf.mk
MODULE = content
LIBRARY_NAME = gkconhtmldoc_s
LIBXUL_LIBRARY = 1
FAIL_ON_WARNINGS = 1
CPPSRCS = \
nsHTMLContentSink.cpp \

View File

@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk
MODULE = content
LIBRARY_NAME = gkcontentmathml_s
LIBXUL_LIBRARY = 1
FAIL_ON_WARNINGS = 1
CPPSRCS = \
nsMathMLElement.cpp \

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