Merge mozilla-central -> tracemonkey

This commit is contained in:
Blake Kaplan 2008-08-27 14:28:27 -07:00
commit 2c4a1c4007
579 changed files with 10522 additions and 50793 deletions

View File

@ -4,6 +4,7 @@
~$
\.pyc$
(^|/)TAGS$
\.DS_Store$
# User files that may appear at the root
^\.mozconfig$

View File

@ -170,6 +170,7 @@ ACCESSIBILITY_ATOM(href, "href") // XUL, XLink
ACCESSIBILITY_ATOM(increment, "increment") // XUL
ACCESSIBILITY_ATOM(lang, "lang")
ACCESSIBILITY_ATOM(linkedPanel, "linkedpanel") // XUL
ACCESSIBILITY_ATOM(longDesc, "longdesc")
ACCESSIBILITY_ATOM(maxpos, "maxpos") // XUL
ACCESSIBILITY_ATOM(minpos, "minpos") // XUL
ACCESSIBILITY_ATOM(multiline, "multiline") // XUL

View File

@ -105,6 +105,8 @@ nsApplicationAccessible::Init()
NS_IMETHODIMP
nsApplicationAccessible::GetName(nsAString& aName)
{
aName.Truncate();
nsCOMPtr<nsIStringBundleService> bundleService =
do_GetService(NS_STRINGBUNDLE_CONTRACTID);

View File

@ -118,8 +118,11 @@ nsRootAccessible::~nsRootAccessible()
// helpers
/* readonly attribute AString name; */
NS_IMETHODIMP nsRootAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsRootAccessible::GetName(nsAString& aName)
{
aName.Truncate();
if (!mDocument) {
return NS_ERROR_FAILURE;
}

View File

@ -275,8 +275,11 @@ NS_IMETHODIMP nsHTMLButtonAccessible::GetRole(PRUint32 *_retval)
return NS_OK;
}
NS_IMETHODIMP nsHTMLButtonAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsHTMLButtonAccessible::GetName(nsAString& aName)
{
aName.Truncate();
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
@ -398,8 +401,11 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible::GetRole(PRUint32 *aRole)
return NS_OK;
}
NS_IMETHODIMP nsHTMLTextFieldAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsHTMLTextFieldAccessible::GetName(nsAString& aName)
{
aName.Truncate();
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
if (!content) {
return NS_ERROR_FAILURE;
@ -606,12 +612,14 @@ nsIContent* nsHTMLGroupboxAccessible::GetLegend()
return nsnull;
}
NS_IMETHODIMP nsHTMLGroupboxAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsHTMLGroupboxAccessible::GetName(nsAString& aName)
{
aName.Truncate();
if (!mDOMNode) {
return NS_ERROR_FAILURE;
}
aName.Truncate();
if (mRoleMapEntry) {
nsAccessible::GetName(aName);
if (!aName.IsEmpty()) {

View File

@ -210,9 +210,46 @@ void nsHTMLImageAccessible::CacheChildren()
mAccChildCount = childCount;
}
NS_IMETHODIMP nsHTMLImageAccessible::DoAction(PRUint8 index)
NS_IMETHODIMP
nsHTMLImageAccessible::GetNumActions(PRUint8 *aNumActions)
{
if (index == eAction_ShowLongDescription) {
NS_ENSURE_ARG_POINTER(aNumActions);
*aNumActions = 0;
if (IsDefunct())
return NS_ERROR_FAILURE;
nsresult rv= nsLinkableAccessible::GetNumActions(aNumActions);
NS_ENSURE_SUCCESS(rv, rv);
if (HasLongDesc())
(*aNumActions)++;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLImageAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
{
aName.Truncate();
if (IsDefunct())
return NS_ERROR_FAILURE;
if (IsValidLongDescIndex(aIndex)) {
aName.AssignLiteral("showlongdesc");
return NS_OK;
}
return nsLinkableAccessible::GetActionName(aIndex, aName);
}
NS_IMETHODIMP
nsHTMLImageAccessible::DoAction(PRUint8 aIndex)
{
if (IsDefunct())
return NS_ERROR_FAILURE;
if (IsValidLongDescIndex(aIndex)) {
//get the long description uri and open in a new window
nsCOMPtr<nsIDOMHTMLImageElement> element(do_QueryInterface(mDOMNode));
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
@ -230,7 +267,7 @@ NS_IMETHODIMP nsHTMLImageAccessible::DoAction(PRUint8 index)
return win->Open(longDesc, NS_LITERAL_STRING(""), NS_LITERAL_STRING(""),
getter_AddRefs(tmp));
}
return nsLinkableAccessible::DoAction(index);
return nsLinkableAccessible::DoAction(aIndex);
}
////////////////////////////////////////////////////////////////////////////////
@ -405,3 +442,29 @@ nsHTMLImageAccessible::GetAreaAccessible(nsIDOMHTMLCollection *aAreaCollection,
return accessible;
}
////////////////////////////////////////////////////////////////////////////////
// Private methods
PRBool
nsHTMLImageAccessible::HasLongDesc()
{
if (IsDefunct())
return PR_FALSE;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
return (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::longDesc));
}
PRBool
nsHTMLImageAccessible::IsValidLongDescIndex(PRUint8 aIndex)
{
if (!HasLongDesc())
return PR_FALSE;
PRUint8 numActions = 0;
nsresult rv = nsLinkableAccessible::GetNumActions(&numActions);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
return (aIndex == numActions);
}

View File

@ -55,15 +55,14 @@ class nsHTMLImageAccessible : public nsLinkableAccessible,
NS_DECL_ISUPPORTS_INHERITED
public:
//action0 may exist depends on whether an onclick is associated with it
enum { eAction_ShowLongDescription = 1 };
nsHTMLImageAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
// nsIAccessible
NS_IMETHOD GetName(nsAString& _retval);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
NS_IMETHOD GetRole(PRUint32 *_retval);
NS_IMETHOD GetNumActions(PRUint8 *aNumActions);
NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
NS_IMETHOD DoAction(PRUint8 index);
// nsIAccessibleHyperLink
@ -95,6 +94,25 @@ protected:
// share area elements but we need to have separate area accessibles for
// each image accessible.
nsAccessNodeHashtable *mAccessNodeCache;
private:
/**
* Determine if this image accessible has a longdesc attribute.
*
* @returns true if the longdesc attribute is present.
*/
PRBool HasLongDesc();
/**
* Used by GetActionName and DoAction to ensure the index for opening the
* longdesc URL is valid.
* It is always assumed that the highest possible index opens the longdesc.
*
* @param aIndex The 0-based index to be tested.
*
* @returns true if index is valid for longdesc action.
*/
PRBool IsValidLongDescIndex(PRUint8 aIndex);
};
#endif

View File

@ -513,8 +513,11 @@ NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetRole(PRUint32 *aRole)
/**
* Get our Name from our Content's subtree
*/
NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsHTMLSelectOptionAccessible::GetName(nsAString& aName)
{
aName.Truncate();
// CASE #1 -- great majority of the cases
// find the label attribute - this is what the W3C says we should use
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(mDOMNode));
@ -1383,8 +1386,11 @@ NS_IMETHODIMP nsHTMLComboboxButtonAccessible::GetParent(nsIAccessible **aParent)
/**
* Gets the name from GetActionName()
*/
NS_IMETHODIMP nsHTMLComboboxButtonAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsHTMLComboboxButtonAccessible::GetName(nsAString& aName)
{
aName.Truncate();
return GetActionName(eAction_Click, aName);
}

View File

@ -37,7 +37,6 @@
* ***** END LICENSE BLOCK ***** */
#include "nsAccessNodeWrap.h"
#include <tchar.h>
#include "ISimpleDOMNode_i.c"
#include "nsAccessibilityAtoms.h"
#include "nsIAccessibilityService.h"
@ -72,6 +71,10 @@ PRBool nsAccessNodeWrap::gIsIA2Disabled = PR_FALSE;
nsIAccessibleTextChangeEvent *nsAccessNodeWrap::gTextEvent = nsnull;
// Pref to disallow CtrlTab preview functionality if JAWS or Window-Eyes are
// running.
#define CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF "browser.ctrlTab.disallowForScreenReaders"
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
@ -662,7 +665,7 @@ GetHRESULT(nsresult aResult)
PRBool nsAccessNodeWrap::IsOnlyMsaaCompatibleJawsPresent()
{
HMODULE jhookhandle = ::GetModuleHandleW(NS_LITERAL_STRING("jhook").get());
HMODULE jhookhandle = ::GetModuleHandleW(L"jhook");
if (!jhookhandle)
return PR_FALSE; // No JAWS, or some other screen reader, use IA2
@ -691,9 +694,44 @@ PRBool nsAccessNodeWrap::IsOnlyMsaaCompatibleJawsPresent()
|| (dwLeftMost == 8 && dwSecondRight < 2173));
}
void nsAccessNodeWrap::TurnOffNewTabSwitchingForJawsAndWE()
{
HMODULE srHandle = ::GetModuleHandleW(L"jhook");
if (!srHandle) {
// No JAWS, try Window-Eyes
srHandle = ::GetModuleHandleW(L"gwm32inc");
if (!srHandle) {
// no screen reader we're interested in. Bail out.
return;
}
}
// Check to see if the pref for disallowing CtrlTab is already set.
// If so, bail out.
// If not, set it.
nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefs) {
PRBool hasDisallowNewCtrlTabPref = PR_FALSE;
nsresult rv = prefs->PrefHasUserValue(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF,
&hasDisallowNewCtrlTabPref);
if (NS_SUCCEEDED(rv) && hasDisallowNewCtrlTabPref) {
// This pref has been set before. There is no default for it.
// Do nothing further, respect the setting that's there.
// That way, if noone touches it, it'll stay on after toggled once.
// If someone decided to turn it off, we respect that, too.
return;
}
// Value has never been set, set it.
prefs->SetBoolPref(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF, PR_TRUE);
}
}
void nsAccessNodeWrap::DoATSpecificProcessing()
{
if (IsOnlyMsaaCompatibleJawsPresent())
// All versions below 8.0.2173 are not compatible
gIsIA2Disabled = PR_TRUE;
TurnOffNewTabSwitchingForJawsAndWE();
}

View File

@ -159,6 +159,9 @@ class nsAccessNodeWrap : public nsAccessNode,
static int FilterA11yExceptions(unsigned int aCode, EXCEPTION_POINTERS *aExceptionInfo);
static PRBool IsOnlyMsaaCompatibleJawsPresent();
static void TurnOffNewTabSwitchingForJawsAndWE();
static void DoATSpecificProcessing();
protected:
void GetAccessibleFor(nsIDOMNode *node, nsIAccessible **newAcc);

View File

@ -92,9 +92,12 @@ nsXULColorPickerTileAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState
return NS_OK;
}
NS_IMETHODIMP nsXULColorPickerTileAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP
nsXULColorPickerTileAccessible::GetName(nsAString& aName)
{
return GetXULName(_retval);
aName.Truncate();
return GetXULName(aName);
}
NS_IMETHODIMP nsXULColorPickerTileAccessible::GetValue(nsAString& _retval)

View File

@ -389,13 +389,16 @@ nsXULMenuitemAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
return NS_OK;
}
NS_IMETHODIMP nsXULMenuitemAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP
nsXULMenuitemAccessible::GetName(nsAString& aName)
{
aName.Truncate();
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
if (!element) {
return NS_ERROR_FAILURE;
}
element->GetAttribute(NS_LITERAL_STRING("label"), _retval);
element->GetAttribute(NS_LITERAL_STRING("label"), aName);
return NS_OK;
}
@ -578,9 +581,11 @@ nsXULMenuSeparatorAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
return NS_OK;
}
NS_IMETHODIMP nsXULMenuSeparatorAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP
nsXULMenuSeparatorAccessible::GetName(nsAString& aName)
{
_retval.Truncate();
aName.Truncate();
return NS_OK;
}
@ -752,9 +757,10 @@ nsXULMenubarAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
}
NS_IMETHODIMP nsXULMenubarAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP
nsXULMenubarAccessible::GetName(nsAString& aName)
{
_retval.AssignLiteral("Application");
aName.AssignLiteral("Application");
return NS_OK;
}

View File

@ -110,6 +110,8 @@ nsXULColumnItemAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
NS_IMETHODIMP
nsXULColumnItemAccessible::GetName(nsAString& aName)
{
aName.Truncate();
return GetXULName(aName);
}
@ -857,8 +859,11 @@ nsXULListitemAccessible::GetListAccessible()
* If there is a Listcell as a child ( not anonymous ) use it, otherwise
* default to getting the name from GetXULName
*/
NS_IMETHODIMP nsXULListitemAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP
nsXULListitemAccessible::GetName(nsAString& aName)
{
aName.Truncate();
if (!mDOMNode)
return NS_ERROR_FAILURE;
@ -869,12 +874,12 @@ NS_IMETHODIMP nsXULListitemAccessible::GetName(nsAString& _retval)
nsAutoString tagName;
childElement->GetLocalName(tagName);
if (tagName.EqualsLiteral("listcell")) {
childElement->GetAttribute(NS_LITERAL_STRING("label"), _retval);
childElement->GetAttribute(NS_LITERAL_STRING("label"), aName);
return NS_OK;
}
}
}
return GetXULName(_retval);
return GetXULName(aName);
}
/**

View File

@ -297,9 +297,11 @@ NS_IMETHODIMP nsXULTabsAccessible::GetValue(nsAString& _retval)
}
/** no name*/
NS_IMETHODIMP nsXULTabsAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP
nsXULTabsAccessible::GetName(nsAString& aName)
{
_retval.Truncate();
aName.Truncate();
return NS_OK;
}

View File

@ -56,8 +56,11 @@ nsHyperTextAccessibleWrap(aDomNode, aShell)
}
/* wstring getName (); */
NS_IMETHODIMP nsXULTextAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsXULTextAccessible::GetName(nsAString& aName)
{
aName.Truncate();
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
@ -117,8 +120,11 @@ nsLeafAccessible(aDomNode, aShell)
{
}
NS_IMETHODIMP nsXULTooltipAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsXULTooltipAccessible::GetName(nsAString& aName)
{
aName.Truncate();
return GetXULName(aName, PR_TRUE);
}

View File

@ -783,8 +783,11 @@ NS_IMETHODIMP nsXULTreeitemAccessible::Shutdown()
return nsLeafAccessible::Shutdown();
}
NS_IMETHODIMP nsXULTreeitemAccessible::GetName(nsAString& aName)
NS_IMETHODIMP
nsXULTreeitemAccessible::GetName(nsAString& aName)
{
aName.Truncate();
if (IsDefunct())
return NS_ERROR_FAILURE;

View File

@ -47,6 +47,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
moz.png \
longdesc_src.html \
nsIAccessible_actions.js \
nsIAccessible_name.css \
nsIAccessible_name.xbl \
@ -78,6 +79,7 @@ _TEST_FILES =\
testTextboxes.js \
test_bug428479.html \
test_bug429285.html \
test_bug434464.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>Mozilla logo</title>
</head>
<body>
<p>This file would contain a longer description of the Mozilla logo, if I knew what it looked like.</p>
</body>
</html>

View File

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=434464
-->
<head>
<title>Test NSIAccessNode cache invalidation</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript">
function doTest()
{
var accRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
getService(Components.interfaces.nsIAccessibleRetrieval);
var parentElm = document.getElementById("parent");
if (!parentElm) {
ok(false, "no parent element for paragraph!");
SimpleTest.finish();
}
var elm = document.getElementById("para");
if (!elm) {
ok(false, "no element for paragraph!");
SimpleTest.finish();
}
// It's currently hidden. Ask for its parent's nsIAccessNode.
var parentElmAccNode = null;
try {
parentElmAccNode = accRetrieval.getAccessibleFor(parentElm).
QueryInterface(Components.interfaces.nsIAccessNode);
} catch(e) {}
if (!parentElmAccNode) {
ok(false, "No accessNode for parent of hidden paragraph!");
SimpleTest.finish();
}
// Get the paragraph's accessNode.
var elmAccNode = null;
try {
elmAccNode = parentElmAccNode.firstChildNode;
} catch(e) {}
if (!elmAccNode) {
ok(false, "No accessNode for hidden paragraph!");
SimpleTest.finish();
}
// Now make the paragraph visible. This invalidates the just-retrieved
// AccessNode. An nsIAccessible should then be retrievable.
elm.style.display = "block";
// Now, get an accessible for it. Use a timeout so the layout engine can
// catch up.
window.setTimeout(
function()
{
var elmAcc = null;
try {
elmAcc = accRetrieval.getAccessibleFor(elm);
} catch(e) {}
ok(elmAcc, "No accessible for paragraph after it became visible!");
SimpleTest.finish();
},
200);
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=434464">Mozilla Bug 434464</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="parent"><p style="display: none;" id="para">I'm hidden initially, but then made visible.</p></div>
</body>
</html>

View File

@ -85,7 +85,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
is(height.value, aHeight, "wrong height for " + aID + "!");
}
function testThis(aID, aName, aSRC, aWidth, aHeight)
function testThis(aID, aName, aSRC, aWidth, aHeight,
aNumActions, aActionNames)
{
var elem = document.getElementById(aID);
var acc;
@ -110,6 +111,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
ok(attributes, "no attributes on " + aID + "!");
is(attributes.getStringProperty("src"), aSRC,
"no correct src attribute for " + aID + "!");
if (aNumActions) {
is(acc.numActions, aNumActions,
"Wrong number of actions for " + aID + "!");
for (index = 0; index < aActionNames.length; index++) {
is(acc.getActionName(index), aActionNames[index],
"Wrong action name for " + aID + ", index " + index +"!");
}
}
}
function doTest()
@ -147,6 +158,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
// Test linked image with empty alt attribute and title
testThis("linkedImageEmptyAltAndTitle", "Link to Mozilla Foundation", "moz.png", 93, 42);
// Image with long desc
var actionNamesArray = new Array("showlongdesc");
testThis("longdesc", "Image of Mozilla logo", "moz.png", 89, 38, 1,
actionNamesArray);
// Image with click and long desc
actionNamesArray = null;
actionNamesArray = new Array("click", "showlongdesc");
testThis("clickAndLongdesc", "Another image of Mozilla logo", "moz.png",
89, 38, 2, actionNamesArray);
// Image with click
actionNamesArray = null;
actionNamesArray = new Array("click");
testThis("click", "A third image of Mozilla logo", "moz.png",
89, 38, 1, actionNamesArray);
SimpleTest.finish();
}
@ -182,5 +210,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
<br>Linked image with empty alt and title:<br>
<a href="http://www.mozilla.org"><img id="linkedImageEmptyAltAndTitle" src="moz.png" alt=""
title="Link to Mozilla Foundation"/></a>
<br>Image with longdesc:<br>
<img id="longdesc" src="moz.png" longdesc="longdesc_src.html"
alt="Image of Mozilla logo"/>
<br>Image with click and longdesc:<br>
<img id="clickAndLongdesc" src="moz.png" longdesc="longdesc_src.html"
alt="Another image of Mozilla logo" onclick="alert('Clicked!');"/>
<br>Image with click:<br>
<img id="click" src="moz.png"
alt="A third image of Mozilla logo" onclick="alert('Clicked, too!');"/>
</body>
</html>

View File

@ -67,7 +67,7 @@
return;
}
var errorMsg = " for " + aID + "at offset " + aOffset;
var errorMsg = " for " + aID + " at offset " + aOffset;
is(startOffset.value, aStartOffset,
"Wrong start offset" + errorMsg);
is(endOffset.value, aEndOffset,
@ -98,10 +98,10 @@
if (!(prop.key in aExpectedAttrs))
ok(false,
"Unexpected attribute '" + prop.key + "'" + aErrorMsg);
"Unexpected attribute '" + prop.key + "' " + aErrorMsg);
else
is(prop.value, aExpectedAttrs[prop.key],
"Attribute '" + prop.key + "' has wrong value" + aErrorMsg);
"Attribute '" + prop.key + " 'has wrong value" + aErrorMsg);
}
for (var name in aExpectedAttrs) {
@ -113,7 +113,7 @@
if (!value)
ok(false,
"There is no expected attribute '" + name + "'" + aErrorMsg);
"There is no expected attribute '" + name + "' " + aErrorMsg);
}
}
@ -176,6 +176,7 @@
testTextAttrs(ID, 0, attrs, 0, 11, defAttrs);
testTextAttrs(ID, 11, misspelledAttrs, 11, 17, defAttrs);
testTextAttrs(ID, 17, attrs, 17, 18, defAttrs);
testTextAttrs(ID, 18, misspelledAttrs, 18, 22, defAttrs);
is(gA11yEventObserver.mTextAttrChangedEventCounter, 2,

7
aclocal.m4 vendored
View File

@ -13,7 +13,10 @@ builtin(include, build/autoconf/libart.m4)dnl
builtin(include, build/autoconf/pkg.m4)dnl
builtin(include, build/autoconf/freetype2.m4)dnl
builtin(include, build/autoconf/codeset.m4)dnl
dnl
define(MOZ_TOPSRCDIR,.)dnl MOZ_TOPSRCDIR is used in altoptions.m4
builtin(include, build/autoconf/altoptions.m4)dnl
# Read the user's .mozconfig script. We can't do this in
# configure.in: autoconf puts the argument parsing code above anything
# expanded from configure.in, and we need to get the configure options
# from .mozconfig in place before that argument parsing code.
MOZ_READ_MOZCONFIG(.)

View File

@ -216,6 +216,7 @@ pref("browser.urlbar.matchOnlyTyped", false);
// 0: Match anywhere (e.g., middle of words)
// 1: Match on word boundaries and then try matching anywhere
// 2: Match only on word boundaries (e.g., after / or .)
// 3: Match at the beginning of the url or title
pref("browser.urlbar.matchBehavior", 1);
pref("browser.urlbar.filter.javascript", true);

View File

@ -1082,7 +1082,9 @@ function delayedStartup()
gBrowser.addEventListener("command", BrowserOnCommand, false);
tabPreviews.init();
if (gPrefService.getBoolPref("browser.ctrlTab.mostRecentlyUsed"))
if ((!gPrefService.prefHasUserValue("browser.ctrlTab.disallowForScreenReaders") ||
!gPrefService.getBoolPref("browser.ctrlTab.disallowForScreenReaders")) &&
gPrefService.getBoolPref("browser.ctrlTab.mostRecentlyUsed"))
ctrlTab.init();
// Delayed initialization of the livemarks update timer.
@ -5408,14 +5410,8 @@ var OfflineApps = {
// XXX: duplicated in preferences/advanced.js
_getOfflineAppUsage: function (host)
{
var cacheService = Components.classes["@mozilla.org/network/cache-service;1"].
getService(Components.interfaces.nsICacheService);
var cacheSession = cacheService.createSession("HTTP-offline",
Components.interfaces.nsICache.STORE_OFFLINE,
true).
QueryInterface(Components.interfaces.nsIOfflineCacheSession);
var usage = cacheSession.getDomainUsage(host);
// XXX Bug 442810: include offline cache usage.
var usage = 0;
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);
usage += storageManager.getUsage(host);

View File

@ -131,7 +131,16 @@ nsContextMenu.prototype = {
},
initOpenItems: function CM_initOpenItems() {
var shouldShow = this.onSaveableLink ||
var isMailtoInternal = false;
if (this.onMailtoLink) {
var mailtoHandler = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
getService(Ci.nsIExternalProtocolService).
getProtocolHandlerInfo("mailto");
isMailtoInternal = (!mailtoHandler.alwaysAskBeforeHandling &&
mailtoHandler.preferredAction == Ci.nsIHandlerInfo.useHelperApp &&
(mailtoHandler.preferredApplicationHandler instanceof Ci.nsIWebHandlerApp));
}
var shouldShow = this.onSaveableLink || isMailtoInternal ||
(this.inDirList && this.onLink);
this.showItem("context-openlink", shouldShow);
this.showItem("context-openlinkintab", shouldShow);

View File

@ -188,10 +188,6 @@ var gImageHash = { };
var gStrings = { };
var gBundle;
const DRAGSERVICE_CONTRACTID = "@mozilla.org/widget/dragservice;1";
const TRANSFERABLE_CONTRACTID = "@mozilla.org/widget/transferable;1";
const ARRAY_CONTRACTID = "@mozilla.org/supports-array;1";
const STRING_CONTRACTID = "@mozilla.org/supports-string;1";
const PERMISSION_CONTRACTID = "@mozilla.org/permissionmanager;1";
const PREFERENCES_CONTRACTID = "@mozilla.org/preferences-service;1";
const ATOM_CONTRACTID = "@mozilla.org/atom-service;1";
@ -663,32 +659,16 @@ function onBeginLinkDrag(event,urlField,descField)
if (row == -1)
return;
// Getting drag-system needed services
var dragService = Components.classes[DRAGSERVICE_CONTRACTID].getService()
.QueryInterface(Components.interfaces.nsIDragService);
var transArray = Components.classes[ARRAY_CONTRACTID]
.createInstance(Components.interfaces.nsISupportsArray);
if (!transArray)
return;
var trans = Components.classes[TRANSFERABLE_CONTRACTID]
.createInstance(Components.interfaces.nsITransferable);
if (!trans)
return;
// Adding URL flavor
trans.addDataFlavor("text/x-moz-url");
var col = tree.columns[urlField];
var url = tree.view.getCellText(row, col);
col = tree.columns[descField];
var desc = tree.view.getCellText(row, col);
var stringURL = Components.classes[STRING_CONTRACTID]
.createInstance(Components.interfaces.nsISupportsString);
stringURL.data = url + "\n" + desc;
trans.setTransferData("text/x-moz-url", stringURL, stringURL.data.length * 2 );
transArray.AppendElement(trans.QueryInterface(Components.interfaces.nsISupports));
dragService.invokeDragSession(event.target, transArray, null, dragService.DRAGDROP_ACTION_NONE);
var dt = event.dataTransfer;
dt.setData("text/x-moz-url", url + "\n" + desc);
dt.setData("text/url-list", url);
dt.setData("text/plain", url);
}
//******** Image Stuff

View File

@ -1543,7 +1543,7 @@
if ("owner" in aTab && aTab.owner &&
this.mPrefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
for (var i = 0; i < length; ++i) {
tab = this.mTabContainer.childNodes[i];
var tab = this.mTabContainer.childNodes[i];
if (tab == aTab.owner) {
newIndex = i;
break;

View File

@ -76,6 +76,14 @@ DistributionCustomizer.prototype = {
return this.__annoSvc;
},
__livemarkSvc: null,
get _livemarkSvc() {
if (!this.__livemarkSvc)
this.__livemarkSvc = Cc["@mozilla.org/browser/livemark-service;2"].
getService(Ci.nsILivemarkService);
return this.__livemarkSvc;
},
__dirSvc: null,
get _dirSvc() {
if (!this.__dirSvc)
@ -179,6 +187,18 @@ DistributionCustomizer.prototype = {
this._bmSvc.insertSeparator(parentId, index);
break;
case "livemark":
if (iid < defaultItemId)
index = prependIndex++;
newId = this._livemarkSvc.
createLivemark(parentId,
items[iid]["title"],
this._makeURI(items[iid]["siteLink"]),
this._makeURI(items[iid]["feedLink"]),
index);
break;
case "bookmark":
default:
if (iid < defaultItemId)
@ -218,8 +238,16 @@ DistributionCustomizer.prototype = {
return;
let bmProcessed = false;
let bmProcessedPref = "distribution." +
this._ini.getString("Global", "id") + ".bookmarksProcessed";
let bmProcessedPref;
try {
bmProcessedPref = this._ini.getString("Global",
"bookmarks.initialized.pref");
} catch (e) {
bmProcessedPref = "distribution." +
this._ini.getString("Global", "id") + ".bookmarksProcessed";
}
try {
bmProcessed = this._prefs.getBoolPref(bmProcessedPref);
} catch (e) {}

View File

@ -216,13 +216,8 @@ var gAdvancedPane = {
// XXX: duplicated in browser.js
_getOfflineAppUsage: function (host)
{
var cacheService = Components.classes["@mozilla.org/network/cache-service;1"].
getService(Components.interfaces.nsICacheService);
var cacheSession = cacheService.createSession("HTTP-offline",
Components.interfaces.nsICache.STORE_OFFLINE,
true).
QueryInterface(Components.interfaces.nsIOfflineCacheSession);
var usage = cacheSession.getDomainUsage(host);
// XXX Bug 442710: include offline cache usage.
var usage = 0;
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);

View File

@ -42,7 +42,7 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS += chrome \
DIRS += browser \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -45,6 +45,8 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_350525.js \
browser_393716.js \
browser_448741.js \
$(NULL)

View File

@ -0,0 +1,100 @@
function test() {
/** Test for Bug 350525 **/
function test(aLambda) {
try {
return aLambda() || true;
}
catch (ex) { }
return false;
}
// test setup
let tabbrowser = getBrowser();
waitForExplicitFinish();
// component
let ssComponent = test(function() Cc["@mozilla.org/browser/sessionstore;1"]);
ok(ssComponent, "reference the sessionstore component");
// service
let ss = test(function() ssComponent.getService(Ci.nsISessionStore));
ok(ss, "reference the sessionstore service");
////////////////////////////
// setWindowValue, et al. //
////////////////////////////
let key = "Unique name: " + Date.now();
let value = "Unique value: " + Math.random();
// test adding
ok(test(function() ss.setWindowValue(window, key, value)), "set a window value");
// test retrieving
is(ss.getWindowValue(window, key), value, "stored window value matches original");
// test deleting
ok(test(function() ss.deleteWindowValue(window, key)), "delete the window value");
// value should not exist post-delete
is(ss.getWindowValue(window, key), "", "window value was deleted");
/////////////////////////
// setTabValue, et al. //
/////////////////////////
key = "Unique name: " + Math.random();
value = "Unique value: " + Date.now();
let tab = tabbrowser.addTab();
// test adding
ok(test(function() ss.setTabValue(tab, key, value)), "store a tab value");
// test retrieving
is(ss.getTabValue(tab, key), value, "stored tab value match original");
// test deleting
ok(test(function() ss.deleteTabValue(tab, key)), "delete the tab value");
// value should not exist post-delete
is(ss.getTabValue(tab, key), "", "tab value was deleted");
// clean up
tabbrowser.removeTab(tab);
/////////////////////////////////////
// getClosedTabCount, undoCloseTab //
/////////////////////////////////////
// get closed tab count
let count = ss.getClosedTabCount(window);
let max_tabs_undo = gPrefService.getIntPref("browser.sessionstore.max_tabs_undo");
ok(0 <= count && count <= max_tabs_undo,
"getClosedTabCount returns zero or at most max_tabs_undo");
// create a new tab
let testURL = "about:";
tab = tabbrowser.addTab(testURL);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
// make sure that the next closed tab will increase getClosedTabCount
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
// remove tab
tabbrowser.removeTab(tab);
// getClosedTabCount
var newcount = ss.getClosedTabCount(window);
ok(newcount > count, "after closing a tab, getClosedTabCount has been incremented");
// undoCloseTab
ok(test(function() ss.undoCloseTab(window, 0)), "undoCloseTab doesn't throw")
tab = tabbrowser.selectedTab;
tab.linkedBrowser.addEventListener("load", function(aEvent) {
is(this.currentURI.spec, testURL, "correct tab was reopened");
// clean up
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo);
tabbrowser.removeTab(tab);
finish();
}, true);
}, true);
}

View File

@ -0,0 +1,78 @@
function test() {
/** Test for Bug 393716 **/
// set up the basics (SessionStore service, tabbrowser)
try {
var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
}
catch (ex) { }
ok(ss, "SessionStore service is available");
let tabbrowser = getBrowser();
waitForExplicitFinish();
/////////////////
// getTabState //
/////////////////
let key = "Unique key: " + Date.now();
let value = "Unique value: " + Math.random();
let testURL = "about:config";
// create a new tab
let tab = tabbrowser.addTab(testURL);
ss.setTabValue(tab, key, value);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
// get the tab's state
let state = ss.getTabState(tab);
ok(state, "get the tab's state");
// verify the tab state's integrity
state = eval("(" + state + ")");
ok(state instanceof Object && state.entries instanceof Array && state.entries.length > 0,
"state object seems valid");
ok(state.entries.length == 1 && state.entries[0].url == testURL,
"Got the expected state object (test URL)");
ok(state.extData && state.extData[key] == value,
"Got the expected state object (test manually set tab value)");
// clean up
tabbrowser.removeTab(tab);
}, true);
//////////////////////////////////
// setTabState and duplicateTab //
//////////////////////////////////
let key2 = "key2";
let value2 = "Value " + Math.random();
let value3 = "Another value: " + Date.now();
let state = { entries: [{ url: testURL }], extData: { key2: value2 } };
// create a new tab
let tab2 = tabbrowser.addTab();
// set the tab's state
ss.setTabState(tab2, state.toSource());
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
// verify the correctness of the restored tab
ok(ss.getTabValue(tab2, key2) == value2 && this.currentURI.spec == testURL,
"the tab's state was correctly restored");
// add text data
let textbox = this.contentDocument.getElementById("textbox");
textbox.wrappedJSObject.value = value3;
// duplicate the tab
let duplicateTab = ss.duplicateTab(window, tab2);
tabbrowser.removeTab(tab2);
duplicateTab.linkedBrowser.addEventListener("load", function(aEvent) {
// verify the correctness of the duplicated tab
ok(ss.getTabValue(duplicateTab, key2) == value2 && this.currentURI.spec == testURL,
"correctly duplicated the tab's state");
let textbox = this.contentDocument.getElementById("textbox");
is(textbox.wrappedJSObject.value, value3, "also duplicated text data");
// clean up
tabbrowser.removeTab(duplicateTab);
finish();
}, true);
}, true);
}

View File

@ -1,132 +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=350525
-->
<window title="Mozilla Bug 350525"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<title>Test for Bug 350525</title>
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=350525">Mozilla Bug 350525</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript">
/** Test for Bug 350525 **/
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
// component
try {
Cc["@mozilla.org/browser/sessionstore;1"];
ok(1==1, "Able to reference the sessionstore component?");
} catch(ex) {
alert(ex);
ok(1==2, "Able to reference the sessionstore component?");
}
// service
try {
var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
ok(true, "Able to reference the sessionstore service?");
} catch(ex) {
ok(false, "Able to reference the sessionstore service?");
}
// get current window, tabbrowser
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
var windowEnumerator = wm.getEnumerator("navigator:browser");
var currentWindow = windowEnumerator.getNext();
var tabbrowser = currentWindow.getBrowser();
/*****************
undoCloseTab, getClosedTabCount
*****************/
// get closed tab count
var count = ss.getClosedTabCount(currentWindow);
ok(count > -1, "getClosedTabCount returns zero or more?");
// create a new tab
var newTab = tabbrowser.addTab("http://www.mozilla.org");
// remove tab
tabbrowser.removeTab(newTab);
// getClosedTabCount
var newcount = ss.getClosedTabCount(currentWindow);
todo(newcount > count, "After closing a tab, getClosedTabCount has been incremented? " + newcount + " > " + count);
// undoCloseTab
var undid = ss.undoCloseTab(currentWindow, null);
ok(undid != -1, "undoCloseTab throws?");
// clean up
tabbrowser.removeAllTabsBut(tabbrowser.selectedTab);
/*****************
setWindowValue
*****************/
var key = "key1";
var value = "value1";
// create a new tab
var newTab = tabbrowser.addTab("http://www.mozilla.org");
// test adding
ok(ss.setWindowValue(currentWindow, key, value) != -1, "Able to set a window value?");
// test retrieving
var storedValue = ss.getWindowValue(currentWindow, key);
is(value, storedValue, "Stored window value matches original?");
// test deleting
ok(ss.deleteWindowValue(currentWindow, key) != -1, "Delete window value?");
// value should not exist post-delete
is(ss.getWindowValue(currentWindow, key), "", "Fetching deleted window value fails?");
// clean up
tabbrowser.removeTab(newTab);
/*********************
tabValues
*********************/
key = "key1";
value = "value1";
// create a new tab
newTab = tabbrowser.addTab("http://www.mozilla.org");
// test adding
ok(ss.setTabValue(newTab, key, value) != -1, "Able to store a tab value?");
// test retrieving
var storedValue = ss.getTabValue(newTab, key);
ok(value==storedValue, "Stored tab value match original?");
// test deleting
ok(ss.deleteTabValue(newTab, key) != -1, "Able to delete a tab value?");
// value should not exist post-delete
ok(ss.getTabValue(newTab, key) == "", "Unable to retrieve deleted tab value?");
// clean up
tabbrowser.removeTab(newTab);
</script>
</pre>
</body>
</window>

View File

@ -1,101 +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=393716
-->
<window title="Mozilla Bug 393716"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<title>Test for Bug 393716</title>
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=393716">Mozilla Bug 393716</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript">
<![CDATA[
const Cc = Components.classes;
const Ci = Components.interfaces;
// set up the basics (SessionStore service, tabbrowser)
try {
var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
} catch (ex) {
ok(false, "SessionStore service available?");
}
try {
var windowEnumerator = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator).
getEnumerator("navigator:browser");
var currentWindow = windowEnumerator.getNext();
var tabbrowser = currentWindow.getBrowser();
} catch (ex) {
ok(false, "tabbrowser available?");
}
/**************
* getTabState
**************/
var key = "key1", value = "value1";
// create a new tab
var newTab = tabbrowser.addTab();
ss.setTabValue(newTab, key, value);
// get the tab's state
var state = ss.getTabState(newTab);
ok(state, "Able to get the tab's state?");
// verify the tab state's integrity
state = eval("(" + state + ")");
ok(state instanceof Object && state.entries instanceof Array && state.entries.length > 0,
"Got a valid state object?");
ok(state.entries.length == 1 && state.entries[0].url == "about:blank",
"Got the expected state object (test URL)?");
ok(state.extData && state.extData[key] == value,
"Got the expected state object (test manually set tab value)?");
// clean up
tabbrowser.removeTab(newTab);
/*****************************
* setTabState / duplicateTab
*****************************/
key = "key2";
value = "value2";
state = { entries: [{ url: "about:blank" }], extData: { key2: value } };
// create a new tab
newTab = tabbrowser.addTab();
// set the tab's state
ss.setTabState(newTab, state.toSource());
// verify the correctness of the restored tab
ok(ss.getTabValue(newTab, key) == value, "Correctly restored the tab's state?");
// duplicate the tab
var duplicateTab = ss.duplicateTab(currentWindow, newTab);
// verify the correctness of the duplicated tab
ok(ss.getTabValue(duplicateTab, key) == value, "Correctly duplicated the tab's state?");
// clean up
tabbrowser.removeTab(newTab);
tabbrowser.removeTab(duplicateTab);
]]>
</script>
</pre>
</body>
</window>

View File

@ -90,6 +90,7 @@ bin/components/dom_canvas.xpt
bin/components/dom_core.xpt
bin/components/dom_css.xpt
bin/components/dom_events.xpt
bin/components/dom_geolocation.xpt
bin/components/dom_html.xpt
bin/components/dom_offline.xpt
bin/components/dom_json.xpt
@ -240,6 +241,7 @@ bin/components/nsHandlerService.js
bin/components/nsWebHandlerApp.js
bin/components/libdbusservice.so
bin/components/aboutRobots.js
bin/components/nsBadCertHandler.js
; Modules
bin/modules/*

View File

@ -97,6 +97,7 @@ bin\components\dom_canvas.xpt
bin\components\dom_core.xpt
bin\components\dom_css.xpt
bin\components\dom_events.xpt
bin\components\dom_geolocation.xpt
bin\components\dom_html.xpt
bin\components\dom_offline.xpt
bin\components\dom_json.xpt
@ -246,6 +247,7 @@ bin\components\nsContentDispatchChooser.js
bin\components\nsHandlerService.js
bin\components\nsWebHandlerApp.js
bin\components\aboutRobots.js
bin\components\nsBadCertHandler.js
; Modules
bin\modules\*

View File

@ -319,3 +319,23 @@ ifdef MOZ_CRASHREPORTER
libs:: $(addprefix $(LOCALE_SRCDIR)/,crashreporter/crashreporter-override.ini)
$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)
endif
# This variable is to allow the wget-en-US target to know which ftp server to download from
ifndef EN_US_BINARY_URL
EN_US_BINARY_URL = $(error You must set EN_US_BINARY_URL)
endif
# This make target allows us to wget the latest en-US binary from a specified website
# The make installers-% target needs the en-US binary in dist/
# and for the windows repackages we need the .installer.exe in dist/sea
wget-en-US:
ifndef WGET
$(error Wget not installed)
endif
@$(WGET) -nv --output-document $(_ABS_DIST)/$(PACKAGE) $(EN_US_BINARY_URL)/$(PACKAGE)
@echo "Downloaded $(EN_US_BINARY_URL)/$(PACKAGE) to $(_ABS_DIST)/$(PACKAGE)"
ifeq ($(OS_ARCH), WINNT)
$(NSINSTALL) -D $(_ABS_DIST)/install/sea
@$(WGET) -nv --output-document $(_ABS_DIST)/install/sea/$(PKG_BASENAME).installer.exe $(EN_US_BINARY_URL)/$(PKG_BASENAME).installer.exe
@echo "Downloaded $(EN_US_BINARY_URL)/$(PKG_BASENAME).installer.exe to $(_ABS_DIST)/install/sea/$(PKG_BASENAME)"
endif

View File

@ -152,6 +152,3 @@ AC_DEFUN([MOZ_READ_MOZCONFIG],
# See the mozconfig2configure script for more details.
_AUTOCONF_TOOLS_DIR=`dirname [$]0`/[$1]/build/autoconf
. $_AUTOCONF_TOOLS_DIR/mozconfig2configure])
dnl This gets inserted at the top of the configure script
MOZ_READ_MOZCONFIG(MOZ_TOPSRCDIR)

View File

@ -89,11 +89,9 @@ endif
TOPSRCDIR = $(CWD)
endif
ifeq (Darwin,$(shell uname -s))
AUTOCONF ?= autoconf213
else
AUTOCONF ?= $(shell which autoconf-2.13 autoconf2.13 autoconf213 | head -1)
endif
# try to find autoconf 2.13 - discard errors from 'which'
# MacOS X 10.4 sends "no autoconf*" errors to stdout, discard those via grep
AUTOCONF ?= $(shell which autoconf-2.13 autoconf2.13 autoconf213 2>/dev/null | grep -v '^no autoconf' | head -1)
MKDIR := mkdir
SH := /bin/sh
@ -164,6 +162,7 @@ endif
endif # MOZ_BUILD_PROJECTS
# 'configure' scripts generated by autoconf.
CONFIGURES := $(TOPSRCDIR)/configure
CONFIGURES += $(TOPSRCDIR)/nsprpub/configure
@ -276,20 +275,15 @@ EXTRA_CONFIG_DEPS := \
$(wildcard $(TOPSRCDIR)/build/autoconf/*.m4) \
$(NULL)
$(TOPSRCDIR)/configure: $(TOPSRCDIR)/configure.in $(EXTRA_CONFIG_DEPS)
$(CONFIGURES): %: %.in $(EXTRA_CONFIG_DEPS)
@echo Generating $@ using autoconf
cd $(TOPSRCDIR); $(AUTOCONF)
$(TOPSRCDIR)/nsprpub/configure: $(TOPSRCDIR)/nsprpub/configure.in $(EXTRA_CONFIG_DEPS)
@echo Generating $@ using autoconf
cd $(TOPSRCDIR)/nsprpub; $(AUTOCONF)
cd $(@D); $(AUTOCONF)
endif
CONFIG_STATUS_DEPS := \
$(TOPSRCDIR)/configure \
$(wildcard $(CONFIGURES)) \
$(TOPSRCDIR)/allmakefiles.sh \
$(TOPSRCDIR)/.mozconfig.mk \
$(wildcard $(TOPSRCDIR)/nsprpub/configure) \
$(wildcard $(TOPSRCDIR)/directory/c-sdk/configure) \
$(wildcard $(TOPSRCDIR)/config/milestone.txt) \
$(wildcard $(TOPSRCDIR)/config/chrome-versions.sh) \
@ -309,7 +303,9 @@ ifdef MOZ_TOOLS
CONFIGURE = $(TOPSRCDIR)/configure
endif
configure:: $(CONFIGURES)
configure-files: $(CONFIGURES)
configure:: configure-files
ifdef MOZ_BUILD_PROJECTS
@if test ! -d $(MOZ_OBJDIR); then $(MKDIR) $(MOZ_OBJDIR); else true; fi
endif

View File

@ -395,6 +395,7 @@ MAKE = @MAKE@
PBBUILD_BIN = @PBBUILD@
SDP = @SDP@
NSINSTALL_BIN = @NSINSTALL_BIN@
WGET = @WGET@
ifdef MOZ_NATIVE_JPEG
JPEG_CFLAGS = @JPEG_CFLAGS@

View File

@ -1133,7 +1133,7 @@ ifdef IS_COMPONENT
cp $(VMS_SYMVEC_FILE_COMP) $(VMS_SYMVEC_FILE); \
fi
endif
endif
endif # OpenVMS
ifdef NO_LD_ARCHIVE_FLAGS
ifdef SHARED_LIBRARY_LIBS
@rm -f $(SUB_SHLOBJS)
@ -1171,7 +1171,7 @@ endif
done
@rm -f $(MOZILLA_PROBE_LIBS)
else
else # ! DTRACE_LIB_DEPENDENT
$(MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(DTRACE_PROBE_OBJ) $(LOBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE)
endif # DTRACE_LIB_DEPENDENT

View File

@ -1374,6 +1374,23 @@ if test "$GNU_CXX"; then
_DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(DEPTH)/mozilla-config.h'
_USE_CPP_INCLUDE_FLAG=1
AC_CACHE_CHECK(whether the compiler supports -Wno-invalid-offsetof,
ac_has_wno_invalid_offsetof,
[
AC_LANG_SAVE
_SAVE_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS ${_COMPILER_PREFIX}-Wno-invalid-offsetof"
AC_TRY_COMPILE([],
[return(0);],
ac_has_wno_invalid_offsetof="yes",
ac_has_wno_invalid_offsetof="no")
CXXFLAGS="$_SAVE_CXXFLAGS"
AC_LANG_RESTORE
])
if test "$ac_has_wno_invalid_offsetof" = "yes"; then
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-Wno-invalid-offsetof"
fi
else
_DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_MOZILLA_CONFIG_H_ $(ACDEFINES)'
fi
@ -1458,7 +1475,6 @@ AC_MSG_RESULT("$ac_cv_static_assertion_macros_work")
if test "$ac_cv_static_assertion_macros_work" = "no"; then
AC_MSG_ERROR([Compiler cannot compile macros used in autoconf tests.])
fi
fi # COMPILE_ENVIRONMENT
dnl ========================================================
@ -4630,6 +4646,10 @@ standalone)
esac
if test -z "$MOZ_XUL_APP"; then
AC_MSG_ERROR([builds with unsetting MOZ_XUL_APP in confvars.sh are not supported.])
fi
AC_SUBST(MOZ_BUILD_APP)
AC_SUBST(MOZ_XUL_APP)
AC_SUBST(MOZ_PHOENIX)
@ -4776,7 +4796,7 @@ cairo-mac|cairo-cocoa)
AC_DEFINE(XP_MACOSX)
AC_DEFINE(TARGET_CARBON)
AC_DEFINE(TARGET_API_MAC_CARBON)
TK_LIBS='-framework Carbon -framework CoreAudio -framework AudioToolbox -framework AudioUnit'
TK_LIBS='-framework Carbon -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework AddressBook'
TK_CFLAGS="-I${MACOS_SDK_DIR}/Developer/Headers/FlatCarbon"
CFLAGS="$CFLAGS $TK_CFLAGS"
CXXFLAGS="$CXXFLAGS $TK_CFLAGS"
@ -5775,6 +5795,11 @@ fi
AC_MSG_RESULT([$TAR])
AC_SUBST(TAR)
AC_MSG_CHECKING([for wget])
AC_CHECK_PROGS(WGET, wget, "")
AC_MSG_RESULT([$WGET])
AC_SUBST(WGET)
dnl ========================================================
dnl Updater
dnl ========================================================

View File

@ -101,6 +101,7 @@ struct JSRuntime;
class nsICaseConversion;
class nsIUGenCategory;
class nsIWidget;
class nsIDragSession;
class nsPIDOMWindow;
#ifdef MOZ_XTF
class nsIXTFService;
@ -1218,6 +1219,11 @@ public:
*/
static void HidePopupsInDocument(nsIDocument* aDocument);
/**
* Retrieve the current drag session, or null if no drag is currently occuring
*/
static already_AddRefed<nsIDragSession> GetDragSession();
/**
* Return true if aURI is a local file URI (i.e. file://).
*/

View File

@ -97,8 +97,8 @@ class nsFrameLoader;
// IID for the nsIDocument interface
#define NS_IDOCUMENT_IID \
{ 0x5f0203a8, 0xd926, 0x4adf, \
{ 0xba, 0x96, 0xe6, 0xc3, 0xe6, 0xbb, 0x1b, 0xe5 } }
{ 0xd5b1e3c5, 0x85dc, 0x403e, \
{ 0xbb, 0x4a, 0x54, 0x66, 0xdc, 0xbe, 0x15, 0x69 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -569,6 +569,11 @@ public:
GetScriptHandlingObject(PRBool& aHasHadScriptHandlingObject) const = 0;
virtual void SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject) = 0;
/**
* Sets script handling object to null and marks that document has had one.
*/
virtual void ClearScriptHandlingObject() = 0;
/**
* Get the object that is used as the scope for all of the content
* wrappers whose owner document is this document. Unlike the script global
@ -898,6 +903,14 @@ public:
nsCompatibility GetCompatibilityMode() const {
return mCompatMode;
}
/**
* Check whether we've ever fired a DOMTitleChanged event for this
* document.
*/
PRBool HaveFiredDOMTitleChange() const {
return mHaveFiredTitleChange;
}
/**
* See GetXBLChildNodesFor on nsBindingManager
@ -1060,6 +1073,9 @@ protected:
// If true, whoever is creating the document has gotten it to the
// point where it's safe to start layout on it.
PRPackedBool mMayStartLayout;
// True iff we've ever fired a DOMTitleChanged event for this document
PRPackedBool mHaveFiredTitleChange;
// The bidi options for this document. What this bitfield means is
// defined in nsBidiUtils.h

File diff suppressed because it is too large Load Diff

View File

@ -58,6 +58,7 @@ class nsIDocument;
class nsIURI;
class nsIFile;
class nsISimpleEnumerator;
class nsDOMDataTransfer;
// {1f34bc80-1bc7-11d6-a384-d705dd0746fc}
#define NS_CONTENTAREADRAGDROP_CID \
@ -76,13 +77,11 @@ class nsISimpleEnumerator;
// RemoveChromeListeners().
//
class nsContentAreaDragDrop : public nsIDOMDragListener,
public nsIDragDropHandler,
public nsIFlavorDataProvider
public nsIDragDropHandler
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDRAGDROPHANDLER
NS_DECL_NSIFLAVORDATAPROVIDER
nsContentAreaDragDrop();
virtual ~nsContentAreaDragDrop();
@ -97,6 +96,33 @@ public:
NS_IMETHOD DragEnd(nsIDOMEvent* aMouseEvent);
NS_IMETHOD HandleEvent(nsIDOMEvent *event);
/**
* Determine what data in the content area, if any, is being dragged.
*
* aWindow - the window containing the target node
* aTarget - the mousedown event target that started the drag
* aSelectionTargetNode - the node where the drag event should be fired
* aIsAltKeyPressed - true if the Alt key is pressed. In some cases, this
* will prevent the drag from occuring. For example,
* holding down Alt over a link should select the text,
* not drag the link.
* aDataTransfer - the dataTransfer for the drag event.
* aCanDrag - [out] set to true if the drag may proceed, false to stop the
* drag entirely
* aDragSelection - [out] set to true to indicate that a selection is being
* dragged, rather than a specific node
* aDragNode - [out] the link, image or area being dragged, or null if the
* drag occured on another element.
*/
static nsresult GetDragData(nsIDOMWindow* aWindow,
nsIContent* aTarget,
nsIContent* aSelectionTargetNode,
PRBool aIsAltKeyPressed,
nsDOMDataTransfer* aDataTransfer,
PRBool* aCanDrag,
PRBool* aDragSelection,
nsIContent** aDragNode);
private:
// Add/remove the relevant listeners
@ -109,14 +135,9 @@ private:
static void GetEventDocument(nsIDOMEvent* inEvent,
nsIDOMDocument** outDocument);
static nsresult SaveURIToFile(nsAString& inSourceURIString,
nsIFile* inDestFile);
void ExtractURLFromData(const nsACString & inFlavor,
nsISupports* inDataWrapper, PRUint32 inDataLen,
nsAString & outURL);
nsresult GetHookEnumeratorFromEvent(nsIDOMEvent* inEvent,
nsISimpleEnumerator** outEnumerator);
static void ExtractURLFromData(const nsACString & inFlavor,
nsISupports* inDataWrapper, PRUint32 inDataLen,
nsAString & outURL);
PRPackedBool mListenerInstalled;
@ -128,6 +149,20 @@ private:
};
// this is used to save images to disk lazily when the image data is asked for
// during the drop instead of when it is added to the drag data transfer. This
// ensures that the image data is only created when an image drop is allowed.
class nsContentAreaDragDropDataProvider : public nsIFlavorDataProvider
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIFLAVORDATAPROVIDER
virtual ~nsContentAreaDragDropDataProvider() {}
nsresult SaveURIToFile(nsAString& inSourceURIString,
nsIFile* inDestFile);
};
#endif /* nsContentAreaDragDrop_h__ */

View File

@ -71,6 +71,8 @@
#include "nsIScriptGlobalObject.h"
#include "nsNetCID.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsIApplicationCache.h"
#include "nsIApplicationCacheContainer.h"
#include "nsIScriptSecurityManager.h"
#include "nsIDOMLoadStatus.h"
#include "nsICookieService.h"
@ -881,6 +883,24 @@ nsContentSink::ProcessOfflineManifest(nsIContent *aElement)
return;
}
// XXX: at this point in the spec there is an algorithm for
// confirming whether the cache that was selected at load time was
// the proper application cache for this document. This will
// be implemented in a separate patch; For now just assume that we
// chose an acceptable application cache.
nsCOMPtr<nsIApplicationCacheContainer> channelContainer =
do_QueryInterface(mDocument->GetChannel());
nsCOMPtr<nsIApplicationCacheContainer> docContainer =
do_QueryInterface(mDocument);
if (channelContainer && docContainer) {
nsCOMPtr<nsIApplicationCache> appCache;
channelContainer->GetApplicationCache(getter_AddRefs(appCache));
docContainer->SetApplicationCache(appCache);
}
nsCOMPtr<nsIURI> manifestURI;
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI),
manifestSpec, mDocument,
@ -1419,6 +1439,10 @@ nsContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
void
nsContentSink::DidBuildModelImpl(void)
{
if (!mDocument->HaveFiredDOMTitleChange()) {
mDocument->NotifyPossibleTitleChange(PR_FALSE);
}
// Cancel a timer if we had one out there
if (mNotificationTimer) {
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,

View File

@ -154,6 +154,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsAttrValue.h"
#include "nsReferencedElement.h"
#include "nsIUGenCategory.h"
#include "nsIDragService.h"
#ifdef IBMBIDI
#include "nsIBidiKeyboard.h"
@ -417,13 +418,16 @@ nsContentUtils::InitializeEventTable() {
{ &nsGkAtoms::oncommand, { NS_XUL_COMMAND, EventNameType_XUL }},
{ &nsGkAtoms::onbroadcast, { NS_XUL_BROADCAST, EventNameType_XUL }},
{ &nsGkAtoms::oncommandupdate, { NS_XUL_COMMAND_UPDATE, EventNameType_XUL }},
{ &nsGkAtoms::ondragenter, { NS_DRAGDROP_ENTER, EventNameType_XUL }},
{ &nsGkAtoms::ondragover, { NS_DRAGDROP_OVER_SYNTH, EventNameType_XUL }},
{ &nsGkAtoms::ondragenter, { NS_DRAGDROP_ENTER, EventNameType_HTMLXUL }},
{ &nsGkAtoms::ondragover, { NS_DRAGDROP_OVER_SYNTH, EventNameType_HTMLXUL }},
{ &nsGkAtoms::ondragexit, { NS_DRAGDROP_EXIT_SYNTH, EventNameType_XUL }},
{ &nsGkAtoms::ondragdrop, { NS_DRAGDROP_DROP, EventNameType_XUL }},
{ &nsGkAtoms::ondragdrop, { NS_DRAGDROP_DRAGDROP, EventNameType_XUL }},
{ &nsGkAtoms::ondraggesture, { NS_DRAGDROP_GESTURE, EventNameType_XUL }},
{ &nsGkAtoms::ondrag, { NS_DRAGDROP_DRAG, EventNameType_XUL }},
{ &nsGkAtoms::ondragend, { NS_DRAGDROP_END, EventNameType_XUL }},
{ &nsGkAtoms::ondrag, { NS_DRAGDROP_DRAG, EventNameType_HTMLXUL }},
{ &nsGkAtoms::ondragend, { NS_DRAGDROP_END, EventNameType_HTMLXUL }},
{ &nsGkAtoms::ondragstart, { NS_DRAGDROP_START, EventNameType_HTMLXUL }},
{ &nsGkAtoms::ondragleave, { NS_DRAGDROP_LEAVE_SYNTH, EventNameType_HTMLXUL }},
{ &nsGkAtoms::ondrop, { NS_DRAGDROP_DROP, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onoverflow, { NS_SCROLLPORT_OVERFLOW, EventNameType_XUL }},
{ &nsGkAtoms::onunderflow, { NS_SCROLLPORT_UNDERFLOW, EventNameType_XUL }}
#ifdef MOZ_SVG
@ -804,41 +808,7 @@ nsContentUtils::GetOfflineAppManifest(nsIDOMWindow *aWindow, nsIURI **aURI)
PRBool
nsContentUtils::OfflineAppAllowed(nsIURI *aURI)
{
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
if (!innerURI)
return PR_FALSE;
// only http and https applications can use offline APIs.
PRBool match;
nsresult rv = innerURI->SchemeIs("http", &match);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
if (!match) {
rv = innerURI->SchemeIs("https", &match);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
if (!match) {
return PR_FALSE;
}
}
nsCOMPtr<nsIPermissionManager> permissionManager =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (!permissionManager) {
return PR_FALSE;
}
PRUint32 perm;
permissionManager->TestExactPermission(innerURI, "offline-app", &perm);
if (perm == nsIPermissionManager::UNKNOWN_ACTION) {
return GetBoolPref("offline-apps.allow_by_default");
}
if (perm == nsIPermissionManager::DENY_ACTION) {
return PR_FALSE;
}
return PR_TRUE;
return NS_OfflineAppAllowed(aURI, sPrefBranch);
}
// static
@ -4307,6 +4277,18 @@ nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
#endif
}
/* static */
already_AddRefed<nsIDragSession>
nsContentUtils::GetDragSession()
{
nsIDragSession* dragSession = nsnull;
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService)
dragService->GetCurrentSession(&dragSession);
return dragSession;
}
/* static */
PRBool
nsContentUtils::URIIsLocalFile(nsIURI *aURI)

View File

@ -1143,6 +1143,7 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNodeSelector)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
// nsNodeSH::PreCreate() depends on the identity pointer being the
// same as nsINode (which nsIDocument inherits), so if you change
// the below line, make sure nsNodeSH::PreCreate() still does the
@ -1953,6 +1954,22 @@ nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
}
NS_IMETHODIMP
nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
{
NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
return NS_OK;
}
NS_IMETHODIMP
nsDocument::SetApplicationCache(nsIApplicationCache *aApplicationCache)
{
mApplicationCache = aApplicationCache;
return NS_OK;
}
NS_IMETHODIMP
nsDocument::GetContentType(nsAString& aContentType)
{
@ -3025,6 +3042,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
mScriptGlobalObject = aScriptGlobalObject;
if (aScriptGlobalObject) {
mScriptObject = nsnull;
mHasHadScriptHandlingObject = PR_TRUE;
// Go back to using the docshell for the layout history state
mLayoutHistoryState = nsnull;
@ -4462,6 +4480,7 @@ void
nsDocument::DoNotifyPossibleTitleChange()
{
mPendingTitleChangeEvent.Forget();
mHaveFiredTitleChange = PR_TRUE;
nsAutoString title;
GetTitle(title);

View File

@ -93,6 +93,8 @@
#include "nsCycleCollectionParticipant.h"
#include "nsContentList.h"
#include "nsGkAtoms.h"
#include "nsIApplicationCache.h"
#include "nsIApplicationCacheContainer.h"
// Put these here so all document impls get them automatically
#include "nsHTMLStyleSheet.h"
@ -408,6 +410,7 @@ class nsDocument : public nsIDocument,
public nsIScriptObjectPrincipal,
public nsIRadioGroupContainer,
public nsIDOMNodeSelector,
public nsIApplicationCacheContainer,
public nsStubMutationObserver
{
public:
@ -561,6 +564,12 @@ public:
GetScriptHandlingObject(PRBool& aHasHadScriptHandlingObject) const;
virtual void SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject);
virtual void ClearScriptHandlingObject()
{
mScriptObject = nsnull;
mHasHadScriptHandlingObject = PR_TRUE;
}
virtual nsIScriptGlobalObject* GetScopeObject();
/**
@ -752,6 +761,9 @@ public:
// nsIScriptObjectPrincipal
virtual nsIPrincipal* GetPrincipal();
// nsIApplicationCacheContainer
NS_DECL_NSIAPPLICATIONCACHECONTAINER
virtual nsresult Init();
virtual nsresult AddXMLEventsContent(nsIContent * aXMLEventsElement);
@ -1021,6 +1033,10 @@ protected:
// Our update nesting level
PRUint32 mUpdateNestLevel;
// The application cache that this document is associated with, if
// any. This can change during the lifetime of the document.
nsCOMPtr<nsIApplicationCache> mApplicationCache;
private:
friend class nsUnblockOnloadEvent;

View File

@ -2791,9 +2791,11 @@ nsGenericElement::doPreHandleEvent(nsIContent* aContent,
PRBool isAnonForEvents = aContent->IsRootOfNativeAnonymousSubtree();
if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
// This is an optimization - try to stop event propagation when
// event has just possibly been retargeted.
static_cast<nsISupports*>(aContent) == aVisitor.mEvent->target) {
// Check if we should stop event propagation when event has just been
// dispatched or when we're about to propagate from
// native anonymous subtree.
((static_cast<nsISupports*>(aContent) == aVisitor.mEvent->originalTarget &&
!aContent->IsInNativeAnonymousSubtree()) || isAnonForEvents)) {
nsCOMPtr<nsIContent> relatedTarget =
do_QueryInterface(static_cast<nsMouseEvent*>
(aVisitor.mEvent)->relatedTarget);
@ -2823,19 +2825,37 @@ nsGenericElement::doPreHandleEvent(nsIContent* aContent,
anonOwnerRelated = FindNativeAnonymousSubtreeOwner(anonOwnerRelated);
}
if (anonOwner == anonOwnerRelated) {
nsCOMPtr<nsIContent> target =
#ifdef DEBUG_smaug
nsCOMPtr<nsIContent> originalTarget =
do_QueryInterface(aVisitor.mEvent->originalTarget);
// Because XBL and native anon content both do event re-targeting,
// static_cast<nsISupports*>(aContent) == aVisitor.mEvent->target
// optimization may not always work. So be paranoid and make
// sure we never stop event propagation when we shouldn't!
if (relatedTarget->FindFirstNonNativeAnonymous() ==
target->FindFirstNonNativeAnonymous()) {
aVisitor.mParentTarget = nsnull;
// Event should not propagate to non-anon content.
aVisitor.mCanHandle = isAnonForEvents;
return NS_OK;
nsAutoString ot, ct, rt;
if (originalTarget) {
originalTarget->Tag()->ToString(ot);
}
aContent->Tag()->ToString(ct);
relatedTarget->Tag()->ToString(rt);
printf("Stopping %s propagation:"
"\n\toriginalTarget=%s \n\tcurrentTarget=%s %s"
"\n\trelatedTarget=%s %s \n%s",
(aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH)
? "mouseover" : "mouseout",
NS_ConvertUTF16toUTF8(ot).get(),
NS_ConvertUTF16toUTF8(ct).get(),
isAnonForEvents
? "(is native anonymous)"
: (aContent->IsInNativeAnonymousSubtree()
? "(is in native anonymous subtree)" : ""),
NS_ConvertUTF16toUTF8(rt).get(),
relatedTarget->IsInNativeAnonymousSubtree()
? "(is in native anonymous subtree)" : "",
(originalTarget && relatedTarget->FindFirstNonNativeAnonymous() ==
originalTarget->FindFirstNonNativeAnonymous())
? "" : "Wrong event propagation!?!\n");
#endif
aVisitor.mParentTarget = nsnull;
// Event should not propagate to non-anon content.
aVisitor.mCanHandle = isAnonForEvents;
return NS_OK;
}
}
}

View File

@ -404,8 +404,6 @@ public:
friend class nsNSElementTearoff;
friend class nsNSElementTearoff;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
/**

View File

@ -311,10 +311,14 @@ GK_ATOM(dragend, "dragend")
GK_ATOM(dragenter, "dragenter")
GK_ATOM(dragevent, "dragevent")
GK_ATOM(dragexit, "dragexit")
GK_ATOM(draggable, "draggable")
GK_ATOM(draggesture, "draggesture")
GK_ATOM(dragging, "dragging")
GK_ATOM(dragleave, "dragleave")
GK_ATOM(dragover, "dragover")
GK_ATOM(dragSession, "dragSession")
GK_ATOM(dragstart, "dragstart")
GK_ATOM(drop, "drop")
GK_ATOM(dropAfter, "dropAfter")
GK_ATOM(dropBefore, "dropBefore")
GK_ATOM(dropOn, "dropOn")

View File

@ -398,7 +398,7 @@ nsRange::ComparePoint(nsIDOMNode* aParent, PRInt32 aOffset, PRInt16* aResult)
*aResult = cmp;
}
else if (nsContentUtils::ComparePoints(mEndParent, mEndOffset,
parent, aOffset) == -1) {
parent, aOffset) <= 0) {
*aResult = 1;
}
else {

View File

@ -1064,6 +1064,8 @@ nsXMLHttpRequest::Abort()
ChangeState(XML_HTTP_REQUEST_UNINITIALIZED, PR_FALSE); // IE seems to do it
}
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
return NS_OK;
}
@ -2342,8 +2344,6 @@ nsXMLHttpRequest::Abort(nsIDOMEvent* aEvent)
{
Abort();
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
return NS_OK;
}

View File

@ -190,6 +190,7 @@ _TEST_FILES = test_bug5141.html \
bug435425_redirect.sjs \
test_bug438519.html \
test_bug444722.html \
test_bug451376.html \
test_text_replaceWholeText.html \
test_text_wholeText.html \
wholeTexty-helper.xml \

View File

@ -35,7 +35,8 @@ function logEvent(evt) {
}
ok(i != currentEvents.length, "Extra or wrong event?");
is(evt.type, currentEvents[i].type, "Wrong event!")
ok(evt.target instanceof currentEvents[i].target, "Wrong event target [" + evt.type + "]!");
ok(evt.target instanceof currentEvents[i].target,
"Wrong event target [" + evt.target + "," + evt.type + "]!");
// If we handled non-optional event, remove all optional events before the
// handled event and then the non-optional event from the list.
if (!currentEvents[i].optional) {

View File

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=451376
-->
<head>
<title>Test for Bug 451376</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="doTest()">
<a target="_blank"
title="IAccessibleText::attributes provides incorrect info after a mis-spelled word"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=451376">Mozilla Bug 451376</a>
<p id="display"></p>
<div id="content" style="display:none">
</div>
<pre id="test">
<div id="area"><button>btn1</button>text<button>btn2</button></div>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
function testRange(aRangeID,
aStartNode, aStartOffset,
aEndNode, aEndOffset,
aBeforeRangeNode, aBeforeRangeOffset,
aInRangeNode, aInRangeOffset,
aAfterRangeNode, aAfterRangeOffset)
{
var range = document.createRange().
QueryInterface(Components.interfaces.nsIDOMNSRange);
range.setStart(aStartNode, aStartOffset);
range.setEnd(aEndNode, aEndOffset);
if (aBeforeRangeNode)
is(range.comparePoint(aBeforeRangeNode, aBeforeRangeOffset), -1,
"Wrong result for the point before the range '" + aRangeID + "'");
if (aInRangeNode)
is(range.comparePoint(aInRangeNode, aInRangeOffset), 0,
"Wrong result for the point inside the range '" + aRangeID + "'");
if (aAfterRangeNode)
is(range.comparePoint(aAfterRangeNode, aAfterRangeOffset), 1,
"Wrong result for the point after the range '" + aRangeID + "'");
}
function doTest()
{
var area = document.getElementById("area");
var btn1 = area.firstChild;
var text = btn1.nextSibling;
var btn2 = area.lastChild;
testRange("range1", area, 0, area, 1,
null, 0,
area, 0,
area, 1);
testRange("range2", text, 2, text, 4,
text, 0,
text, 3,
text, 4);
testRange("range3", text, 4, area, 2,
text, 0,
text, 4,
area, 2);
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -76,6 +76,7 @@ function testDynamics() {
testDynamic("html3", "Hello", "Appending HTML <title> element to root element", function(doc){
var t = doc.createElement("title"); t.textContent = "Hello"; doc.documentElement.appendChild(t);
});
testDynamic("xhtml3", "Hello", "Setting 'title' clears existing <title> contents", function(doc){
doc.title = "Hello";
}, function(doc, desc) {
@ -133,26 +134,8 @@ function testDynamics() {
setTimeout(end, 500);
}
function acid() {
var doctype = document.implementation.createDocumentType("html", "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
is(doctype.ownerDocument, null, "doctype's ownerDocument was wrong after creation");
var doc = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", doctype);
doc.documentElement.appendChild(doc.createElementNS("http://www.w3.org/1999/xhtml", "head"));
doc.documentElement.appendChild(doc.createElementNS("http://www.w3.org/1999/xhtml", "body"));
var t = doc.createElementNS("http://www.w3.org/1999/xhtml", "title");
doc.documentElement.firstChild.appendChild(t);
// ok we have a conforming XHTML1 doc in |doc| now.
is(doctype.ownerDocument, doc, "doctype's ownerDocument didn't change when it was assigned to another document");
is(doc.title, "", "document had unexpected title");
t.textContent = "Sparrow";
is(doc.title, "Sparrow", "document.title did not update dynamically");
doc.body.appendChild(doc.createElementNS("http://www.w3.org/1999/xhtml", "form"));
is(doc.forms.length, 1, "document.forms not updated after inserting a form");
}
function runTests() {
testStatics();
// acid();
testDynamics();
}

View File

@ -83,6 +83,8 @@ NS_NewDOMMouseEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContex
nsresult
NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent);
nsresult
NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsDragEvent *aEvent);
nsresult
NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsKeyEvent *aEvent);
nsresult
NS_NewDOMMutationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsMutationEvent* aEvent);

View File

@ -76,6 +76,7 @@ CPPSRCS = \
nsDOMTextEvent.cpp \
nsDOMMouseEvent.cpp \
nsDOMMouseScrollEvent.cpp \
nsDOMDragEvent.cpp \
nsDOMMutationEvent.cpp \
nsDOMPopupBlockedEvent.cpp \
nsDOMBeforeUnloadEvent.cpp \
@ -92,6 +93,7 @@ CPPSRCS = \
nsIMEStateManager.cpp \
nsQueryContentEventHandler.cpp \
nsDOMProgressEvent.cpp \
nsDOMDataTransfer.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib.

View File

@ -0,0 +1,768 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMDataTransfer.h"
#include "prlog.h"
#include "nsAutoPtr.h"
#include "nsString.h"
#include "nsIServiceManager.h"
#include "nsIVariant.h"
#include "nsISupportsPrimitives.h"
#include "nsDOMClassInfo.h"
#include "nsDOMLists.h"
#include "nsGUIEvent.h"
#include "nsDOMError.h"
#include "nsIDragService.h"
#include "nsIScriptableRegion.h"
#include "nsContentUtils.h"
NS_IMPL_CYCLE_COLLECTION_2(nsDOMDataTransfer, mDragTarget, mDragImage)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMDataTransfer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMDataTransfer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMDataTransfer)
NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSDataTransfer)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer)
NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(DataTransfer)
NS_INTERFACE_MAP_END
// the size of the array
const char nsDOMDataTransfer::sEffects[8][9] = {
"none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
};
nsDOMDataTransfer::nsDOMDataTransfer()
: mEventType(NS_DRAGDROP_START),
mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED),
mReadOnly(PR_FALSE),
mIsExternal(PR_FALSE),
mDragImageX(0),
mDragImageY(0)
{
}
nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType, PRUint32 aAction)
: mEventType(aEventType),
mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
mReadOnly(PR_TRUE),
mIsExternal(PR_TRUE),
mDragImageX(0),
mDragImageY(0)
{
mEffectAllowed = aAction &
(nsIDragService::DRAGDROP_ACTION_COPY |
nsIDragService::DRAGDROP_ACTION_LINK |
nsIDragService::DRAGDROP_ACTION_MOVE);
CacheExternalFormats();
}
nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType,
const PRUint32 aEffectAllowed,
PRBool aIsExternal,
nsTArray<nsTArray<TransferItem> >& aItems,
nsIDOMElement* aDragImage,
PRUint32 aDragImageX,
PRUint32 aDragImageY)
: mEventType(aEventType),
mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
mEffectAllowed(aEffectAllowed),
mReadOnly(PR_TRUE),
mIsExternal(aIsExternal),
mItems(aItems),
mDragImage(aDragImage),
mDragImageX(aDragImageX),
mDragImageY(aDragImageY)
{
// The items are copied from aItems into mItems. There is no need to copy
// the actual data in the items as the data transfer will be read only. The
// draggesture and dragstart events are the only times when items are
// modifiable, but those events should have been using the first constructor
// above.
NS_ASSERTION(aEventType != NS_DRAGDROP_GESTURE &&
aEventType != NS_DRAGDROP_START,
"invalid event type for nsDOMDataTransfer constructor");
}
NS_IMETHODIMP
nsDOMDataTransfer::GetDropEffect(nsAString& aDropEffect)
{
aDropEffect.AssignASCII(sEffects[mDropEffect]);
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::SetDropEffect(const nsAString& aDropEffect)
{
// the drop effect can only be 'none', 'copy', 'move' or 'link'.
for (PRUint32 e = 0; e <= nsIDragService::DRAGDROP_ACTION_LINK; e++) {
if (aDropEffect.EqualsASCII(sEffects[e])) {
// don't allow copyMove
if (e != (nsIDragService::DRAGDROP_ACTION_COPY |
nsIDragService::DRAGDROP_ACTION_MOVE))
mDropEffect = e;
break;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::GetEffectAllowed(nsAString& aEffectAllowed)
{
if (mEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
aEffectAllowed.AssignLiteral("uninitialized");
else
aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]);
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed)
{
if (aEffectAllowed.EqualsLiteral("uninitialized")) {
mEffectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
return NS_OK;
}
PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_NONE == 0);
PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_COPY == 1);
PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_MOVE == 2);
PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_LINK == 4);
for (PRUint32 e = 0; e < NS_ARRAY_LENGTH(sEffects); e++) {
if (aEffectAllowed.EqualsASCII(sEffects[e])) {
mEffectAllowed = e;
break;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::GetDropEffectInt(PRUint32* aDropEffect)
{
*aDropEffect = mDropEffect;
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::SetDropEffectInt(PRUint32 aDropEffect)
{
mDropEffect = aDropEffect;
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::GetEffectAllowedInt(PRUint32* aEffectAllowed)
{
*aEffectAllowed = mEffectAllowed;
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::SetEffectAllowedInt(PRUint32 aEffectAllowed)
{
mEffectAllowed = aEffectAllowed;
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::GetTypes(nsIDOMDOMStringList** aTypes)
{
return MozTypesAt(0, aTypes);
}
NS_IMETHODIMP
nsDOMDataTransfer::GetData(const nsAString& aFormat, nsAString& aData)
{
// return an empty string if data for the format was not found
aData.Truncate();
nsCOMPtr<nsIVariant> data;
nsresult rv = MozGetDataAt(aFormat, 0, getter_AddRefs(data));
if (rv == NS_ERROR_DOM_INDEX_SIZE_ERR)
return NS_OK;
NS_ENSURE_SUCCESS(rv, rv);
if (data) {
nsAutoString stringdata;
data->GetAsAString(stringdata);
// for the URL type, parse out the first URI from the list. The URIs are
// separated by newlines
if (aFormat.EqualsLiteral("URL")) {
PRInt32 lastidx = 0, idx;
PRInt32 length = stringdata.Length();
while (lastidx < length) {
idx = stringdata.FindChar('\n', lastidx);
// lines beginning with # are comments
if (stringdata[lastidx] == '#') {
if (idx == -1)
break;
}
else {
if (idx == -1)
aData.Assign(Substring(stringdata, lastidx));
else
aData.Assign(Substring(stringdata, lastidx, idx - lastidx));
aData = nsContentUtils::TrimWhitespace(aData, PR_TRUE);
return NS_OK;
}
lastidx = idx + 1;
}
}
else {
aData = stringdata;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::SetData(const nsAString& aFormat, const nsAString& aData)
{
nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
variant->SetAsAString(aData);
return MozSetDataAt(aFormat, variant, 0);
}
NS_IMETHODIMP
nsDOMDataTransfer::ClearData(const nsAString& aFormat)
{
nsresult rv = MozClearDataAt(aFormat, 0);
return (rv == NS_ERROR_DOM_INDEX_SIZE_ERR) ? NS_OK : rv;
}
NS_IMETHODIMP
nsDOMDataTransfer::GetMozItemCount(PRUint32* aCount)
{
*aCount = mItems.Length();
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::MozTypesAt(PRUint32 aIndex, nsIDOMDOMStringList** aTypes)
{
*aTypes = nsnull;
nsRefPtr<nsDOMStringList> types = new nsDOMStringList();
NS_ENSURE_TRUE(types, NS_ERROR_OUT_OF_MEMORY);
if (aIndex < mItems.Length()) {
// note that you can retrieve the types regardless of their principal
nsTArray<TransferItem>& item = mItems[aIndex];
for (PRUint32 i = 0; i < item.Length(); i++)
types->Add(item[i].mFormat);
}
*aTypes = types;
NS_ADDREF(*aTypes);
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::MozGetDataAt(const nsAString& aFormat,
PRUint32 aIndex,
nsIVariant** aData)
{
*aData = nsnull;
if (aFormat.IsEmpty())
return NS_OK;
if (aIndex >= mItems.Length())
return NS_ERROR_DOM_INDEX_SIZE_ERR;
nsAutoString format;
GetRealFormat(aFormat, format);
nsTArray<TransferItem>& item = mItems[aIndex];
// allow access to any data in the drop and dragdrop events, or if the
// UniversalBrowserRead privilege is set, otherwise only allow access to
// data from the same principal.
nsIPrincipal* principal = nsnull;
if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
!nsContentUtils::IsCallerTrustedForCapability("UniversalBrowserRead"))
principal = GetCurrentPrincipal();
PRUint32 count = item.Length();
for (PRUint32 i = 0; i < count; i++) {
TransferItem& formatitem = item[i];
if (formatitem.mFormat.Equals(format)) {
PRBool subsumes;
if (formatitem.mPrincipal && principal &&
(NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes))
return NS_ERROR_DOM_SECURITY_ERR;
if (!formatitem.mData)
FillInExternalDragData(formatitem, aIndex);
*aData = formatitem.mData;
NS_IF_ADDREF(*aData);
return NS_OK;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::MozSetDataAt(const nsAString& aFormat,
nsIVariant* aData,
PRUint32 aIndex)
{
NS_ENSURE_TRUE(aData, NS_ERROR_NULL_POINTER);
if (aFormat.IsEmpty())
return NS_OK;
if (mReadOnly)
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
// Specifying an index less than the current length will replace an existing
// item. Specifying an index equal to the current length will add a new item.
if (aIndex > mItems.Length())
return NS_ERROR_DOM_INDEX_SIZE_ERR;
// don't allow non-chrome to add file data
// XXX perhaps this should also limit any non-string type as well
if ((aFormat.EqualsLiteral("application/x-moz-file-promise") ||
aFormat.EqualsLiteral("application/x-moz-file")) &&
!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
return SetDataWithPrincipal(aFormat, aData, aIndex, GetCurrentPrincipal());
}
NS_IMETHODIMP
nsDOMDataTransfer::MozClearDataAt(const nsAString& aFormat, PRUint32 aIndex)
{
if (mReadOnly)
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
if (aIndex >= mItems.Length())
return NS_ERROR_DOM_INDEX_SIZE_ERR;
nsAutoString format;
GetRealFormat(aFormat, format);
nsIPrincipal* principal = GetCurrentPrincipal();
// if the format is empty, clear all formats
PRBool clearall = format.IsEmpty();
nsTArray<TransferItem>& item = mItems[aIndex];
// count backwards so that the count and index don't have to be adjusted
// after removing an element
for (PRInt32 i = item.Length() - 1; i >= 0; i--) {
TransferItem& formatitem = item[i];
if (clearall || formatitem.mFormat.Equals(format)) {
// don't allow removing data that has a stronger principal
PRBool subsumes;
if (formatitem.mPrincipal && principal &&
(NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes))
return NS_ERROR_DOM_SECURITY_ERR;
item.RemoveElementAt(i);
// if a format was specified, break out. Otherwise, loop around until
// all formats have been removed
if (!clearall)
break;
}
}
// if the last format for an item is removed, remove the entire item
if (!item.Length())
mItems.RemoveElementAt(aIndex);
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::SetDragImage(nsIDOMElement* aImage, PRInt32 aX, PRInt32 aY)
{
if (mReadOnly)
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
mDragImage = aImage;
mDragImageX = aX;
mDragImageY = aY;
return NS_OK;
}
NS_IMETHODIMP
nsDOMDataTransfer::AddElement(nsIDOMElement* aElement)
{
NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
if (mReadOnly)
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
mDragTarget = do_QueryInterface(aElement);
return NS_OK;
}
nsresult
nsDOMDataTransfer::Clone(PRUint32 aEventType,
nsIDOMDataTransfer** aNewDataTransfer)
{
nsDOMDataTransfer* newDataTransfer =
new nsDOMDataTransfer(aEventType, mEffectAllowed, mIsExternal,
mItems, mDragImage, mDragImageX, mDragImageY);
NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_OUT_OF_MEMORY);
*aNewDataTransfer = newDataTransfer;
NS_ADDREF(*aNewDataTransfer);
return NS_OK;
}
void
nsDOMDataTransfer::GetTransferables(nsISupportsArray** aArray)
{
*aArray = nsnull;
nsCOMPtr<nsISupportsArray> transArray =
do_CreateInstance("@mozilla.org/supports-array;1");
if (!transArray)
return;
PRBool added = PR_FALSE;
PRUint32 count = mItems.Length();
for (PRUint32 i = 0; i < count; i++) {
nsTArray<TransferItem>& item = mItems[i];
PRUint32 count = item.Length();
if (!count)
continue;
nsCOMPtr<nsITransferable> transferable =
do_CreateInstance("@mozilla.org/widget/transferable;1");
if (!transferable)
return;
for (PRUint32 f = 0; f < count; f++) {
TransferItem& formatitem = item[f];
if (!formatitem.mData) // skip empty items
continue;
PRUint32 length;
nsCOMPtr<nsISupports> convertedData;
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length))
continue;
// the underlying drag code uses text/unicode, so use that instead of text/plain
const char* format;
NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
if (utf8format.EqualsLiteral("text/plain"))
format = kUnicodeMime;
else
format = utf8format.get();
// if a converter is set for a format, set the converter for the
// transferable and don't add the item
nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData);
if (converter) {
transferable->AddDataFlavor(format);
transferable->SetConverter(converter);
continue;
}
nsresult rv = transferable->SetTransferData(format, convertedData, length);
if (NS_FAILED(rv))
return;
added = PR_TRUE;
}
// only append the transferable if data was successfully added to it
if (added)
transArray->AppendElement(transferable);
}
NS_ADDREF(*aArray = transArray);
}
PRBool
nsDOMDataTransfer::ConvertFromVariant(nsIVariant* aVariant,
nsISupports** aSupports,
PRUint32* aLength)
{
*aSupports = nsnull;
*aLength = 0;
PRUint16 type;
aVariant->GetDataType(&type);
if (type == nsIDataType::VTYPE_INTERFACE ||
type == nsIDataType::VTYPE_INTERFACE_IS) {
if (NS_FAILED(aVariant->GetAsISupports(aSupports)))
return PR_FALSE;
// for flavour data providers, use kFlavorHasDataProvider (which has the
// value 0) as the length.
nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(*aSupports);
*aLength = fdp ? sizeof(nsISupports) : nsITransferable::kFlavorHasDataProvider;
}
PRUnichar* chrs;
nsresult rv = aVariant->GetAsWString(&chrs);
if (NS_FAILED(rv))
return PR_FALSE;
nsCOMPtr<nsISupportsString>
strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
if (!strSupports)
return PR_FALSE;
nsAutoString str(chrs);
strSupports->SetData(str);
*aSupports = strSupports;
NS_ADDREF(*aSupports);
// each character is two bytes
*aLength = str.Length() << 1;
return PR_TRUE;
}
void
nsDOMDataTransfer::ClearAll()
{
mItems.Clear();
}
nsresult
nsDOMDataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
nsIVariant* aData,
PRUint32 aIndex,
nsIPrincipal* aPrincipal)
{
nsAutoString format;
GetRealFormat(aFormat, format);
// check if the item for the format already exists. In that case,
// just replace it.
TransferItem* formatitem;
if (aIndex < mItems.Length()) {
nsTArray<TransferItem>& item = mItems[aIndex];
PRUint32 count = item.Length();
for (PRUint32 i = 0; i < count; i++) {
TransferItem& itemformat = item[i];
if (itemformat.mFormat.Equals(format)) {
// don't allow replacing data that has a stronger principal
PRBool subsumes;
if (itemformat.mPrincipal && aPrincipal &&
(NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal, &subsumes)) || !subsumes))
return NS_ERROR_DOM_SECURITY_ERR;
itemformat.mPrincipal = aPrincipal;
itemformat.mData = aData;
return NS_OK;
}
}
// add a new format
formatitem = item.AppendElement();
}
else {
NS_ASSERTION(aIndex == mItems.Length(), "Index out of range");
// add a new index
nsTArray<TransferItem>* item = mItems.AppendElement();
NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
formatitem = item->AppendElement();
}
NS_ENSURE_TRUE(formatitem, NS_ERROR_OUT_OF_MEMORY);
formatitem->mFormat = format;
formatitem->mPrincipal = aPrincipal;
formatitem->mData = aData;
return NS_OK;
}
nsIPrincipal*
nsDOMDataTransfer::GetCurrentPrincipal()
{
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsCOMPtr<nsIPrincipal> currentPrincipal;
ssm->GetSubjectPrincipal(getter_AddRefs(currentPrincipal));
if (!currentPrincipal)
ssm->GetSystemPrincipal(getter_AddRefs(currentPrincipal));
return currentPrincipal.get();
}
void
nsDOMDataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat)
{
// treat text/unicode as equivalent to text/plain
if (aInFormat.EqualsLiteral("Text") || aInFormat.EqualsLiteral("text/unicode"))
aOutFormat.AssignLiteral("text/plain");
else if (aInFormat.EqualsLiteral("URL"))
aOutFormat.AssignLiteral("text/uri-list");
else
aOutFormat.Assign(aInFormat);
}
void
nsDOMDataTransfer::CacheExternalFormats()
{
// Called during the constructor to cache the formats available from an
// external drag. The data associated with each format will be set to null.
// This data will instead only be retrieved in FillInExternalDragData when
// asked for, as it may be time consuming for the source application to
// generate it.
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (!dragService)
return;
nsCOMPtr<nsIDragSession> dragSession;
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (!dragSession)
return;
// make sure that the system principal is used for external drags
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsCOMPtr<nsIPrincipal> sysPrincipal;
ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
// there isn't a way to get a list of the formats that might be available on
// all platforms, so just check for the types that can actually be imported
// XXXndeakin there are some other formats but those are platform specific.
const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime };
PRUint32 count;
dragSession->GetNumDropItems(&count);
for (PRUint32 c = 0; c < count; c++) {
for (PRUint32 f = 0; f < NS_ARRAY_LENGTH(formats); f++) {
// IsDataFlavorSupported doesn't take an index as an argument and just
// checks if any of the items support a particular flavor, even though
// the GetData method does take an index. Here, we just assume that
// every item being dragged has the same set of flavors.
PRBool supported;
dragSession->IsDataFlavorSupported(formats[f], &supported);
// if the format is supported, add an item to the array with null as
// the data. When retrieved, GetRealData will read the data.
if (supported) {
if (formats[f] == kUnicodeMime) {
SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nsnull, c, sysPrincipal);
}
else {
if (formats[f] == kURLDataMime)
SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nsnull, c, sysPrincipal);
SetDataWithPrincipal(NS_ConvertUTF8toUTF16(formats[f]), nsnull, c, sysPrincipal);
}
}
}
}
}
void
nsDOMDataTransfer::FillInExternalDragData(TransferItem& aItem, PRUint32 aIndex)
{
NS_PRECONDITION(mIsExternal, "Not an external drag");
if (!aItem.mData) {
nsCOMPtr<nsITransferable> trans =
do_CreateInstance("@mozilla.org/widget/transferable;1");
if (!trans)
return;
NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
const char* format = utf8format.get();
if (strcmp(format, "text/plain") == 0)
format = kUnicodeMime;
else if (strcmp(format, "text/uri-list") == 0)
format = kURLDataMime;
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (!dragService)
return;
nsCOMPtr<nsIDragSession> dragSession;
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (!dragSession)
return;
trans->AddDataFlavor(format);
dragSession->GetData(trans, aIndex);
PRUint32 length = 0;
nsCOMPtr<nsISupports> data;
trans->GetTransferData(format, getter_AddRefs(data), &length);
if (!data)
return;
nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
if (!variant)
return;
nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
if (supportsstr) {
nsAutoString str;
supportsstr->GetData(str);
variant->SetAsAString(str);
}
else {
variant->SetAsISupports(data);
}
aItem.mData = variant;
}
}

View File

@ -0,0 +1,191 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMDataTransfer_h__
#define nsDOMDataTransfer_h__
#include "nsString.h"
#include "nsTArray.h"
#include "nsIVariant.h"
#include "nsIPrincipal.h"
#include "nsIDOMDataTransfer.h"
#include "nsIDragService.h"
#include "nsIDOMElement.h"
#include "nsCycleCollectionParticipant.h"
class nsITransferable;
/**
* TransferItem is used to hold data for a particular format. Each piece of
* data has a principal set from the caller which added it. This allows a
* caller that wishes to retrieve the data to only be able to access the data
* it is allowed to, yet still allow a chrome caller to retrieve any of the
* data.
*/
struct TransferItem {
nsString mFormat;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIVariant> mData;
};
class nsDOMDataTransfer : public nsIDOMDataTransfer,
public nsIDOMNSDataTransfer
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIDOMDATATRANSFER
NS_DECL_NSIDOMNSDATATRANSFER
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMDataTransfer, nsIDOMDataTransfer)
friend class nsDOMDragEvent;
friend class nsEventStateManager;
protected:
// the constructors are protected so only our friends can call them
// default constructor used for the dragstart/draggesture event and
// synthetic events
nsDOMDataTransfer();
// this constructor must only be used to create a dataTransfer for a drag
// that was started without using a data transfer, either an external drag,
// that is, a drag where the source is another application, or a drag
// started by calling the drag service directly.
nsDOMDataTransfer(PRUint32 aEventType, PRUint32 aAction);
// this constructor is used only by the Clone method to copy the fields as
// needed to a new data transfer.
nsDOMDataTransfer(PRUint32 aEventType,
const PRUint32 aEffectAllowed,
PRBool aIsExternal,
nsTArray<nsTArray<TransferItem> >& aItems,
nsIDOMElement* aDragImage,
PRUint32 aDragImageX,
PRUint32 aDragImageY);
static const char sEffects[8][9];
public:
void GetDragTarget(nsIDOMElement** aDragTarget)
{
*aDragTarget = mDragTarget;
NS_IF_ADDREF(*aDragTarget);
}
// a readonly dataTransfer cannot have new data added or existing data removed.
// Only the dropEffect and effectAllowed may be modified.
void SetReadOnly() { mReadOnly = PR_TRUE; }
// converts the data into an array of nsITransferable objects to be used for
// drag and drop or clipboard operations.
void GetTransferables(nsISupportsArray** transferables);
// converts the data in the variant to an nsISupportString if possible or
// an nsISupports or null otherwise.
PRBool ConvertFromVariant(nsIVariant* aVariant,
nsISupports** aSupports,
PRUint32* aLength);
// clears all of the data
void ClearAll();
// Similar to SetData except also specifies the principal to store.
// aData may be null when called from CacheExternalFormats.
nsresult SetDataWithPrincipal(const nsAString& aFormat,
nsIVariant* aData,
PRUint32 aIndex,
nsIPrincipal* aPrincipal);
protected:
// returns a weak reference to the drag image
nsIDOMElement* GetDragImage(PRInt32* aX, PRInt32* aY)
{
*aX = mDragImageX;
*aY = mDragImageY;
return mDragImage;
}
// returns a weak reference to the current principal
nsIPrincipal* GetCurrentPrincipal();
// converts some formats used for compatibility in aInFormat into aOutFormat.
// Text and text/unicode become text/plain, and URL becomes text/uri-list
void GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat);
// caches the formats that exist in the drag service that were added by an
// external drag
void CacheExternalFormats();
// fills in the data field of aItem with the data from the drag service for
// a given index.
void FillInExternalDragData(TransferItem& aItem, PRUint32 aIndex);
// the event type this data transfer is for. This will correspond to an
// event->message value.
PRUint32 mEventType;
// the drop effect and effect allowed
PRUint32 mDropEffect;
PRUint32 mEffectAllowed;
// readonly data transfers may not be modified except the drop effect and
// effect allowed.
PRPackedBool mReadOnly;
// true for drags started without a data transfer, for example, those from
// another application.
PRPackedBool mIsExternal;
// array of items, each containing an array of format->data pairs
nsTArray<nsTArray<TransferItem> > mItems;
// the target of the drag. The drag and dragend events will fire at this.
nsCOMPtr<nsIDOMElement> mDragTarget;
// the custom drag image and coordinates within the image. If mDragImage is
// null, the default image is created from the drag target.
nsCOMPtr<nsIDOMElement> mDragImage;
PRUint32 mDragImageX;
PRUint32 mDragImageY;
};
#endif // nsDOMDataTransfer_h__

View File

@ -0,0 +1,246 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMDragEvent.h"
#include "nsIServiceManager.h"
#include "nsGUIEvent.h"
#include "nsContentUtils.h"
#include "nsIEventStateManager.h"
#include "nsDOMDataTransfer.h"
#include "nsIDragService.h"
nsDOMDragEvent::nsDOMDragEvent(nsPresContext* aPresContext,
nsInputEvent* aEvent)
: nsDOMMouseEvent(aPresContext, aEvent ? aEvent :
new nsDragEvent(PR_FALSE, 0, nsnull))
{
if (aEvent) {
mEventIsInternal = PR_FALSE;
}
else {
mEventIsInternal = PR_TRUE;
mEvent->time = PR_Now();
mEvent->refPoint.x = mEvent->refPoint.y = 0;
}
}
nsDOMDragEvent::~nsDOMDragEvent()
{
if (mEventIsInternal) {
if (mEvent->eventStructType == NS_DRAG_EVENT)
delete static_cast<nsDragEvent*>(mEvent);
mEvent = nsnull;
}
}
NS_IMPL_ADDREF_INHERITED(nsDOMDragEvent, nsDOMMouseEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMDragEvent, nsDOMMouseEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMDragEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMDragEvent)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DragEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMMouseEvent)
NS_IMETHODIMP
nsDOMDragEvent::InitDragEvent(const nsAString & aType,
PRBool aCanBubble,
PRBool aCancelable,
nsIDOMAbstractView* aView,
PRInt32 aDetail,
nsIDOMDataTransfer* aDataTransfer)
{
nsresult rv = nsDOMUIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
NS_ENSURE_SUCCESS(rv, rv);
if (mEventIsInternal && mEvent) {
nsDragEvent* dragEvent = static_cast<nsDragEvent*>(mEvent);
dragEvent->dataTransfer = aDataTransfer;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMDragEvent::InitDragEventNS(const nsAString & aNamespaceURIArg,
const nsAString & aType,
PRBool aCanBubble,
PRBool aCancelable,
nsIDOMAbstractView* aView,
PRInt32 aDetail,
nsIDOMDataTransfer* aDataTransfer)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMDragEvent::GetDataTransfer(nsIDOMDataTransfer** aDataTransfer)
{
*aDataTransfer = nsnull;
if (!mEvent || mEvent->eventStructType != NS_DRAG_EVENT) {
NS_WARNING("Tried to get dataTransfer from non-drag event!");
return NS_OK;
}
// the dataTransfer field of the event caches the DataTransfer associated
// with the drag. It is initialized when an attempt is made to retrieve it
// rather that when the event is created to avoid duplicating the data when
// no listener ever uses it.
nsDragEvent* dragEvent = static_cast<nsDragEvent*>(mEvent);
if (dragEvent->dataTransfer) {
CallQueryInterface(dragEvent->dataTransfer, aDataTransfer);
return NS_OK;
}
// for synthetic events, just use the supplied data transfer object
if (mEventIsInternal) {
NS_IF_ADDREF(*aDataTransfer = dragEvent->dataTransfer);
return NS_OK;
}
// For draggesture and dragstart events, the data transfer object is
// created before the event fires, so it should already be set. For other
// drag events, get the object from the drag session.
NS_ASSERTION(mEvent->message != NS_DRAGDROP_GESTURE &&
mEvent->message != NS_DRAGDROP_START,
"draggesture event created without a dataTransfer");
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress
nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
if (!initialDataTransfer) {
// A dataTransfer won't exist when a drag was started by some other
// means, for instance calling the drag service directly, or a drag
// from another application. In either case, a new dataTransfer should
// be created that reflects the data. Pass true to the constructor for
// the aIsExternal argument, so that only system access is allowed.
PRUint32 action = 0;
dragSession->GetDragAction(&action);
initialDataTransfer =
new nsDOMDataTransfer(mEvent->message, action);
NS_ENSURE_TRUE(initialDataTransfer, NS_ERROR_OUT_OF_MEMORY);
// now set it in the drag session so we don't need to create it again
dragSession->SetDataTransfer(initialDataTransfer);
}
// each event should use a clone of the original dataTransfer.
nsCOMPtr<nsIDOMNSDataTransfer> initialDataTransferNS =
do_QueryInterface(initialDataTransfer);
NS_ENSURE_TRUE(initialDataTransferNS, NS_ERROR_FAILURE);
initialDataTransferNS->Clone(mEvent->message,
getter_AddRefs(dragEvent->dataTransfer));
NS_ENSURE_TRUE(dragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
// for the dragenter and dragover events, initialize the drop effect
// from the drop action, which platform specific widget code sets before
// the event is fired based on the keyboard state.
if (mEvent->message == NS_DRAGDROP_ENTER ||
mEvent->message == NS_DRAGDROP_OVER) {
nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
do_QueryInterface(dragEvent->dataTransfer);
NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
PRUint32 action, effectAllowed;
dragSession->GetDragAction(&action);
newDataTransfer->GetEffectAllowedInt(&effectAllowed);
newDataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed));
}
else if (mEvent->message == NS_DRAGDROP_DROP ||
mEvent->message == NS_DRAGDROP_DRAGDROP ||
mEvent->message == NS_DRAGDROP_END) {
// For the drop and dragend events, set the drop effect based on the
// last value that the dropEffect had. This will have been set in
// nsEventStateManager::PostHandleEvent for the last dragenter or
// dragover event.
nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
do_QueryInterface(dragEvent->dataTransfer);
NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
PRUint32 dropEffect;
initialDataTransferNS->GetDropEffectInt(&dropEffect);
newDataTransfer->SetDropEffectInt(dropEffect);
}
NS_IF_ADDREF(*aDataTransfer = dragEvent->dataTransfer);
return NS_OK;
}
// static
PRUint32
nsDOMDragEvent::FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed)
{
// It is possible for the drag action to include more than one action, but
// the widget code which sets the action from the keyboard state should only
// be including one. If multiple actions were set, we just consider them in
// the following order:
// copy, link, move
if (aAction & nsIDragService::DRAGDROP_ACTION_COPY)
aAction = nsIDragService::DRAGDROP_ACTION_COPY;
else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK)
aAction = nsIDragService::DRAGDROP_ACTION_LINK;
else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE)
aAction = nsIDragService::DRAGDROP_ACTION_MOVE;
// Filter the action based on the effectAllowed. If the effectAllowed
// doesn't include the action, then that action cannot be done, so adjust
// the action to something that is allowed. For a copy, adjust to move or
// link. For a move, adjust to copy or link. For a link, adjust to move or
// link. Otherwise, use none.
if (aAction & aEffectAllowed ||
aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
return aAction;
if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE)
return nsIDragService::DRAGDROP_ACTION_MOVE;
if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY)
return nsIDragService::DRAGDROP_ACTION_COPY;
if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
return nsIDragService::DRAGDROP_ACTION_LINK;
return nsIDragService::DRAGDROP_ACTION_NONE;
}
nsresult NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsDragEvent *aEvent)
{
nsDOMDragEvent* event = new nsDOMDragEvent(aPresContext, aEvent);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return CallQueryInterface(event, aInstancePtrResult);
}

View File

@ -1,3 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -13,13 +14,12 @@
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Christopher Blizzard <blizzard@mozilla.org>.
* Portions created by the Initial Developer are Copyright (C) 2001
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benjamin Smedberg <benjamin@smedbergs.us>
* Neil Deakin <enndeakin@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -35,27 +35,35 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
#ifndef nsDOMDragEvent_h__
#define nsDOMDragEvent_h__
interface nsIDOMWindow;
#include "nsIDOMDragEvent.h"
#include "nsDOMMouseEvent.h"
#include "nsIDOMDataTransfer.h"
/**
* Responds to incoming xremote requests for the mozilla suite.
*/
class nsIContent;
class nsEvent;
[scriptable, uuid(52add212-2067-4575-8d26-edd5165179b1)]
interface nsISuiteRemoteService : nsISupports
class nsDOMDragEvent : public nsIDOMDragEvent,
public nsDOMMouseEvent
{
/**
* Parse the command given.
*
* @param aCommand The command string, e.g. "openURL(http://www.foo.com/)"
* @param aContext The domwindow to target the command at. May be null, and
* may be ignored.
*/
void parseCommand (in string aCommand, in nsIDOMWindow aContext);
public:
nsDOMDragEvent(nsPresContext* aPresContext, nsInputEvent* aEvent);
virtual ~nsDOMDragEvent();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMDRAGEVENT
NS_FORWARD_TO_NSDOMMOUSEEVENT
// filters the action to fit within the effects allowed and returns it.
static PRUint32 FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed);
};
%{C++
#define NS_SUITEREMOTESERVICE_CONTRACTID "@mozilla.org/browser/xremoteservice;2"
%}
nsresult NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsDragEvent* aEvent);
#endif // nsDOMDragEvent_h__

View File

@ -64,7 +64,7 @@ static const char* const sEventNames[] = {
"compositionstart", "compositionend", "popupshowing", "popupshown",
"popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate",
"dragenter", "dragover", "dragexit", "dragdrop", "draggesture",
"drag", "dragend", "resize",
"drag", "dragend", "dragstart", "dragleave", "drop", "resize",
"scroll", "overflow", "underflow", "overflowchanged",
"DOMSubtreeModified", "DOMNodeInserted", "DOMNodeRemoved",
"DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument",
@ -172,6 +172,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEvent)
case NS_MOUSE_SCROLL_EVENT:
static_cast<nsMouseEvent_base*>(tmp->mEvent)->relatedTarget = nsnull;
break;
case NS_DRAG_EVENT:
static_cast<nsDragEvent*>(tmp->mEvent)->dataTransfer = nsnull;
break;
case NS_XUL_COMMAND_EVENT:
static_cast<nsXULCommandEvent*>(tmp->mEvent)->sourceEvent = nsnull;
break;
@ -198,6 +201,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent)
cb.NoteXPCOMChild(
static_cast<nsMouseEvent_base*>(tmp->mEvent)->relatedTarget);
break;
case NS_DRAG_EVENT:
cb.NoteXPCOMChild(
static_cast<nsDragEvent*>(tmp->mEvent)->dataTransfer);
break;
case NS_XUL_COMMAND_EVENT:
cb.NoteXPCOMChild(
static_cast<nsXULCommandEvent*>(tmp->mEvent)->sourceEvent);
@ -468,6 +475,27 @@ nsDOMEvent::SetEventType(const nsAString& aEventTypeArg)
} else if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
if (atom == nsGkAtoms::onDOMMouseScroll)
mEvent->message = NS_MOUSE_SCROLL;
} else if (mEvent->eventStructType == NS_DRAG_EVENT) {
if (atom == nsGkAtoms::ondragstart)
mEvent->message = NS_DRAGDROP_START;
else if (atom == nsGkAtoms::ondraggesture)
mEvent->message = NS_DRAGDROP_GESTURE;
else if (atom == nsGkAtoms::ondragenter)
mEvent->message = NS_DRAGDROP_ENTER;
else if (atom == nsGkAtoms::ondragover)
mEvent->message = NS_DRAGDROP_OVER_SYNTH;
else if (atom == nsGkAtoms::ondragleave)
mEvent->message = NS_DRAGDROP_LEAVE_SYNTH;
else if (atom == nsGkAtoms::ondragexit)
mEvent->message = NS_DRAGDROP_EXIT;
else if (atom == nsGkAtoms::ondrag)
mEvent->message = NS_DRAGDROP_DRAG;
else if (atom == nsGkAtoms::ondrop)
mEvent->message = NS_DRAGDROP_DROP;
else if (atom == nsGkAtoms::ondragdrop)
mEvent->message = NS_DRAGDROP_DRAGDROP;
else if (atom == nsGkAtoms::ondragend)
mEvent->message = NS_DRAGDROP_END;
} else if (mEvent->eventStructType == NS_KEY_EVENT) {
if (atom == nsGkAtoms::onkeydown)
mEvent->message = NS_KEY_DOWN;
@ -760,6 +788,21 @@ NS_METHOD nsDOMEvent::DuplicatePrivateData()
newEvent = mouseEvent;
break;
}
case NS_DRAG_EVENT:
{
nsDragEvent* oldDragEvent = static_cast<nsDragEvent*>(mEvent);
nsDragEvent* dragEvent =
new nsDragEvent(PR_FALSE, msg, nsnull);
NS_ENSURE_TRUE(dragEvent, NS_ERROR_OUT_OF_MEMORY);
isInputEvent = PR_TRUE;
dragEvent->dataTransfer = oldDragEvent->dataTransfer;
dragEvent->clickCount = oldDragEvent->clickCount;
dragEvent->acceptActivation = oldDragEvent->acceptActivation;
dragEvent->relatedTarget = oldDragEvent->relatedTarget;
dragEvent->button = oldDragEvent->button;
newEvent = dragEvent;
break;
}
case NS_MENU_EVENT:
{
newEvent = new nsMenuEvent(PR_FALSE, msg, nsnull);
@ -1298,7 +1341,7 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_dragover];
case NS_DRAGDROP_EXIT_SYNTH:
return sEventNames[eDOMEvents_dragexit];
case NS_DRAGDROP_DROP:
case NS_DRAGDROP_DRAGDROP:
return sEventNames[eDOMEvents_dragdrop];
case NS_DRAGDROP_GESTURE:
return sEventNames[eDOMEvents_draggesture];
@ -1306,6 +1349,12 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_drag];
case NS_DRAGDROP_END:
return sEventNames[eDOMEvents_dragend];
case NS_DRAGDROP_START:
return sEventNames[eDOMEvents_dragstart];
case NS_DRAGDROP_LEAVE_SYNTH:
return sEventNames[eDOMEvents_dragleave];
case NS_DRAGDROP_DROP:
return sEventNames[eDOMEvents_drop];
case NS_SCROLLPORT_OVERFLOW:
return sEventNames[eDOMEvents_overflow];
case NS_SCROLLPORT_UNDERFLOW:

View File

@ -103,6 +103,9 @@ public:
eDOMEvents_draggesture,
eDOMEvents_drag,
eDOMEvents_dragend,
eDOMEvents_dragstart,
eDOMEvents_dragleave,
eDOMEvents_drop,
eDOMEvents_resize,
eDOMEvents_scroll,
eDOMEvents_overflow,

View File

@ -65,7 +65,7 @@ public:
NS_IMETHOD GetWhich(PRUint32 *aWhich);
};
#define NS_FORWARD_TO_NSDOMMOUSEEVENT \
#define NS_FORWARD_TO_NSDOMMOUSEEVENT \
NS_FORWARD_NSIDOMMOUSEEVENT(nsDOMMouseEvent::) \
NS_FORWARD_TO_NSDOMUIEVENT

View File

@ -122,11 +122,11 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMUIEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
nsPoint nsDOMUIEvent::GetScreenPoint() {
if (!mEvent ||
(mEvent->eventStructType != NS_MOUSE_EVENT &&
mEvent->eventStructType != NS_POPUP_EVENT &&
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
!NS_IS_DRAG_EVENT(mEvent))) {
if (!mEvent ||
(mEvent->eventStructType != NS_MOUSE_EVENT &&
mEvent->eventStructType != NS_POPUP_EVENT &&
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
mEvent->eventStructType != NS_DRAG_EVENT)) {
return nsPoint(0, 0);
}
@ -147,7 +147,7 @@ nsPoint nsDOMUIEvent::GetClientPoint() {
(mEvent->eventStructType != NS_MOUSE_EVENT &&
mEvent->eventStructType != NS_POPUP_EVENT &&
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
!NS_IS_DRAG_EVENT(mEvent)) ||
mEvent->eventStructType != NS_DRAG_EVENT) ||
!mPresContext ||
!((nsGUIEvent*)mEvent)->widget) {
return mClientPoint;

View File

@ -576,6 +576,9 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
case NS_MOUSE_SCROLL_EVENT:
return NS_NewDOMMouseScrollEvent(aDOMEvent, aPresContext,
static_cast<nsInputEvent*>(aEvent));
case NS_DRAG_EVENT:
return NS_NewDOMDragEvent(aDOMEvent, aPresContext,
static_cast<nsDragEvent*>(aEvent));
case NS_POPUPBLOCKED_EVENT:
return NS_NewDOMPopupBlockedEvent(aDOMEvent, aPresContext,
static_cast<nsPopupBlockedEvent*>
@ -622,6 +625,9 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
return NS_NewDOMMouseEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("mousescrollevents"))
return NS_NewDOMMouseScrollEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("dragevent") ||
aEventType.LowerCaseEqualsLiteral("dragevents"))
return NS_NewDOMDragEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("keyboardevent") ||
aEventType.LowerCaseEqualsLiteral("keyevents"))
return NS_NewDOMKeyboardEvent(aDOMEvent, aPresContext, nsnull);

View File

@ -262,10 +262,13 @@ static const EventDispatchData sDragEvents[] = {
{ NS_DRAGDROP_ENTER, HANDLER(&nsIDOMDragListener::DragEnter) },
{ NS_DRAGDROP_OVER_SYNTH, HANDLER(&nsIDOMDragListener::DragOver) },
{ NS_DRAGDROP_EXIT_SYNTH, HANDLER(&nsIDOMDragListener::DragExit) },
{ NS_DRAGDROP_DROP, HANDLER(&nsIDOMDragListener::DragDrop) },
{ NS_DRAGDROP_DRAGDROP, HANDLER(&nsIDOMDragListener::DragDrop) },
{ NS_DRAGDROP_GESTURE, HANDLER(&nsIDOMDragListener::DragGesture) },
{ NS_DRAGDROP_DRAG, HANDLER(&nsIDOMDragListener::Drag) },
{ NS_DRAGDROP_END, HANDLER(&nsIDOMDragListener::DragEnd) }
{ NS_DRAGDROP_END, HANDLER(&nsIDOMDragListener::DragEnd) },
{ NS_DRAGDROP_START, HANDLER(&nsIDOMDragListener::DragStart) },
{ NS_DRAGDROP_LEAVE_SYNTH, HANDLER(&nsIDOMDragListener::DragLeave) },
{ NS_DRAGDROP_DROP, HANDLER(&nsIDOMDragListener::Drop) }
};
static const EventDispatchData sXULEvents[] = {

View File

@ -60,6 +60,7 @@
#include "nsIEditorDocShell.h"
#include "nsIFormControl.h"
#include "nsIComboboxControlFrame.h"
#include "nsIDOMNSHTMLElement.h"
#include "nsIDOMHTMLAnchorElement.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMNSHTMLInputElement.h"
@ -113,10 +114,11 @@
#include "nsIDOMDocumentRange.h"
#include "nsIDOMDocumentEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMDragEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMAbstractView.h"
#include "nsIDOMNSUIEvent.h"
#include "nsDOMDragEvent.h"
#include "nsIDOMRange.h"
#include "nsCaret.h"
@ -140,6 +142,14 @@
#include "nsServiceManagerUtils.h"
#include "nsITimer.h"
#include "nsIDragService.h"
#include "nsIDragSession.h"
#include "nsDOMDataTransfer.h"
#include "nsContentAreaDragDrop.h"
#ifdef MOZ_XUL
#include "nsITreeBoxObject.h"
#endif
#ifdef XP_MACOSX
#include <Events.h>
#endif
@ -853,7 +863,10 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
KillClickHoldTimer();
break;
#endif
case NS_DRAGDROP_DROP:
case NS_DRAGDROP_OVER:
// NS_DRAGDROP_DROP is fired before NS_DRAGDROP_DRAGDROP so send
// the enter/exit events before NS_DRAGDROP_DROP.
GenerateDragDropEnterExit(aPresContext, (nsGUIEvent*)aEvent);
break;
case NS_GOTFOCUS:
@ -1971,18 +1984,36 @@ nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
KillClickHoldTimer();
#endif
nsCOMPtr<nsIContent> targetContent = mGestureDownContent;
nsRefPtr<nsDOMDataTransfer> dataTransfer = new nsDOMDataTransfer();
if (!dataTransfer)
return;
PRBool isSelection = PR_FALSE;
nsCOMPtr<nsIContent> eventContent, targetContent;
mCurrentTarget->GetContentForEvent(aPresContext, aEvent,
getter_AddRefs(eventContent));
if (eventContent)
DetermineDragTarget(aPresContext, eventContent, dataTransfer,
&isSelection, getter_AddRefs(targetContent));
// Stop tracking the drag gesture now. This should stop us from
// reentering GenerateDragGesture inside DOM event processing.
StopTrackingDragGesture();
if (!targetContent)
return;
nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetWindow();
// get the widget from the target frame
nsMouseEvent gestureEvent(NS_IS_TRUSTED_EVENT(aEvent), NS_DRAGDROP_GESTURE,
widget, nsMouseEvent::eReal);
nsDragEvent startEvent(NS_IS_TRUSTED_EVENT(aEvent), NS_DRAGDROP_START, widget);
FillInEventFromGestureDown(&startEvent);
nsDragEvent gestureEvent(NS_IS_TRUSTED_EVENT(aEvent), NS_DRAGDROP_GESTURE, widget);
FillInEventFromGestureDown(&gestureEvent);
startEvent.dataTransfer = gestureEvent.dataTransfer = dataTransfer;
// Dispatch to the DOM. By setting mCurrentTarget we are faking
// out the ESM and telling it that the current target frame is
// actually where the mouseDown occurred, otherwise it will use
@ -1998,11 +2029,28 @@ nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
// Set the current target to the content for the mouse down
mCurrentTargetContent = targetContent;
// Dispatch the draggesture event to the DOM
// Dispatch both the dragstart and draggesture events to the DOM
nsEventStatus status = nsEventStatus_eIgnore;
nsEventDispatcher::Dispatch(targetContent, aPresContext, &gestureEvent, nsnull,
nsEventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nsnull,
&status);
nsDragEvent* event = &startEvent;
if (status != nsEventStatus_eConsumeNoDefault) {
status = nsEventStatus_eIgnore;
nsEventDispatcher::Dispatch(targetContent, aPresContext, &gestureEvent, nsnull,
&status);
event = &gestureEvent;
}
// now that the dataTransfer has been updated in the dragstart and
// draggesture events, make it read only so that the data doesn't
// change during the drag.
dataTransfer->SetReadOnly();
if (status != nsEventStatus_eConsumeNoDefault)
DoDefaultDragStart(aPresContext, event, dataTransfer,
targetContent, isSelection);
// Note that frame event handling doesn't care about NS_DRAGDROP_GESTURE,
// which is just as well since we don't really know which frame to
// send it to
@ -2017,6 +2065,230 @@ nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
}
} // GenerateDragGesture
void
nsEventStateManager::DetermineDragTarget(nsPresContext* aPresContext,
nsIContent* aSelectionTarget,
nsDOMDataTransfer* aDataTransfer,
PRBool* aIsSelection,
nsIContent** aTargetNode)
{
*aTargetNode = nsnull;
nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container);
// GetDragData determines if a selection, link or image in the content
// should be dragged, and places the data associated with the drag in the
// data transfer. Skip this check for chrome shells.
PRBool canDrag;
nsCOMPtr<nsIContent> dragDataNode;
nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(container);
if (dsti) {
PRInt32 type = -1;
if (NS_SUCCEEDED(dsti->GetItemType(&type)) &&
type != nsIDocShellTreeItem::typeChrome) {
// mGestureDownContent is the node where the mousedown event for the drag
// occured, and aSelectionTarget is the node to use when a selection is used
nsresult rv =
nsContentAreaDragDrop::GetDragData(window, mGestureDownContent,
aSelectionTarget, mGestureDownAlt,
aDataTransfer, &canDrag, aIsSelection,
getter_AddRefs(dragDataNode));
if (NS_FAILED(rv) || !canDrag)
return;
}
}
// if GetDragData returned a node, use that as the node being dragged.
// Otherwise, if a selection is being dragged, use the node within the
// selection that was dragged. Otherwise, just use the mousedown target.
nsIContent* dragContent = mGestureDownContent;
if (dragDataNode)
dragContent = dragDataNode;
else if (*aIsSelection)
dragContent = aSelectionTarget;
nsIContent* originalDragContent = dragContent;
// If a selection isn't being dragged, look for an ancestor with the
// draggable property set. If one is found, use that as the target of the
// drag instead of the node that was clicked on. If a draggable node wasn't
// found, just use the clicked node.
if (!*aIsSelection) {
while (dragContent) {
nsCOMPtr<nsIDOMNSHTMLElement> htmlElement = do_QueryInterface(dragContent);
if (htmlElement) {
PRBool draggable = PR_FALSE;
htmlElement->GetDraggable(&draggable);
if (draggable)
break;
}
else {
nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(dragContent);
if (xulElement) {
// All XUL elements are draggable, so if a XUL element is
// encountered, stop looking for draggable nodes and just use the
// original clicked node instead.
// XXXndeakin
// In the future, we will want to improve this so that XUL has a
// better way to specify whether something is draggable than just
// on/off.
dragContent = mGestureDownContent;
break;
}
// otherwise, it's not an HTML or XUL element, so just keep looking
}
dragContent = dragContent->GetParent();
}
}
// if no node in the hierarchy was found to drag, but the GetDragData method
// returned a node, use that returned node. Otherwise, just use the original
// node that was clicked.
if (!dragContent) {
if (dragDataNode)
dragContent = originalDragContent;
else
dragContent = mGestureDownContent;
}
if (dragContent) {
// if an ancestor node was used instead, clear the drag data
// XXXndeakin rework this a bit. Find a way to just not call GetDragData if we don't need to.
if (dragContent != originalDragContent)
aDataTransfer->ClearAll();
*aTargetNode = dragContent;
NS_ADDREF(*aTargetNode);
}
}
void
nsEventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
nsDragEvent* aDragEvent,
nsDOMDataTransfer* aDataTransfer,
nsIContent* aDragTarget,
PRBool aIsSelection)
{
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (!dragService)
return;
// Default handling for the draggesture/dragstart event.
//
// First, check if a drag session already exists. This means that the drag
// service was called directly within a draggesture handler. In this case,
// don't do anything more, as it is assumed that the handler is managing
// drag and drop manually.
nsCOMPtr<nsIDragSession> dragSession;
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (dragSession)
return; // already a drag in progress
// No drag session is currently active, so check if a handler added
// any items to be dragged. If not, there isn't anything to drag.
PRUint32 count = 0;
if (aDataTransfer)
aDataTransfer->GetMozItemCount(&count);
if (!count)
return;
// Get the target being dragged, which may not be the same as the
// target of the mouse event. If one wasn't set in the
// aDataTransfer during the event handler, just use the original
// target instead.
nsCOMPtr<nsIDOMNode> dragTarget;
nsCOMPtr<nsIDOMElement> dragTargetElement;
aDataTransfer->GetDragTarget(getter_AddRefs(dragTargetElement));
dragTarget = do_QueryInterface(dragTargetElement);
if (!dragTarget) {
dragTarget = do_QueryInterface(aDragTarget);
if (!dragTarget)
return;
}
// check which drag effect should initially be used
PRUint32 effectAllowed;
aDataTransfer->GetEffectAllowedInt(&effectAllowed);
PRInt32 action = 0;
if (effectAllowed != nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
action = effectAllowed;
// get any custom drag image that was set
PRInt32 imageX, imageY;
nsIDOMElement* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
// If a selection is being dragged, and no custom drag image was
// set, get the selection so that the drag region can be created
// from the selection area. If a custom image was set, it doesn't
// matter what the selection is since the image will be used instead.
nsISelection* selection = nsnull;
if (aIsSelection && !dragImage) {
nsIDocument* doc = aDragTarget->GetCurrentDoc();
if (doc) {
nsIPresShell* presShell = doc->GetPrimaryShell();
if (presShell) {
selection = presShell->GetCurrentSelection(
nsISelectionController::SELECTION_NORMAL);
}
}
}
nsCOMPtr<nsISupportsArray> transArray;
aDataTransfer->GetTransferables(getter_AddRefs(transArray));
if (!transArray)
return;
// XXXndeakin don't really want to create a new drag DOM event
// here, but we need something to pass to the InvokeDragSession
// methods.
nsCOMPtr<nsIDOMEvent> domEvent;
NS_NewDOMDragEvent(getter_AddRefs(domEvent), aPresContext, aDragEvent);
nsCOMPtr<nsIDOMDragEvent> domDragEvent = do_QueryInterface(domEvent);
// if creating a drag event failed, starting a drag session will
// just fail.
if (selection) {
dragService->InvokeDragSessionWithSelection(selection, transArray,
action, domDragEvent,
aDataTransfer);
}
else {
// if dragging within a XUL tree and no custom drag image was
// set, the region argument to InvokeDragSessionWithImage needs
// to be set to the area encompassing the selected rows of the
// tree to ensure that the drag feedback gets clipped to those
// rows. For other content, region should be null.
nsCOMPtr<nsIScriptableRegion> region;
#ifdef MOZ_XUL
if (dragTarget && !dragImage) {
nsCOMPtr<nsIContent> content = do_QueryInterface(dragTarget);
if (content->NodeInfo()->Equals(nsGkAtoms::treechildren,
kNameSpaceID_XUL)) {
nsIDocument* doc = content->GetCurrentDoc();
if (doc) {
nsIPresShell* presShell = doc->GetPrimaryShell();
if (presShell) {
nsIFrame* frame = presShell->GetPrimaryFrameFor(content);
if (frame) {
nsITreeBoxObject* treeBoxObject;
CallQueryInterface(frame, &treeBoxObject);
treeBoxObject->GetSelectionRegion(getter_AddRefs(region));
}
}
}
}
}
#endif
dragService->InvokeDragSessionWithImage(dragTarget, transArray,
region, action, dragImage,
imageX, imageY, domDragEvent,
aDataTransfer);
}
}
nsresult
nsEventStateManager::GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv)
{
@ -2539,10 +2811,124 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
break;
case NS_DRAGDROP_ENTER:
case NS_DRAGDROP_OVER:
{
NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "Expected a drag event");
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
if (!dragSession)
break;
// the initial dataTransfer is the one from the dragstart event that
// was set on the dragSession when the drag began.
nsCOMPtr<nsIDOMNSDataTransfer> dataTransfer;
nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
nsCOMPtr<nsIDOMNSDataTransfer> initialDataTransferNS =
do_QueryInterface(initialDataTransfer);
// cancelling a dragenter or dragover event means that a drop should be
// allowed, so update the dropEffect and the canDrop state to indicate
// that a drag is allowed. If the event isn't cancelled, a drop won't be
// allowed. Essentially, to allow a drop somewhere, specify the effects
// using the effectAllowed and dropEffect properties in a dragenter or
// dragover event and cancel the event. To not allow a drop somewhere,
// don't cancel the event or set the effectAllowed or dropEffect to
// "none". This way, if the event is just ignored, no drop will be
// allowed.
PRUint32 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
if (nsEventStatus_eConsumeNoDefault == *aStatus) {
// if the event has a dataTransfer set, use it.
nsDragEvent *dragEvent = (nsDragEvent*)aEvent;
if (dragEvent->dataTransfer) {
// get the dataTransfer and the dropEffect that was set on it
dataTransfer = do_QueryInterface(dragEvent->dataTransfer);
dataTransfer->GetDropEffectInt(&dropEffect);
}
else {
// if dragEvent->dataTransfer is null, it means that no attempt was
// made to access the dataTransfer during the event, yet the event
// was cancelled. Instead, use the initial data transfer available
// from the drag session. The drop effect would not have been
// initialized (which is done in nsDOMDragEvent::GetDataTransfer),
// so set it from the drag action. We'll still want to filter it
// based on the effectAllowed below.
dataTransfer = initialDataTransferNS;
PRUint32 action;
dragSession->GetDragAction(&action);
// filter the drop effect based on the action. Use UNINITIALIZED as
// any effect is allowed.
dropEffect = nsDOMDragEvent::FilterDropEffect(action,
nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
}
// At this point, if the dataTransfer is null, it means that the
// drag was originally started by directly calling the drag service.
// Just assume that all effects are allowed.
PRUint32 effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
if (dataTransfer)
dataTransfer->GetEffectAllowedInt(&effectAllowed);
// set the drag action based on the drop effect and effect allowed.
// The drop effect field on the drag transfer object specifies the
// desired current drop effect. However, it cannot be used if the
// effectAllowed state doesn't include that type of action. If the
// dropEffect is "none", then the action will be 'none' so a drop will
// not be allowed.
PRUint32 action = nsIDragService::DRAGDROP_ACTION_NONE;
if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
dropEffect & effectAllowed)
action = dropEffect;
if (action == nsIDragService::DRAGDROP_ACTION_NONE)
dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
// inform the drag session that a drop is allowed on this node.
dragSession->SetDragAction(action);
dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
}
// now set the drop effect in the initial dataTransfer. This ensures
// that we can get the desired drop effect in the drop event.
if (initialDataTransferNS)
initialDataTransferNS->SetDropEffectInt(dropEffect);
}
break;
case NS_DRAGDROP_DROP:
{
// now fire the dragdrop event, for compatibility with XUL
if (mCurrentTarget && nsEventStatus_eConsumeNoDefault != *aStatus) {
nsCOMPtr<nsIContent> targetContent;
mCurrentTarget->GetContentForEvent(presContext, aEvent,
getter_AddRefs(targetContent));
nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetWindow();
nsDragEvent event(NS_IS_TRUSTED_EVENT(aEvent), NS_DRAGDROP_DRAGDROP, widget);
nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
event.refPoint = mouseEvent->refPoint;
event.isShift = mouseEvent->isShift;
event.isControl = mouseEvent->isControl;
event.isAlt = mouseEvent->isAlt;
event.isMeta = mouseEvent->isMeta;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (presShell) {
presShell->HandleEventWithTarget(&event, mCurrentTarget,
targetContent, &status);
}
}
break;
}
case NS_DRAGDROP_EXIT:
// clean up after ourselves. make sure we do this _after_ the event, else we'll
// clean up too early!
// make sure to fire the enter and exit_synth events after the
// NS_DRAGDROP_EXIT event, otherwise we'll clean up too early
GenerateDragDropEnterExit(presContext, (nsGUIEvent*)aEvent);
break;
@ -3176,6 +3562,8 @@ nsEventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
//The frame has changed but the content may not have. Check before dispatching to content
mLastDragOverFrame->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(lastContent));
FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_LEAVE_SYNTH,
targetContent, lastContent, mLastDragOverFrame);
FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_EXIT_SYNTH,
targetContent, lastContent, mLastDragOverFrame);
}
@ -3196,6 +3584,8 @@ nsEventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
nsCOMPtr<nsIContent> lastContent;
mLastDragOverFrame->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(lastContent));
FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_LEAVE_SYNTH,
nsnull, lastContent, mLastDragOverFrame);
FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_EXIT_SYNTH,
nsnull, lastContent, mLastDragOverFrame);
@ -3221,8 +3611,7 @@ nsEventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
nsWeakFrame& aTargetFrame)
{
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent), aMsg,
aEvent->widget, nsMouseEvent::eReal);
nsDragEvent event(NS_IS_TRUSTED_EVENT(aEvent), aMsg, aEvent->widget);
event.refPoint = aEvent->refPoint;
event.isShift = ((nsMouseEvent*)aEvent)->isShift;
event.isControl = ((nsMouseEvent*)aEvent)->isControl;

View File

@ -60,6 +60,7 @@ class nsIDocShellTreeNode;
class nsIDocShellTreeItem;
class nsIFocusController;
class imgIContainer;
class nsDOMDataTransfer;
// mac uses click-hold context menus, a holdover from 4.x
#ifdef XP_MACOSX
@ -257,7 +258,7 @@ protected:
* that recursively called us in it's Up phase. The initial caller
* passes |nsnull| here. This is to avoid an infinite loop.
* @param aAccessKeyState Normal, Down or Up processing phase (see enums
* above). The initial event reciever uses 'normal', then 'down' when
* above). The initial event receiver uses 'normal', then 'down' when
* processing children and Up when recursively calling its ancestor.
* @param aModifierMask modifier mask for the key event
*/
@ -318,6 +319,38 @@ protected:
nsIFrame* inDownFrame ) ;
void StopTrackingDragGesture ( ) ;
void GenerateDragGesture ( nsPresContext* aPresContext, nsMouseEvent *aEvent ) ;
/**
* Determine which node the drag should be targeted at.
* This is either the node clicked when there is a selection, or, for HTML,
* the element with a draggable property set to true.
*
* aSelectionTarget - target to check for selection
* aDataTransfer - data transfer object that will contain the data to drag
* aIsSelection - [out] set to true if a selection is being dragged
* aTargetNode - [out] the draggable node, or null if there isn't one
*/
void DetermineDragTarget(nsPresContext* aPresContext,
nsIContent* aSelectionTarget,
nsDOMDataTransfer* aDataTransfer,
PRBool* aIsSelection,
nsIContent** aTargetNode);
/*
* Perform the default handling for the dragstart/draggesture event and set up a
* drag for aDataTransfer if it contains any data.
*
* aDragEvent - the dragstart/draggesture event
* aDataTransfer - the data transfer that holds the data to be dragged
* aDragTarget - the target of the drag
* aIsSelection - true if a selection is being dragged
*/
void DoDefaultDragStart(nsPresContext* aPresContext,
nsDragEvent* aDragEvent,
nsDOMDataTransfer* aDataTransfer,
nsIContent* aDragTarget,
PRBool aIsSelection);
PRBool IsTrackingDragGesture ( ) const { return mGestureDownContent != nsnull; }
/**
* Set the fields of aEvent to reflect the mouse position and modifier keys

View File

@ -61,6 +61,8 @@ _TEST_FILES = \
test_bug412567.html \
test_bug443985.html \
test_bug447736.html \
test_draggableprop.html \
test_dragstart.html \
$(NULL)
_CHROME_FILES = \

View File

@ -0,0 +1,91 @@
<html>
<head>
<title>Tests for the draggable property on HTML elements</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<span id="elem1">One</span>
<span id="elem2" draggable="true">Two</span>
<span id="elem3" draggable="">Three</span>
<span id="elem4" draggable="false">Four</span>
<span id="elem5" draggable="other">Five</span>
<img id="img1" src="../happy.png">
<img id="img2" src="../happy.png" draggable="true">
<img id="img3" src="../happy.png" draggable="">
<img id="img4" src="../happy.png" draggable="false">
<img id="img5" src="../happy.png" draggable="other">
<a id="a1">One</a>
<a id="a2" draggable="true">Two</a>
<a id="a3" draggable="">Three</a>
<a id="a4" draggable="false">Four</a>
<a id="a5" draggable="other">Five</a>
<a id="ahref1" href="http://www.mozilla.org">One</a>
<a id="ahref2" href="http://www.mozilla.org" draggable="true">Two</a>
<a id="ahref3" href="http://www.mozilla.org" draggable="">Three</a>
<a id="ahref4" href="http://www.mozilla.org" draggable="false">Four</a>
<a id="ahref5" href="http://www.mozilla.org" draggable="other">Five</a>
<script>
function check()
{
try {
checkElements(1, false, true, false, true);
checkElements(2, true, true, true, true);
checkElements(3, false, true, false, true);
checkElements(4, false, false, false, false);
checkElements(5, false, true, false, true);
}
catch (ex) {
is("script error", ex, "fail");
}
}
function checkElements(idx, estate, istate, astate, ahrefstate)
{
checkElement("elem" + idx, estate, false);
checkElement("img" + idx, istate, true);
checkElement("a" + idx, astate, false);
checkElement("ahref" + idx, ahrefstate, true);
}
function checkElement(elemid, state, statedef)
{
var elem = document.getElementById(elemid);
is(elem.draggable, state, elemid + "-initial");
elem.draggable = true;
is(elem.draggable, true, elemid + "-true");
elem.draggable = false;
is(elem.draggable, false, elemid + "-false");
elem.setAttribute("draggable", "true");
is(elem.draggable, true, elemid + "-attr-true");
elem.setAttribute("draggable", "false");
is(elem.draggable, false, elemid + "-attr-false");
elem.setAttribute("draggable", "other");
is(elem.draggable, statedef, elemid + "-attr-other");
elem.setAttribute("draggable", "");
is(elem.draggable, statedef, elemid + "-attr-empty");
elem.removeAttribute("draggable");
is(elem.draggable, statedef, elemid + "-attr-removed");
}
check();
</script>
</body>
</html>

View File

@ -0,0 +1,537 @@
<html>
<head>
<title>Tests for the dragstart event</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<!--
This test checks the dragstart event and the DataTransfer object
-->
<script>
SimpleTest.waitForExplicitFinish();
var gDragInfo;
var gDataTransfer = null;
var gExtraDragTests = 0;
function runTests()
{
// first, create a selection and try dragging it
var draggable = $("draggable");
window.getSelection().selectAllChildren(draggable);
synthesizeMouse(draggable, 6, 6, { type: "mousedown" });
synthesizeMouse(draggable, 14, 14, { type: "mousemove" });
// drags are asynchronous on Linux, so this extra event is needed to make
// sure the drag gets processed
synthesizeMouse(draggable, 15, 15, { type: "mousemove" });
}
function afterDragTests()
{
// the dragstart should have occured due to moving the mouse. gDataTransfer
// caches the dataTransfer that was used, however it should now be empty and
// be read only.
ok(gDataTransfer instanceof DataTransfer, "DataTransfer after dragstart event");
checkTypes(gDataTransfer, [], 0, "after dragstart event");
expectError(function() gDataTransfer.setData("text/plain", "Some Text"),
"NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR", "setData when read only");
expectError(function() gDataTransfer.clearData("text/plain"),
"NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR", "clearData when read only");
expectError(function() gDataTransfer.mozSetDataAt("text/plain", "Some Text", 0),
"NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR", "setDataAt when read only");
expectError(function() gDataTransfer.mozClearDataAt("text/plain", 0),
"NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR", "clearDataAt when read only");
expectError(function() gDataTransfer.setDragImage(draggable, 10, 10),
"NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR", "setDragImage when read only");
expectError(function() gDataTransfer.addElement(draggable),
"NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR", "addElement when read only");
var evt = document.createEvent("dragevent");
ok(evt instanceof DragEvent, "synthetic dragevent class")
ok(evt instanceof MouseEvent, "synthetic event inherits from MouseEvent")
evt.initDragEvent("dragstart", true, true, window, 1, null);
$("synthetic").dispatchEvent(evt);
var evt = document.createEvent("dragevents");
ok(evt instanceof DragEvent, "synthetic dragevents class")
evt.initDragEvent("dragover", true, true, window, 0, null);
$("synthetic2").dispatchEvent(evt);
// next, dragging links and images
sendMouseEventsForDrag("link");
sendMouseEventsForDrag("image");
// disable testing input dragging for now, as it doesn't seem to be testable
// draggable = $("input");
// draggable.setSelectionRange(0, 4);
// synthesizeMouse(draggable, 8, 8, { type: "mousedown" });
// synthesizeMouse(draggable, 15, 15, { type: "mousemove" });
// sendMouseEventsForDrag("input");
// next, check if the draggable attribute can be used to adjust the drag target
gDragInfo = { target: $("dragtrue"), testid: "draggable true node" };
sendMouseEventsForDrag("dragtrue");
gDragInfo = { target: $("dragtrue"), testid: "draggable true child" };
sendMouseEventsForDrag("spantrue");
gDragInfo = { target: $("dragfalse").firstChild, testid: "draggable false node" };
sendMouseEventsForDrag("dragfalse");
gDragInfo = { target: $("spanfalse").firstChild, testid: "draggable false child" };
sendMouseEventsForDrag("spanfalse");
}
function sendMouseEventsForDrag(nodeid)
{
var draggable = $(nodeid);
synthesizeMouse(draggable, 3, 3, { type: "mousedown" });
synthesizeMouse(draggable, 10, 10, { type: "mousemove" });
synthesizeMouse(draggable, 12, 12, { type: "mousemove" });
}
function doDragStartSelection(event)
{
is(event.type, "dragstart", "dragstart event type");
is(event.target, $("draggable").firstChild, "dragstart event target");
is(event.bubbles, true, "dragstart event bubbles");
is(event.cancelable, true, "dragstart event cancelable");
var dt = event.dataTransfer;
ok(dt instanceof DataTransfer, "dataTransfer is DataTransfer");
gDataTransfer = dt;
var types = dt.types;
is(types instanceof DOMStringList, true, "initial types is a DOMStringList");
checkTypes(dt, ["text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial selection");
is(dt.getData("text/plain"), "This is a draggable bit of text.", "initial selection text/plain");
is(dt.getData("text/html"), "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>",
"initial selection text/html");
// text/unicode and Text are available for compatibility. They retrieve the
// text/plain data
is(dt.getData("text/unicode"), "This is a draggable bit of text.", "initial selection text/unicode");
is(dt.getData("Text"), "This is a draggable bit of text.", "initial selection Text");
is(dt.mozItemCount, 1, "initial selection item count");
dt.clearData("text/plain");
dt.clearData("text/html");
dt.clearData("text/_moz_htmlinfo");
dt.clearData("text/_moz_htmlcontext");
test_DataTransfer(dt);
setTimeout(afterDragTests, 0);
}
function test_DataTransfer(dt)
{
is(dt.mozItemCount, 0, "empty itemCount");
var types = dt.types;
is(types instanceof DOMStringList, true, "empty types is a DOMStringList");
checkTypes(dt, [], 0, "empty");
is(dt.getData("text/plain"), "", "empty data is empty");
// calling setDataAt requires an index that is 0 <= index <= dt.itemCount
expectError(function() dt.mozSetDataAt("text/plain", "Some Text", 1),
"NS_ERROR_DOM_INDEX_SIZE_ERR", "setDataAt index too high");
// because an exception occured, the data should not have been added
is(dt.mozItemCount, 0, "empty setDataAt index too high itemCount");
dt.getData("text/plain", "", "empty setDataAt index too high getData");
// if the type is '', do nothing, or return ''
dt.setData("", "Invalid Type");
is(dt.types.length, 0, "invalid type setData");
is(dt.getData(""), "", "invalid type getData"),
dt.mozSetDataAt("", "Invalid Type", 0);
is(dt.types.length, 0, "invalid type setDataAt");
is(dt.mozGetDataAt("", 0), null, "invalid type getDataAt"),
// similar with clearDataAt and getDataAt
expectError(function() dt.mozGetDataAt("text/plain", 1),
"NS_ERROR_DOM_INDEX_SIZE_ERR", "getDataAt index too high");
expectError(function() dt.mozClearDataAt("text/plain", 1),
"NS_ERROR_DOM_INDEX_SIZE_ERR", "clearDataAt index too high");
dt.setData("text/plain", "Sample Text");
is(dt.mozItemCount, 1, "added plaintext itemCount");
checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext");
// after all those exceptions, the data should still be the same
checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext after exception");
// modifying the data associated with the format should give it the new value
dt.setData("text/plain", "Modified Text");
is(dt.mozItemCount, 1, "modified plaintext itemCount");
checkOneDataItem(dt, ["text/plain"], ["Modified Text"], 0, "modified plaintext");
dt.setData("text/html", "<strong>Modified Text</strong>");
is(dt.mozItemCount, 1, "modified html itemCount");
checkOneDataItem(dt, ["text/plain", "text/html"],
["Modified Text", "<strong>Modified Text</strong>"],
0, "modified html");
// modifying data for a type that already exists should adjust it in place,
// not reinsert it at the beginning
dt.setData("text/plain", "New Text");
is(dt.mozItemCount, 1, "modified text again itemCount");
checkOneDataItem(dt, ["text/plain", "text/html"],
["New Text", "<strong>Modified Text</strong>"],
0, "modified text again");
var draggable = $("draggable");
dt.setData("application/-moz-node", draggable);
checkOneDataItem(dt, ["text/plain", "text/html", "application/-moz-node"],
["New Text", "<strong>Modified Text</strong>", draggable],
0, "added node");
dt.clearData(""); // null means clear all
is(dt.mozItemCount, 0, "itemCount after clearData empty string");
checkTypes(dt, [], 0, "empty after clearData empty string");
dt.setData("text/plain", 22);
dt.setData("text/html", 5.6);
dt.setData("text/xml", 5.6);
checkTypes(dt, ["text/plain", "text/html", "text/xml"], ["22", "5.6", ""], 0, "add numeric and empty data");
dt.clearData(); // no argument means clear all
is(dt.mozItemCount, 0, "itemCount after clearData no argument");
checkTypes(dt, [], 0, "empty after clearData no argument");
// check 'Text' type which should convert into text/plain
dt.setData("Text", "Sample Text");
checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "set Text");
is(dt.getData("Text"), "Sample Text", "getData Text");
is(dt.mozGetDataAt("Text", 0), "Sample Text", "getDataAt Text");
dt.setData("text/plain", "More Text");
checkOneDataItem(dt, ["text/plain"], ["More Text"], 0, "set text/plain after set Text");
dt.mozClearDataAt("", 0); // null means clear all
is(dt.mozItemCount, 0, "itemCount after clearDataAt empty string");
checkTypes(dt, [], 0, "empty after clearDataAt empty string");
// check text/uri-list type
dt.setData("text/uri-list", "http://www.mozilla.org");
checkURL(dt, "http://www.mozilla.org", "http://www.mozilla.org", 0, "set text/uri-list");
// check URL type which should add text/uri-list data
dt.setData("URL", "ftp://ftp.example.com");
checkURL(dt, "ftp://ftp.example.com", "ftp://ftp.example.com", 0, "set URL");
checkTypes(dt, ["text/uri-list"], ["ftp://ftp.example.com"], "url types");
// clearing text/uri-list data
dt.clearData("text/uri-list");
is(dt.mozItemCount, 0, "itemCount after clear url-list");
is(dt.getData("text/uri-list"), "", "text/uri-list after clear url-list");
is(dt.getData("URL"), "", "URL after clear url-list");
// check text/uri-list parsing
dt.setData("text/uri-list", "#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com");
checkURL(dt, "http://www.xulplanet.com",
"#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com",
0, "uri-list 3 lines");
dt.setData("text/uri-list", "#http://www.mozilla.org");
is(dt.getData("URL"), "", "uri-list commented");
dt.setData("text/uri-list", "#http://www.mozilla.org\n");
is(dt.getData("URL"), "", "uri-list commented with newline");
// check that clearing the URL type also clears the text/uri-list type
dt.clearData("URL");
is(dt.getData("text/uri-list"), "", "clear URL");
dt.setData("text/uri-list", "#http://www.mozilla.org\n\n\n\n\n");
is(dt.getData("URL"), "", "uri-list with blank lines");
dt.setData("text/uri-list", "");
is(dt.getData("URL"), "", "empty uri-list");
dt.setData("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n");
is(dt.getData("URL"), "http://www.xulplanet.com", "uri-list mix");
dt.setData("text/uri-list", "\nhttp://www.mozilla.org");
is(dt.getData("URL"), "", "empty line to start uri-list");
dt.setData("text/uri-list", " http://www.mozilla.org#anchor ");
is(dt.getData("URL"), "http://www.mozilla.org#anchor", "uri-list with spaces and hash");
// ensure that setDataAt works the same way
dt.mozSetDataAt("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n", 0);
checkURL(dt, "http://www.xulplanet.com",
"#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n",
0, "uri-list mix setDataAt");
// now test adding multiple items to be dragged using the setDataAt method
dt.clearData();
dt.mozSetDataAt("text/plain", "First Item", 0);
dt.mozSetDataAt("text/plain", "Second Item", 1);
expectError(function() dt.mozSetDataAt("text/plain", "Some Text", 3),
"NS_ERROR_DOM_INDEX_SIZE_ERR", "setDataAt index too high with two items");
is(dt.mozItemCount, 2, "setDataAt item itemCount");
checkOneDataItem(dt, ["text/plain"], ["First Item"], 0, "setDataAt item at index 0");
checkOneDataItem(dt, ["text/plain"], ["Second Item"], 1, "setDataAt item at index 1");
dt.mozSetDataAt("text/html", "<em>First Item</em>", 0);
dt.mozSetDataAt("text/html", "<em>Second Item</em>", 1);
is(dt.mozItemCount, 2, "setDataAt two types item itemCount");
checkOneDataItem(dt, ["text/plain", "text/html"],
["First Item", "<em>First Item</em>"], 0, "setDataAt two types item at index 0");
checkOneDataItem(dt, ["text/plain", "text/html"],
["Second Item", "<em>Second Item</em>"], 1, "setDataAt two types item at index 1");
dt.mozSetDataAt("text/html", "<em>Changed First Item</em>", 0);
dt.mozSetDataAt("text/plain", "Changed Second Item", 1);
is(dt.mozItemCount, 2, "changed with setDataAt item itemCount");
checkOneDataItem(dt, ["text/plain", "text/html"],
["First Item", "<em>Changed First Item</em>"], 0, "changed with setDataAt item at index 0");
checkOneDataItem(dt, ["text/plain", "text/html"],
["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setDataAt item at index 1");
dt.setData("text/html", "Changed with setData");
is(dt.mozItemCount, 2, "changed with setData");
checkOneDataItem(dt, ["text/plain", "text/html"],
["First Item", "Changed with setData"], 0, "changed with setData item at index 0");
checkOneDataItem(dt, ["text/plain", "text/html"],
["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setData item at index 1");
dt.mozSetDataAt("application/-moz-node", draggable, 2);
is(dt.mozItemCount, 3, "setDataAt node itemCount");
checkOneDataItem(dt, ["application/-moz-node"], [draggable], 2, "setDataAt node item at index 2");
dt.mozClearDataAt("text/html", 1);
is(dt.mozItemCount, 3, "clearDataAt itemCount");
checkOneDataItem(dt, ["text/plain", "text/html"],
["First Item", "Changed with setData"], 0, "clearDataAt item at index 0");
checkOneDataItem(dt, ["text/plain"], ["Changed Second Item"], 1, "clearDataAt item at index 1");
dt.mozClearDataAt("text/plain", 1);
is(dt.mozItemCount, 2, "clearDataAt last type itemCount");
checkOneDataItem(dt, ["text/plain", "text/html"],
["First Item", "Changed with setData"], 0, "clearDataAt last type at index 0");
checkOneDataItem(dt, ["application/-moz-node"], [draggable], 1, "clearDataAt last type item at index 2");
expectError(function() dt.mozGetDataAt("text/plain", 2),
"NS_ERROR_DOM_INDEX_SIZE_ERR", "getDataAt after item removed index too high");
dt.mozSetDataAt("text/unknown", "Unknown type", 2);
dt.mozSetDataAt("text/unknown", "Unknown type", 1);
is(dt.mozItemCount, 3, "add unknown type");
checkOneDataItem(dt, ["application/-moz-node", "text/unknown"],
[draggable, "Unknown type"], 1, "add unknown type item at index 1");
checkOneDataItem(dt, ["text/unknown"], ["Unknown type"], 2, "add unknown type item at index 2");
dt.mozClearDataAt("", 1);
is(dt.mozItemCount, 2, "clearDataAt empty string");
checkOneDataItem(dt, ["text/plain", "text/html"],
["First Item", "Changed with setData"], 0, "clearDataAt empty string item at index 0");
checkOneDataItem(dt, ["text/unknown"],
["Unknown type"], 1, "clearDataAt empty string item at index 1");
// passing a format that doesn't exist to clearData or clearDataAt should just
// do nothing
dt.clearData("text/something");
dt.mozClearDataAt("text/something", 1);
is(dt.mozItemCount, 2, "clearData type that does not exist");
checkOneDataItem(dt, ["text/plain", "text/html"],
["First Item", "Changed with setData"], 0, "clearData type that does not exist item at index 0");
checkOneDataItem(dt, ["text/unknown"],
["Unknown type"], 1, "clearData type that does not exist item at index 1");
expectError(function() dt.mozClearDataAt("text/plain", 3),
"NS_ERROR_DOM_INDEX_SIZE_ERR", "clearData index too high with two items");
// ensure that clearData() removes all data associated with the first item
dt.clearData();
is(dt.mozItemCount, 1, "clearData no argument with multiple items itemCount");
checkOneDataItem(dt, ["text/unknown"],
["Unknown type"], 0, "clearData no argument with multiple items item at index 1");
// remove tha remaining data
dt.mozClearDataAt("", 0);
is(dt.mozItemCount, 0, "all data cleared");
// now check the effectAllowed and dropEffect properties
is(dt.dropEffect, "none", "initial dropEffect");
is(dt.effectAllowed, "uninitialized", "initial effectAllowed");
["copy", "none", "link", "", "other", "copyMove", "all", "uninitialized", "move"].forEach(
function (i) {
dt.dropEffect = i;
is(dt.dropEffect, i == "" || i == "other" || i == "copyMove" ||
i == "all" || i == "uninitialized" ? "link" : i,
"dropEffect set to " + i);
is(dt.effectAllowed, "uninitialized", "effectAllowed not modified by dropEffect set to " + i);
}
);
["move", "copy", "link", "", "other", "moveCopy", "copyMove",
"linkMove", "copyLink", "all", "uninitialized", "none"].forEach(
function (i) {
dt.effectAllowed = i;
is(dt.dropEffect, "move", "dropEffect not modified by effectAllowed set to " + i);
is(dt.effectAllowed, i == "" || i == "other" || i == "moveCopy" ? "link" : i,
"effectAllowed set to " + i);
}
);
}
function doDragStartLink(event)
{
var dt = event.dataTransfer;
checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
"text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial link");
is(dt.mozItemCount, 1, "initial link item count");
is(dt.getData("text/uri-list"), "http://www.mozilla.org/", "link text/uri-list");
is(dt.getData("text/plain"), "http://www.mozilla.org/", "link text/plain");
event.preventDefault();
gExtraDragTests++;
}
function doDragStartImage(event)
{
var dataurl = $("image").src;
var dt = event.dataTransfer;
checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
"text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial image");
is(dt.mozItemCount, 1, "initial image item count");
is(dt.getData("text/uri-list"), dataurl, "image text/uri-list");
is(dt.getData("text/plain"), dataurl, "image text/plain");
event.preventDefault();
gExtraDragTests++;
}
function doDragStartInput(event)
{
var dt = event.dataTransfer;
checkTypes(dt, ["text/plain"], 0, "initial input");
is(dt.mozItemCount, 1, "initial input item count");
// is(dt.getData("text/plain"), "Text", "input text/plain");
// event.preventDefault();
}
function doDragStartSynthetic(event)
{
is(event.type, "dragstart", "synthetic dragstart event type");
return;
var dt = event.dataTransfer;
ok(dt instanceof DataTransfer, "synthetic dragstart dataTransfer is DataTransfer");
checkTypes(dt, [], 0, "synthetic dragstart");
is(event.detail, 1, "synthetic dragstart detail");
dt.setData("text/plain", "Text");
is(dt.getData("text/plain"), "Text", "synthetic dragstart data is set after adding");
}
function doDragOverSynthetic(event)
{
is(event.type, "dragover", "synthetic dragover event type");
return;
var dt = event.dataTransfer;
ok(dt instanceof DataTransfer, "synthetic dragover dataTransfer is DataTransfer");
checkTypes(dt, [], 0, "synthetic dragover");
dt.setData("text/plain", "Text");
is(dt.getData("text/plain"), "Text", "synthetic dragover data is set after adding");
}
function onDragStartDraggable(event)
{
var dt = event.dataTransfer;
ok(dt.mozItemCount == 0 && dt.types.length == 0 && event.originalTarget == gDragInfo.target, gDragInfo.testid);
gExtraDragTests++;
if (gExtraDragTests == 6)
SimpleTest.finish();
}
function checkOneDataItem(dt, expectedtypes, expecteddata, index, testid)
{
checkTypes(dt, expectedtypes, index, testid);
for (var f = 0; f < expectedtypes.length; f++) {
if (index == 0)
is(dt.getData(expectedtypes[f]), expecteddata[f], testid + " getData " + expectedtypes[f]);
is(dt.mozGetDataAt(expectedtypes[f], index), expecteddata[f] ? expecteddata[f] : null,
testid + " getDataAt " + expectedtypes[f]);
}
}
function checkTypes(dt, expectedtypes, index, testid)
{
if (index == 0) {
var types = dt.types;
is(types.length, expectedtypes.length, testid + " types length");
for (var f = 0; f < expectedtypes.length; f++) {
is(types[f], expectedtypes[f], testid + " " + types[f] + " check");
}
}
types = dt.mozTypesAt(index);
is(types.length, expectedtypes.length, testid + " typesAt length");
for (var f = 0; f < expectedtypes.length; f++) {
is(types[f], expectedtypes[f], testid + " " + types[f] + " at " + index + " check");
}
}
function checkURL(dt, url, fullurllist, index, testid)
{
is(dt.getData("text/uri-list"), fullurllist, testid + " text/uri-list");
is(dt.getData("URL"), url, testid + " URL");
is(dt.mozGetDataAt("text/uri-list", 0), fullurllist, testid + " text/uri-list");
is(dt.mozGetDataAt("URL", 0), fullurllist, testid + " URL");
}
function expectError(fn, eid, testid)
{
var error = "";
try {
fn();
} catch (ex) {
error = ex.name;
}
is(error, eid, testid + " causes exception " + eid);
}
</script>
</head>
<body style="height: 300px; overflow: auto;" onload="setTimeout(runTests, 0)">
<div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> bit of text.</div>
<a id="link" href="http://www.mozilla.org/" ondragstart="doDragStartLink(event)">mozilla.org</a>
<img id="image" src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"
ondragstart="doDragStartImage(event)">
<input id="input" value="Text in a box" ondragstart="doDragStartInput(event)">
<div style="-moz-user-select: none;" ondragstart="onDragStartDraggable(event)">
<div id="dragtrue" draggable="true">
This is a <span id="spantrue">draggable</span> area.
</div>
<div id="dragfalse" draggable="false">
This is a <span id="spanfalse">non-draggable</span> area.
</div>
</div>
<!--iframe src="http://www.mozilla.org" width="400" height="400"></iframe-->
<div id="synthetic" ondragstart="doDragStartSynthetic(event)">Synthetic Event Dispatch</div>
<div id="synthetic2" ondragover="doDragOverSynthetic(event)">Synthetic Event Dispatch</div>
</body>
</html>

View File

@ -0,0 +1,7 @@
<html>
<head>
</head>
<body>
<input type="file" type="file">
</body>
</html>

View File

@ -4,4 +4,4 @@ load 338649-1.xhtml
load 339501-1.xhtml
load 339501-2.xhtml
load 423371-1.html
load 451123-1.html

View File

@ -856,6 +856,22 @@ nsGenericHTMLElement::SetSpellcheck(PRBool aSpellcheck)
return SetAttrHelper(nsGkAtoms::spellcheck, NS_LITERAL_STRING("false"));
}
NS_IMETHODIMP
nsGenericHTMLElement::GetDraggable(PRBool* aDraggable)
{
*aDraggable = AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
nsGkAtoms::_true, eIgnoreCase);
return NS_OK;
}
NS_IMETHODIMP
nsGenericHTMLElement::SetDraggable(PRBool aDraggable)
{
return SetAttrHelper(nsGkAtoms::draggable,
aDraggable ? NS_LITERAL_STRING("true") :
NS_LITERAL_STRING("false"));
}
PRBool
nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
{

View File

@ -145,15 +145,17 @@ public:
virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
nsresult ScrollIntoView(PRBool aTop);
// Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetSpellcheck() and
// SetSpellcheck() such that classes that inherit interfaces with those
// methods properly override them
// Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetSpellcheck(),
// SetSpellcheck(), and GetDraggable() such that classes that inherit interfaces
// with those methods properly override them
NS_IMETHOD Focus();
NS_IMETHOD Blur();
NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex);
NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
NS_IMETHOD GetSpellcheck(PRBool* aSpellcheck);
NS_IMETHOD SetSpellcheck(PRBool aSpellcheck);
NS_IMETHOD GetDraggable(PRBool* aDraggable);
NS_IMETHOD SetDraggable(PRBool aDraggable);
nsresult GetContentEditable(nsAString &aContentEditable);
nsresult SetContentEditable(const nsAString &aContentEditable);

View File

@ -103,6 +103,9 @@ public:
NS_IMETHOD LinkAdded() { return NS_OK; }
NS_IMETHOD LinkRemoved() { return NS_OK; }
// override from nsGenericHTMLElement
NS_IMETHOD GetDraggable(PRBool* aDraggable);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers);
@ -178,6 +181,20 @@ NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLAnchorElement, TabIndex, tabindex, 0)
NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, Type, type)
NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, AccessKey, accesskey)
NS_IMETHODIMP
nsHTMLAnchorElement::GetDraggable(PRBool* aDraggable)
{
// links can be dragged as long as there is an href and the
// draggable attribute isn't false
if (HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
*aDraggable = !AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
nsGkAtoms::_false, eIgnoreCase);
return NS_OK;
}
// no href, so just use the same behavior as other elements
return nsGenericHTMLElement::GetDraggable(aDraggable);
}
nsresult
nsHTMLAnchorElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,

View File

@ -107,6 +107,9 @@ public:
// nsIDOMNSHTMLImageElement
NS_DECL_NSIDOMNSHTMLIMAGEELEMENT
// override from nsGenericHTMLElement
NS_IMETHOD GetDraggable(PRBool* aDraggable);
// nsIJSNativeInitializer
NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aContext,
JSObject* aObj, PRUint32 argc, jsval* argv);
@ -217,6 +220,15 @@ NS_IMPL_URI_ATTR(nsHTMLImageElement, Src, src)
NS_IMPL_STRING_ATTR(nsHTMLImageElement, UseMap, usemap)
NS_IMPL_INT_ATTR(nsHTMLImageElement, Vspace, vspace)
NS_IMETHODIMP
nsHTMLImageElement::GetDraggable(PRBool* aDraggable)
{
// images may be dragged unless the draggable attribute is false
*aDraggable = !AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
nsGkAtoms::_false, eIgnoreCase);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLImageElement::GetComplete(PRBool* aComplete)
{

View File

@ -1997,23 +1997,25 @@ nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID,
newType = NS_FORM_INPUT_TEXT;
}
// Make sure to do the check for newType being NS_FORM_INPUT_FILE and the
// corresponding SetValueInternal() call _before_ we set mType. That way
// the logic in SetValueInternal() will work right (that logic makes
// assumptions about our frame based on mType, but we won't have had time
// to recreate frames yet -- that happens later in the SetAttr()
// process).
if (newType == NS_FORM_INPUT_FILE) {
// These calls aren't strictly needed any more since we'll never
// confuse values and filenames. However they're there for backwards
// compat.
SetFileName(EmptyString());
SetValueInternal(EmptyString(), nsnull, PR_FALSE);
} else if (mType == NS_FORM_INPUT_FILE) {
SetFileName(EmptyString());
}
if (newType != mType) {
// Make sure to do the check for newType being NS_FORM_INPUT_FILE and
// the corresponding SetValueInternal() call _before_ we set mType.
// That way the logic in SetValueInternal() will work right (that logic
// makes assumptions about our frame based on mType, but we won't have
// had time to recreate frames yet -- that happens later in the
// SetAttr() process).
if (newType == NS_FORM_INPUT_FILE) {
// These calls aren't strictly needed any more since we'll never
// confuse values and filenames. However they're there for backwards
// compat.
SetFileName(EmptyString());
SetValueInternal(EmptyString(), nsnull, PR_FALSE);
} else if (mType == NS_FORM_INPUT_FILE) {
SetFileName(EmptyString());
}
mType = newType;
mType = newType;
}
return success;
}

View File

@ -120,6 +120,7 @@ _TEST_FILES = test_bug589.html \
test_bug430392.html \
bug441930_iframe.html \
test_bug441930.html \
test_bug448166.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,36 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=448166
-->
<head>
<title>Test for Bug 448166</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448166">Mozilla Bug 448166</a>
<p id="display">
<a id="test" href="http://www.moz&#xdc00;illa.org">should not be Mozilla</a>
<a id="control" href="http://www.mozilla.org">should not be Mozilla</a>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 448166 **/
isnot($("test").href, "http://www.mozilla.org/",
"Should notice unpaired surrogate");
is($("test").href, "http://www.moz\ufffdilla.org/",
"Should replace unpaired surrogate with replacement char");
is($("control").href, "http://www.mozilla.org/",
"Just making sure .href works");
</script>
</pre>
</body>
</html>

View File

@ -2076,12 +2076,18 @@ HTMLContentSink::OpenBody(const nsIParserNode& aNode)
// insertionPoint is not -1, but this code will try to handle
// those cases too.
PRBool oldUpdates = mUpdatesInNotification;
mUpdatesInNotification = 0;
if (insertionPoint != -1) {
NotifyInsert(parent, mBody, insertionPoint - 1);
} else {
NotifyAppend(parent, numFlushed);
}
mCurrentContext->mStack[parentIndex].mNumFlushed = childCount;
if (mUpdatesInNotification > 1) {
UpdateChildCounts();
}
mUpdatesInNotification = oldUpdates;
}
StartLayout(PR_FALSE);
@ -2232,12 +2238,18 @@ HTMLContentSink::OpenFrameset(const nsIParserNode& aNode)
// insertionPoint is not -1, but this code will try to handle
// those cases too.
PRBool oldUpdates = mUpdatesInNotification;
mUpdatesInNotification = 0;
if (insertionPoint != -1) {
NotifyInsert(parent, mFrameset, insertionPoint - 1);
} else {
NotifyAppend(parent, numFlushed);
}
mCurrentContext->mStack[parentIndex].mNumFlushed = childCount;
if (mUpdatesInNotification > 1) {
UpdateChildCounts();
}
mUpdatesInNotification = oldUpdates;
}
return rv;

View File

@ -3158,12 +3158,19 @@ DocAllResultMatch(nsIContent* aContent, PRInt32 aNamespaceID, nsIAtom* aAtom,
}
nsIAtom* tag = elm->Tag();
if (tag != nsGkAtoms::img &&
tag != nsGkAtoms::form &&
if (tag != nsGkAtoms::a &&
tag != nsGkAtoms::applet &&
tag != nsGkAtoms::embed &&
tag != nsGkAtoms::button &&
tag != nsGkAtoms::embed &&
tag != nsGkAtoms::form &&
tag != nsGkAtoms::iframe &&
tag != nsGkAtoms::img &&
tag != nsGkAtoms::input &&
tag != nsGkAtoms::map &&
tag != nsGkAtoms::meta &&
tag != nsGkAtoms::object &&
tag != nsGkAtoms::input) {
tag != nsGkAtoms::select &&
tag != nsGkAtoms::textarea) {
return PR_FALSE;
}

View File

@ -70,6 +70,7 @@ _TEST_FILES = test_bug1682.html \
test_bug404320.html \
test_form-parsing.html \
test_viewport.html \
test_documentAll.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,155 @@
<html>
<!--
Tests for document.all
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Tests for document.all</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=259332">Mozilla Bug 259332</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=393629">Mozilla Bug 393629</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448904">Mozilla Bug 448904</a>
<p id="display">
</p>
<div id="content" style="display: none">
<a id="id1">A</a>
<a id="id2">B</a>
<a id="id2">C</a>
<a id="id3">D</a>
<a id="id3">E</a>
<a id="id3">F</a>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
p = document.getElementById("content");
// Test that several elements with the same id or name behave correctly
function testNumSame() {
is(document.all.id0, null, "no ids");
is(document.all.id1, p.children[0], "one id");
is(document.all.id2[0], p.children[1], "two ids");
is(document.all.id2[1], p.children[2], "two ids");
is(document.all.id2.length, 2, "two length");
is(document.all.id3[0], p.children[3], "three ids");
is(document.all.id3[1], p.children[4], "three ids");
is(document.all.id3[2], p.children[5], "three ids");
is(document.all.id3.length, 3, "three length");
}
testNumSame();
p.innerHTML = p.innerHTML.replace("id=", "name=", "g");
testNumSame();
// Test that dynamic changes behave properly
// Add two elements and check that they are added to the correct lists
child = Array.prototype.slice.call(p.children);
child[6] = document.createElement("a");
child[6].id = "id0";
p.appendChild(child[6]);
child[7] = document.createElement("a");
child[7].id = "id1";
p.appendChild(child[7]);
is(document.all.id0, child[6], "now one id");
is(document.all.id1[0], child[0], "now two ids");
is(document.all.id1[1], child[7], "now two ids");
is(document.all.id1.length, 2, "now two length");
// Remove and element and check that the list shrinks
rC(child[1]);
is(document.all.id2, child[2], "now just one id");
// Change an id and check that its removed and added to the correct lists
child[4].name = "id1";
is(document.all.id1[0], child[0], "now three ids");
is(document.all.id1[1], child[4], "now three ids");
is(document.all.id1[2], child[7], "now three ids");
is(document.all.id1.length, 3, "now three length");
is(document.all.id3[1], child[5], "now just two ids");
is(document.all.id3.length, 2, "now two length");
// Remove all elements from a list and check that it goes empty
id3list = document.all.id3;
rC(child[3]);
is(id3list.length, 1, "now one length");
rC(child[5]);
is(document.all.id3, null, "now none");
is(id3list.length, 0, "now none length");
// Give an element both a name and id and check that it appears in two lists
p.insertBefore(child[1], child[2]); // restore previously removed
id1list = document.all.id1;
id2list = document.all.id2;
child[1].id = "id1";
is(id1list[0], child[0], "now four ids");
is(id1list[1], child[1], "now four ids");
is(id1list[2], child[4], "now four ids");
is(id1list[3], child[7], "now four ids");
is(id1list.length, 4, "now four length");
is(id2list[0], child[1], "still two ids");
is(id2list[1], child[2], "still two ids");
is(id2list.length, 2, "still two length");
// Check that document.all behaves list a list of all elements
allElems = document.getElementsByTagName("*");
ok(testArraysSame(document.all, allElems), "arrays same");
length = document.all.length;
expectedLength = length + p.getElementsByTagName("*").length + 1;
p.appendChild(p.cloneNode(true));
ok(testArraysSame(document.all, allElems), "arrays still same");
is(document.all.length, expectedLength, "grew correctly");
// Check which elements the 'name' attribute works on
var elementNames =
['applet','abbr','acronym','address','area','a','b','base','basefont',
'bgsound','big','blink','blockquote','br','canvas','center','cite','code',
'col','colgroup','dd','del','dfn','dir','div','dir','dl','dt','em','embed',
'fieldset','font','form','frame','frameset','head','i','iframe','img',
'input','ins','isindex','kbd','keygen','label','li','legend','link','menu',
'multicol','noscript','noframes','object','spacer','table','td','td','th',
'thead','tfoot','tr','textarea','select','option','spacer','param',
'marquee','hr','title','hx','tt','u','ul','var','wbr','sub','sup','cite',
'code','q','nobr','ol','p','pre','s','samp','small','body','html','map',
'bdo','legend','listing','style','script','tbody','caption','meta',
'optgroup','button','span','strike','strong','td'].sort();
var hasName =
['applet','a','embed','form','iframe','img','input','object','textarea',
'select','map','meta','button'].sort();
elementNames.forEach(function (name) {
nameval = 'namefor' + name;
e = document.createElement(name);
p.appendChild(e);
e.setAttribute('name', nameval);
if (name == hasName[0]) {
is(document.all[nameval], e, "should have name");
hasName.shift();
}
else {
is(document.all[nameval], null, "shouldn't have name");
}
});
is(hasName.length, 0, "found all names");
// Utility functions
function rC(node) {
node.parentNode.removeChild(node);
}
function testArraysSame(a1, a2) {
return Array.prototype.every.call(a1, function(e, index) {
return a2[index] === e;
}) && a1.length == a2.length;
}
</script>
</pre>
</body>
</html>

View File

@ -506,6 +506,7 @@ void nsOggDecoder::Stop()
}
if (mPresentationThread) {
if (!mFirstFrameLoaded) {
nsAutoLock lock(mFirstFrameLock);
mFirstFrameLoaded = PR_TRUE;
PR_NotifyAllCondVar(mFirstFrameCondVar);
}

View File

@ -421,6 +421,9 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n");
}
else {
// Clear script handling object on asynchronously loaded XBL documents.
doc->ClearScriptHandlingObject();
// We have to do a flush prior to notification of the document load.
// This has to happen since the HTML content sink can be holding on
// to notifications related to our children (e.g., if you bind to the
@ -1320,6 +1323,9 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
rv = nsSyncLoadService::PushSyncStreamToListener(in, listener, channel);
NS_ENSURE_SUCCESS(rv, rv);
// Clear script handling on synchronously loaded XBL documents.
doc->ClearScriptHandlingObject();
doc.swap(*aResult);
return NS_OK;

View File

@ -169,6 +169,13 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument,
// Create the document
rv = NS_NewXMLDocument(getter_AddRefs(mDocument));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> source = do_QueryInterface(aSourceDocument);
NS_ENSURE_STATE(source);
PRBool hasHadScriptObject = PR_FALSE;
nsIScriptGlobalObject* sgo =
source->GetScriptHandlingObject(hasHadScriptObject);
NS_ENSURE_STATE(sgo || !hasHadScriptObject);
mDocument->SetScriptHandlingObject(sgo);
}
else {
mDocument = do_QueryInterface(aResultDocument);

View File

@ -833,6 +833,13 @@ txMozillaXMLOutput::createResultDocument(const nsSubstring& aName, PRInt32 aNsID
rv = NS_NewXMLDocument(getter_AddRefs(mDocument));
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIDocument> source = do_QueryInterface(aSourceDocument);
NS_ENSURE_STATE(source);
PRBool hasHadScriptObject = PR_FALSE;
nsIScriptGlobalObject* sgo =
source->GetScriptHandlingObject(hasHadScriptObject);
NS_ENSURE_STATE(sgo || !hasHadScriptObject);
mDocument->SetScriptHandlingObject(sgo);
}
else {
mDocument = do_QueryInterface(aResultDocument);

View File

@ -143,6 +143,9 @@
#include "nsINestedURI.h"
#include "nsITransportSecurityInfo.h"
#include "nsINSSErrorsService.h"
#include "nsIApplicationCache.h"
#include "nsIApplicationCacheContainer.h"
#include "nsIPermissionManager.h"
// Editor-related
#include "nsIEditingSession.h"
@ -458,6 +461,22 @@ NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
return *aSink ? NS_OK : NS_NOINTERFACE;
}
else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer)) &&
NS_SUCCEEDED(EnsureContentViewer())) {
*aSink = nsnull;
// Return the toplevel document as an
// nsIApplicationCacheContainer.
nsCOMPtr<nsIDocShellTreeItem> rootItem;
GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(rootItem);
NS_ASSERTION(domDoc, "Should have a document.");
if (!domDoc)
return NS_ERROR_NO_INTERFACE;
return domDoc->QueryInterface(aIID, aSink);
}
else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
NS_SUCCEEDED(EnsureScriptEnvironment())) {
nsresult rv;
@ -7275,6 +7294,15 @@ nsDocShell::DoURILoad(nsIURI * aURI,
if (aFirstParty) {
// tag first party URL loads
loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
// Toplevel document loads in domains with the offline-app
// permission should check for an associated application
// cache.
nsCOMPtr<nsIDocShellTreeItem> root;
GetSameTypeRootTreeItem(getter_AddRefs(root));
if (root == this && NS_OfflineAppAllowed(aURI)) {
loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
}
}
if (mLoadType == LOAD_ERROR_PAGE) {

View File

@ -44,6 +44,8 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_bug113934.xul \
bug113934_window.xul \
test_bug364461.xul \
bug364461_window.xul \
test_bug396519.xul \

View File

@ -0,0 +1,103 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window title="Mozilla Bug 113934" onload="doTheTest()"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox>
<vbox>
<browser type="content" id="f1" width="300" height="200"/>
<browser type="content" id="f2" width="300" height="200"/>
</vbox>
<vbox>
<browser type="content" id="f3" width="30" height="200"/>
</vbox>
<spacer flex="1"/>
</hbox>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
var imports = [ "SimpleTest", "is", "isnot", "ok", "snapshotWindow",
"compareSnapshots" ];
for each (var import in imports) {
window[import] = window.opener.wrappedJSObject[import];
}
function $(id) {
return document.getElementById(id);
}
/** Test for Bug 113934 **/
var doc1 =
"data:text/html,<html><body onbeforeunload='document.documentElement.textContent = \"\"' onunload='document.documentElement.textContent = \"\"' onpagehide='document.documentElement.textContent = \"\"'>This is a test</body></html>";
var doc2 = "data:text/html,<html><body>This is a second test</body></html>";
$("f1").setAttribute("src", doc1);
$("f2").setAttribute("src", doc2);
$("f3").setAttribute("src", doc2);
function doTheTest() {
var s1 = snapshotWindow($("f1").contentWindow);
var s2 = snapshotWindow($("f2").contentWindow);
var s3 = snapshotWindow($("f3").contentWindow);
ok(!compareSnapshots(s2, s3)[0],
"Should look different due to different sizing");
function getDOM(id) {
return $(id).contentDocument.documentElement.innerHTML;
}
var dom1 = getDOM("f1");
var dom2 = getDOM("f2");
$("f2").contentDocument.body.textContent = "Modified the text";
var dom2star = getDOM("f2");
isnot(dom2, dom2star, "We changed the DOM!");
$("f1").swapDocShells($("f2"));
// now we have doms 2*, 1, 2 in the frames
is(getDOM("f1"), dom2star, "Shouldn't have changed the DOM on swap");
is(getDOM("f2"), dom1, "Shouldn't have fired event handlers");
var strs = { "f1": "", "f3" : "" };
function attachListener(node, type) {
var listener = function(e) {
if (strs[node.id]) strs[node.id] += " ";
strs[node.id] += node.id + ".page" + type;
}
node.addEventListener("page" + type, listener, false);
listener.detach = function() {
node.removeEventListener("page" + type, listener, false);
}
return listener;
}
var l1 = attachListener($("f1"), "show");
var l2 = attachListener($("f1"), "hide");
var l3 = attachListener($("f3"), "show");
var l4 = attachListener($("f3"), "hide");
$("f1").swapDocShells($("f3"));
// now we have DOMs 2, 1, 2* in the frames
l1.detach();
l2.detach();
l3.detach();
l4.detach();
var s1_new = snapshotWindow($("f1").contentWindow);
var [same, first, second] = compareSnapshots(s1_new, s2);
ok(same, "Should reflow on swap", "Expected " + second + " but got " + first);
is(strs["f1"], "f1.pagehide f1.pageshow");
is(strs["f3"], "f3.pagehide f3.pageshow");
window.close();
SimpleTest.finish();
}
]]></script>
</window>

View File

@ -0,0 +1,33 @@
<?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=113934
-->
<window title="Mozilla Bug 113934"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=113934"
target="_blank">Mozilla Bug 396519</a>
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
window.open("bug113934_window.xul", "bug113934",
"chrome,width=800,height=800");
});
]]></script>
</window>

View File

@ -44,11 +44,14 @@
/*
* The listener for drag events.
*
* The reason for two events for the same operation are for compatibility
* between the WHAT-WG drag and drop spec and existing XUL code.
*/
#define NS_IDOMDRAGLISTENER_IID \
{ /* CD5186C4-228F-4413-AFD9-B65DAA105714 */ \
0xcd5186c4, 0x228f, 0x4413, \
{0xaf, 0xd9, 0xb6, 0x5d, 0xaa, 0x10, 0x57, 0x14} }
{ /* 1A107271-1E26-419A-BCF1-0A4CF7A66B45 */ \
0x1a107271, 0x1e26, 0x419a, \
{0xbc, 0xf1, 0x0a, 0x4c, 0xf7, 0xa6, 0x6b, 0x45} }
@ -129,6 +132,11 @@ public:
* @returns whether the event was consumed or ignored. @see nsresult
*/
NS_IMETHOD Drag(nsIDOMEvent* aMouseEvent) = 0;
// these methods are for compatibility
NS_IMETHOD DragStart(nsIDOMEvent* aMouseEvent) { return NS_OK; }
NS_IMETHOD DragLeave(nsIDOMEvent* aMouseEvent) { return NS_OK; }
NS_IMETHOD Drop(nsIDOMEvent* aMouseEvent) { return NS_OK; }
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMDragListener, NS_IDOMDRAGLISTENER_IID)

View File

@ -47,7 +47,7 @@
interface nsIDOMElement;
[scriptable, uuid(ee6500aa-fd51-4b89-801f-d4fbf2663beb)]
[scriptable, uuid(9a1ff4e0-5e31-46af-b393-2cbab8093442)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -168,11 +168,17 @@ interface nsIDOMWindowUtils : nsISupports {
* @param aKeyCode key code
* @param aCharCode character code
* @param aModifiers modifiers pressed, using constants defined in nsIDOMNSEvent
* @param aPreventDefault if true, preventDefault() the event before dispatch
*
* @return false if the event had preventDefault() called on it,
* true otherwise. In other words, true if and only if the
* default action was taken.
*/
void sendKeyEvent(in AString aType,
in long aKeyCode,
in long aCharCode,
in long aModifiers);
boolean sendKeyEvent(in AString aType,
in long aKeyCode,
in long aCharCode,
in long aModifiers,
[optional] in boolean aPreventDefault);
/**
* See nsIWidget::SynthesizeNativeKeyEvent

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