Land DOM_AGNOSTIC3_BRANCH, bug 255942. r=a few people, sr=brendan.

This commit is contained in:
mhammond%skippinet.com.au 2006-06-13 03:07:47 +00:00
Родитель c5b0a97e63
Коммит d5ad1dc2b9
71 изменённых файлов: 4446 добавлений и 2060 удалений

Просмотреть файл

@ -1543,6 +1543,14 @@ for extension in $MOZ_EXTENSIONS; do
extensions/python/xpcom/test/Makefile
extensions/python/xpcom/test/test_component/Makefile
" ;;
python/dom ) MAKEFILES_extensions="$MAKEFILES_extensions
extensions/python/dom/Makefile
extensions/python/dom/test/Makefile
extensions/python/dom/test/pyxultest/Makefile
extensions/python/dom/src/Makefile
extensions/python/dom/nsdom/Makefile
extensions/python/dom/nsdom/test/Makefile
" ;;
sql ) MAKEFILES_extensions="$MAKEFILES_extensions
$MAKEFILES_sql"
;;

Просмотреть файл

@ -81,6 +81,7 @@
#include "nsIObserverService.h"
#include "nsIContent.h"
#include "nsAutoPtr.h"
#include "nsDOMJSUtils.h"
#include "nsAboutProtocolUtils.h"
#include "nsIClassInfo.h"
#include "nsIURIFixup.h"

Просмотреть файл

@ -4029,7 +4029,7 @@ MOZ_PREF_EXTENSIONS=1
MOZ_PROFILELOCKING=1
MOZ_PROFILESHARING=1
MOZ_PSM=1
MOZ_PYTHON_EXTENSIONS="xpcom"
MOZ_PYTHON_EXTENSIONS="xpcom dom"
MOZ_PYTHON=
MOZ_PYTHON_DEBUG_SUFFIX=
MOZ_PYTHON_DLL_SUFFIX=
@ -7088,7 +7088,7 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c python` -ne 0; then
fi
if test "$OS_ARCH" = "WINNT"; then
dnl Convert to cygwin style "mixed" (ie, "c:/path/file.exe")
PYTHON=`cygpath -t mixed $PYTHON`
PYTHON=`$CYGPATH_W $PYTHON | $CYGPATH_S`
fi
if test ! -x "$PYTHON"; then
AC_MSG_ERROR([Could not find Python - please adjust your PATH, or set PYTHON.])
@ -7103,7 +7103,7 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c python` -ne 0; then
MOZ_PYTHON_PREFIX=`$PYTHON -c "import sys; print sys.prefix"`
dnl Setup the include and library directories.
if test "$OS_ARCH" = "WINNT"; then
MOZ_PYTHON_PREFIX=`cygpath -t mixed $MOZ_PYTHON_PREFIX`
MOZ_PYTHON_PREFIX=`$CYGPATH_W $MOZ_PYTHON_PREFIX | $CYGPATH_S`
dnl Source trees have "include" and "PC" for .h, and "PCbuild" for .lib
dnl Binary trees have "include" for .h, and "libs" for .lib
dnl We add 'em both - along with quotes, to handle spaces.
@ -7153,7 +7153,18 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c python` -ne 0; then
fi
AC_MSG_RESULT(Building Python extensions using python-$MOZ_PYTHON_VER_DOTTED from $MOZ_PYTHON_PREFIX)
fi
dnl Later we may allow MOZ_PYTHON_EXTENSIONS to be specified, but not necessary now.
dnl If the user asks for the 'python' extension, then we add
dnl MOZ_PYTHON_EXTENSIONS to MOZ_EXTENSIONS - but with the leading 'python/'
dnl Note the careful regex - it must match 'python' followed by anything
dnl other than a '/', including the end-of-string.
if test `echo "$MOZ_EXTENSIONS" | grep -c 'python\([[^/]]\|$\)'` -ne 0; then
for pyext in $MOZ_PYTHON_EXTENSIONS; do
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS python/$pyext`
done
fi
dnl Later we may allow MOZ_PYTHON_EXTENSIONS to be specified on the
dnl command-line, but not yet
AC_SUBST(MOZ_PYTHON_EXTENSIONS)
AC_SUBST(MOZ_PYTHON)
AC_SUBST(MOZ_PYTHON_PREFIX)

Просмотреть файл

@ -573,11 +573,13 @@ public:
}
/**
* Returns the appropriate event argument name for the specified
* namespace. Added because we need to switch between SVG's "evt"
* and the rest of the world's "event".
* Returns the appropriate event argument names for the specified
* namespace and event name. Added because we need to switch between
* SVG's "evt" and the rest of the world's "event", and because onerror
* takes 3 args.
*/
static const char *GetEventArgName(PRInt32 aNameSpaceID);
static void GetEventArgNames(PRInt32 aNameSpaceID, nsIAtom *aEventName,
PRUint32 *aArgCount, const char*** aArgNames);
/**
* Return the nsIXPConnect service.

Просмотреть файл

@ -42,6 +42,7 @@
#include "nsCaseTreatment.h"
#include "nsChangeHint.h"
#include "nsINode.h"
#include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
// Forward declarations
class nsIAtom;
@ -60,8 +61,8 @@ class nsAttrName;
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0x67b73e9b, 0x6ec8, 0x4f20, \
{ 0x89, 0xb2, 0xb1, 0x46, 0x9e, 0x0a, 0x51, 0x68 } }
{ 0x469b2ce5, 0x3e00, 0x45e0, \
{ 0x9c, 0x6e, 0x4e, 0x80, 0xfb, 0x27, 0x59, 0x7d } }
// hack to make egcs / gcc 2.95.2 happy
class nsIContent_base : public nsINode {
@ -614,6 +615,19 @@ public:
return 0;
}
/* The default script type (language) ID for this content.
All content must support fetching the default script language.
*/
virtual PRUint32 GetScriptTypeID() const
{ return nsIProgrammingLanguage::JAVASCRIPT; }
/* Not all content supports setting a new default language */
virtual nsresult SetScriptTypeID(PRUint32 aLang)
{
NS_NOTREACHED("SetScriptTypeID not implemented");
return NS_ERROR_NOT_IMPLEMENTED;
}
/**
* Clones this node, using aNodeInfoManager to get the nodeinfo for the
* clone. When cloning an element, all attributes of the element will be

Просмотреть файл

@ -79,8 +79,11 @@ class nsVoidArray;
// NOTE: Should only be used on nsIContent nodes
#define NODE_MAY_HAVE_FRAME 0x00000020U
// Four bits for the script-type ID
#define NODE_SCRIPT_TYPE_OFFSET 6
// Remaining bits are node type specific.
#define NODE_TYPE_SPECIFIC_BITS_OFFSET 6
#define NODE_TYPE_SPECIFIC_BITS_OFFSET 0x0a
// IID for the nsINode interface
#define NS_INODE_IID \

Просмотреть файл

@ -2198,17 +2198,34 @@ nsContentUtils::UnregisterPrefCallback(const char *aPref,
}
static const char gEventName[] = "event";
static const char gSVGEventName[] = "evt";
static const char *gEventNames[] = {"event"};
static const char *gSVGEventNames[] = {"evt"};
// for b/w compat, the first name to onerror is still 'event', even though it
// is actually the error message. (pre this code, the other 2 were not avail.)
// XXXmarkh - a quick lxr shows no affected code - should we correct this?
static const char *gOnErrorNames[] = {"event", "source", "lineno"};
// static
const char *
nsContentUtils::GetEventArgName(PRInt32 aNameSpaceID)
void
nsContentUtils::GetEventArgNames(PRInt32 aNameSpaceID,
nsIAtom *aEventName,
PRUint32 *aArgCount,
const char*** aArgArray)
{
if (aNameSpaceID == kNameSpaceID_SVG)
return gSVGEventName;
#define SET_EVENT_ARG_NAMES(names) \
*aArgCount = sizeof(names)/sizeof(names[0]); \
*aArgArray = names;
return gEventName;
// nsJSEventListener is what does the arg magic for onerror, and it does
// not seem to take the namespace into account. So we let onerror in all
// namespaces get the 3 arg names.
if (aEventName == nsLayoutAtoms::onerror) {
SET_EVENT_ARG_NAMES(gOnErrorNames);
} else if (aNameSpaceID == kNameSpaceID_SVG) {
SET_EVENT_ARG_NAMES(gSVGEventNames);
} else {
SET_EVENT_ARG_NAMES(gEventNames);
}
}
nsCxPusher::nsCxPusher(nsISupports *aCurrentTarget)

Просмотреть файл

@ -215,11 +215,8 @@ nsresult nsCopySupport::HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16
// Add the URL DataFlavor to the transferable. Don't use kURLMime, as it will
// cause an unnecessary UniformResourceLocator to be added which confuses
// some apps eg. Outlook 2000 - (See Bug 315370). Don't use
// kURLDataMime, as it will cause a bogus 'url ' flavor to
// show up on the Mac clipboard, confusing other apps, like
// Terminal (see bug 336012).
rv = AppendString(trans, shortcut, kURLPrivateMime);
// some apps eg. Outlook 2000 - (See Bug 315370)
rv = AppendString(trans, shortcut, kURLDataMime );
NS_ENSURE_SUCCESS(rv, rv);
}
}

Просмотреть файл

@ -65,6 +65,7 @@
#include "nsThreadUtils.h"
#include "nsNetCID.h"
#include "nsContentUtils.h"
#include "nsDOMJSUtils.h"
static const char* kLoadAsData = "loadAsData";

Просмотреть файл

@ -58,6 +58,7 @@
#include "nsIBaseWindow.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIScriptRuntime.h"
#include "nsCOMArray.h"
#include "nsGUIEvent.h"
@ -1373,7 +1374,23 @@ nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
if (aHeaderField == nsHTMLAtoms::headerContentLanguage) {
CopyUTF16toUTF8(aData, mContentLanguage);
}
// Set the default script-type on the root element.
if (aHeaderField == nsHTMLAtoms::headerContentScriptType) {
nsIContent *root = GetRootContent();
if (root) {
// Get the script-type ID for this value.
nsresult rv;
nsCOMPtr<nsIScriptRuntime> runtime;
rv = NS_GetScriptRuntime(aData, getter_AddRefs(runtime));
if (NS_FAILED(rv) || runtime == nsnull) {
NS_WARNING("The script-type is unknown");
} else {
root->SetScriptTypeID(runtime->GetScriptTypeID());
}
}
}
if (aHeaderField == nsHTMLAtoms::headerDefaultStyle) {
// switch alternate style sheets based on default
// XXXldb What if we don't have all the sheets yet? Should this use
@ -5097,3 +5114,17 @@ nsDocument::UpdateLinkMap()
}
mVisitednessChangedURIs.Clear();
}
NS_IMETHODIMP
nsDocument::GetScriptTypeID(PRUint32 *aScriptType)
{
NS_ERROR("No default script type here - ask some element");
return nsIProgrammingLanguage::UNKNOWN;
}
NS_IMETHODIMP
nsDocument::SetScriptTypeID(PRUint32 aScriptType)
{
NS_ERROR("Can't change default script type for a document");
return NS_ERROR_NOT_IMPLEMENTED;
}

Просмотреть файл

@ -855,6 +855,20 @@ nsDOMEventRTTearoff::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
return manager->GetSystemEventGroupLM(aGroup);
}
NS_IMETHODIMP
nsDOMEventRTTearoff::GetScriptTypeID(PRUint32 *aLang)
{
*aLang = mContent->GetScriptTypeID();
return NS_OK;
}
NS_IMETHODIMP
nsDOMEventRTTearoff::SetScriptTypeID(PRUint32 aLang)
{
return mContent->SetScriptTypeID(aLang);
}
// nsIDOMEventTarget
NS_IMETHODIMP
nsDOMEventRTTearoff::AddEventListener(const nsAString& aType,
@ -985,6 +999,9 @@ nsGenericElement::nsDOMSlots::IsEmpty()
nsGenericElement::nsGenericElement(nsINodeInfo *aNodeInfo)
: nsIXMLContent(aNodeInfo)
{
// Set the default scriptID to JS - but skip SetScriptTypeID as it
// does extra work we know isn't necessary here...
SetFlags(nsIProgrammingLanguage::JAVASCRIPT << NODE_SCRIPT_TYPE_OFFSET);
}
nsGenericElement::~nsGenericElement()
@ -2301,6 +2318,29 @@ nsGenericElement::MayHaveFrame() const
return HasFlag(NODE_MAY_HAVE_FRAME);
}
PRUint32
nsGenericElement::GetScriptTypeID() const
{
PtrBits flags = GetFlags();
/* 4 bits reserved for script-type ID. */
return (flags >> NODE_SCRIPT_TYPE_OFFSET) & 0x000F;
}
nsresult
nsGenericElement::SetScriptTypeID(PRUint32 aLang)
{
if ((aLang & 0x000F) != aLang) {
NS_ERROR("script ID too large!");
return NS_ERROR_FAILURE;
}
/* SetFlags will just mask in the specific flags set, leaving existing
ones alone. So we must clear all the bits first */
UnsetFlags(0x000FU << NODE_SCRIPT_TYPE_OFFSET);
SetFlags(aLang << NODE_SCRIPT_TYPE_OFFSET);
return NS_OK;
}
nsresult
nsGenericElement::InsertChildAt(nsIContent* aKid,
PRUint32 aIndex,
@ -3128,7 +3168,8 @@ nsGenericElement::TriggerLink(nsPresContext* aPresContext,
nsresult
nsGenericElement::AddScriptEventListener(nsIAtom* aEventName,
const nsAString& aValue)
const nsAString& aValue,
PRBool aDefer)
{
NS_PRECONDITION(aEventName, "Must have event name!");
nsCOMPtr<nsISupports> target;
@ -3143,8 +3184,11 @@ nsGenericElement::AddScriptEventListener(nsIAtom* aEventName,
if (manager) {
nsIDocument *ownerDoc = GetOwnerDoc();
defer = defer && aDefer; // only defer if everyone agrees...
PRUint32 lang = GetScriptTypeID();
rv =
manager->AddScriptEventListener(target, aEventName, aValue, defer,
manager->AddScriptEventListener(target, aEventName, aValue, lang, defer,
!nsContentUtils::IsChromeDoc(ownerDoc));
}

Просмотреть файл

@ -373,6 +373,9 @@ public:
virtual void SetMayHaveFrame(PRBool aMayHaveFrame);
virtual PRBool MayHaveFrame() const;
virtual PRUint32 GetScriptTypeID() const;
virtual nsresult SetScriptTypeID(PRUint32 aLang);
/**
* This calls Clone to do the actual cloning so that we end up with the
* right class for the clone.
@ -487,9 +490,11 @@ public:
* (like onclick) and with the value as JS
* @param aEventName the event listener name
* @param aValue the JS to attach
* @param aDefer indicates if deferred execution is allowed
*/
nsresult AddScriptEventListener(nsIAtom* aEventName,
const nsAString& aValue);
const nsAString& aValue,
PRBool aDefer = PR_TRUE);
/**
* Trigger a link with uri aLinkURI. If aClick is false, this triggers a

Просмотреть файл

@ -172,7 +172,7 @@ nsParserUtils::GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
// Returns PR_TRUE if the language name is a version of JavaScript and
// PR_FALSE otherwise
PRBool
nsParserUtils::IsJavaScriptLanguage(const nsString& aName, const char* *aVersion)
nsParserUtils::IsJavaScriptLanguage(const nsString& aName, PRUint32 *aFlags)
{
JSVersion version = JSVERSION_UNKNOWN;
@ -204,7 +204,7 @@ nsParserUtils::IsJavaScriptLanguage(const nsString& aName, const char* *aVersion
}
if (version == JSVERSION_UNKNOWN)
return PR_FALSE;
*aVersion = JS_VersionToString(version);
*aFlags = version;
return PR_TRUE;
}

Просмотреть файл

@ -63,7 +63,7 @@ public:
nsAString& aValue);
static PRBool
IsJavaScriptLanguage(const nsString& aName, const char* *aVersion);
IsJavaScriptLanguage(const nsString& aName, PRUint32 *aVerFlags);
static void
SplitMimeType(const nsAString& aValue, nsString& aType,

Просмотреть файл

@ -52,6 +52,7 @@
#include "nsNetUtil.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsIScriptRuntime.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPrincipal.h"
#include "nsContentPolicyUtils.h"
@ -60,7 +61,7 @@
#include "nsIScriptElement.h"
#include "nsIDOMHTMLScriptElement.h"
#include "nsIDocShell.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "nsContentUtils.h"
#include "nsUnicharUtils.h"
#include "nsAutoPtr.h"
@ -117,8 +118,7 @@ class nsScriptLoadRequest : public nsISupports {
public:
nsScriptLoadRequest(nsIScriptElement* aElement,
nsIScriptLoaderObserver* aObserver,
const char* aVersionString,
PRBool aHasE4XOption);
PRUint32 aVersion);
virtual ~nsScriptLoadRequest();
NS_DECL_ISUPPORTS
@ -132,21 +132,19 @@ public:
PRPackedBool mLoading; // Are we still waiting for a load to complete?
PRPackedBool mWasPending; // Processed immediately or pending
PRPackedBool mIsInline; // Is the script inline or loaded?
PRPackedBool mHasE4XOption; // Has E4X=1 script type parameter
nsString mScriptText; // Holds script for loaded scripts
const char* mJSVersion; // We don't own this string
PRUint32 mJSVersion;
nsCOMPtr<nsIURI> mURI;
PRInt32 mLineNo;
};
nsScriptLoadRequest::nsScriptLoadRequest(nsIScriptElement* aElement,
nsIScriptLoaderObserver* aObserver,
const char* aVersionString,
PRBool aHasE4XOption) :
PRUint32 aVersion) :
mElement(aElement), mObserver(aObserver),
mLoading(PR_TRUE), mWasPending(PR_FALSE),
mIsInline(PR_TRUE), mHasE4XOption(aHasE4XOption),
mJSVersion(aVersionString), mLineNo(1)
mIsInline(PR_TRUE),
mJSVersion(aVersion), mLineNo(1)
{
}
@ -382,10 +380,16 @@ nsScriptLoader::DoProcessScriptElement(nsIScriptElement *aElement,
// Script evaluation can also be disabled in the current script
// context even though it's enabled in the document.
// XXX - still hard-coded for JS here, even though another language
// may be specified. Should this check be made *after* we examine
// the attributes to locate the script-type?
// For now though, if JS is disabled we assume every language is
// disabled.
nsIScriptGlobalObject *globalObject = mDocument->GetScriptGlobalObject();
if (globalObject)
{
nsIScriptContext *context = globalObject->GetContext();
nsIScriptContext *context = globalObject->GetScriptContext(
nsIProgrammingLanguage::JAVASCRIPT);
// If scripts aren't enabled in the current context, there's no
// point in going on.
@ -394,35 +398,15 @@ nsScriptLoader::DoProcessScriptElement(nsIScriptElement *aElement,
}
}
PRBool isJavaScript = PR_TRUE;
PRBool hasE4XOption = PR_FALSE;
const char* jsVersionString = nsnull;
// Default script language is whatever the root content specifies
// (which may come from a header or http-meta tag)
PRUint32 typeID = mDocument->GetRootContent()->GetScriptTypeID();
PRUint32 version = 0;
nsAutoString language, type, src;
// "language" is a deprecated attribute of HTML, so we check it only for
// HTML script elements.
nsCOMPtr<nsIDOMHTMLScriptElement> htmlScriptElement =
do_QueryInterface(aElement);
if (htmlScriptElement) {
// Check the language attribute first, so type can trump language.
htmlScriptElement->GetAttribute(NS_LITERAL_STRING("language"), language);
if (!language.IsEmpty()) {
isJavaScript = nsParserUtils::IsJavaScriptLanguage(language,
&jsVersionString);
// IE, Opera, etc. do not respect language version, so neither should
// we at this late date in the browser wars saga. Note that this change
// affects HTML but not XUL or SVG (but note also that XUL has its own
// code to check nsParserUtils::IsJavaScriptLanguage -- that's probably
// a separate bug, one we may not be able to fix short of XUL2). See
// bug 255895 (https://bugzilla.mozilla.org/show_bug.cgi?id=255895).
jsVersionString = ::JS_VersionToString(JSVERSION_DEFAULT);
}
}
nsresult rv = NS_OK;
// Check the type attribute to determine language and version.
// If type exists, it trumps the deprecated 'language='
aElement->GetScriptType(type);
if (!type.IsEmpty()) {
nsCOMPtr<nsIMIMEHeaderParam> mimeHdrParser =
@ -437,6 +421,7 @@ nsScriptLoader::DoProcessScriptElement(nsIScriptElement *aElement,
mimeType);
NS_ENSURE_SUCCESS(rv, rv);
// Javascript keeps the fast path, optimized for most-likely type
// Table ordered from most to least likely JS MIME types.
// See bug 62485, feel free to add <script type="..."> survey data to it,
// or to a new bug once 62485 is closed.
@ -449,38 +434,54 @@ nsScriptLoader::DoProcessScriptElement(nsIScriptElement *aElement,
nsnull
};
isJavaScript = PR_FALSE;
PRBool isJavaScript = PR_FALSE;
for (PRInt32 i = 0; jsTypes[i]; i++) {
if (mimeType.LowerCaseEqualsASCII(jsTypes[i])) {
isJavaScript = PR_TRUE;
break;
}
}
if (isJavaScript) {
JSVersion jsVersion = JSVERSION_DEFAULT;
nsAutoString value;
if (isJavaScript)
typeID = nsIProgrammingLanguage::JAVASCRIPT;
else {
// Use the object factory to locate a matching language.
nsCOMPtr<nsIScriptRuntime> runtime;
rv = NS_GetScriptRuntime(mimeType, getter_AddRefs(runtime));
if (NS_FAILED(rv) || runtime == nsnull) {
// Failed to get the explicitly specified language
NS_WARNING("Failed to find a scripting language");
typeID = nsIProgrammingLanguage::UNKNOWN;
} else
typeID = runtime->GetScriptTypeID();
}
if (typeID != nsIProgrammingLanguage::UNKNOWN) {
// Get the version string, and ensure the language supports it.
nsAutoString versionName;
rv = mimeHdrParser->GetParameter(typeAndParams, "version",
EmptyCString(), PR_FALSE, nsnull,
value);
versionName);
if (NS_FAILED(rv)) {
// no version attribute - version remains 0.
if (rv != NS_ERROR_INVALID_ARG)
return rv;
} else {
if (value.Length() != 3 || value[0] != '1' || value[1] != '.')
jsVersion = JSVERSION_UNKNOWN;
else switch (value[2]) {
case '0': jsVersion = JSVERSION_1_0; break;
case '1': jsVersion = JSVERSION_1_1; break;
case '2': jsVersion = JSVERSION_1_2; break;
case '3': jsVersion = JSVERSION_1_3; break;
case '4': jsVersion = JSVERSION_1_4; break;
case '5': jsVersion = JSVERSION_1_5; break;
case '6': jsVersion = JSVERSION_1_6; break;
default: jsVersion = JSVERSION_UNKNOWN;
nsCOMPtr<nsIScriptRuntime> runtime;
rv = NS_GetScriptRuntimeByID(typeID, getter_AddRefs(runtime));
if (NS_FAILED(rv)) {
NS_ERROR("Failed to locate the language with this ID");
return rv;
}
rv = runtime->ParseVersion(versionName, &version);
if (NS_FAILED(rv)) {
NS_WARNING("This script language version is not supported - ignored");
typeID = nsIProgrammingLanguage::UNKNOWN;
}
}
jsVersionString = ::JS_VersionToString(jsVersion);
}
// Some js specifics yet to be abstracted.
if (typeID == nsIProgrammingLanguage::JAVASCRIPT) {
nsAutoString value;
rv = mimeHdrParser->GetParameter(typeAndParams, "e4x",
EmptyCString(), PR_FALSE, nsnull,
@ -490,20 +491,62 @@ nsScriptLoader::DoProcessScriptElement(nsIScriptElement *aElement,
return rv;
} else {
if (value.Length() == 1 && value[0] == '1')
hasE4XOption = PR_TRUE;
// This means that we need to set JSOPTION_XML in the JS options.
// We re-use our knowledge of the implementation to reuse
// JSVERSION_HAS_XML as a safe version flag.
// If version has JSVERSION_UNKNOWN (-1), then this is still OK.
version |= JSVERSION_HAS_XML;
}
}
} else {
// no 'type=' element
// "language" is a deprecated attribute of HTML, so we check it only for
// HTML script elements.
nsCOMPtr<nsIDOMHTMLScriptElement> htmlScriptElement =
do_QueryInterface(aElement);
if (htmlScriptElement) {
htmlScriptElement->GetAttribute(NS_LITERAL_STRING("language"), language);
if (!language.IsEmpty()) {
if (nsParserUtils::IsJavaScriptLanguage(language, &version))
typeID = nsIProgrammingLanguage::JAVASCRIPT;
else
typeID = nsIProgrammingLanguage::UNKNOWN;
// IE, Opera, etc. do not respect language version, so neither should
// we at this late date in the browser wars saga. Note that this change
// affects HTML but not XUL or SVG (but note also that XUL has its own
// code to check nsParserUtils::IsJavaScriptLanguage -- that's probably
// a separate bug, one we may not be able to fix short of XUL2). See
// bug 255895 (https://bugzilla.mozilla.org/show_bug.cgi?id=255895).
NS_ASSERTION(JSVERSION_DEFAULT == 0,
"We rely on all languages having 0 as a version default");
version = 0;
}
}
}
// If this isn't JavaScript, we don't know how to evaluate.
// XXX How and where should we deal with other scripting languages?
// See bug 255942 (https://bugzilla.mozilla.org/show_bug.cgi?id=255942).
if (!isJavaScript) {
// If we don't know the language, we don't know how to evaluate
if (typeID == nsIProgrammingLanguage::UNKNOWN) {
return NS_ERROR_NOT_AVAILABLE;
}
// If not from a chrome document (which is always trusted), we need some way
// of checking the language is "safe". Currently the only other language
// impl is Python, and that is *not* safe in untrusted code - so fixing
// this isn't a priority.!
// See also similar code in nsXULContentSink.cpp
if (typeID != nsIProgrammingLanguage::JAVASCRIPT &&
!nsContentUtils::IsChromeDoc(mDocument)) {
NS_WARNING("Untrusted language called from non-chrome - ignored");
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIContent> eltContent(do_QueryInterface(aElement));
if (eltContent)
eltContent->SetScriptTypeID(typeID);
else
NS_ERROR("Element is not nsIContent - can't set scripttype");
// Create a request object for this script
nsRefPtr<nsScriptLoadRequest> request = new nsScriptLoadRequest(aElement, aObserver, jsVersionString, hasE4XOption);
nsRefPtr<nsScriptLoadRequest> request = new nsScriptLoadRequest(aElement, aObserver, version);
NS_ENSURE_TRUE(request, NS_ERROR_OUT_OF_MEMORY);
// First check to see if this is an external script
@ -715,10 +758,20 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
nsIScriptGlobalObject *globalObject = mDocument->GetScriptGlobalObject();
NS_ENSURE_TRUE(globalObject, NS_ERROR_FAILURE);
// Get the script-type to be used by this element.
nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
NS_ASSERTION(scriptContent, "no content - what is default script-type?");
PRUint32 stid = scriptContent ? scriptContent->GetScriptTypeID() :
nsIProgrammingLanguage::JAVASCRIPT;
// and make sure we are setup for this type of script.
rv = globalObject->EnsureScriptEnvironment(stid);
if (NS_FAILED(rv))
return rv;
// Make sure context is a strong reference since we access it after
// we've executed a script, which may cause all other references to
// the context to go away.
nsCOMPtr<nsIScriptContext> context = globalObject->GetContext();
nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext(stid);
if (!context) {
return NS_ERROR_FAILURE;
}
@ -735,48 +788,38 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
PRBool oldProcessingScriptTag = context->GetProcessingScriptTag();
context->SetProcessingScriptTag(PR_TRUE);
JSContext *cx = (JSContext *)context->GetNativeContext();
uint32 options = ::JS_GetOptions(cx);
JSBool changed = (aRequest->mHasE4XOption ^ !!(options & JSOPTION_XML));
if (changed) {
::JS_SetOptions(cx,
aRequest->mHasE4XOption
? options | JSOPTION_XML
: options & ~JSOPTION_XML);
}
// Update our current script.
nsCOMPtr<nsIScriptElement> oldCurrent = mCurrentScript;
mCurrentScript = aRequest->mElement;
PRBool isUndefined;
rv = context->EvaluateString(aScript, globalObject->GetGlobalJSObject(),
mDocument->NodePrincipal(), url.get(),
aRequest->mLineNo, aRequest->mJSVersion, nsnull,
&isUndefined);
rv = context->EvaluateString(aScript,
globalObject->GetScriptGlobal(stid),
mDocument->NodePrincipal(), url.get(),
aRequest->mLineNo, aRequest->mJSVersion, nsnull,
&isUndefined);
// Put the old script back in case it wants to do anything else.
mCurrentScript = oldCurrent;
JSAutoRequest ar(cx);
if (NS_FAILED(rv)) {
::JS_ReportPendingException(cx);
}
if (changed) {
::JS_SetOptions(cx, options);
if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
JS_BeginRequest((JSContext *)context->GetNativeContext());
}
if (NS_FAILED(rv) && stid == nsIProgrammingLanguage::JAVASCRIPT)
::JS_ReportPendingException((JSContext *)context->GetNativeContext());
context->SetProcessingScriptTag(oldProcessingScriptTag);
nsCOMPtr<nsIXPCNativeCallContext> ncc;
nsContentUtils::XPConnect()->
GetCurrentNativeCallContext(getter_AddRefs(ncc));
if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
nsCOMPtr<nsIXPCNativeCallContext> ncc;
nsContentUtils::XPConnect()->
GetCurrentNativeCallContext(getter_AddRefs(ncc));
if (ncc) {
ncc->SetExceptionWasThrown(PR_FALSE);
if (ncc) {
ncc->SetExceptionWasThrown(PR_FALSE);
}
JS_EndRequest((JSContext *)context->GetNativeContext());
}
return rv;
}

Просмотреть файл

@ -79,6 +79,7 @@
#include "nsICachingChannel.h"
#include "nsContentUtils.h"
#include "nsEventDispatcher.h"
#include "nsDOMJSUtils.h"
#include "nsCOMArray.h"
#include "nsDOMClassInfo.h"

Просмотреть файл

@ -47,7 +47,6 @@ class nsIScriptContext;
class nsIDOMEventTarget;
class nsIDOMEventGroup;
class nsIAtom;
struct JSObject;
/*
* Event listener manager interface.
@ -102,6 +101,7 @@ public:
NS_IMETHOD AddScriptEventListener(nsISupports *aObject,
nsIAtom *aName,
const nsAString& aFunc,
PRUint32 aLanguage,
PRBool aDeferCompilation,
PRBool aPermitUntrustedEvents) = 0;
@ -116,7 +116,7 @@ public:
* @param the name of an event listener
*/
NS_IMETHOD RegisterScriptEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScopeObject,
nsISupports *aObject,
nsIAtom* aName) = 0;
@ -125,7 +125,7 @@ public:
* script object for a given event type.
* @param an event listener */
NS_IMETHOD CompileScriptEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScopeObject,
nsISupports *aObject,
nsIAtom* aName,
PRBool *aDidCompile) = 0;

Просмотреть файл

@ -70,6 +70,7 @@
#include "nsIJSEventListener.h"
#include "prmem.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptRuntime.h"
#include "nsLayoutAtoms.h"
#include "nsLayoutUtils.h"
#ifdef MOZ_XUL
@ -106,6 +107,8 @@
#include "nsIDOMEventGroup.h"
#include "nsContentCID.h"
#include "nsEventDispatcher.h"
#include "nsDOMJSUtils.h"
#include "nsDOMScriptObjectHolder.h"
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -1144,7 +1147,7 @@ nsEventListenerManager::FindJSEventListener(EventArrayType aType)
nsresult
nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScopeObject,
nsISupports *aObject,
nsIAtom* aName,
PRBool aIsString,
@ -1198,32 +1201,50 @@ NS_IMETHODIMP
nsEventListenerManager::AddScriptEventListener(nsISupports *aObject,
nsIAtom *aName,
const nsAString& aBody,
PRUint32 aLanguage,
PRBool aDeferCompilation,
PRBool aPermitUntrustedEvents)
{
NS_PRECONDITION(aLanguage != nsIProgrammingLanguage::UNKNOWN,
"Must know the language for the script event listener");
nsIScriptContext *context = nsnull;
JSContext* cx = nsnull;
// |aPermitUntrustedEvents| is set to False for chrome - events
// *generated* from an unknown source are not allowed.
// However, for script languages with no 'sandbox', we want to reject
// such scripts based on the source of their code, not just the source
// of the event.
if (aPermitUntrustedEvents &&
aLanguage != nsIProgrammingLanguage::JAVASCRIPT) {
NS_WARNING("Discarding non-JS event listener from untrusted source");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsINode> node(do_QueryInterface(aObject));
nsCOMPtr<nsIDocument> doc;
nsISupports *objiSupp = aObject;
JSObject *scope = nsnull;
nsCOMPtr<nsIScriptGlobalObject> global;
if (node) {
// Try to get context from doc
doc = node->GetOwnerDoc();
nsIScriptGlobalObject *global;
if (doc)
global = doc->GetScriptGlobalObject();
if (global) {
// This might be the first reference to this language in the global
// We must init the language before we attempt to fetch its context.
if (NS_FAILED(global->EnsureScriptEnvironment(aLanguage))) {
NS_WARNING("Failed to setup script environment for this language");
// but fall through and let the inevitable failure below handle it.
}
if (doc && (global = doc->GetScriptGlobalObject())) {
context = global->GetContext();
scope = global->GetGlobalJSObject();
context = global->GetScriptContext(aLanguage);
NS_ASSERTION(context, "Failed to get language context from global");
}
} else {
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aObject));
nsCOMPtr<nsIScriptGlobalObject> global;
if (win) {
NS_ASSERTION(win->IsInnerWindow(),
"Event listener added to outer window!");
@ -1236,12 +1257,25 @@ nsEventListenerManager::AddScriptEventListener(nsISupports *aObject,
global = do_QueryInterface(aObject);
}
if (global) {
context = global->GetContext();
scope = global->GetGlobalJSObject();
// As above - ensure the global is setup for the language.
if (NS_FAILED(global->EnsureScriptEnvironment(aLanguage))) {
NS_WARNING("Failed to setup script environment for this language");
// but fall through and let the inevitable failure below handle it.
}
context = global->GetScriptContext(aLanguage);
}
}
if (!context) {
NS_ASSERTION(aLanguage == nsIProgrammingLanguage::JAVASCRIPT,
"Need a multi-language stack?!?!?");
// I've only ever seen the above fire when something else has gone wrong -
// in normal processing, languages other than JS should not be able to get
// here, as these languages are only called via nsIScriptContext
// OTOH, maybe using JS will do here - all we need is the global - try and
// keep going...
JSContext* cx = nsnull;
// Get JSContext from stack, or use the safe context (and hidden
// window global) if no JS is running.
nsCOMPtr<nsIThreadJSContextStack> stack =
@ -1257,48 +1291,32 @@ nsEventListenerManager::AddScriptEventListener(nsISupports *aObject,
context = nsJSUtils::GetDynamicScriptContext(cx);
NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
scope = ::JS_GetGlobalObject(cx);
} else if (!scope) {
global = context->GetGlobalObject();
// but if the language is *not* js , we now have the wrong context.
context = global->GetScriptContext(aLanguage);
NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
}
if (!global) {
NS_ERROR("Context reachable, but no scope reachable in "
"AddScriptEventListener()!");
return NS_ERROR_NOT_AVAILABLE;
}
void *scope = global->GetScriptGlobal(aLanguage);
nsresult rv;
if (!aDeferCompilation) {
JSContext *cx = (JSContext *)context->GetNativeContext();
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = nsContentUtils::XPConnect()->WrapNative(cx, scope, aObject,
NS_GET_IID(nsISupports),
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
// Since JSEventListeners only have a raw nsISupports pointer, it's
// important that it point to the same object that the WrappedNative wraps.
// (In the case of a tearoff, the tearoff will not persist).
nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(holder);
NS_ASSERTION(wrapper, "wrapper must impl nsIXPConnectWrappedNative");
objiSupp = wrapper->Native();
JSObject *scriptObject = nsnull;
rv = holder->GetJSObject(&scriptObject);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
do_QueryInterface(aObject);
void *handler = nsnull;
nsScriptObjectHolder handler(context);
PRBool done = PR_FALSE;
if (handlerOwner) {
rv = handlerOwner->GetCompiledEventHandler(aName, &handler);
rv = handlerOwner->GetCompiledEventHandler(aName, handler);
if (NS_SUCCEEDED(rv) && handler) {
rv = context->BindCompiledEventHandler(scriptObject, aName, handler);
rv = context->BindCompiledEventHandler(aObject, scope, aName, handler);
if (NS_FAILED(rv))
return rv;
done = PR_TRUE;
@ -1319,8 +1337,8 @@ nsEventListenerManager::AddScriptEventListener(nsISupports *aObject,
if (handlerOwner) {
// Always let the handler owner compile the event handler, as
// it may want to use a special context or scope object.
rv = handlerOwner->CompileEventHandler(context, scriptObject, aName,
aBody, url.get(), lineNo, &handler);
rv = handlerOwner->CompileEventHandler(context, aObject, aName,
aBody, url.get(), lineNo, handler);
}
else {
PRInt32 nameSpace = kNameSpaceID_Unknown;
@ -1335,13 +1353,19 @@ nsEventListenerManager::AddScriptEventListener(nsISupports *aObject,
if (root)
nameSpace = root->GetNameSpaceID();
}
const char *eventName = nsContentUtils::GetEventArgName(nameSpace);
PRUint32 argCount;
const char **argNames;
nsContentUtils::GetEventArgNames(nameSpace, aName, &argCount,
&argNames);
rv = context->CompileEventHandler(scriptObject, aName, eventName,
rv = context->CompileEventHandler(aName, argCount, argNames,
aBody,
url.get(), lineNo,
PR_FALSE,
nsnull);
handler);
NS_ENSURE_SUCCESS(rv, rv);
// And bind it.
rv = context->BindCompiledEventHandler(aObject, scope,
aName, handler);
}
if (NS_FAILED(rv)) return rv;
}
@ -1383,7 +1407,7 @@ nsEventListenerManager::sAddListenerID = JSVAL_VOID;
NS_IMETHODIMP
nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScope,
nsISupports *aObject,
nsIAtom *aName)
{
@ -1402,25 +1426,6 @@ nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext,
if (NS_FAILED(rv = stack->Peek(&cx)))
return rv;
JSContext *current_cx = (JSContext *)aContext->GetNativeContext();
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = nsContentUtils::XPConnect()->
WrapNative(current_cx, aScopeObject, aObject, NS_GET_IID(nsISupports),
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
// Since JSEventListeners only have a raw nsISupports pointer, it's
// important that it point to the same object that the WrappedNative wraps.
// (In the case of a tearoff, the tearoff will not persist).
nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(holder);
NS_ASSERTION(wrapper, "wrapper must impl nsIXPConnectWrappedNative");
JSObject *jsobj = nsnull;
rv = holder->GetJSObject(&jsobj);
NS_ENSURE_SUCCESS(rv, rv);
if (cx) {
if (sAddListenerID == JSVAL_VOID) {
JSAutoRequest ar(cx);
@ -1428,26 +1433,41 @@ nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext,
STRING_TO_JSVAL(::JS_InternString(cx, "addEventListener"));
}
rv = nsContentUtils::GetSecurityManager()->
CheckPropertyAccess(cx, jsobj,
"EventTarget",
sAddListenerID,
nsIXPCSecurityManager::ACCESS_SET_PROPERTY);
if (NS_FAILED(rv)) {
// XXX set pending exception on the native call context?
return rv;
if (aContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = nsContentUtils::XPConnect()->
WrapNative(cx, (JSObject *)aScope, aObject, NS_GET_IID(nsISupports),
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
JSObject *jsobj = nsnull;
rv = holder->GetJSObject(&jsobj);
NS_ENSURE_SUCCESS(rv, rv);
rv = nsContentUtils::GetSecurityManager()->
CheckPropertyAccess(cx, jsobj,
"EventTarget",
sAddListenerID,
nsIXPCSecurityManager::ACCESS_SET_PROPERTY);
if (NS_FAILED(rv)) {
// XXX set pending exception on the native call context?
return rv;
}
} else {
NS_WARNING("Skipping CheckPropertyAccess for non JS language");
}
}
// Untrusted events are always permitted for non-chrome script
// handlers.
return SetJSEventListener(aContext, aScopeObject, wrapper->Native(), aName,
return SetJSEventListener(aContext, aScope, aObject, aName,
PR_FALSE, !nsContentUtils::IsCallerChrome());
}
nsresult
nsEventListenerManager::CompileScriptEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScope,
nsISupports *aObject,
nsIAtom *aName,
PRBool *aDidCompile)
@ -1470,7 +1490,7 @@ nsEventListenerManager::CompileScriptEventListener(nsIScriptContext *aContext,
}
if (ls->mHandlerIsString & subType) {
rv = CompileEventHandlerInternal(aContext, aScopeObject, aObject, aName,
rv = CompileEventHandlerInternal(aContext, aScope, aObject, aName,
ls, /*XXX fixme*/nsnull, subType);
}
@ -1486,7 +1506,7 @@ nsEventListenerManager::CompileScriptEventListener(nsIScriptContext *aContext,
nsresult
nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScope,
nsISupports *aObject,
nsIAtom *aName,
nsListenerStruct *aListenerStruct,
@ -1495,27 +1515,16 @@ nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
{
nsresult result = NS_OK;
JSContext *cx = (JSContext *)aContext->GetNativeContext();
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
result = nsContentUtils::XPConnect()->WrapNative(cx, aScopeObject, aObject,
NS_GET_IID(nsISupports),
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(result, result);
JSObject *jsobj = nsnull;
result = holder->GetJSObject(&jsobj);
NS_ENSURE_SUCCESS(result, result);
nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
do_QueryInterface(aObject);
void* handler = nsnull;
nsScriptObjectHolder handler(aContext);
if (handlerOwner) {
result = handlerOwner->GetCompiledEventHandler(aName, &handler);
result = handlerOwner->GetCompiledEventHandler(aName,
handler);
if (NS_SUCCEEDED(result) && handler) {
result = aContext->BindCompiledEventHandler(jsobj, aName, handler);
// XXXmarkh - why do we bind here, but not after compilation below?
result = aContext->BindCompiledEventHandler(aObject, aScope, aName, handler);
aListenerStruct->mHandlerIsString &= ~aSubType;
}
}
@ -1568,20 +1577,27 @@ nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
// Always let the handler owner compile the event
// handler, as it may want to use a special
// context or scope object.
result = handlerOwner->CompileEventHandler(aContext, jsobj, aName,
result = handlerOwner->CompileEventHandler(aContext, aObject, aName,
handlerBody,
url.get(), lineNo,
&handler);
handler);
}
else {
const char *eventName =
nsContentUtils::GetEventArgName(content->GetNameSpaceID());
PRUint32 argCount;
const char **argNames;
nsContentUtils::GetEventArgNames(content->GetNameSpaceID(), aName,
&argCount, &argNames);
result = aContext->CompileEventHandler(jsobj, aName, eventName,
result = aContext->CompileEventHandler(aName,
argCount, argNames,
handlerBody,
url.get(), lineNo,
(handlerOwner != nsnull),
&handler);
handler);
NS_ENSURE_SUCCESS(result, result);
// And bind it.
result = aContext->BindCompiledEventHandler(aObject, aScope,
aName, handler);
NS_ENSURE_SUCCESS(result, result);
}
if (NS_SUCCEEDED(result)) {

Просмотреть файл

@ -141,15 +141,16 @@ public:
NS_IMETHOD AddScriptEventListener(nsISupports *aObject,
nsIAtom *aName,
const nsAString& aFunc,
PRUint32 aLanguage,
PRBool aDeferCompilation,
PRBool aPermitUntrustedEvents);
NS_IMETHOD RegisterScriptEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScopeObject,
nsISupports *aObject,
nsIAtom* aName);
NS_IMETHOD RemoveScriptEventListener(nsIAtom *aName);
NS_IMETHOD CompileScriptEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScopeObject,
nsISupports *aObject,
nsIAtom* aName, PRBool *aDidCompile);
@ -210,7 +211,7 @@ protected:
PRUint32 aSubType,
PRUint32 aPhaseFlags);
nsresult CompileEventHandlerInternal(nsIScriptContext *aContext,
JSObject *aScopeObject,
void *aScopeObject,
nsISupports *aObject,
nsIAtom *aName,
nsListenerStruct *aListenerStruct,
@ -218,7 +219,8 @@ protected:
PRUint32 aSubType);
nsListenerStruct* FindJSEventListener(EventArrayType aType);
nsresult SetJSEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject, nsISupports *aObject,
void *aScopeGlobal,
nsISupports *aObject,
nsIAtom* aName, PRBool aIsString,
PRBool aPermitUntrustedEvents);
nsresult AddEventListener(nsIDOMEventListener *aListener,

Просмотреть файл

@ -60,7 +60,8 @@
#include "nsIDOMDocument.h"
#include "nsEventDispatcher.h"
#include "nsContentErrors.h"
#include "nsIArray.h"
#include "nsDOMJSUtils.h"
//
// Helper class used to support <SCRIPT FOR=object EVENT=handler ...>
@ -229,9 +230,10 @@ nsHTMLScriptEventHandler::Invoke(nsISupports *aTargetObject,
// wrap the target object...
JSContext *cx = (JSContext *)scriptContext->GetNativeContext();
JSObject *scriptObject = nsnull;
JSObject *scope = sgo->GetGlobalJSObject();
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsContentUtils::XPConnect()->WrapNative(cx, sgo->GetGlobalJSObject(),
nsContentUtils::XPConnect()->WrapNative(cx, scope,
aTargetObject,
NS_GET_IID(nsISupports),
getter_AddRefs(holder));
@ -299,10 +301,17 @@ nsHTMLScriptEventHandler::Invoke(nsISupports *aTargetObject,
return rv;
}
// Create an nsIArray for the args (the JS context will efficiently
// re-fetch the jsvals from this object)
nsCOMPtr<nsIArray> argarray;
rv = NS_CreateJSArgv(cx, aArgCount, (jsval *)aArgs, getter_AddRefs(argarray));
if (NS_FAILED(rv))
return rv;
// Invoke the event handler script...
jsval dummy;
return scriptContext->CallEventHandler(scriptObject, (JSObject *)funcObject,
aArgCount, (jsval *)aArgs, &dummy);
nsCOMPtr<nsIVariant> ret;
return scriptContext->CallEventHandler(aTargetObject, scope, funcObject,
argarray, getter_AddRefs(ret));
}

Просмотреть файл

@ -869,6 +869,9 @@ nsXBLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
return NS_ERROR_OUT_OF_MEMORY;
prototype->mNodeInfo = aNodeInfo;
// XXX - we need to do exactly what the XUL content-sink does (eg,
// look for 'type', 'version' etc attributes)
prototype->mScriptTypeID = nsIProgrammingLanguage::JAVASCRIPT;
AddAttributesToXULPrototype(aAtts, aAttsCount, prototype);

Просмотреть файл

@ -43,6 +43,7 @@
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsIScriptRuntime.h"
#include "nsIDOMScriptObjectFactory.h"
#include "jsapi.h"
#include "nsIURI.h"
@ -52,7 +53,8 @@
#include "nsIPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsContentUtils.h"
#include "nsDOMJSUtils.h"
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
// An XBLDocumentInfo object has a special context associated with it which we can use to pre-compile
@ -67,14 +69,16 @@ public:
NS_DECL_ISUPPORTS
// nsIScriptGlobalObject methods
virtual void SetContext(nsIScriptContext *aContext);
virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID);
virtual nsresult SetScriptContext(PRUint32 lang_id, nsIScriptContext *aContext);
virtual nsIScriptContext *GetContext();
virtual void SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner);
virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner();
virtual JSObject *GetGlobalJSObject();
virtual void OnFinalize(JSObject *aObject);
virtual void OnFinalize(PRUint32 aLangID, void *aScriptGlobal);
virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
virtual nsresult SetNewArguments(PRUint32 aArgc, void* aArgv);
virtual nsresult SetNewArguments(nsIArray *aArguments);
// nsIScriptObjectPrincipal methods
virtual nsIPrincipal* GetPrincipal();
@ -85,6 +89,10 @@ public:
protected:
virtual ~nsXBLDocGlobalObject();
void SetContext(nsIScriptContext *aContext);
nsIScriptContext *GetScriptContext(PRUint32 language);
void *GetScriptGlobal(PRUint32 language);
nsCOMPtr<nsIScriptContext> mScriptContext;
JSObject *mJSObject; // XXX JS language rabies bigotry badness
@ -155,7 +163,7 @@ nsXBLDocGlobalObject_finalize(JSContext *cx, JSObject *obj)
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
if (sgo)
sgo->OnFinalize(obj);
sgo->OnFinalize(nsIProgrammingLanguage::JAVASCRIPT, obj);
// The addref was part of JSObject construction
NS_RELEASE(nativeThis);
@ -229,15 +237,92 @@ XBL_ProtoErrorReporter(JSContext *cx,
//
void
nsXBLDocGlobalObject::SetContext(nsIScriptContext *aContext)
nsXBLDocGlobalObject::SetContext(nsIScriptContext *aScriptContext)
{
mScriptContext = aContext;
if (mScriptContext) {
JSContext* cx = (JSContext *)mScriptContext->GetNativeContext();
JS_SetErrorReporter(cx, XBL_ProtoErrorReporter);
if (!aScriptContext) {
mScriptContext = nsnull;
return;
}
NS_ASSERTION(aScriptContext->GetScriptTypeID() ==
nsIProgrammingLanguage::JAVASCRIPT,
"xbl is not multi-language");
aScriptContext->WillInitializeContext();
// NOTE: We init this context with a NULL global, so we automatically
// hook up to the existing nsIScriptGlobalObject global setup by
// nsGlobalWindow.
nsresult rv;
rv = aScriptContext->InitContext(nsnull);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Script Language's InitContext failed");
aScriptContext->DidInitializeContext();
// and we set up our global manually
mScriptContext = aScriptContext;
}
nsresult
nsXBLDocGlobalObject::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aContext)
{
NS_ASSERTION(lang_id == nsIProgrammingLanguage::JAVASCRIPT, "Only JS allowed!");
SetContext(aContext);
return NS_OK;
}
nsIScriptContext *
nsXBLDocGlobalObject::GetScriptContext(PRUint32 language)
{
// This impl still assumes JS
NS_ENSURE_TRUE(language==nsIProgrammingLanguage::JAVASCRIPT, nsnull);
return GetContext();
}
void *
nsXBLDocGlobalObject::GetScriptGlobal(PRUint32 language)
{
// This impl still assumes JS
NS_ENSURE_TRUE(language==nsIProgrammingLanguage::JAVASCRIPT, nsnull);
return GetGlobalJSObject();
}
nsresult
nsXBLDocGlobalObject::EnsureScriptEnvironment(PRUint32 aLangID)
{
if (aLangID != nsIProgrammingLanguage::JAVASCRIPT) {
NS_WARNING("XBL still JS only");
return NS_ERROR_INVALID_ARG;
}
if (mScriptContext)
return NS_OK; // already initialized for this lang
nsCOMPtr<nsIDOMScriptObjectFactory> factory = do_GetService(kDOMScriptObjectFactoryCID);
NS_ENSURE_TRUE(factory, nsnull);
nsresult rv;
nsCOMPtr<nsIScriptRuntime> scriptRuntime;
rv = NS_GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRuntime));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIScriptContext> newCtx;
rv = scriptRuntime->CreateContext(getter_AddRefs(newCtx));
NS_ENSURE_SUCCESS(rv, rv);
rv = SetScriptContext(aLangID, newCtx);
JSContext *cx = (JSContext *)mScriptContext->GetNativeContext();
JSAutoRequest ar(cx);
// nsJSEnvironment set the error reporter to NS_ScriptErrorReporter so
// we must apparently override that with our own (although it isn't clear
// why - see bug 339647)
JS_SetErrorReporter(cx, XBL_ProtoErrorReporter);
mJSObject = ::JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
if (!mJSObject)
return nsnull;
::JS_SetGlobalObject(cx, mJSObject);
// Add an owning reference from JS back to us. This'll be
// released when the JSObject is finalized.
::JS_SetPrivate(cx, mJSObject, this);
NS_ADDREF(this);
return NS_OK;
}
nsIScriptContext *
nsXBLDocGlobalObject::GetContext()
@ -245,48 +330,27 @@ nsXBLDocGlobalObject::GetContext()
// This whole fragile mess is predicated on the fact that
// GetContext() will be called before GetScriptObject() is.
if (! mScriptContext) {
nsCOMPtr<nsIDOMScriptObjectFactory> factory = do_GetService(kDOMScriptObjectFactoryCID);
NS_ENSURE_TRUE(factory, nsnull);
nsresult rv = factory->NewScriptContext(nsnull, getter_AddRefs(mScriptContext));
if (NS_FAILED(rv))
return nsnull;
JSContext *cx = (JSContext *)mScriptContext->GetNativeContext();
JSAutoRequest ar(cx);
JS_SetErrorReporter(cx, XBL_ProtoErrorReporter);
mJSObject = ::JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
if (!mJSObject)
return nsnull;
::JS_SetGlobalObject(cx, mJSObject);
// Add an owning reference from JS back to us. This'll be
// released when the JSObject is finalized.
::JS_SetPrivate(cx, mJSObject, this);
NS_ADDREF(this);
nsresult rv = EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT);
// JS is builtin so we make noise if it fails to initialize.
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to setup JS!?");
NS_ENSURE_SUCCESS(rv, nsnull);
NS_ASSERTION(mScriptContext, "Failed to find a script context!?");
}
return mScriptContext;
}
void
nsXBLDocGlobalObject::SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner)
{
mGlobalObjectOwner = aOwner; // weak reference
}
nsIScriptGlobalObjectOwner *
nsXBLDocGlobalObject::GetGlobalObjectOwner()
{
return mGlobalObjectOwner;
}
JSObject *
nsXBLDocGlobalObject::GetGlobalJSObject()
{
@ -296,17 +360,21 @@ nsXBLDocGlobalObject::GetGlobalJSObject()
if (!mScriptContext)
return nsnull;
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
mScriptContext->GetNativeContext());
JSContext* cx = NS_STATIC_CAST(JSContext*,
mScriptContext->GetNativeContext());
if (!cx)
return nsnull;
return ::JS_GetGlobalObject(cx);
JSObject *ret = ::JS_GetGlobalObject(cx);
NS_ASSERTION(mJSObject == ret, "How did this magic switch happen?");
return ret;
}
void
nsXBLDocGlobalObject::OnFinalize(JSObject *aObject)
nsXBLDocGlobalObject::OnFinalize(PRUint32 aLangID, void *aObject)
{
NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
"Only JS supported");
NS_ASSERTION(aObject == mJSObject, "Wrong object finalized!");
mJSObject = nsnull;
@ -319,7 +387,7 @@ nsXBLDocGlobalObject::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
}
nsresult
nsXBLDocGlobalObject::SetNewArguments(PRUint32 aArgc, void* aArgv)
nsXBLDocGlobalObject::SetNewArguments(nsIArray *aArguments)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
@ -382,7 +450,8 @@ nsXBLDocumentInfo::~nsXBLDocumentInfo()
{
/* destructor code */
if (mGlobalObject) {
mGlobalObject->SetContext(nsnull); // remove circular reference
// remove circular reference
mGlobalObject->SetScriptContext(nsIProgrammingLanguage::JAVASCRIPT, nsnull);
mGlobalObject->SetGlobalObjectOwner(nsnull); // just in case
}
delete mBindingTable;

Просмотреть файл

@ -102,9 +102,8 @@ nsXBLProtoImplField::InstallMember(nsIScriptContext* aContext,
return NS_OK; // nothing to do.
JSContext* cx = (JSContext*) aContext->GetNativeContext();
JSObject * scriptObject = (JSObject *) aScriptObject;
NS_ASSERTION(scriptObject, "uh-oh, script Object should NOT be null or bad things will happen");
if (!scriptObject)
NS_ASSERTION(aScriptObject, "uh-oh, script Object should NOT be null or bad things will happen");
if (!aScriptObject)
return NS_ERROR_FAILURE;
nsCAutoString bindingURI(aClassStr);
@ -126,7 +125,7 @@ nsXBLProtoImplField::InstallMember(nsIScriptContext* aContext,
nsCOMPtr<nsIScriptContext> context = aContext;
rv = context->EvaluateStringWithValue(nsDependentString(mFieldText,
mFieldTextLength),
scriptObject,
aScriptObject,
nsnull, bindingURI.get(),
mLineNumber, nsnull,
(void*) &result, &undefined);
@ -137,8 +136,9 @@ nsXBLProtoImplField::InstallMember(nsIScriptContext* aContext,
// Define the evaluated result as a JS property
nsDependentString name(mName);
JSAutoRequest ar(cx);
if (!::JS_DefineUCProperty(cx, scriptObject, NS_REINTERPRET_CAST(const jschar*, mName),
name.Length(), result, nsnull, nsnull, mJSAttributes))
if (!::JS_DefineUCProperty(cx, NS_STATIC_CAST(JSObject *, aScriptObject),
NS_REINTERPRET_CAST(const jschar*, mName),
name.Length(), result, nsnull, nsnull, mJSAttributes))
return NS_ERROR_OUT_OF_MEMORY;
}

Просмотреть файл

@ -85,6 +85,7 @@
#include "nsXBLEventHandler.h"
#include "nsHTMLAtoms.h"
#include "nsEventDispatcher.h"
#include "nsDOMScriptObjectHolder.h"
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -402,8 +403,9 @@ nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventReceiver* aReceiver,
onEvent += str;
nsCOMPtr<nsIAtom> onEventAtom = do_GetAtom(onEvent);
void* handler = nsnull;
// Compile the event handler.
PRUint32 stID = nsIProgrammingLanguage::JAVASCRIPT;
// Compile the handler and bind it to the element.
nsCOMPtr<nsIScriptGlobalObject> boundGlobal;
nsCOMPtr<nsPIWindowRoot> winRoot(do_QueryInterface(aReceiver));
@ -451,32 +453,25 @@ nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventReceiver* aReceiver,
if (!boundGlobal)
return NS_OK;
nsIScriptContext *boundContext = boundGlobal->GetContext();
nsIScriptContext *boundContext = boundGlobal->GetScriptContext(stID);
if (!boundContext) return NS_OK;
JSObject* scriptObject = nsnull;
// strong ref to a GC root we'll need to protect scriptObject in the case
// where it is not the global object (!winRoot).
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
nsScriptObjectHolder handler(boundContext);
nsISupports *scriptTarget;
if (winRoot) {
scriptObject = boundGlobal->GetGlobalJSObject();
scriptTarget = boundGlobal;
} else {
JSObject *global = boundGlobal->GetGlobalJSObject();
JSContext *cx = (JSContext *)boundContext->GetNativeContext();
// XXX: Don't use the global object!
rv = nsContentUtils::XPConnect()->WrapNative(cx, global, aReceiver,
NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
rv = wrapper->GetJSObject(&scriptObject);
NS_ENSURE_SUCCESS(rv, rv);
scriptTarget = aReceiver;
}
// XXX - apparently we should not be using the global as the scope - what
// should we use? See bug 339649, which is trying to find out!
void *scope = boundGlobal->GetScriptGlobal(stID);
const char *eventName = nsContentUtils::GetEventArgName(kNameSpaceID_XBL);
PRUint32 argCount;
const char **argNames;
nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, onEventAtom, &argCount,
&argNames);
nsDependentString handlerText(mHandlerText);
if (handlerText.IsEmpty())
@ -485,21 +480,20 @@ nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventReceiver* aReceiver,
nsCAutoString bindingURI;
mPrototypeBinding->DocURI()->GetSpec(bindingURI);
rv = boundContext->CompileEventHandler(scriptObject, onEventAtom, eventName,
rv = boundContext->CompileEventHandler(onEventAtom, argCount, argNames,
handlerText, bindingURI.get(),
mLineNumber, PR_TRUE, &handler);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoGCRoot root(&handler, &rv);
mLineNumber, handler);
NS_ENSURE_SUCCESS(rv, rv);
// Temporarily bind it to the bound element
boundContext->BindCompiledEventHandler(scriptObject, onEventAtom, handler);
rv = boundContext->BindCompiledEventHandler(scriptTarget, scope,
onEventAtom, handler);
NS_ENSURE_SUCCESS(rv, rv);
// Execute it.
nsCOMPtr<nsIDOMEventListener> eventListener;
NS_NewJSEventListener(boundContext, boundGlobal->GetGlobalJSObject(),
aReceiver, getter_AddRefs(eventListener));
NS_NewJSEventListener(boundContext, scope,
scriptTarget, getter_AddRefs(eventListener));
nsCOMPtr<nsIJSEventListener> jsListener(do_QueryInterface(eventListener));
jsListener->SetEventName(onEventAtom);

Просмотреть файл

@ -26,6 +26,7 @@
* Peter Annema <disttsc@bart.nl>
* Brendan Eich <brendan@mozilla.org>
* Mike Shaver <shaver@mozilla.org>
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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"),
@ -55,7 +56,6 @@
*/
#include "jsapi.h" // for JS_AddNamedRoot and JS_RemoveRootRT
#include "jsxdrapi.h"
#include "nsCOMPtr.h"
#include "nsDOMCID.h"
#include "nsDOMError.h"
@ -98,6 +98,7 @@
#include "nsIRDFNode.h"
#include "nsIRDFService.h"
#include "nsIScriptContext.h"
#include "nsIScriptRuntime.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptGlobalObjectOwner.h"
#include "nsIServiceManager.h"
@ -296,6 +297,10 @@ nsXULElement::Create(nsXULPrototypeElement* aPrototype, nsINodeInfo *aNodeInfo,
element->mPrototype = aPrototype;
NS_ASSERTION(aPrototype->mScriptTypeID != nsIProgrammingLanguage::UNKNOWN,
"Need to know the language!");
element->SetScriptTypeID(aPrototype->mScriptTypeID);
if (aIsScriptable) {
// Check each attribute on the prototype to see if we need to do
// any additional processing and hookup that would otherwise be
@ -438,11 +443,18 @@ nsXULElement::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep,
nsRefPtr<nsXULElement> element;
if (mPrototype) {
element = nsXULElement::Create(mPrototype, aNodeInfo, PR_TRUE);
NS_ASSERTION(GetScriptTypeID() == mPrototype->mScriptTypeID,
"Didn't get the default language from proto?");
fakeBeingInDocument = IsInDoc();
}
else {
element = new nsXULElement(aNodeInfo);
if (element) {
// If created from a prototype, we will already have the script
// language specified by the proto - otherwise copy it directly
element->SetScriptTypeID(GetScriptTypeID());
}
}
if (!element) {
@ -607,16 +619,17 @@ nsXULElement::IsFocusable(PRInt32 *aTabIndex)
// nsIScriptEventHandlerOwner interface
nsresult
nsXULElement::GetCompiledEventHandler(nsIAtom *aName, void** aHandler)
nsXULElement::GetCompiledEventHandler(nsIAtom *aName,
nsScriptObjectHolder &aHandler)
{
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheTests);
*aHandler = nsnull;
aHandler.drop();
nsXULPrototypeAttribute *attr =
FindPrototypeAttribute(kNameSpaceID_None, aName);
if (attr) {
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheHits);
*aHandler = attr->mEventHandler;
aHandler.set(attr->mEventHandler);
}
return NS_OK;
@ -624,15 +637,14 @@ nsXULElement::GetCompiledEventHandler(nsIAtom *aName, void** aHandler)
nsresult
nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsISupports* aTarget,
nsIAtom *aName,
const nsAString& aBody,
const char* aURL,
PRUint32 aLineNo,
void** aHandler)
nsScriptObjectHolder &aHandler)
{
nsresult rv;
JSObject* scopeObject;
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
@ -642,9 +654,6 @@ nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
nsIScriptContext *context;
if (mPrototype && xuldoc) {
// It'll be shared among the instances of the prototype.
// Use null for the scope object when precompiling shared
// prototype scripts.
scopeObject = nsnull;
// Use the prototype document's special context. Because
// scopeObject is null, the JS engine has no other source of
@ -663,28 +672,37 @@ nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
nsIScriptGlobalObject* global = globalOwner->GetScriptGlobalObject();
NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
context = global->GetContext();
context = global->GetScriptContext(aContext->GetScriptTypeID());
// It could be possible the language has been setup on aContext but
// not on the global - we don't demand-create language contexts on the
// nsGlobalWindow
NS_ASSERTION(context,
"Failed to get a language context from the global!?");
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
}
else {
// We don't have a prototype; do a one-off compile.
// We don't have a prototype, so the passed context is ok.
NS_ASSERTION(aTarget != nsnull, "no prototype and no target?!");
scopeObject = NS_REINTERPRET_CAST(JSObject*, aTarget);
context = aContext;
}
// Compile the event handler
const char *eventName = nsContentUtils::GetEventArgName(kNameSpaceID_XUL);
rv = context->CompileEventHandler(scopeObject, aName, eventName, aBody,
aURL, aLineNo, !scopeObject,
aHandler);
PRUint32 argCount;
const char **argNames;
nsContentUtils::GetEventArgNames(kNameSpaceID_XUL, aName, &argCount,
&argNames);
rv = context->CompileEventHandler(aName, argCount, argNames,
aBody, aURL, aLineNo, aHandler);
if (NS_FAILED(rv)) return rv;
if (! scopeObject) {
if (mPrototype && xuldoc) {
// If it's a shared handler, we need to bind the shared
// function object to the real target.
// XXX: Shouldn't this use context and not aContext?
rv = aContext->BindCompiledEventHandler(aTarget, aName, *aHandler);
// XXXmarkh - is GetNativeGlobal() the correct scope?
rv = aContext->BindCompiledEventHandler(aTarget, aContext->GetNativeGlobal(),
aName, aHandler);
if (NS_FAILED(rv)) return rv;
}
@ -692,19 +710,11 @@ nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
FindPrototypeAttribute(kNameSpaceID_None, aName);
if (attr) {
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
attr->mEventHandler = *aHandler;
// take a copy of the event handler, and tell the language about it.
attr->mEventHandler = (void *)aHandler;
if (attr->mEventHandler) {
JSContext *cx = (JSContext*) context->GetNativeContext();
if (!cx)
return NS_ERROR_UNEXPECTED;
rv = nsContentUtils::AddJSGCRoot(&attr->mEventHandler,
"nsXULPrototypeAttribute::mEventHandler");
if (NS_FAILED(rv)) {
attr->mEventHandler = nsnull;
return rv;
}
rv = aContext->HoldScriptObject(attr->mEventHandler);
if (NS_FAILED(rv)) return rv;
}
}
@ -726,7 +736,7 @@ nsXULElement::AddListenerFor(const nsAttrName& aName,
if (aCompileEventHandlers && IsEventHandler(attr)) {
nsAutoString value;
GetAttr(kNameSpaceID_None, attr, value);
AddScriptEventListener(attr, value);
AddScriptEventListener(attr, value, PR_TRUE);
}
}
}
@ -869,7 +879,7 @@ nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// XXXbz why do we have attributes depending on the current document?
// Shouldn't they depend on the owner document? Or is this code just
// misplaced, basically?
PRInt32 count = mAttrsAndChildren.AttrCount();
PRBool haveLocalAttributes = (count > 0);
PRInt32 i;
@ -879,6 +889,11 @@ nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
}
if (mPrototype) {
// If we have a prototype, the node we are binding to should
// have the same script-type - otherwise we will compile the
// event handlers incorrectly.
NS_ASSERTION(mPrototype->mScriptTypeID == GetScriptTypeID(),
"Prototype and node confused about default language?");
PRInt32 count = mPrototype->mNumAttributes;
for (i = 0; i < count; i++) {
nsXULPrototypeAttribute *protoattr =
@ -1181,7 +1196,14 @@ nsXULElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
// the attribute isn't set yet.
MaybeAddPopupListener(aName);
if (IsEventHandler(aName) && aValue) {
AddScriptEventListener(aName, *aValue);
// If mPrototype->mScriptTypeID != GetScriptTypeID(), it means
// we are resolving an overlay with a different default script
// language. We can't defer compilation of those handlers as
// we will have lost the script language (storing it on each
// nsXULPrototypeAttribute is expensive!)
PRBool defer = mPrototype == nsnull ||
mPrototype->mScriptTypeID == GetScriptTypeID();
AddScriptEventListener(aName, *aValue, defer);
}
// Hide chrome if needed
@ -2455,8 +2477,17 @@ nsXULElement::BoolAttrIsTrue(nsIAtom* aName)
nsXULPrototypeAttribute::~nsXULPrototypeAttribute()
{
MOZ_COUNT_DTOR(nsXULPrototypeAttribute);
if (mEventHandler)
nsContentUtils::RemoveJSGCRoot(&mEventHandler);
NS_ASSERTION(!mEventHandler, "Finalize not called - language object leak!");
}
void
nsXULPrototypeAttribute::Finalize(PRUint32 aLangID)
{
if (mEventHandler) {
if (NS_FAILED(NS_DropScriptObject(aLangID, mEventHandler)))
NS_ERROR("Failed to drop script object");
mEventHandler = nsnull;
}
}
@ -2467,7 +2498,7 @@ nsXULPrototypeAttribute::~nsXULPrototypeAttribute()
nsresult
nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
const nsCOMArray<nsINodeInfo> *aNodeInfos)
{
nsresult rv;
@ -2475,6 +2506,9 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
// Write basic prototype data
rv = aStream->Write32(mType);
// Write script language
rv |= aStream->Write32(mScriptTypeID);
// Write Node Info
PRInt32 index = aNodeInfos->IndexOf(mNodeInfo);
NS_ASSERTION(index >= 0, "unknown nsINodeInfo index");
@ -2512,27 +2546,29 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
switch (child->mType) {
case eType_Element:
case eType_Text:
rv |= child->Serialize(aStream, aContext, aNodeInfos);
rv |= child->Serialize(aStream, aGlobal, aNodeInfos);
break;
case eType_Script:
rv |= aStream->Write32(child->mType);
nsXULPrototypeScript* script = NS_STATIC_CAST(nsXULPrototypeScript*, child);
rv |= aStream->Write32(script->mScriptObject.getScriptTypeID());
rv |= aStream->Write8(script->mOutOfLine);
if (! script->mOutOfLine) {
rv |= script->Serialize(aStream, aContext, aNodeInfos);
rv |= script->Serialize(aStream, aGlobal, aNodeInfos);
} else {
rv |= aStream->WriteCompoundObject(script->mSrcURI,
NS_GET_IID(nsIURI),
PR_TRUE);
if (script->mJSObject) {
if (script->mScriptObject) {
// This may return NS_OK without muxing script->mSrcURI's
// data into the FastLoad file, in the case where that
// muxed document is already there (written by a prior
// session, or by an earlier FastLoad episode during this
// session).
rv |= script->SerializeOutOfLine(aStream, aContext);
rv |= script->SerializeOutOfLine(aStream, aGlobal);
}
}
break;
@ -2544,16 +2580,18 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
nsresult
nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
nsIURI* aDocumentURI,
const nsCOMArray<nsINodeInfo> *aNodeInfos)
{
NS_PRECONDITION(aNodeInfos, "missing nodeinfo array");
nsresult rv;
// Read script language
rv = aStream->Read32(&mScriptTypeID);
// Read Node Info
PRUint32 number;
rv = aStream->Read32(&number);
rv |= aStream->Read32(&number);
mNodeInfo = aNodeInfos->SafeObjectAt(number);
if (!mNodeInfo)
return NS_ERROR_UNEXPECTED;
@ -2605,7 +2643,7 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
return NS_ERROR_OUT_OF_MEMORY;
child->mType = childType;
rv |= child->Deserialize(aStream, aContext, aDocumentURI,
rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
aNodeInfos);
break;
case eType_Text:
@ -2614,33 +2652,30 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
return NS_ERROR_OUT_OF_MEMORY;
child->mType = childType;
rv |= child->Deserialize(aStream, aContext, aDocumentURI,
rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
aNodeInfos);
break;
case eType_Script: {
PRUint32 langID = nsIProgrammingLanguage::UNKNOWN;
rv |= aStream->Read32(&langID);
// language version/options obtained during deserialization.
// Don't clobber rv here, since it might already be a failure!
nsresult result;
nsXULPrototypeScript* script =
new nsXULPrototypeScript(0, nsnull, PR_FALSE, &result);
nsXULPrototypeScript* script = new nsXULPrototypeScript(langID, 0, 0);
if (! script)
return NS_ERROR_OUT_OF_MEMORY;
if (NS_FAILED(result)) {
delete script;
return result;
}
child = script;
child->mType = childType;
rv |= aStream->Read8(&script->mOutOfLine);
if (! script->mOutOfLine) {
rv |= script->Deserialize(aStream, aContext, aDocumentURI,
rv |= script->Deserialize(aStream, aGlobal, aDocumentURI,
aNodeInfos);
} else {
rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(script->mSrcURI));
rv |= script->DeserializeOutOfLine(aStream, aContext);
rv |= script->DeserializeOutOfLine(aStream, aGlobal);
}
// If we failed to deserialize, consider deleting 'script'?
break;
}
}
@ -2721,93 +2756,45 @@ nsXULPrototypeElement::SetAttrAt(PRUint32 aPos, const nsAString& aValue,
// nsXULPrototypeScript
//
nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLineNo,
const char *aVersion,
PRBool aHasE4XOption,
nsresult* rv)
nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, PRUint32 aVersion)
: nsXULPrototypeNode(eType_Script),
mLineNo(aLineNo),
mSrcLoading(PR_FALSE),
mOutOfLine(PR_TRUE),
mHasE4XOption(aHasE4XOption),
mSrcLoadWaiters(nsnull),
mJSObject(nsnull),
mScriptObject(aLangID, nsnull),
mLangVersion(aVersion)
{
NS_LOG_ADDREF(this, 1, ClassName(), ClassSize());
*rv = nsContentUtils::AddJSGCRoot(&mJSObject,
"nsXULPrototypeScript::mJSObject");
mAddedGCRoot = NS_SUCCEEDED(*rv);
NS_ASSERTION(aLangID != nsIProgrammingLanguage::UNKNOWN,
"The language ID must be known and constant");
}
nsXULPrototypeScript::~nsXULPrototypeScript()
{
if (mAddedGCRoot) {
nsContentUtils::RemoveJSGCRoot(&mJSObject);
}
}
nsresult
nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
const nsCOMArray<nsINodeInfo> *aNodeInfos)
{
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mJSObject,
nsIScriptContext *context = aGlobal->GetScriptContext(
mScriptObject.getScriptTypeID());
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mScriptObject,
"script source still loading when serializing?!");
if (!mJSObject)
if (!mScriptObject)
return NS_ERROR_FAILURE;
nsresult rv;
// Write basic prototype data
aStream->Write32(mLineNo);
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
aContext->GetNativeContext());
JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE);
if (! xdr)
return NS_ERROR_OUT_OF_MEMORY;
xdr->userdata = (void*) aStream;
JSScript *script = NS_REINTERPRET_CAST(JSScript*,
::JS_GetPrivate(cx, mJSObject));
JSAutoRequest ar(cx);
if (! ::JS_XDRScript(xdr, &script)) {
rv = NS_ERROR_FAILURE; // likely to be a principals serialization error
} else {
// Get the encoded JSXDRState data and write it. The JSXDRState owns
// this buffer memory and will free it beneath ::JS_XDRDestroy.
//
// If an XPCOM object needs to be written in the midst of the JS XDR
// encoding process, the C++ code called back from the JS engine (e.g.,
// nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data
// from the JSXDRState to aStream, then write the object, then return
// to JS XDR code with xdr reset so new JS data is encoded at the front
// of the xdr's data buffer.
//
// However many XPCOM objects are interleaved with JS XDR data in the
// stream, when control returns here from ::JS_XDRScript, we'll have
// one last buffer of data to write to aStream.
uint32 size;
const char* data = NS_REINTERPRET_CAST(const char*,
::JS_XDRMemGetData(xdr, &size));
NS_ASSERTION(data, "no decoded JSXDRState data!");
rv = aStream->Write32(size);
if (NS_SUCCEEDED(rv))
rv = aStream->WriteBytes(data, size);
}
::JS_XDRDestroy(xdr);
nsresult rv;
rv = aStream->Write32(mLineNo);
if (NS_FAILED(rv)) return rv;
PRUint32 version = PRUint32(mLangVersion
? ::JS_StringToVersion(mLangVersion)
: JSVERSION_DEFAULT);
rv = aStream->Write32(version);
rv = aStream->Write32(mLangVersion);
if (NS_FAILED(rv)) return rv;
// And delegate the writing to the nsIScriptContext
rv = context->Serialize(aStream, mScriptObject);
if (NS_FAILED(rv)) return rv;
return NS_OK;
@ -2815,7 +2802,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
nsresult
nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext)
nsIScriptGlobalObject* aGlobal)
{
nsIXULPrototypeCache* cache = GetXULCache();
#ifdef NS_DEBUG
@ -2864,7 +2851,7 @@ nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
nsCOMPtr<nsIURI> oldURI;
rv |= fastLoadService->SelectMuxedDocument(mSrcURI, getter_AddRefs(oldURI));
rv |= Serialize(objectOutput, aContext, nsnull);
rv |= Serialize(objectOutput, aGlobal, nsnull);
rv |= fastLoadService->EndMuxedDocument(mSrcURI);
if (oldURI) {
@ -2881,94 +2868,38 @@ nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
nsresult
nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
nsIURI* aDocumentURI,
const nsCOMArray<nsINodeInfo> *aNodeInfos)
{
NS_TIMELINE_MARK_FUNCTION("chrome js deserialize");
NS_TIMELINE_MARK_FUNCTION("chrome script deserialize");
nsresult rv;
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mScriptObject,
"prototype script not well-initialized when deserializing?!");
// Read basic prototype data
aStream->Read32(&mLineNo);
aStream->Read32(&mLangVersion);
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mJSObject,
"prototype script not well-initialized when deserializing?!");
PRUint32 size;
rv = aStream->Read32(&size);
if (NS_FAILED(rv)) return rv;
char* data;
rv = aStream->ReadBytes(size, &data);
if (NS_SUCCEEDED(rv)) {
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
aContext->GetNativeContext());
JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_DECODE);
if (! xdr) {
rv = NS_ERROR_OUT_OF_MEMORY;
} else {
xdr->userdata = (void*) aStream;
JSAutoRequest ar(cx);
::JS_XDRMemSetData(xdr, data, size);
JSScript *script = nsnull;
if (! ::JS_XDRScript(xdr, &script)) {
rv = NS_ERROR_FAILURE; // principals deserialization error?
} else {
mJSObject = ::JS_NewScriptObject(cx, script);
if (! mJSObject) {
rv = NS_ERROR_OUT_OF_MEMORY; // certain error
::JS_DestroyScript(cx, script);
}
}
// Update data in case ::JS_XDRScript called back into C++ code to
// read an XPCOM object.
//
// In that case, the serialization process must have flushed a run
// of counted bytes containing JS data at the point where the XPCOM
// object starts, after which an encoding C++ callback from the JS
// XDR code must have written the XPCOM object directly into the
// nsIObjectOutputStream.
//
// The deserialization process will XDR-decode counted bytes up to
// but not including the XPCOM object, then call back into C++ to
// read the object, then read more counted bytes and hand them off
// to the JSXDRState, so more JS data can be decoded.
//
// This interleaving of JS XDR data and XPCOM object data may occur
// several times beneath the call to ::JS_XDRScript, above. At the
// end of the day, we need to free (via nsMemory) the data owned by
// the JSXDRState. So we steal it back, nulling xdr's buffer so it
// doesn't get passed to ::JS_free by ::JS_XDRDestroy.
uint32 junk;
data = (char*) ::JS_XDRMemGetData(xdr, &junk);
if (data)
::JS_XDRMemSetData(xdr, NULL, 0);
::JS_XDRDestroy(xdr);
}
// If data is null now, it must have been freed while deserializing an
// XPCOM object (e.g., a principal) beneath ::JS_XDRScript.
if (data)
nsMemory::Free(data);
nsIScriptContext *context = aGlobal->GetScriptContext(
mScriptObject.getScriptTypeID());
NS_ASSERTION(context != nsnull, "Have no context for deserialization");
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
nsScriptObjectHolder newScriptObject(context);
rv = context->Deserialize(aStream, newScriptObject);
if (NS_FAILED(rv)) {
NS_WARNING("Language deseralization failed");
return rv;
}
if (NS_FAILED(rv)) return rv;
PRUint32 version;
rv = aStream->Read32(&version);
if (NS_FAILED(rv)) return rv;
mLangVersion = ::JS_VersionToString(JSVersion(version));
mScriptObject = newScriptObject;
return NS_OK;
}
nsresult
nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
nsIScriptContext* aContext)
nsIScriptGlobalObject* aGlobal)
{
// Keep track of FastLoad failure via rv, so we can
// AbortFastLoads if things look bad.
@ -3001,11 +2932,27 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
cache->GetEnabled(&useXULCache);
if (useXULCache) {
cache->GetScript(mSrcURI, NS_REINTERPRET_CAST(void**, &mJSObject));
void *newScriptObject = nsnull;
PRUint32 newLangID = nsIProgrammingLanguage::UNKNOWN;
cache->GetScript(mSrcURI, &newLangID, &newScriptObject);
if (newScriptObject) {
// Things may blow here if we simply change the script
// language - other code may already have pre-fetched the
// global for the language. (You can see this code by
// setting langID to UNKNOWN in the nsXULPrototypeScript
// ctor and not setting it until the scriptObject is set -
// code that pre-fetches these globals will then start
// asserting.)
if (mScriptObject.getScriptTypeID() != newLangID) {
NS_ERROR("XUL cache gave different language?");
return NS_ERROR_UNEXPECTED;
}
}
mScriptObject.set(newScriptObject);
}
}
if (! mJSObject) {
if (! mScriptObject) {
nsCOMPtr<nsIURI> oldURI;
if (mSrcURI) {
@ -3027,13 +2974,13 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
}
// We do reflect errors into rv, but our caller may want to
// ignore our return value, because mJSObject will be null
// ignore our return value, because mScriptObject will be null
// after any error, and that suffices to cause the script to
// be reloaded (from the src= URI, if any) and recompiled.
// We're better off slow-loading than bailing out due to a
// FastLoad error.
if (NS_SUCCEEDED(rv))
rv = Deserialize(objectInput, aContext, nsnull, nsnull);
rv = Deserialize(objectInput, aGlobal, nsnull, nsnull);
if (NS_SUCCEEDED(rv) && mSrcURI) {
rv = fastLoadService->EndMuxedDocument(mSrcURI);
@ -3052,7 +2999,9 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
PRBool isChrome = PR_FALSE;
mSrcURI->SchemeIs("chrome", &isChrome);
if (isChrome) {
cache->PutScript(mSrcURI, NS_REINTERPRET_CAST(void*, mJSObject));
cache->PutScript(mSrcURI,
mScriptObject.getScriptTypeID(),
mScriptObject);
}
}
} else {
@ -3100,8 +3049,7 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
if (! global)
return NS_ERROR_UNEXPECTED;
context = global->GetContext();
context = global->GetScriptContext(mScriptObject.getScriptTypeID());
NS_ASSERTION(context != nsnull, "no context for script global");
if (! context)
return NS_ERROR_UNEXPECTED;
@ -3112,22 +3060,7 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
// Ok, compile it to create a prototype script object!
// XXXbe violate nsIScriptContext layering because its version parameter
// is mis-typed as const char * -- if it were uint32, we could more easily
// extend version to include compile-time option, as the JS engine does.
// It'd also be more efficient than converting to and from a C string.
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
context->GetNativeContext());
uint32 options = ::JS_GetOptions(cx);
JSBool changed = (mHasE4XOption ^ !!(options & JSOPTION_XML));
if (changed) {
::JS_SetOptions(cx,
mHasE4XOption
? options | JSOPTION_XML
: options & ~JSOPTION_XML);
}
nsScriptObjectHolder newScriptObject(context);
rv = context->CompileScript(aText,
aTextLength,
nsnull,
@ -3138,11 +3071,11 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
urlspec.get(),
aLineNo,
mLangVersion,
(void**)&mJSObject);
newScriptObject);
if (NS_FAILED(rv))
return rv;
if (changed) {
::JS_SetOptions(cx, options);
}
mScriptObject = newScriptObject;
return rv;
}
@ -3153,7 +3086,7 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
nsresult
nsXULPrototypeText::Serialize(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
const nsCOMArray<nsINodeInfo> *aNodeInfos)
{
nsresult rv;
@ -3168,7 +3101,7 @@ nsXULPrototypeText::Serialize(nsIObjectOutputStream* aStream,
nsresult
nsXULPrototypeText::Deserialize(nsIObjectInputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
nsIURI* aDocumentURI,
const nsCOMArray<nsINodeInfo> *aNodeInfos)
{

Просмотреть файл

@ -24,6 +24,7 @@
* Peter Annema <disttsc@bart.nl>
* Mike Shaver <shaver@mozilla.org>
* Ben Goodger <ben@netscape.com>
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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"),
@ -78,6 +79,7 @@
#include "nsXULAtoms.h"
#include "nsAutoPtr.h"
#include "nsGenericElement.h"
#include "nsDOMScriptObjectHolder.h"
class nsIDocument;
class nsIRDFService;
@ -125,8 +127,14 @@ public:
nsAttrName mName;
nsAttrValue mValue;
// mEventHandler is only valid for the language ID specified in the
// containing nsXULPrototypeElement. We would ideally use
// nsScriptObjectHolder, but want to avoid the extra lang ID.
void* mEventHandler;
// Containing element must tell us the langID so we can cleanup.
void Finalize(PRUint32 aLangID);
#ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
/**
If enough attributes, on average, are event handlers, it pays to keep
@ -197,10 +205,10 @@ public:
virtual ~nsXULPrototypeNode() {}
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
const nsCOMArray<nsINodeInfo> *aNodeInfos) = 0;
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
nsIURI* aDocumentURI,
const nsCOMArray<nsINodeInfo> *aNodeInfos) = 0;
@ -235,13 +243,17 @@ public:
mNumChildren(0),
mChildren(nsnull),
mNumAttributes(0),
mAttributes(nsnull)
mAttributes(nsnull),
mScriptTypeID(nsIProgrammingLanguage::UNKNOWN)
{
NS_LOG_ADDREF(this, 1, ClassName(), ClassSize());
}
virtual ~nsXULPrototypeElement()
{
PRUint32 i;
for (i = 0; i < mNumAttributes; i++)
mAttributes[i].Finalize(mScriptTypeID);
delete[] mAttributes;
delete[] mChildren;
}
@ -264,10 +276,10 @@ public:
}
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
const nsCOMArray<nsINodeInfo> *aNodeInfos);
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
nsIURI* aDocumentURI,
const nsCOMArray<nsINodeInfo> *aNodeInfos);
@ -281,6 +293,11 @@ public:
PRUint32 mNumAttributes;
nsXULPrototypeAttribute* mAttributes; // [OWNER]
// The language ID can not be set on a per-node basis, but is tracked
// so that the language ID from the originating root can be used
// (eg, when a node from an overlay ends up in our document, that node
// must use its original script language, not our document's default.
PRUint32 mScriptTypeID;
static void ReleaseGlobals()
{
NS_IF_RELEASE(sCSSParser);
@ -301,17 +318,12 @@ protected:
static nsICSSParser* sCSSParser;
};
struct JSRuntime;
struct JSObject;
class nsXULDocument;
class nsXULPrototypeScript : public nsXULPrototypeNode
{
public:
// Note: if *rv is failure after the script is constructed, delete
// it and return *rv.
nsXULPrototypeScript(PRUint32 aLineNo, const char *aVersion,
PRBool aHasE4XOption, nsresult* rv);
nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, PRUint32 version);
virtual ~nsXULPrototypeScript();
#ifdef NS_BUILD_REFCNT_LOGGING
@ -320,16 +332,16 @@ public:
#endif
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
const nsCOMArray<nsINodeInfo> *aNodeInfos);
nsresult SerializeOutOfLine(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext);
nsIScriptGlobalObject* aGlobal);
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
nsIURI* aDocumentURI,
const nsCOMArray<nsINodeInfo> *aNodeInfos);
nsresult DeserializeOutOfLine(nsIObjectInputStream* aInput,
nsIScriptContext* aContext);
nsIScriptGlobalObject* aGlobal);
nsresult Compile(const PRUnichar* aText, PRInt32 aTextLength,
nsIURI* aURI, PRUint32 aLineNo,
@ -340,11 +352,9 @@ public:
PRUint32 mLineNo;
PRPackedBool mSrcLoading;
PRPackedBool mOutOfLine;
PRPackedBool mHasE4XOption;
PRPackedBool mAddedGCRoot;
nsXULDocument* mSrcLoadWaiters; // [OWNER] but not COMPtr
JSObject* mJSObject;
const char* mLangVersion;
PRUint32 mLangVersion;
nsScriptObjectHolder mScriptObject;
static void ReleaseGlobals()
{
@ -381,10 +391,10 @@ public:
#endif
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
const nsCOMArray<nsINodeInfo> *aNodeInfos);
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
nsIScriptContext* aContext,
nsIScriptGlobalObject* aGlobal,
nsIURI* aDocumentURI,
const nsCOMArray<nsINodeInfo> *aNodeInfos);
@ -496,6 +506,7 @@ public:
PRBool aNotify);
virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const;
virtual PRUint32 GetAttrCount() const;
#ifdef DEBUG
virtual void List(FILE* out, PRInt32 aIndent) const;
virtual void DumpContent(FILE* out, PRInt32 aIndent,PRBool aDumpAll) const
@ -548,13 +559,14 @@ public:
// nsIScriptEventHandlerOwner
nsresult CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsISupports* aTarget,
nsIAtom *aName,
const nsAString& aBody,
const char* aURL,
PRUint32 aLineNo,
void** aHandler);
nsresult GetCompiledEventHandler(nsIAtom *aName, void** aHandler);
nsScriptObjectHolder &aHandler);
nsresult GetCompiledEventHandler(nsIAtom *aName,
nsScriptObjectHolder &aHandler);
// nsIChromeEventHandler
NS_DECL_NSICHROMEEVENTHANDLER

Просмотреть файл

@ -59,9 +59,9 @@ class nsIFastLoadService;
#define NS_XULPROTOTYPECACHE_CID \
{ 0x3a0a0fc1, 0x8349, 0x11d3, { 0xbe, 0x47, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } }
// {CD196299-18E9-4642-AD43-666315C4D241}
// {F53A6C7E-0344-4543-9213-AFFFD30AC2BE}
#define NS_IXULPROTOTYPECACHE_IID \
{ 0xcd196299, 0x18e9, 0x4642, { 0xad, 0x43, 0x66, 0x63, 0x15, 0xc4, 0xd2, 0x41 } }
{ 0xf53a6c7e, 0x344, 0x4543, { 0x92, 0x13, 0xaf, 0xff, 0xd3, 0xa, 0xc2, 0xbe } };
class nsIXULPrototypeCache : public nsISupports
@ -77,8 +77,8 @@ public:
NS_IMETHOD PutStyleSheet(nsICSSStyleSheet* aStyleSheet) = 0;
NS_IMETHOD FlushStyleSheets() = 0;
NS_IMETHOD GetScript(nsIURI* aURI, void** aScriptObject) = 0;
NS_IMETHOD PutScript(nsIURI* aURI, void* aScriptObject) = 0;
NS_IMETHOD GetScript(nsIURI* aURI, PRUint32 *aLangID, void** aScriptObject) = 0;
NS_IMETHOD PutScript(nsIURI* aURI, PRUint32 aLangID, void* aScriptObject) = 0;
NS_IMETHOD FlushScripts() = 0;
NS_IMETHOD GetXBLDocumentInfo(nsIURI* aURL, nsIXBLDocumentInfo** aResult) = 0;

Просмотреть файл

@ -23,6 +23,7 @@
* Chris Waterson <waterson@netscape.com>
* David Hyatt <hyatt@netscape.com>
* Brendan Eich <brendan@mozilla.org>
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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"),
@ -68,6 +69,7 @@
#include "nsIParser.h"
#include "nsIPresShell.h"
#include "nsIScriptContext.h"
#include "nsIScriptRuntime.h"
#include "nsIScriptGlobalObject.h"
#include "nsIServiceManager.h"
#include "nsITextContent.h"
@ -90,7 +92,7 @@
#include "nsXULElement.h"
#include "prlog.h"
#include "prmem.h"
#include "jsapi.h" // for JSVERSION_*, JS_VersionToString, etc.
#include "jscntxt.h" // for JSVERSION_HAS_XML
#include "nsCRT.h"
#include "nsIFastLoadService.h" // XXXbe temporary
@ -168,6 +170,9 @@ protected:
static PRBool IsDataInBuffer(PRUnichar* aBuffer, PRInt32 aLength);
nsresult SetElementScriptType(nsXULPrototypeElement* element,
const PRUnichar** aAttributes,
const PRUint32 aAttrLen);
// Text management
nsresult FlushText(PRBool aCreateTextNode = PR_TRUE);
@ -221,6 +226,7 @@ protected:
nsresult GetTopNode(nsXULPrototypeNode** aNode);
nsresult GetTopChildren(nsVoidArray** aChildren);
nsresult GetTopNodeScriptType(PRUint32 *aScriptType);
};
friend class ContextStack;
@ -310,6 +316,38 @@ XULContentSinkImpl::ContextStack::GetTopChildren(nsVoidArray** aChildren)
return NS_OK;
}
nsresult
XULContentSinkImpl::ContextStack::GetTopNodeScriptType(PRUint32 *aScriptType)
{
if (mDepth == 0)
return NS_ERROR_UNEXPECTED;
// This would be much simpler if nsXULPrototypeNode itself
// stored the language ID - but text elements don't need it!
nsresult rv = NS_OK;
nsXULPrototypeNode* node;
rv = GetTopNode(&node);
if (NS_FAILED(rv)) return rv;
switch (node->mType) {
case nsXULPrototypeNode::eType_Element: {
nsXULPrototypeElement *parent = \
NS_REINTERPRET_CAST(nsXULPrototypeElement*, node);
*aScriptType = parent->mScriptTypeID;
break;
}
case nsXULPrototypeNode::eType_Script: {
nsXULPrototypeScript *parent = \
NS_REINTERPRET_CAST(nsXULPrototypeScript*, node);
*aScriptType = parent->mScriptObject.getScriptTypeID();
break;
}
default: {
NS_WARNING("Unexpected parent node type");
rv = NS_ERROR_UNEXPECTED;
}
}
return rv;
}
//----------------------------------------------------------------------
@ -807,7 +845,7 @@ XULContentSinkImpl::HandleEndElement(const PRUnichar *aName)
NS_STATIC_CAST(nsXULPrototypeScript*, node);
// If given a src= attribute, we must ignore script tag content.
if (! script->mSrcURI && ! script->mJSObject) {
if (! script->mSrcURI && ! script->mScriptObject) {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
script->mOutOfLine = PR_FALSE;
@ -1035,6 +1073,52 @@ XULContentSinkImpl::ReportError(const PRUnichar* aErrorText,
return rv;
}
nsresult
XULContentSinkImpl::SetElementScriptType(nsXULPrototypeElement* element,
const PRUnichar** aAttributes,
const PRUint32 aAttrLen)
{
// First check if the attributes specify an explicit script type.
nsresult rv = NS_OK;
PRUint32 i;
PRBool found = PR_FALSE;
for (i=0;i<aAttrLen;i++) {
const nsDependentString key(aAttributes[i*2]);
if (key.EqualsLiteral("script-type")) {
const nsDependentString value(aAttributes[i*2+1]);
if (!value.IsEmpty()) {
nsCOMPtr<nsIScriptRuntime> runtime;
rv = NS_GetScriptRuntime(value, getter_AddRefs(runtime));
if (NS_SUCCEEDED(rv))
element->mScriptTypeID = runtime->GetScriptTypeID();
else {
// probably just a bad language name (typo, etc)
NS_WARNING("Failed to load the node's script language!");
// Leave the default language as unknown - we don't want js
// trying to execute this stuff.
NS_ASSERTION(element->mScriptTypeID == nsIProgrammingLanguage::UNKNOWN,
"Default script type should be unknown");
}
found = PR_TRUE;
break;
}
}
}
// If not specified, look at the context stack and use the element
// there.
if (!found) {
if (mContextStack.Depth() == 0) {
// This is the root element - default to JS
element->mScriptTypeID = nsIProgrammingLanguage::JAVASCRIPT;
} else {
// Ask the top-node for its script type (which has already
// had this function called for it - so no need to recurse
// until we find it)
rv = mContextStack.GetTopNodeScriptType(&element->mScriptTypeID);
}
}
return rv;
}
nsresult
XULContentSinkImpl::OpenRoot(const PRUnichar** aAttributes,
@ -1074,6 +1158,10 @@ XULContentSinkImpl::OpenRoot(const PRUnichar** aAttributes,
return rv;
}
// Set the correct script-type for the element.
rv = SetElementScriptType(element, aAttributes, aAttrLen);
if (NS_FAILED(rv)) return rv;
// Push the element onto the context stack, so that child
// containers will hook up to us as their parent.
rv = mContextStack.Push(element, mState);
@ -1133,11 +1221,19 @@ XULContentSinkImpl::OpenTag(const PRUnichar** aAttributes,
if (aNodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XHTML) ||
aNodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XUL)) {
// Do scripty things now. OpenScript will push the
// nsPrototypeScriptElement onto the stack, so we're done after this.
// Do scripty things now. Set a script language for the element,
// even though it is ignored (the nsPrototypeScriptElement
// has its own script-type).
element->mScriptTypeID = nsIProgrammingLanguage::JAVASCRIPT;
// OpenScript will push the nsPrototypeScriptElement onto the
// stack, so we're done after this.
return OpenScript(aAttributes, aLineNumber);
}
// Set the correct script-type for the element.
rv = SetElementScriptType(element, aAttributes, aAttrLen);
if (NS_FAILED(rv)) return rv;
// Push the element onto the context stack, so that child
// containers will hook up to us as their parent.
rv = mContextStack.Push(element, mState);
@ -1151,10 +1247,10 @@ nsresult
XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
const PRUint32 aLineNumber)
{
nsresult rv = NS_OK;
PRBool isJavaScript = PR_TRUE;
PRBool hasE4XOption = PR_TRUE;
const char* jsVersionString = nsnull;
PRUint32 langID;
nsresult rv = mContextStack.GetTopNodeScriptType(&langID);
if (NS_FAILED(rv)) return rv;
PRUint32 version = 0;
// Look for SRC attribute and look for a LANGUAGE attribute
nsAutoString src;
@ -1176,6 +1272,7 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
mimeType);
NS_ENSURE_SUCCESS(rv, rv);
// Javascript keeps the fast path, optimized for most-likely type
// Table ordered from most to least likely JS MIME types. For .xul
// files that we host, the likeliest type is application/x-javascript.
// See bug 62485, feel free to add <script type="..."> survey data to it,
@ -1189,7 +1286,7 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
nsnull
};
isJavaScript = PR_FALSE;
PRBool isJavaScript = PR_FALSE;
for (PRInt32 i = 0; jsTypes[i]; i++) {
if (mimeType.LowerCaseEqualsASCII(jsTypes[i])) {
isJavaScript = PR_TRUE;
@ -1198,30 +1295,44 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
}
if (isJavaScript) {
JSVersion jsVersion = JSVERSION_DEFAULT;
nsAutoString value;
rv = mimeHdrParser->GetParameter(typeAndParams, "version",
EmptyCString(), PR_FALSE, nsnull,
value);
if (NS_FAILED(rv)) {
langID = nsIProgrammingLanguage::JAVASCRIPT;
} else {
// Use the script object factory to locate the language.
nsCOMPtr<nsIScriptRuntime> runtime;
rv = NS_GetScriptRuntime(mimeType, getter_AddRefs(runtime));
if (NS_FAILED(rv) || runtime == nsnull) {
// Failed to get the explicitly specified language
NS_WARNING("Failed to find a scripting language");
langID = nsIProgrammingLanguage::UNKNOWN;
} else
langID = runtime->GetScriptTypeID();
}
if (langID != nsIProgrammingLanguage::UNKNOWN) {
// Get the version string, and ensure the language supports it.
nsAutoString versionName;
rv = mimeHdrParser->GetParameter(typeAndParams, "version",
EmptyCString(), PR_FALSE, nsnull,
versionName);
if (NS_FAILED(rv)) {
// no version specified - version remains 0.
if (rv != NS_ERROR_INVALID_ARG)
return rv;
} else {
if (value.Length() != 3 || value[0] != '1' || value[1] != '.')
jsVersion = JSVERSION_UNKNOWN;
else switch (value[2]) {
case '0': jsVersion = JSVERSION_1_0; break;
case '1': jsVersion = JSVERSION_1_1; break;
case '2': jsVersion = JSVERSION_1_2; break;
case '3': jsVersion = JSVERSION_1_3; break;
case '4': jsVersion = JSVERSION_1_4; break;
case '5': jsVersion = JSVERSION_1_5; break;
case '6': jsVersion = JSVERSION_1_6; break;
default: jsVersion = JSVERSION_UNKNOWN;
nsCOMPtr<nsIScriptRuntime> runtime;
rv = NS_GetScriptRuntimeByID(langID, getter_AddRefs(runtime));
if (NS_FAILED(rv))
return rv;
rv = runtime->ParseVersion(versionName, &version);
if (NS_FAILED(rv)) {
NS_WARNING("This script language version is not supported - ignored");
langID = nsIProgrammingLanguage::UNKNOWN;
}
}
jsVersionString = ::JS_VersionToString(jsVersion);
}
// Some js specifics yet to be abstracted.
if (langID == nsIProgrammingLanguage::JAVASCRIPT) {
nsAutoString value;
rv = mimeHdrParser->GetParameter(typeAndParams, "e4x",
EmptyCString(), PR_FALSE, nsnull,
value);
@ -1230,29 +1341,48 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
return rv;
} else {
if (value.Length() == 1 && value[0] == '0')
hasE4XOption = PR_FALSE;
// This means that we need to set JSOPTION_XML in the JS
// options. We use our implementation knowledge to reuse
// JSVERSION_HAS_XML as a safe version flag. If version
// has JSVERSION_UNKNOWN (-1), then this is still OK.
version |= JSVERSION_HAS_XML;
}
}
}
else if (key.EqualsLiteral("language")) {
// Language is deprecated, and the impl in nsScriptLoader ignores the
// various version strings anyway. So we make no attempt to support
// languages other than JS for language=
nsAutoString lang(aAttributes[1]);
isJavaScript =
nsParserUtils::IsJavaScriptLanguage(lang, &jsVersionString);
if (nsParserUtils::IsJavaScriptLanguage(lang, &version))
langID = nsIProgrammingLanguage::JAVASCRIPT;
}
aAttributes += 2;
}
// Don't process scripts that aren't JavaScript
if (isJavaScript) {
// Not all script languages have a "sandbox" concept. At time of
// writing, Python is the only other language, and it does not.
// For such languages, neither any inline script nor remote script are
// safe to execute from untrusted sources.
// So for such languages, we only allow script when the document
// itself is from chrome. We then don't bother to check the
// "src=" tag - we trust chrome to do the right thing.
// (See also similar code in nsScriptLoader.cpp)
nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
if (langID != nsIProgrammingLanguage::UNKNOWN &&
langID != nsIProgrammingLanguage::JAVASCRIPT &&
doc && !nsContentUtils::IsChromeDoc(doc)) {
langID = nsIProgrammingLanguage::UNKNOWN;
NS_WARNING("Non JS language called from non chrome - ignored");
}
// Don't process scripts that aren't known
if (langID != nsIProgrammingLanguage::UNKNOWN) {
nsIScriptGlobalObject* globalObject = nsnull; // borrowed reference
if (doc)
globalObject = doc->GetScriptGlobalObject();
nsXULPrototypeScript* script =
new nsXULPrototypeScript(aLineNumber, jsVersionString, hasE4XOption,
&rv);
new nsXULPrototypeScript(langID, aLineNumber, version);
if (! script)
return NS_ERROR_OUT_OF_MEMORY;
if (NS_FAILED(rv)) {
delete script;
return rv;
}
// If there is a SRC attribute...
if (! src.IsEmpty()) {
@ -1286,15 +1416,8 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
// file right away. Otherwise we'll end up reloading the script and
// corrupting the FastLoad file trying to serialize it, in the case
// where it's already there.
nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
if (doc) {
nsIScriptGlobalObject* globalObject = doc->GetScriptGlobalObject();
if (globalObject) {
nsIScriptContext *scriptContext = globalObject->GetContext();
if (scriptContext)
script->DeserializeOutOfLine(nsnull, scriptContext);
}
}
if (globalObject)
script->DeserializeOutOfLine(nsnull, globalObject);
}
nsVoidArray* children;

Просмотреть файл

@ -109,6 +109,7 @@
#include "nsContentList.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptGlobalObjectOwner.h"
#include "nsIScriptRuntime.h"
#include "nsIScriptSecurityManager.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
@ -642,6 +643,10 @@ nsXULDocument::SynchronizeBroadcastListener(nsIDOMElement *aBroadcaster,
nsCOMPtr<nsIContent> broadcaster = do_QueryInterface(aBroadcaster);
nsCOMPtr<nsIContent> listener = do_QueryInterface(aListener);
// We may be copying event handlers etc, so we must also copy
// the script-type to the listener.
listener->SetScriptTypeID(broadcaster->GetScriptTypeID());
if (aAttr.EqualsLiteral("*")) {
PRUint32 count = broadcaster->GetAttrCount();
while (count-- > 0) {
@ -2767,9 +2772,9 @@ nsXULDocument::ResumeWalk()
if (NS_SUCCEEDED(rv) && blocked)
return NS_OK;
}
else if (scriptproto->mJSObject) {
else if (scriptproto->mScriptObject) {
// An inline script
rv = ExecuteScript(scriptproto->mJSObject);
rv = ExecuteScript(scriptproto);
if (NS_FAILED(rv)) return rv;
}
}
@ -2959,8 +2964,8 @@ nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, PRBool* aBlock)
// Load a transcluded script
nsresult rv;
if (aScriptProto->mJSObject) {
rv = ExecuteScript(aScriptProto->mJSObject);
if (aScriptProto->mScriptObject) {
rv = ExecuteScript(aScriptProto);
// Ignore return value from execution, and don't block
*aBlock = PR_FALSE;
@ -2974,11 +2979,23 @@ nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, PRBool* aBlock)
gXULCache->GetEnabled(&useXULCache);
if (useXULCache) {
void *newScriptObject = nsnull;
PRUint32 fetchedLang = nsIProgrammingLanguage::UNKNOWN;
gXULCache->GetScript(aScriptProto->mSrcURI,
NS_REINTERPRET_CAST(void**, &aScriptProto->mJSObject));
&fetchedLang,
&newScriptObject);
if (newScriptObject) {
// The script language for a proto must remain constant - we
// can't just change it for this unexpected language.
if (aScriptProto->mScriptObject.getScriptTypeID() != fetchedLang) {
NS_ERROR("XUL cache gave me an incorrect script language");
return NS_ERROR_UNEXPECTED;
}
aScriptProto->mScriptObject.set(newScriptObject);
}
if (aScriptProto->mJSObject) {
rv = ExecuteScript(aScriptProto->mJSObject);
if (aScriptProto->mScriptObject) {
rv = ExecuteScript(aScriptProto);
// Ignore return value from execution, and don't block
*aBlock = PR_FALSE;
@ -3069,7 +3086,7 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
// be writing a new FastLoad file. If we were reading this script
// from the FastLoad file, XULContentSinkImpl::OpenScript (over in
// nsXULContentSink.cpp) would have already deserialized a non-null
// script->mJSObject, causing control flow at the top of LoadScript
// script->mScriptObject, causing control flow at the top of LoadScript
// not to reach here.
nsCOMPtr<nsIURI> uri = scriptProto->mSrcURI;
@ -3083,8 +3100,8 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
1, this, mCurrentPrototype);
aStatus = rv;
if (NS_SUCCEEDED(rv) && scriptProto->mJSObject) {
rv = ExecuteScript(scriptProto->mJSObject);
if (NS_SUCCEEDED(rv)) {
rv = ExecuteScript(scriptProto);
// If the XUL cache is enabled, save the script object there in
// case different XUL documents source the same script.
@ -3112,7 +3129,8 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
if (useXULCache && IsChromeURI(mDocumentURI)) {
gXULCache->PutScript(scriptProto->mSrcURI,
NS_REINTERPRET_CAST(void*, scriptProto->mJSObject));
scriptProto->mScriptObject.getScriptTypeID(),
scriptProto->mScriptObject);
}
if (mIsWritingFastLoad && mCurrentPrototype != mMasterPrototype) {
@ -3134,9 +3152,13 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
NS_ASSERTION(global != nsnull, "master prototype w/o global?!");
if (global) {
nsIScriptContext *scriptContext = global->GetContext();
PRUint32 stid = scriptProto->mScriptObject.getScriptTypeID();
nsIScriptContext *scriptContext = \
global->GetScriptContext(stid);
NS_ASSERTION(scriptContext != nsnull,
"Failed to get script context for language");
if (scriptContext)
scriptProto->SerializeOutOfLine(nsnull, scriptContext);
scriptProto->SerializeOutOfLine(nsnull, global);
}
}
}
@ -3162,8 +3184,8 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
doc->mNextSrcLoadWaiter = nsnull;
// Execute only if we loaded and compiled successfully, then resume
if (NS_SUCCEEDED(aStatus) && scriptProto->mJSObject) {
doc->ExecuteScript(scriptProto->mJSObject);
if (NS_SUCCEEDED(aStatus) && scriptProto->mScriptObject) {
doc->ExecuteScript(scriptProto);
}
doc->ResumeWalk();
NS_RELEASE(doc);
@ -3174,23 +3196,43 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
nsresult
nsXULDocument::ExecuteScript(JSObject* aScriptObject)
nsXULDocument::ExecuteScript(nsIScriptContext * aContext, void * aScriptObject)
{
NS_PRECONDITION(aScriptObject != nsnull, "null ptr");
if (! aScriptObject)
NS_PRECONDITION(aScriptObject != nsnull && aContext != nsnull, "null ptr");
if (! aScriptObject || ! aContext)
return NS_ERROR_NULL_POINTER;
// Execute the precompiled script with the given version
nsresult rv = NS_ERROR_UNEXPECTED;
nsresult rv;
void *global = mScriptGlobalObject->GetScriptGlobal(
aContext->GetScriptTypeID());
rv = aContext->ExecuteScript(aScriptObject,
global,
nsnull, nsnull);
NS_ASSERTION(mScriptGlobalObject != nsnull, "no script global object");
return rv;
}
nsCOMPtr<nsIScriptContext> context;
if (mScriptGlobalObject && (context = mScriptGlobalObject->GetContext()))
rv = context->ExecuteScript(aScriptObject,
mScriptGlobalObject->GetGlobalJSObject(),
nsnull, nsnull);
nsresult
nsXULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
{
NS_PRECONDITION(aScript != nsnull, "null ptr");
NS_ENSURE_TRUE(aScript, NS_ERROR_NULL_POINTER);
PRUint32 stid = aScript->mScriptObject.getScriptTypeID();
nsresult rv;
rv = mScriptGlobalObject->EnsureScriptEnvironment(stid);
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptContext *context;
context = mScriptGlobalObject->GetScriptContext(stid);
// failure getting a script context is fatal.
NS_ENSURE_TRUE(context != nsnull, NS_ERROR_UNEXPECTED);
if (aScript->mScriptObject)
rv = ExecuteScript(context, aScript->mScriptObject);
else
rv = NS_ERROR_UNEXPECTED;
return rv;
}
@ -3523,7 +3565,14 @@ nsXULDocument::OverlayForwardReference::Resolve()
if (! target)
return eResolve_Error;
// While merging, set the default script language of the element to be
// the language from the overlay - attributes will then be correctly
// hooked up with the appropriate language (while child nodes ignore
// the default language - they have it in their proto.
PRUint32 oldDefLang = target->GetScriptTypeID();
target->SetScriptTypeID(mOverlay->GetScriptTypeID());
rv = Merge(target, mOverlay, notify);
target->SetScriptTypeID(oldDefLang);
if (NS_FAILED(rv)) return eResolve_Error;
// Add child and any descendants to the element map

Просмотреть файл

@ -345,7 +345,13 @@ protected:
* Execute the precompiled script object scoped by this XUL document's
* containing window object, and using its associated script context.
*/
nsresult ExecuteScript(JSObject* aScriptObject);
nsresult ExecuteScript(nsIScriptContext *aContext, void* aScriptObject);
/**
* Helper method for the above that uses aScript to find the appropriate
* script context and object.
*/
nsresult ExecuteScript(nsXULPrototypeScript *aScript);
/**
* Create a delegate content model element from a prototype.
@ -385,11 +391,6 @@ protected:
static nsresult
CreateTemplateBuilder(nsIContent* aElement);
/**
* Do hookup for <xul:observes> tag
*/
nsresult HookupObserver(nsIContent* aElement);
/**
* Add the current prototype's style sheets to the document.
*/

Просмотреть файл

@ -24,6 +24,7 @@
* Brendan Eich <brendan@mozilla.org>
* Ben Goodger <ben@netscape.com>
* Benjamin Smedberg <bsmedberg@covad.net>
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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"),
@ -54,8 +55,7 @@
#include "nsIXBLDocumentInfo.h"
#include "nsIServiceManager.h"
#include "nsXULDocument.h"
#include "nsIJSRuntimeService.h"
#include "jsapi.h"
#include "nsIScriptRuntime.h"
#include "nsIChromeRegistry.h"
#include "nsIFastLoadService.h"
@ -72,6 +72,12 @@
#include "nsDataHashtable.h"
#include "nsAppDirectoryServiceDefs.h"
struct CacheScriptEntry
{
PRUint32 mScriptTypeID; // the script language ID.
void* mScriptObject; // the script object.
};
class nsXULPrototypeCache : public nsIXULPrototypeCache,
nsIObserver
{
@ -88,8 +94,8 @@ public:
NS_IMETHOD PutStyleSheet(nsICSSStyleSheet* aStyleSheet);
NS_IMETHOD FlushStyleSheets();
NS_IMETHOD GetScript(nsIURI* aURI, void** aScriptObject);
NS_IMETHOD PutScript(nsIURI* aURI, void* aScriptObject);
NS_IMETHOD GetScript(nsIURI* aURI, PRUint32 *langID, void** aScriptObject);
NS_IMETHOD PutScript(nsIURI* aURI, PRUint32 langID, void* aScriptObject);
NS_IMETHOD FlushScripts();
NS_IMETHOD GetXBLDocumentInfo(nsIURI* aURL, nsIXBLDocumentInfo** _result);
@ -114,15 +120,11 @@ protected:
void FlushSkinFiles();
JSRuntime* GetJSRuntime();
nsInterfaceHashtable<nsURIHashKey,nsIXULPrototypeDocument> mPrototypeTable;
nsInterfaceHashtable<nsURIHashKey,nsICSSStyleSheet> mStyleSheetTable;
nsDataHashtable<nsURIHashKey,void*> mScriptTable;
nsDataHashtable<nsURIHashKey,CacheScriptEntry> mScriptTable;
nsInterfaceHashtable<nsURIHashKey,nsIXBLDocumentInfo> mXBLDocTable;
JSRuntime* mJSRuntime;
///////////////////////////////////////////////////////////////////////////
// FastLoad
// this is really a hash set, with a dummy data parameter
@ -164,7 +166,6 @@ nsIFastLoadService* nsXULPrototypeCache::gFastLoadService = nsnull;
nsIFile* nsXULPrototypeCache::gFastLoadFile = nsnull;
nsXULPrototypeCache::nsXULPrototypeCache()
: mJSRuntime(nsnull)
{
}
@ -298,18 +299,6 @@ nsXULPrototypeCache::PutPrototype(nsIXULPrototypeDocument* aDocument)
return NS_OK;
}
JSRuntime*
nsXULPrototypeCache::GetJSRuntime()
{
if (!mJSRuntime) {
nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
if (rtsvc)
rtsvc->GetRuntime(&mJSRuntime);
}
return mJSRuntime;
}
NS_IMETHODIMP
nsXULPrototypeCache::FlushPrototypes()
{
@ -351,30 +340,46 @@ nsXULPrototypeCache::FlushStyleSheets()
NS_IMETHODIMP
nsXULPrototypeCache::GetScript(nsIURI* aURI, void** aScriptObject)
nsXULPrototypeCache::GetScript(nsIURI* aURI, PRUint32 *aLangID,
void** aScriptObject)
{
if (!mScriptTable.Get(aURI, aScriptObject))
CacheScriptEntry entry;
if (!mScriptTable.Get(aURI, &entry)) {
*aLangID = nsIProgrammingLanguage::UNKNOWN;
*aScriptObject = nsnull;
} else {
*aScriptObject = entry.mScriptObject;
*aLangID = entry.mScriptTypeID;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::PutScript(nsIURI* aURI, void* aScriptObject)
nsXULPrototypeCache::PutScript(nsIURI* aURI, PRUint32 aLangID, void* aScriptObject)
{
NS_ENSURE_TRUE(mScriptTable.Put(aURI, aScriptObject), NS_ERROR_OUT_OF_MEMORY);
CacheScriptEntry entry = {aLangID, aScriptObject};
NS_ENSURE_TRUE(mScriptTable.Put(aURI, entry), NS_ERROR_OUT_OF_MEMORY);
// Lock the object from being gc'd until it is removed from the cache
JS_LockGCThingRT(GetJSRuntime(), aScriptObject);
return NS_OK;
nsresult rv;
nsCOMPtr<nsIScriptRuntime> rt;
rv = NS_GetScriptRuntimeByID(aLangID, getter_AddRefs(rt));
if (NS_SUCCEEDED(rv))
rv = rt->HoldScriptObject(aScriptObject);
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to GC lock the object");
// On failure doing the lock, we should remove the map entry?
return rv;
}
/* static */
PR_STATIC_CALLBACK(PLDHashOperator)
ReleaseJSObjectCallback(nsIURI* aKey, void* &aData, void* aClosure)
ReleaseScriptObjectCallback(nsIURI* aKey, CacheScriptEntry &aData, void* aClosure)
{
JS_UnlockGCThingRT((JSRuntime*) aClosure, aData);
nsCOMPtr<nsIScriptRuntime> rt;
if (NS_SUCCEEDED(NS_GetScriptRuntimeByID(aData.mScriptTypeID, getter_AddRefs(rt))))
rt->DropScriptObject(aData.mScriptObject);
return PL_DHASH_REMOVE;
}
@ -382,7 +387,8 @@ NS_IMETHODIMP
nsXULPrototypeCache::FlushScripts()
{
// This callback will unlock each object so it can once again be gc'd.
mScriptTable.Enumerate(ReleaseJSObjectCallback, (void*) GetJSRuntime());
// XXX - this might be slow - we fetch the runtime each and every object.
mScriptTable.Enumerate(ReleaseScriptObjectCallback, nsnull);
return NS_OK;
}

Просмотреть файл

@ -23,6 +23,7 @@
* Chris Waterson <waterson@netscape.com>
* L. David Baron <dbaron@dbaron.org>
* Ben Goodger <ben@netscape.com>
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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"),
@ -54,8 +55,10 @@
#include "nsIScriptGlobalObjectOwner.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScriptRuntime.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsISupportsArray.h" // deprecated array interface.
#include "nsIArray.h" // blessed array interface.
#include "nsIURI.h"
#include "nsIXULDocument.h"
#include "nsIXULPrototypeDocument.h"
@ -70,6 +73,7 @@
#include "nsNodeInfoManager.h"
#include "nsContentUtils.h"
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -85,14 +89,17 @@ public:
NS_DECL_ISUPPORTS
// nsIScriptGlobalObject methods
virtual void SetContext(nsIScriptContext *aContext);
virtual nsIScriptContext *GetContext();
virtual void SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner);
virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner();
virtual JSObject *GetGlobalJSObject();
virtual void OnFinalize(JSObject *aObject);
virtual void OnFinalize(PRUint32 aLangID, void *aGlobal);
virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
virtual nsresult SetNewArguments(PRUint32 aArgc, void* aArgv);
virtual nsresult SetNewArguments(nsIArray *aArguments);
virtual void *GetScriptGlobal(PRUint32 lang);
virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID);
virtual nsIScriptContext *GetScriptContext(PRUint32 lang);
virtual nsresult SetScriptContext(PRUint32 language, nsIScriptContext *ctx);
// nsIScriptObjectPrincipal methods
virtual nsIPrincipal* GetPrincipal();
@ -100,11 +107,11 @@ public:
protected:
virtual ~nsXULPDGlobalObject();
nsCOMPtr<nsIScriptContext> mScriptContext;
JSObject *mJSObject; // XXX JS language rabies bigotry badness
nsIScriptGlobalObjectOwner* mGlobalObjectOwner; // weak reference
nsCOMPtr<nsIScriptContext> mScriptContexts[NS_STID_ARRAY_UBOUND];
void * mScriptGlobals[NS_STID_ARRAY_UBOUND];
static JSClass gSharedGlobalClass;
};
@ -194,7 +201,7 @@ nsXULPDGlobalObject_finalize(JSContext *cx, JSObject *obj)
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
if (sgo) {
sgo->OnFinalize(obj);
sgo->OnFinalize(nsIProgrammingLanguage::JAVASCRIPT, obj);
}
// The addref was part of JSObject construction
@ -255,8 +262,8 @@ nsXULPrototypeDocument::Init()
nsXULPrototypeDocument::~nsXULPrototypeDocument()
{
if (mGlobalObject) {
mGlobalObject->SetContext(nsnull); // remove circular reference
mGlobalObject->SetGlobalObjectOwner(nsnull); // just in case
// cleaup cycles etc.
mGlobalObject->SetGlobalObjectOwner(nsnull);
}
if (mRoot)
@ -393,10 +400,6 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
if (! mRoot)
return NS_ERROR_OUT_OF_MEMORY;
nsIScriptContext *scriptContext = mGlobalObject->GetContext();
NS_ASSERTION(scriptContext != nsnull,
"no prototype script context!");
// nsINodeInfo table
nsCOMArray<nsINodeInfo> nodeInfos;
@ -419,7 +422,7 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
if ((nsXULPrototypeNode::Type)type != nsXULPrototypeNode::eType_Element)
return NS_ERROR_FAILURE;
rv |= mRoot->Deserialize(aStream, scriptContext, mURI, &nodeInfos);
rv |= mRoot->Deserialize(aStream, mGlobalObject, mURI, &nodeInfos);
rv |= NotifyLoadDone();
return rv;
@ -532,10 +535,8 @@ nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
nsIScriptContext *scriptContext = globalObject->GetContext();
if (mRoot)
rv |= mRoot->Serialize(aStream, scriptContext, &nodeInfos);
rv |= mRoot->Serialize(aStream, globalObject, &nodeInfos);
return rv;
}
@ -768,9 +769,9 @@ nsXULPrototypeDocument::GetScriptGlobalObject()
//
nsXULPDGlobalObject::nsXULPDGlobalObject()
: mJSObject(nsnull),
mGlobalObjectOwner(nsnull)
: mGlobalObjectOwner(nsnull)
{
memset(mScriptGlobals, 0, sizeof(mScriptGlobals));
}
@ -792,51 +793,129 @@ NS_INTERFACE_MAP_END
// nsIScriptGlobalObject methods
//
void
nsXULPDGlobalObject::SetContext(nsIScriptContext *aContext)
nsresult
nsXULPDGlobalObject::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
{
mScriptContext = aContext;
// almost a clone of nsGlobalWindow
nsresult rv;
PRBool ok = NS_STID_VALID(lang_id);
NS_ASSERTION(ok, "Invalid programming language ID requested");
NS_ENSURE_TRUE(ok, NS_ERROR_INVALID_ARG);
PRUint32 lang_ndx = NS_STID_INDEX(lang_id);
if (!aScriptContext)
NS_WARNING("Possibly early removal of script object, see bug #41608");
else {
// should probably assert the context is clean???
aScriptContext->WillInitializeContext();
// NOTE: We init this context with a NULL global - this is subtly
// different than nsGlobalWindow which passes 'this'
rv = aScriptContext->InitContext(nsnull);
NS_ENSURE_SUCCESS(rv, rv);
}
nsIScriptContext *existing;
existing = mScriptContexts[lang_ndx];
NS_ASSERTION(!aScriptContext || !existing, "Bad call to SetContext()!");
if (existing)
existing->SetOwner(nsnull);
void *script_glob = nsnull;
if (aScriptContext) {
aScriptContext->DidInitializeContext();
script_glob = aScriptContext->GetNativeGlobal();
NS_ASSERTION(script_glob, "GetNativeGlobal returned NULL!");
}
mScriptContexts[lang_ndx] = aScriptContext;
mScriptGlobals[lang_ndx] = script_glob;
return NS_OK;
}
nsIScriptContext *
nsXULPDGlobalObject::GetContext()
nsresult
nsXULPDGlobalObject::EnsureScriptEnvironment(PRUint32 lang_id)
{
// This whole fragile mess is predicated on the fact that
// GetContext() will be called before GetScriptObject() is.
if (! mScriptContext) {
nsCOMPtr<nsIDOMScriptObjectFactory> factory =
do_GetService(kDOMScriptObjectFactoryCID);
NS_ENSURE_TRUE(factory, nsnull);
PRBool ok = NS_STID_VALID(lang_id);
NS_ASSERTION(ok, "Invalid programming language ID requested");
NS_ENSURE_TRUE(ok, NS_ERROR_INVALID_ARG);
PRUint32 lang_ndx = NS_STID_INDEX(lang_id);
nsresult rv =
factory->NewScriptContext(nsnull, getter_AddRefs(mScriptContext));
if (NS_FAILED(rv))
return nsnull;
if (mScriptContexts[lang_ndx] == nsnull) {
nsresult rv;
NS_ASSERTION(mScriptGlobals[lang_ndx] == nsnull, "Have global without context?");
JSContext *cx = (JSContext *)mScriptContext->GetNativeContext();
nsCOMPtr<nsIScriptRuntime> languageRuntime;
rv = NS_GetScriptRuntimeByID(lang_id, getter_AddRefs(languageRuntime));
NS_ENSURE_SUCCESS(rv, nsnull);
JSAutoRequest ar(cx);
nsCOMPtr<nsIScriptContext> ctxNew;
rv = languageRuntime->CreateContext(getter_AddRefs(ctxNew));
// For JS, we have to setup a special global object. We do this then
// attach it as the global for this context. Then, ::SetScriptContext
// will re-fetch the global and set it up in our language globals array.
if (lang_id == nsIProgrammingLanguage::JAVASCRIPT) {
// some special JS specific code we should abstract
JSContext *cx = (JSContext *)ctxNew->GetNativeContext();
JSAutoRequest ar(cx);
JSObject *newGlob = ::JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
if (!newGlob)
return nsnull;
mJSObject = ::JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
if (!mJSObject)
return nsnull;
::JS_SetGlobalObject(cx, newGlob);
::JS_SetGlobalObject(cx, mJSObject);
// Add an owning reference from JS back to us. This'll be
// released when the JSObject is finalized.
::JS_SetPrivate(cx, mJSObject, this);
NS_ADDREF(this);
// Add an owning reference from JS back to us. This'll be
// released when the JSObject is finalized.
::JS_SetPrivate(cx, newGlob, this);
NS_ADDREF(this);
}
return mScriptContext;
NS_ENSURE_SUCCESS(rv, nsnull);
rv = SetScriptContext(lang_id, ctxNew);
NS_ENSURE_SUCCESS(rv, nsnull);
}
return NS_OK;
}
nsIScriptContext *
nsXULPDGlobalObject::GetScriptContext(PRUint32 lang_id)
{
// This global object creates a context on demand - do that now.
nsresult rv = EnsureScriptEnvironment(lang_id);
if (NS_FAILED(rv)) {
NS_ERROR("Failed to setup script language");
return nsnull;
}
// Note that EnsureScriptEnvironment has validated lang_id
return mScriptContexts[NS_STID_INDEX(lang_id)];
}
void *
nsXULPDGlobalObject::GetScriptGlobal(PRUint32 lang_id)
{
PRBool ok = NS_STID_VALID(lang_id);
NS_ASSERTION(ok, "Invalid programming language ID requested");
NS_ENSURE_TRUE(ok, nsnull);
PRUint32 lang_ndx = NS_STID_INDEX(lang_id);
NS_ASSERTION(mScriptContexts[lang_ndx] != nsnull, "Querying for global before setting up context?");
return mScriptGlobals[lang_ndx];
}
void
nsXULPDGlobalObject::SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner)
{
if (aOwner == nsnull) {
// this means we should cleanup
PRUint32 lang_ndx;
NS_STID_FOR_INDEX(lang_ndx) {
if (mScriptContexts[lang_ndx]) {
mScriptContexts[lang_ndx]->FinalizeContext();
mScriptContexts[lang_ndx] = nsnull;
}
}
}
mGlobalObjectOwner = aOwner; // weak reference
}
@ -848,29 +927,13 @@ nsXULPDGlobalObject::GetGlobalObjectOwner()
}
JSObject *
nsXULPDGlobalObject::GetGlobalJSObject()
{
// The prototype document has its own special secret script object
// that can be used to compile scripts and event handlers.
if (!mScriptContext)
return nsnull;
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
mScriptContext->GetNativeContext());
if (!cx)
return nsnull;
return ::JS_GetGlobalObject(cx);
}
void
nsXULPDGlobalObject::OnFinalize(JSObject *aObject)
nsXULPDGlobalObject::OnFinalize(PRUint32 aLangID, void *aObject)
{
NS_ASSERTION(aObject == mJSObject, "Wrong object finalized!");
mJSObject = nsnull;
NS_ASSERTION(NS_STID_VALID(aLangID), "Invalid language ID");
NS_ASSERTION(aObject == mScriptGlobals[NS_STID_INDEX(aLangID)],
"Wrong object finalized!");
mScriptGlobals[NS_STID_INDEX(aLangID)] = nsnull;
}
void
@ -880,7 +943,7 @@ nsXULPDGlobalObject::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
}
nsresult
nsXULPDGlobalObject::SetNewArguments(PRUint32 aArgc, void* aArgv)
nsXULPDGlobalObject::SetNewArguments(nsIArray *aArguments)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;

Просмотреть файл

@ -97,6 +97,7 @@
#include "nsIWritablePropertyBag2.h"
#include "nsIAppShell.h"
#include "nsWidgetsCID.h"
#include "nsDOMJSUtils.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@ -8320,13 +8321,12 @@ nsDocShell::EnsureScriptEnvironment()
SetGlobalObjectOwner(NS_STATIC_CAST
(nsIScriptGlobalObjectOwner *, this));
nsCOMPtr<nsIScriptContext> context;
factory->NewScriptContext(mScriptGlobal, getter_AddRefs(context));
NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
// Note that mScriptGlobal has taken a reference to the script
// context, so we don't have to.
// Ensure the script object is set to run javascript - other languages
// setup on demand.
// XXXmarkh - should this be setup to run the default language for this doc?
nsresult rv;
rv = mScriptGlobal->EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

Просмотреть файл

@ -53,10 +53,12 @@ XPIDLSRCS = nsIScriptContextOwner.idl \
EXPORTS=nsIScriptContext.h \
nsIJSNativeInitializer.h \
nsIScriptRuntime.h \
nsIScriptObjectOwner.h \
nsIScriptObjectPrincipal.h \
nsIScriptGlobalObject.h \
nsIScriptGlobalObjectOwner.h \
nsIScriptTimeoutHandler.h \
nsIDOMScriptObjectFactory.h \
nsDOMCID.h \
nsIScriptExternalNameSet.h \
@ -67,6 +69,8 @@ EXPORTS=nsIScriptContext.h \
nsDOMClassInfoID.h \
nsIBaseDOMException.h \
nsDOMString.h \
nsDOMJSUtils.h \
nsDOMScriptObjectHolder.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -67,12 +67,14 @@ enum PopupControlState {
class nsIDocShell;
class nsIFocusController;
class nsIDocument;
class nsIScriptTimeoutHandler;
class nsPresContext;
struct nsTimeout;
#define NS_PIDOMWINDOW_IID \
{ 0xad6640fb, 0x575e, 0x4bfe, \
{ 0x92, 0x92, 0xe6, 0x36, 0xfb, 0xee, 0xff, 0x3d } }
{ /* {D0A82BF8-969B-4092-8FE7-D885622DA5BF} */ \
0xd0a82bf8, 0x969b, 0x4092, \
{ 0x8f, 0xe7, 0xd8, 0x85, 0x62, 0x2d, 0xa5, 0xbf } }
class nsPIDOMWindow : public nsIDOMWindowInternal
{
@ -267,6 +269,14 @@ public:
// the window was frozen.
virtual nsresult FireDelayedDOMEvents() = 0;
// Add a timeout to this window.
virtual nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
PRInt32 interval,
PRBool aIsInterval, PRInt32 *aReturn) = 0;
// Clear a timeout from this window.
virtual nsresult ClearTimeoutOrInterval(PRInt32 aTimerID) = 0;
nsPIDOMWindow *GetOuterWindow()
{
return mIsInnerWindow ? mOuterWindow : this;

Просмотреть файл

@ -44,7 +44,7 @@
* the Document Object Model.
*/
[scriptable, uuid(6cbbbf64-212f-4ef8-9ad4-7240dbb8d6ac)]
[scriptable, uuid(37CA0054-C715-42df-83C7-35C69E24A632)]
interface nsIDOMNSEventTarget : nsISupports
{
/**
@ -68,4 +68,16 @@ interface nsIDOMNSEventTarget : nsISupports
in nsIDOMEventListener listener,
in boolean useCapture,
in boolean wantsUntrusted);
/**
* The default script type (language) for events firing on this target.
* Must be one of the nsIProgrammingLanguage enums, but must not be
* nsIProgrammingLanguage::UNKNOWN. Most implementations will provide
* a default type of nsIProgrammingLanguage::JAVASCRIPT.
*
* All targets must support fetching the script language, but not all
* script targets must support changing it - ie, some targets may only
* support event handlers written in their default language.
*/
attribute PRUint32 scriptTypeID;
};

39
dom/public/nsDOMJSUtils.h Normal file
Просмотреть файл

@ -0,0 +1,39 @@
#ifndef nsDOMJSUtils_h__
#define nsDOMJSUtils_h__
#include "jsapi.h"
#include "nsIScriptContext.h"
// seems like overkill for just this 1 function - but let's see what else
// falls out first.
inline nsIScriptContext *
GetScriptContextFromJSContext(JSContext *cx)
{
if (!(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
return nsnull;
}
nsCOMPtr<nsIScriptContext> scx =
do_QueryInterface(NS_STATIC_CAST(nsISupports *,
::JS_GetContextPrivate(cx)));
// This will return a pointer to something that's about to be
// released, but that's ok here.
return scx;
}
// A factory function for turning a jsval argv into an nsIArray
// but also supports an effecient way of extracting the original argv.
// Bug 312003 describes why this must be "void *", but argv will be cast to
// jsval* and the args are found at:
// ((jsval*)aArgv)[0], ..., ((jsval*)aArgv)[aArgc - 1]
// The resulting object will take a copy of the array, and ensure each
// element is rooted.
// Optionally, aArgv may be NULL, in which case the array is allocated and
// rooted, but all items remain NULL. This presumably means the caller will
// then QI us for nsIJSArgArray, and set our array elements.
nsresult NS_CreateJSArgv(JSContext *aContext, PRUint32 aArgc, void *aArgv,
nsIArray **aArray);
#endif // nsDOMJSUtils_h__

Просмотреть файл

@ -0,0 +1,231 @@
/* -*- 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
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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 nsDOMScriptObjectHolder_h__
#define nsDOMScriptObjectHolder_h__
#include "nsIScriptRuntime.h"
#include "nsIDOMScriptObjectFactory.h"
class nsIScriptContext;
// Drop a reference to a script object when all you have is the script
// language ID.
inline nsresult NS_DropScriptObject(PRUint32 aLangID, void *aThing)
{
nsresult rv;
nsCOMPtr<nsIScriptRuntime> scriptRT;
NS_DEFINE_CID(cid, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
nsCOMPtr<nsIDOMScriptObjectFactory> factory = do_GetService(cid, &rv);
if (NS_SUCCEEDED(rv))
rv = factory->GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRT));
if (NS_SUCCEEDED(rv))
rv = scriptRT->DropScriptObject(aThing);
if (NS_FAILED(rv))
NS_ERROR("Failed to drop the script object");
return rv;
}
// Hold a reference to a script object when all you have is the script
// language ID, and you need to take a copy of the void script object.
// Must be matched by an NS_DropScriptObject
inline nsresult NS_HoldScriptObject(PRUint32 aLangID, void *aThing)
{
nsresult rv;
nsCOMPtr<nsIScriptRuntime> scriptRT;
NS_DEFINE_CID(cid, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
nsCOMPtr<nsIDOMScriptObjectFactory> factory = do_GetService(cid, &rv);
if (NS_SUCCEEDED(rv))
rv = factory->GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRT));
if (NS_SUCCEEDED(rv))
rv = scriptRT->HoldScriptObject(aThing);
if (NS_FAILED(rv))
NS_ERROR("Failed to hold the script object");
return rv;
}
// A thin class used to help with script object memory management. No virtual
// functions and a fully inline implementation should keep the cost down.
// [Note that a fully inline implementation is necessary for use by other
// languages, which do not link against the layout component module]
class nsScriptObjectHolder {
public:
// A constructor that will cause a reference to |ctx| to be stored in
// the object. Only use for short-lived object holders.
nsScriptObjectHolder(nsIScriptContext *ctx, void *aObject = nsnull) :
mObject(aObject), mContextOrLangID(NS_REINTERPRET_CAST(PtrBits, ctx)) {
NS_ASSERTION(ctx, "Must provide a valid context");
NS_ADDREF(ctx);
}
// A constructor that stores only the integer language ID - freeing the
// script object is slower in this case, but is safe for long-lived
// object holders.
nsScriptObjectHolder(PRUint32 aLangID, void *aObject = nsnull) :
mObject(aObject),
mContextOrLangID((aLangID << 1) | SOH_HAS_LANGID_BIT) {
NS_ASSERTION(aLangID != nsIProgrammingLanguage::UNKNOWN,
"Please supply a valid language ID");
}
// copy constructor
nsScriptObjectHolder(const nsScriptObjectHolder& other) :
mObject(other.mObject),
mContextOrLangID(other.mContextOrLangID)
{
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
if (mObject) {
NS_HoldScriptObject(getScriptTypeIDFromBits(), mObject);
}
} else {
// New hold the script object and new reference on the script context.
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "Lost context pointer?");
NS_ADDREF(ctx);
if (mObject)
ctx->HoldScriptObject(mObject);
}
}
~nsScriptObjectHolder() {
// If we have a language ID, then we only need to NS_DropScriptObject if
// we are holding a script object.
// If we have a script context, we must always release our reference to it,
// even if we are not holding a script object.
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
if (mObject) {
NS_DropScriptObject(getScriptTypeIDFromBits(), mObject);
}
} else {
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "Lost context pointer?");
if (mObject) {
ctx->DropScriptObject(mObject);
}
NS_IF_RELEASE(ctx);
}
}
// misc operators
nsScriptObjectHolder &operator=(const nsScriptObjectHolder &other) {
set(other);
return *this;
}
PRBool operator!() const {
return !mObject;
}
operator void *() const {
return mObject;
}
// Drop the script object - but *not* the nsIScriptContext nor the language
// ID.
nsresult drop() {
nsresult rv = NS_OK;
if (mObject) {
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
rv = NS_DropScriptObject(getScriptTypeIDFromBits(), mObject);
} else {
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "Lost ctx pointer!");
rv = ctx->DropScriptObject(mObject);
}
mObject = nsnull;
}
return rv;
}
nsresult set(void *object) {
NS_ASSERTION(getScriptTypeID() != nsIProgrammingLanguage::UNKNOWN,
"Must know the language!");
nsresult rv = drop();
if (NS_FAILED(rv))
return rv;
if (object) {
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
rv = NS_HoldScriptObject(getScriptTypeIDFromBits(), object);
} else {
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
rv = ctx->HoldScriptObject(object);
}
// don't store the pointer if we failed to lock it.
if (NS_SUCCEEDED(rv)) {
mObject = object;
}
}
return rv;
}
nsresult set(const nsScriptObjectHolder &other) {
NS_ASSERTION(getScriptTypeID() == other.getScriptTypeID(),
"Must have identical languages!");
nsresult rv = drop();
if (NS_FAILED(rv))
return rv;
return set(other.mObject);
}
// Get the language ID.
PRUint32 getScriptTypeID() const {
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
return getScriptTypeIDFromBits();
}
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "How did I lose my pointer?");
return ctx->GetScriptTypeID();
}
protected:
PRUint32 getScriptTypeIDFromBits() const {
NS_ASSERTION(mContextOrLangID & SOH_HAS_LANGID_BIT, "Not in the bits!");
return (mContextOrLangID & ~SOH_HAS_LANGID_BIT) >> 1;
}
void *mObject;
// We store either an nsIScriptContext* if this bit is clear,
// else the language ID (specifically, ((lang_id << 1) | SOH_HAS_LANGID_BIT)
// when set.
typedef PRWord PtrBits;
enum { SOH_HAS_LANGID_BIT = 0x1 };
PtrBits mContextOrLangID;
};
#endif // nsDOMScriptObjectHolder_h__

Просмотреть файл

@ -43,19 +43,35 @@
#include "nsString.h"
#define NS_IDOM_SCRIPT_OBJECT_FACTORY_IID \
{ 0xbac2482a, 0x456e, 0x4ea5, \
{ 0x83, 0xfb, 0x16, 0xe1, 0x24, 0x9c, 0x16, 0x6f } }
{ /* {38EC7717-6CBE-44a8-B2BB-53F2BA998B31} */ \
0x38ec7717, 0x6cbe, 0x44a8, \
{ 0xb2, 0xbb, 0x53, 0xf2, 0xba, 0x99, 0x8b, 0x31 } }
class nsIScriptContext;
class nsIScriptGlobalObject;
class nsIScriptRuntime;
class nsIDOMEventListener;
class nsIDOMScriptObjectFactory : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOM_SCRIPT_OBJECT_FACTORY_IID)
NS_IMETHOD NewScriptContext(nsIScriptGlobalObject *aGlobal,
nsIScriptContext **aContext) = 0;
// Get a script language given its "name" (ie, the mime-type)
// Note that to fetch javascript from this function, you must currently
// use the name "application/javascript" (but also note that all existing
// callers of this function optimize the detection of JS, so do not
// ask this function for JS)
NS_IMETHOD GetScriptRuntime(const nsAString &aLanguageName,
nsIScriptRuntime **aLanguage) = 0;
// Get a script language given its nsIProgrammingLanguage ID.
NS_IMETHOD GetScriptRuntimeByID(PRUint32 aScriptTypeID,
nsIScriptRuntime **aLanguage) = 0;
// Get the ID for a language given its name - but like GetScriptRuntime,
// only "application/javascript" is currently supported for JS.
NS_IMETHOD GetIDForScriptType(const nsAString &aLanguageName,
PRUint32 *aScriptTypeID) = 0;
NS_IMETHOD NewScriptGlobalObject(PRBool aIsChrome,
nsIScriptGlobalObject **aGlobal) = 0;

Просмотреть файл

@ -43,29 +43,42 @@
class nsIScriptObjectOwner;
class nsIDOMEventListener;
class nsIAtom;
struct JSObject;
#define NS_IJSEVENTLISTENER_IID \
{ 0xa6cf9118, 0x15b3, 0x11d2, \
{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
// Implemented by JS event listeners. Used to retrieve the
// JSObject corresponding to the event target.
// Implemented by script event listeners. Used to retrieve the
// script object corresponding to the event target.
// (Note this interface is now used to store script objects for all
// script languages, so is no longer JS specific)
class nsIJSEventListener : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSEVENTLISTENER_IID)
nsIJSEventListener(nsIScriptContext *aContext, JSObject *aScopeObject,
nsIJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports *aTarget)
: mContext(aContext), mScopeObject(aScopeObject), mTarget(aTarget)
: mContext(aContext), mScopeObject(aScopeObject), mTarget(nsnull)
{
// mTarget is a weak reference. We are guaranteed because of the
// ownership model that the target will be freed (and the
// references dropped) before either the context or the owner goes
// away.
NS_IF_ADDREF(mContext);
// We keep a weak-ref to the event target to prevent cycles that prevent
// GC from cleaning up our global in all cases. However, as this is a
// weak-ref, we must ensure it is the identity of the event target and
// not a "tear-off" or similar that may not live as long as we expect.
aTarget->QueryInterface(NS_GET_IID(nsISupports),
NS_REINTERPRET_CAST(void **, &mTarget));
if (mTarget)
// We keep a weak-ref, so remove the reference the QI added.
mTarget->Release();
else {
NS_ERROR("Failed to get identity pointer");
}
// To help debug such leaks, we keep a counter of the event listeners
// currently alive. If you change |mTarget| to a strong-ref, this never
// hits zero (running seamonkey.)
#ifdef NS_DEBUG
PR_AtomicIncrement(&sNumJSEventListeners);
#endif
}
nsIScriptContext *GetEventContext()
@ -78,29 +91,34 @@ public:
return mTarget;
}
JSObject *GetEventScope()
void *GetEventScope()
{
return mScopeObject;
}
virtual void SetEventName(nsIAtom* aName) = 0;
protected:
~nsIJSEventListener()
{
NS_IF_RELEASE(mContext);
}
#ifdef NS_DEBUG
static PRInt32 sNumJSEventListeners;
#endif
nsIScriptContext *mContext;
JSObject *mScopeObject;
nsISupports *mTarget;
protected:
virtual ~nsIJSEventListener()
{
#ifdef NS_DEBUG
PR_AtomicDecrement(&sNumJSEventListeners);
#endif
}
nsCOMPtr<nsIScriptContext> mContext;
void *mScopeObject;
nsISupports *mTarget; // weak ref.
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
/* factory function */
nsresult NS_NewJSEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject, nsISupports *aObject,
void *aScopeObject, nsISupports *aObject,
nsIDOMEventListener **aReturn);
#endif // nsIJSEventListener_h__

Просмотреть файл

@ -42,20 +42,26 @@
#include "nsStringGlue.h"
#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "jsapi.h"
#include "nsIProgrammingLanguage.h"
class nsIScriptGlobalObject;
class nsIScriptSecurityManager;
class nsIScriptContextOwner;
class nsIPrincipal;
class nsIAtom;
class nsIArray;
class nsIVariant;
class nsIObjectInputStream;
class nsIObjectOutputStream;
class nsScriptObjectHolder;
class nsIDOMDocument;
typedef void (*nsScriptTerminationFunc)(nsISupports* aRef);
#define NS_ISCRIPTCONTEXT_IID \
{ /* b3fd8821-b46d-4160-913f-cc8fe8176f5f */ \
0xb3fd8821, 0xb46d, 0x4160, \
{0x91, 0x3f, 0xcc, 0x8f, 0xe8, 0x17, 0x6f, 0x5f} }
{ /* {52B46C37-A078-4952-AED7-035D83C810C0} */ \
0x52b46c37, 0xa078, 0x4952, \
{0xae, 0xd7, 0x3, 0x5d, 0x83, 0xc8, 0x10, 0xc0 } }
/**
* It is used by the application to initialize a runtime and run scripts.
@ -69,11 +75,14 @@ class nsIScriptContext : public nsISupports
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTCONTEXT_IID)
/* Get the ID of this language. */
virtual PRUint32 GetScriptTypeID() = 0;
/**
* Compile and execute a script.
*
* @param aScript a string representing the script to be executed
* @param aScopeObject a JavaScript JSObject for the scope to execute in, or
* @param aScopeObject a script object for the scope to execute in, or
* nsnull to use a default scope
* @param aPrincipal the principal that produced the script
* @param aURL the URL or filename for error messages
@ -93,16 +102,18 @@ public:
nsIPrincipal *aPrincipal,
const char *aURL,
PRUint32 aLineNo,
const char* aVersion,
PRUint32 aVersion,
nsAString *aRetValue,
PRBool* aIsUndefined) = 0;
// Note JS bigotry remains here - 'void *aRetValue' is assumed to be a
// jsval. This must move to JSObject before it can be made agnostic.
virtual nsresult EvaluateStringWithValue(const nsAString& aScript,
void *aScopeObject,
nsIPrincipal *aPrincipal,
const char *aURL,
PRUint32 aLineNo,
const char* aVersion,
PRUint32 aVersion,
void* aRetValue,
PRBool* aIsUndefined) = 0;
@ -118,10 +129,9 @@ public:
* @param aLineNo the starting line number of the script for error messages
* @param aVersion the script language version to use when executing
* @param aScriptObject an executable object that's the result of compiling
* the script. The caller is responsible for GC rooting
* this object.
* the script.
*
* @return NS_OK if the script source was valid and got compiled
* @return NS_OK if the script source was valid and got compiled.
*
**/
virtual nsresult CompileScript(const PRUnichar* aText,
@ -130,8 +140,8 @@ public:
nsIPrincipal* aPrincipal,
const char* aURL,
PRUint32 aLineNo,
const char* aVersion,
void** aScriptObject) = 0;
PRUint32 aVersion,
nsScriptObjectHolder &aScriptObject) = 0;
/**
* Execute a precompiled script object.
@ -154,11 +164,13 @@ public:
/**
* Compile the event handler named by atom aName, with function body aBody
* into a function object returned if ok via *aHandler. Bind the lowercase
* ASCII name to the function in its parent object aTarget.
* into a function object returned if ok via aHandler. Does NOT bind the
* function to anything - BindCompiledEventHandler() should be used for that
* purpose. Note that this event handler is always considered 'shared' and
* hence is compiled without principals. Never call the returned object
* directly - it must be bound (and thereby cloned, and therefore have the
* correct principals) before use!
*
* @param aTarget an object telling the scope in which to bind the compiled
* event handler function to aName.
* @param aName an nsIAtom pointer naming the function; it must be lowercase
* and ASCII, and should not be longer than 63 chars. This bound on
* length is enforced only by assertions, so caveat caller!
@ -166,41 +178,33 @@ public:
* @param aBody the event handler function's body
* @param aURL the URL or filename for error messages
* @param aLineNo the starting line number of the script for error messages
* @param aShared flag telling whether the compiled event handler will be
* shared via nsIScriptEventHandlerOwner, in which case any static
* link compiled into it based on aTarget should be cleared, both
* to avoid entraining garbage to be collected, and to trigger static
* link re-binding in BindCompiledEventHandler (see below).
* @param aHandler the out parameter in which a void pointer to the compiled
* function object is returned on success; may be null, meaning the
* caller doesn't need to store the handler for later use.
* function object is stored on success
*
* @return NS_OK if the function body was valid and got compiled
*/
virtual nsresult CompileEventHandler(void* aTarget,
nsIAtom* aName,
const char* aEventName,
virtual nsresult CompileEventHandler(nsIAtom* aName,
PRUint32 aArgCount,
const char** aArgNames,
const nsAString& aBody,
const char* aURL,
PRUint32 aLineNo,
PRBool aShared,
void** aHandler) = 0;
const char* aURL, PRUint32 aLineNo,
nsScriptObjectHolder &aHandler) = 0;
/**
* Call the function object with given args and return its boolean result,
* or true if the result isn't boolean.
*
* @param aTarget an object telling the scope in which to bind the compiled
* @param aTarget the event target
* @param aScript an object telling the scope in which to call the compiled
* event handler function.
* @param aHandler function object (function and static scope) to invoke.
* @param argc actual argument count; length of argv
* @param argv vector of arguments; length is argc
* @param aBoolResult out parameter returning boolean function result, or
* true if the result was not boolean.
* @param argv array of arguments. Note each element is assumed to
* be an nsIVariant.
* @param rval out parameter returning result
**/
virtual nsresult CallEventHandler(JSObject* aTarget, JSObject* aHandler,
uintN argc, jsval* argv,
jsval* rval) = 0;
virtual nsresult CallEventHandler(nsISupports* aTarget,
void *aScope, void* aHandler,
nsIArray *argv, nsIVariant **rval) = 0;
/**
* Bind an already-compiled event handler function to a name in the given
@ -209,19 +213,43 @@ public:
* static scoping must re-bind the scope chain for aHandler to begin (after
* the activation scope for aHandler itself, typically) with aTarget's scope.
*
* Logically, this 'bind' operation is more of a 'copy' - it simply
* stashes/associates the event handler function with the event target, so
* it can be fetched later with GetBoundEventHandler().
*
* @param aTarget an object telling the scope in which to bind the compiled
* event handler function.
* event handler function. The context will presumably associate
* this nsISupports with a native script object.
* @param aName an nsIAtom pointer naming the function; it must be lowercase
* and ASCII, and should not be longer than 63 chars. This bound on
* length is enforced only by assertions, so caveat caller!
* @param aHandler the function object to name, created by an earlier call to
* CompileEventHandler
* @return NS_OK if the function was successfully bound to the name
*
* XXXmarkh - fold this in with SetProperty? Exactly the same concept!
*/
virtual nsresult BindCompiledEventHandler(void* aTarget,
virtual nsresult BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom* aName,
void* aHandler) = 0;
/**
* Lookup a previously bound event handler for the specified target. This
* will return an object equivilent to the one passed to
* BindCompiledEventHandler (although the pointer may not be the same).
*
*/
virtual nsresult GetBoundEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom* aName,
nsScriptObjectHolder &aHandler) = 0;
/**
* Compile a function that isn't used as an event handler.
*
* NOTE: Not yet language agnostic (main problem is XBL - not yet agnostic)
* Caller must make sure aFunctionObject is a JS GC root.
*
**/
virtual nsresult CompileFunction(void* aTarget,
const nsACString& aName,
PRUint32 aArgCount,
@ -230,15 +258,14 @@ public:
const char* aURL,
PRUint32 aLineNo,
PRBool aShared,
void** aFunctionObject) = 0;
void **aFunctionObject) = 0;
/**
* Set the default scripting language version for this context, which must
* be a context specific to a particular scripting language.
*
**/
virtual void SetDefaultLanguageVersion(const char* aVersion) = 0;
virtual void SetDefaultLanguageVersion(PRUint32 aVersion) = 0;
/**
* Return the global object.
@ -253,9 +280,38 @@ public:
virtual void *GetNativeContext() = 0;
/**
* Init this context.
* Return the native global object for this context.
*
* @param aGlobalObject the gobal object
**/
virtual void *GetNativeGlobal() = 0;
/**
* Create a new global object that will be used for an inner window.
* Return the native global and an nsISupports 'holder' that can be used
* to manage the lifetime of it.
*/
virtual nsresult CreateNativeGlobalForInner(
nsIScriptGlobalObject *aNewInner,
PRBool aIsChrome,
void **aNativeGlobal,
nsISupports **aHolder) = 0;
/**
* Connect this context to a new inner window, to allow "prototype"
* chaining from the inner to the outer.
* Called after both the the inner and outer windows are initialized
**/
virtual nsresult ConnectToInner(nsIScriptGlobalObject *aNewInner,
void *aOuterGlobal) = 0;
/**
* Init this context ready for use. If aGlobalObject is not NULL, this
* function may initialize based on this global (for example, using the
* global to locate a chrome window, create a new 'scope' for this
* global, etc)
*
* @param aGlobalObject the gobal object, which may be nsnull.
*
* @return NS_OK if context initialization was successful
*
@ -271,6 +327,11 @@ public:
*/
virtual PRBool IsContextInitialized() = 0;
/**
* Called as the global object discards its reference to the context.
*/
virtual void FinalizeContext() = 0;
/**
* For garbage collected systems, do a synchronous collection pass.
* May be a no-op on other systems
@ -293,6 +354,14 @@ public:
*/
virtual void ScriptEvaluated(PRBool aTerminated) = 0;
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
void *aScriptObject) = 0;
/* Deserialize a script from a stream.
*/
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
nsScriptObjectHolder &aResult) = 0;
/**
* Let the script context know who its owner is.
* The script context should not addref the owner. It
@ -310,6 +379,8 @@ public:
virtual nsIScriptContextOwner *GetOwner() = 0;
/**
* JS only - this function need not be implemented by languages other
* than JS (ie, this should be moved to a private interface!)
* Called to specify a function that should be called when the current
* script (if there is one) terminates. Generally used if breakdown
* of script state needs to happen, but should be deferred till
@ -326,6 +397,9 @@ public:
virtual PRBool GetScriptsEnabled() = 0;
virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts) = 0;
// SetProperty is suspect and jst believes should not be needed. Currenly
// used only for "arguments".
virtual nsresult SetProperty(void *aTarget, const char *aPropName, nsISupports *aVal) = 0;
/**
* Called to set/get information if the script context is
* currently processing a script tag
@ -334,7 +408,8 @@ public:
virtual void SetProcessingScriptTag(PRBool aResult) = 0;
/**
* Tell the context whether or not to GC when destroyed.
* Tell the context whether or not to GC when destroyed. An optimization
* used when the window is a [i]frame, so GC will happen anyway.
*/
virtual void SetGCOnDestruction(PRBool aGCOnDestruction) = 0;
@ -344,7 +419,17 @@ public:
* call DidInitializeContext() when a context is fully
* (successfully) initialized.
*/
virtual nsresult InitClasses(JSObject *aGlobalObj) = 0;
virtual nsresult InitClasses(void *aGlobalObj) = 0;
/**
* Clear the scope object - may be called either as we are being torn down,
* or before we are attached to a different document.
* XXXmarkh - aClearPolluter is quite likely bogus - just that some places
* that did this clear did not call InvalidateGlobalScopePolluter. It
* seems likely this param should be dropped and that fn always called.
* OR some extra virtual added to abstract when that Invalidate need happen.
*/
virtual void ClearScope(void* aGlobalObj, PRBool aClearPolluter) = 0;
/**
* Tell the context we're about to be reinitialize it.
@ -355,25 +440,25 @@ public:
* Tell the context we're done reinitializing it.
*/
virtual void DidInitializeContext() = 0;
/**
* Tell the context our global has a new document, and the scope
* used by it.
*/
virtual void DidSetDocument(nsIDOMDocument *aDoc, void *aGlobal) = 0;
/* Memory managment for script objects. Used by the implementation of
* nsScriptObjectHolder to manage the lifetimes of the held script objects.
*
* See also nsIScriptRuntime, which has identical methods and is useful
* in situations when you do not have an nsIScriptContext.
*
*/
virtual nsresult DropScriptObject(void *object) = 0;
virtual nsresult HoldScriptObject(void *object) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContext, NS_ISCRIPTCONTEXT_IID)
inline nsIScriptContext *
GetScriptContextFromJSContext(JSContext *cx)
{
if (!(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
return nsnull;
}
nsCOMPtr<nsIScriptContext> scx =
do_QueryInterface(NS_STATIC_CAST(nsISupports *,
::JS_GetContextPrivate(cx)));
// This will return a pointer to something that's about to be
// released, but that's ok here.
return scx;
}
#endif // nsIScriptContext_h__

Просмотреть файл

@ -41,23 +41,74 @@
#include "nsISupports.h"
#include "nsEvent.h"
#include "nsIProgrammingLanguage.h"
class nsIScriptContext;
class nsIDOMDocument;
class nsIDOMEvent;
class nsPresContext;
class nsIDocShell;
class nsIDOMWindowInternal;
class nsIScriptGlobalObjectOwner;
struct JSObject;
class nsIArray;
class nsScriptErrorEvent;
class nsIScriptGlobalObject;
enum nsEventStatus;
struct JSObject; // until we finally remove GetGlobalJSObject...
// Some helpers for working with integer "script type IDs", and specifically
// for working with arrays of such objects. For example, it is common for
// implementations supporting multiple script languages to keep each
// language's nsIScriptContext in an array indexed by the language ID.
// Implementation note: We always ignore nsIProgrammingLanguage::UNKNOWN and
// nsIProgrammingLanguage::CPLUSPLUS - this gives javascript slot 0. An
// attempted micro-optimization tried to avoid us going all the way to
// nsIProgrammingLanguage::MAX; however:
// * Someone is reportedly working on a PHP impl - that has value 9
// * nsGenericElement therefore allows 4 bits for the value.
// So there is no good reason for us to be more restrictive again...
#define NS_STID_FIRST nsIProgrammingLanguage::JAVASCRIPT
// like nsGenericElement, only 4 bits worth is valid...
#define NS_STID_LAST (nsIProgrammingLanguage::MAX > 0x000FU ? \
0x000FU : nsIProgrammingLanguage::MAX)
// Use to declare the array size
#define NS_STID_ARRAY_UBOUND (NS_STID_LAST-NS_STID_FIRST+1)
// Is a language ID valid?
#define NS_STID_VALID(langID) (langID >= NS_STID_FIRST && langID <= NS_STID_LAST)
// Return an index for a given ID.
#define NS_STID_INDEX(langID) (langID-NS_STID_FIRST)
// Create a 'for' loop iterating over all possible language IDs (*not* indexes)
#define NS_STID_FOR_ID(varName) \
for (varName=NS_STID_FIRST;varName<=NS_STID_LAST;varName++)
// Create a 'for' loop iterating over all indexes (when you don't need to know
// what language it is)
#define NS_STID_FOR_INDEX(varName) \
for (varName=0;varName<=NS_STID_INDEX(NS_STID_LAST);varName++)
// A helper function for nsIScriptGlobalObject implementations to use
// when handling a script error. Generally called by the global when a context
// notifies it of an error via nsIScriptGlobalObject::HandleScriptError.
// Returns PR_TRUE if HandleDOMEvent was actually called, in which case
// aStatus will be filled in with the status.
PRBool
NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
nsScriptErrorEvent *aErrorEvent,
nsEventStatus *aStatus);
#define NS_ISCRIPTGLOBALOBJECT_IID \
{ 0xd3db0400, 0xcf29, 0x45ac, \
{ 0x80, 0x72, 0x94, 0x6d, 0x99, 0x3d, 0x9d, 0xa8 } }
{ /* {6E7EF978-47D0-47c9-9649-CDCDB1E4CCEC} */ \
0x6e7ef978, 0x47d0, 0x47c9, \
{ 0x96, 0x49, 0xcd, 0xcd, 0xb1, 0xe4, 0xcc, 0xec } }
/**
* The JavaScript specific global object. This often used to store
* per-window global state.
+ * The global object which keeps a script context for each supported script
+ * language. This often used to store per-window global state.
*/
class nsIScriptGlobalObject : public nsISupports
@ -65,8 +116,6 @@ class nsIScriptGlobalObject : public nsISupports
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTGLOBALOBJECT_IID)
virtual void SetContext(nsIScriptContext *aContext) = 0;
virtual nsIScriptContext *GetContext() = 0;
/**
* Let the script global object know who its owner is.
@ -84,31 +133,71 @@ public:
*/
virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner() = 0;
virtual JSObject *GetGlobalJSObject() = 0;
/**
* Ensure that the script global object is initialized for working with the
* specified script language ID. This will set up the nsIScriptContext
* and 'script global' for that language, allowing these to be fetched
* and manipulated.
* @return NS_OK if successful; error conditions include that the language
* has not been registered, as well as 'normal' errors, such as
* out-of-memory
*/
virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID) = 0;
/**
* Get a script context (WITHOUT added reference) for the specified language.
*/
virtual nsIScriptContext *GetScriptContext(PRUint32 lang) = 0;
/**
* Get the opaque "global" object for the specified lang.
*/
virtual void *GetScriptGlobal(PRUint32 lang) = 0;
// Set/GetContext deprecated methods - use GetScriptContext/Global
virtual JSObject *GetGlobalJSObject() {
return (JSObject *)GetScriptGlobal(nsIProgrammingLanguage::JAVASCRIPT);
}
virtual nsIScriptContext *GetContext() {
return GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT);
}
/**
* Called when the global JSObject is finalized
* Set a new language context for this global. The native global for the
* context is created by the context's GetNativeGlobal() method.
*/
virtual void OnFinalize(JSObject *aJSObject) = 0;
virtual nsresult SetScriptContext(PRUint32 lang, nsIScriptContext *aContext) = 0;
/**
* Called when the global script for a language is finalized, typically as
* part of its GC process. By the time this call is made, the
* nsIScriptContext for the language has probably already been removed.
* After this call, the passed object is dead - which should generally be the
* same object the global is using for a global for that language.
*/
virtual void OnFinalize(PRUint32 aLangID, void *aScriptGlobal) = 0;
/**
* Called to enable/disable scripts.
*/
virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts) = 0;
/**
* Set a new arguments array for this window. This will be set on
/** Set a new arguments object for this window. This will be set on
* the window right away (if there's an existing document) and it
* will also be installed on the window when the next document is
* loaded. If argc is nonzero, argv must be non-null.
*
* @param aArgc the number of args
* @param aArgv the pointer to the args. This may be cast to jsval* and the
* args are found at
* ((jsval*)aArgv)[0], ..., ((jsval*)aArgv)[aArgc - 1]
* loaded. Each language impl is responsible for converting to
* an array of args as appropriate for that language.
*/
virtual nsresult SetNewArguments(PRUint32 aArgc, void* aArgv) = 0;
virtual nsresult SetNewArguments(nsIArray *aArguments) = 0;
/** Handle a script error. Generally called by a script context.
*/
virtual nsresult HandleScriptError(nsScriptErrorEvent *aErrorEvent,
nsEventStatus *aEventStatus) {
return NS_HandleScriptError(this, aErrorEvent, aEventStatus);
}
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptGlobalObject,

Просмотреть файл

@ -42,6 +42,8 @@
#include "nsIScriptContext.h"
#include "nsAString.h"
class nsScriptObjectHolder;
#define NS_ISCRIPTOBJECTOWNER_IID \
{ /* 8f6bca7e-ce42-11d1-b724-00600891d8c9 */ \
0x8f6bca7e, 0xce42, 0x11d1, \
@ -117,25 +119,25 @@ public:
* @param aBody the handler script body
* @param aURL the URL or filename for error messages
* @param aLineNo the starting line number of the script for error messages
* @param aHandler the compiled, bound handler object
* @param aHandler the holder for the compiled, bound handler object
*/
virtual nsresult CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsISupports* aTarget,
nsIAtom *aName,
const nsAString& aBody,
const char* aURL,
PRUint32 aLineNo,
void** aHandler) = 0;
nsScriptObjectHolder &aHandler) = 0;
/**
* Retrieve an already-compiled event handler that can be bound to a
* target object using a script context.
*
* @param aName the name of the event handler to retrieve
* @param aHandler the compiled event handler
* @param aHandler the holder for the compiled event handler.
*/
virtual nsresult GetCompiledEventHandler(nsIAtom *aName,
void** aHandler) = 0;
nsScriptObjectHolder &aHandler) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptEventHandlerOwner,

Просмотреть файл

@ -0,0 +1,93 @@
/* ***** 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 mozilla.org.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Hammond (initial development)
*
* Alternatively, the contents of this file may be used under the terms of
* either 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 nsIScriptRuntime_h__
#define nsIScriptRuntime_h__
#include "nsIScriptContext.h"
// {47032A4D-0C22-4125-94B7-864A4B744335}
#define NS_ISCRIPTRUNTIME_IID \
{ 0x47032a4d, 0xc22, 0x4125, { 0x94, 0xb7, 0x86, 0x4a, 0x4b, 0x74, 0x43, 0x35 } }
/**
* A singleton language environment for an application. Responsible for
* initializing and cleaning up the global language environment, and a factory
* for language contexts
*/
class nsIScriptRuntime : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTRUNTIME_IID)
/*
* Return the language ID of this script language
*/
virtual PRUint32 GetScriptTypeID() = 0;
/*
* Called as the language factory is shutting down.
*/
virtual void ShutDown() = 0;
/* Parses a "version string" for the language into a bit-mask used by
* the language implementation. If the specified version is not supported
* an error should be returned. If the specified version is blank, a default
* version should be assumed
*/
virtual nsresult ParseVersion(const nsString &aVersionStr, PRUint32 *verFlags) = 0;
/* Factory for a new context for this language */
virtual nsresult CreateContext(nsIScriptContext **ret) = 0;
/* Memory managment for script objects returned from various
* nsIScriptContext methods. These are identical to those in
* nsIScriptContext, but are useful when a script context is not known.
*/
virtual nsresult DropScriptObject(void *object) = 0;
virtual nsresult HoldScriptObject(void *object) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptRuntime, NS_ISCRIPTRUNTIME_IID)
/* helper functions */
nsresult NS_GetScriptRuntime(const nsAString &aLanguageName,
nsIScriptRuntime **aRuntime);
nsresult NS_GetScriptRuntimeByID(PRUint32 aLanguageID,
nsIScriptRuntime **aRuntime);
#endif // nsIScriptRuntime_h__

Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=80: */
/* ***** 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
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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 nsIScriptTimeoutHandler_h___
#define nsIScriptTimeoutHandler_h___
class nsIArray;
#define NS_ISCRIPTTIMEOUTHANDLER_IID \
{ /* {260C0DAB-0DCF-4c75-B820-46C31005718D} */ \
0x260c0dab, 0xdcf, 0x4c75, \
{ 0xb8, 0x20, 0x46, 0xc3, 0x10, 0x5, 0x71, 0x8d } }
/**
* Abstraction of the script objects etc required to do timeouts in a
* language agnostic way.
*/
class nsIScriptTimeoutHandler : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTTIMEOUTHANDLER_IID)
// Get the script-type (language) implementing this timeout.
virtual PRUint32 GetScriptTypeID() = 0;
// Get a script object for the language suitable for passing back to
// the language's context as an event handler. If this returns nsnull,
// GetHandlerText() will be called to get the string.
virtual void *GetScriptObject() = 0;
// Get the handler text of not a compiled object.
virtual const PRUnichar *GetHandlerText() = 0;
// Get the location of the script.
virtual void GetLocation(const char **aFileName, PRUint32 *aLineNo) = 0;
// If a script object, get the argv suitable for passing back to the
// script context.
virtual nsIArray *GetArgv() = 0;
// Get the language version for this timeout.
virtual PRUint32 GetScriptVersion() = 0;
// Set the "secret" final lateness arg. This will be called before
// GetArgv(), which should reflect this lateness value.
virtual void SetLateness(PRIntervalTime aHowLate) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptTimeoutHandler,
NS_ISCRIPTTIMEOUTHANDLER_IID)
#endif // nsIScriptTimeoutHandler_h___

Просмотреть файл

@ -92,6 +92,7 @@ CPPSRCS = \
nsDOMException.cpp \
nsDOMWindowUtils.cpp \
nsJSEnvironment.cpp \
nsJSTimeoutHandler.cpp \
nsFocusController.cpp \
nsGlobalWindow.cpp \
nsGlobalWindowCommands.cpp \

Просмотреть файл

@ -6427,7 +6427,7 @@ nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
sgo->OnFinalize(obj);
sgo->OnFinalize(nsIProgrammingLanguage::JAVASCRIPT, obj);
return nsEventReceiverSH::Finalize(wrapper, cx, obj);
}

Просмотреть файл

@ -45,6 +45,7 @@
#include "jsapi.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScriptContext.h"
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
class nsIDOMWindow;
class nsIDOMNSHTMLOptionCollection;

Просмотреть файл

@ -59,13 +59,17 @@
#include "nsJSEventListener.h"
#include "nsGlobalWindow.h"
#include "nsIJSContextStack.h"
#include "nsISupportsPrimitives.h"
#include "nsDOMException.h"
#include "nsCRT.h"
#ifdef MOZ_XUL
#include "nsIXULPrototypeCache.h"
#endif
nsDOMScriptObjectFactory::nsDOMScriptObjectFactory()
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
nsDOMScriptObjectFactory::nsDOMScriptObjectFactory() :
mLoadedAllLanguages(PR_FALSE)
{
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1");
@ -86,6 +90,8 @@ nsDOMScriptObjectFactory::nsDOMScriptObjectFactory()
xs->RegisterExceptionProvider(this, NS_ERROR_MODULE_DOM_XPATH);
xs->RegisterExceptionProvider(this, NS_ERROR_MODULE_XPCONNECT);
}
// And pre-create the javascript language.
NS_CreateJSRuntime(getter_AddRefs(mLanguageArray[NS_STID_INDEX(nsIProgrammingLanguage::JAVASCRIPT)]));
}
NS_INTERFACE_MAP_BEGIN(nsDOMScriptObjectFactory)
@ -99,12 +105,106 @@ NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMScriptObjectFactory)
NS_IMPL_RELEASE(nsDOMScriptObjectFactory)
/**
* Notes about language registration (for language other than js):
* - All language are expected to register (at least) 2 contract IDs
* @mozilla.org/script-language;1?id=%d
* using the language ID as defined in nsIProgrammingLanguage, and
* @mozilla.org/script-language;1?script-type=%s
* using the "mime-type" of the script language
*
* Theoretically, a language could register multiple script-type
* names, although this is discouraged - each language should have one,
* canonical name.
*
* The most common case is that languages are looked up by ID. For this
* reason, we keep an array of languages indexed by this ID - the registry
* is only looked the first request for a language ID.
*
* The registry is looked up and getService called for each query by name.
* (As services are cached by CID, multiple contractIDs will still work
* correctly)
**/
NS_IMETHODIMP
nsDOMScriptObjectFactory::NewScriptContext(nsIScriptGlobalObject *aGlobal,
nsIScriptContext **aContext)
nsDOMScriptObjectFactory::GetScriptRuntime(const nsAString &aLanguageName,
nsIScriptRuntime **aLanguage)
{
return NS_CreateScriptContext(aGlobal, aContext);
// Note that many callers have optimized detection for JS (along with
// supporting various alternate names for JS), so don't call this.
// One exception is for the new "script-type" attribute on a node - and
// there is no need to support backwards compatible names.
// As JS is the default language, this is still rarely called for JS -
// only when a node explicitly sets JS - so that is done last.
nsCAutoString contractid(NS_LITERAL_CSTRING(
"@mozilla.org/script-language;1?script-type="));
// Arbitrarily use utf8 encoding should the name have extended chars
AppendUTF16toUTF8(aLanguageName, contractid);
nsresult rv;
nsCOMPtr<nsIScriptRuntime> lang =
do_GetService(contractid.get(), &rv);
if (NS_FAILED(rv)) {
if (aLanguageName.Equals(NS_LITERAL_STRING("application/javascript")))
return GetScriptRuntimeByID(nsIProgrammingLanguage::JAVASCRIPT, aLanguage);
// Not JS and nothing else we know about.
NS_WARNING("No script language registered for this mime-type");
return NS_ERROR_FACTORY_NOT_REGISTERED;
}
// And stash it away in our array for fast lookup by ID.
PRUint32 lang_ndx = NS_STID_INDEX(lang->GetScriptTypeID());
if (mLanguageArray[lang_ndx] == nsnull) {
mLanguageArray[lang_ndx] = lang;
} else {
// All languages are services - we should have an identical object!
NS_ASSERTION(mLanguageArray[lang_ndx] == lang,
"Got a different language for this ID???");
}
*aLanguage = lang;
NS_IF_ADDREF(*aLanguage);
return NS_OK;
}
NS_IMETHODIMP
nsDOMScriptObjectFactory::GetScriptRuntimeByID(PRUint32 aLanguageID,
nsIScriptRuntime **aLanguage)
{
if (!NS_STID_VALID(aLanguageID)) {
NS_WARNING("Unknown script language");
return NS_ERROR_UNEXPECTED;
}
*aLanguage = mLanguageArray[NS_STID_INDEX(aLanguageID)];
if (!*aLanguage) {
nsCAutoString contractid(NS_LITERAL_CSTRING(
"@mozilla.org/script-language;1?id="));
char langIdStr[25]; // space for an int.
sprintf(langIdStr, "%d", aLanguageID);
contractid += langIdStr;
nsresult rv;
nsCOMPtr<nsIScriptRuntime> lang = do_GetService(contractid.get(), &rv);
if (NS_FAILED(rv)) {
NS_ERROR("Failed to get the script language");
return rv;
}
*aLanguage = lang;
}
NS_IF_ADDREF(*aLanguage);
return NS_OK;
}
NS_IMETHODIMP
nsDOMScriptObjectFactory::GetIDForScriptType(const nsAString &aLanguageName,
PRUint32 *aScriptTypeID)
{
nsCOMPtr<nsIScriptRuntime> languageRuntime;
nsresult rv;
rv = GetScriptRuntime(aLanguageName, getter_AddRefs(languageRuntime));
if (NS_FAILED(rv))
return rv;
*aScriptTypeID = languageRuntime->GetScriptTypeID();
return NS_OK;
}
NS_IMETHODIMP
@ -184,7 +284,14 @@ nsDOMScriptObjectFactory::Observe(nsISupports *aSubject,
nsGlobalWindow::ShutDown();
nsDOMClassInfo::ShutDown();
nsJSEnvironment::ShutDown();
PRUint32 i;
NS_STID_FOR_INDEX(i) {
if (mLanguageArray[i] != nsnull) {
mLanguageArray[i]->ShutDown();
mLanguageArray[i] = nsnull;
}
}
nsCOMPtr<nsIExceptionService> xs =
do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID);
@ -262,3 +369,38 @@ nsDOMScriptObjectFactory::RegisterDOMClassInfo(const char *aName,
aHasClassInterface,
aConstructorCID);
}
/* static */ nsresult
nsDOMScriptObjectFactory::Startup()
{
nsJSRuntime::Startup();
// nsDOMScriptObjectFactory is a service - assuming that reinitialzing
// xpcom also recreates all services, then everything else should
// reinitialize correctly.
return NS_OK;
}
// Factories
nsresult NS_GetScriptRuntime(const nsAString &aLanguageName,
nsIScriptRuntime **aLanguage)
{
nsresult rv;
*aLanguage = nsnull;
nsCOMPtr<nsIDOMScriptObjectFactory> factory = \
do_GetService(kDOMScriptObjectFactoryCID, &rv);
if (NS_FAILED(rv))
return rv;
return factory->GetScriptRuntime(aLanguageName, aLanguage);
}
nsresult NS_GetScriptRuntimeByID(PRUint32 aScriptTypeID,
nsIScriptRuntime **aLanguage)
{
nsresult rv;
*aLanguage = nsnull;
nsCOMPtr<nsIDOMScriptObjectFactory> factory = \
do_GetService(kDOMScriptObjectFactoryCID, &rv);
if (NS_FAILED(rv))
return rv;
return factory->GetScriptRuntimeByID(aScriptTypeID, aLanguage);
}

Просмотреть файл

@ -53,6 +53,8 @@
#include "nsIDOMScriptObjectFactory.h"
#include "nsIObserver.h"
#include "nsIExceptionService.h"
#include "nsIScriptRuntime.h"
#include "nsIScriptGlobalObject.h" // for misplaced NS_STID_ macros.
class nsDOMScriptObjectFactory : public nsIDOMScriptObjectFactory,
public nsIObserver,
@ -70,8 +72,14 @@ public:
NS_DECL_NSIEXCEPTIONPROVIDER
// nsIDOMScriptObjectFactory
NS_IMETHOD NewScriptContext(nsIScriptGlobalObject *aGlobal,
nsIScriptContext **aContext);
NS_IMETHOD GetScriptRuntime(const nsAString &aLanguageName,
nsIScriptRuntime **aLanguage);
NS_IMETHOD GetScriptRuntimeByID(PRUint32 aLanguageID,
nsIScriptRuntime **aLanguage);
NS_IMETHOD GetIDForScriptType(const nsAString &aLanguageName,
PRUint32 *aLanguageID);
NS_IMETHOD NewScriptGlobalObject(PRBool aIsChrome,
nsIScriptGlobalObject **aGlobal);
@ -86,4 +94,10 @@ public:
PRUint32 aScriptableFlags,
PRBool aHasClassInterface,
const nsCID *aConstructorCID);
static nsresult Startup();
protected:
PRBool mLoadedAllLanguages;
nsCOMPtr<nsIScriptRuntime> mLanguageArray[NS_STID_ARRAY_UBOUND];
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -73,6 +73,7 @@
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptTimeoutHandler.h"
#include "nsITimer.h"
#include "nsIWebBrowserChrome.h"
#include "nsPIDOMWindow.h"
@ -103,6 +104,7 @@ class nsIContent;
class nsPresContext;
class nsIDOMEvent;
class nsIScrollableView;
class nsIArray;
typedef struct nsTimeout nsTimeout;
@ -122,6 +124,12 @@ enum OpenAllowValue {
allowWhitelisted // allowed: it's whitelisted or popup blocking is disabled
};
extern nsresult
NS_CreateJSTimeoutHandler(nsIScriptContext *aContext,
PRBool aIsInterval,
PRInt32 *aInterval,
nsIScriptTimeoutHandler **aRet);
//*****************************************************************************
// nsGlobalWindow: Global Object for Scripting
//*****************************************************************************
@ -165,14 +173,23 @@ public:
NS_DECL_ISUPPORTS
// nsIScriptGlobalObject
virtual void SetContext(nsIScriptContext *aContext);
virtual nsIScriptContext *GetContext();
virtual JSObject *GetGlobalJSObject();
virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID);
virtual nsIScriptContext *GetScriptContext(PRUint32 lang);
virtual void *GetScriptGlobal(PRUint32 lang);
// Set a new script language context for this global. The native global
// for the context is created by the context's GetNativeGlobal() method.
virtual nsresult SetScriptContext(PRUint32 lang, nsIScriptContext *aContext);
virtual void SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner);
virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner();
virtual JSObject *GetGlobalJSObject();
virtual void OnFinalize(JSObject *aJSObject);
virtual void OnFinalize(PRUint32 aLangID, void *aScriptGlobal);
virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
virtual nsresult SetNewArguments(PRUint32 aArgc, void* aArgv);
virtual nsresult SetNewArguments(nsIArray *aArguments);
// nsIScriptObjectPrincipal
virtual nsIPrincipal* GetPrincipal();
@ -278,6 +295,16 @@ public:
return mContext;
}
nsIScriptContext *GetScriptContextInternal(PRUint32 aLangID)
{
NS_ASSERTION(NS_STID_VALID(aLangID), "Invalid language");
if (mOuterWindow) {
return GetOuterWindowInternal()->mScriptContexts[NS_STID_INDEX(aLangID)];
}
return mScriptContexts[NS_STID_INDEX(aLangID)];
}
nsGlobalWindow *GetOuterWindowInternal()
{
return NS_STATIC_CAST(nsGlobalWindow *, GetOuterWindow());
@ -312,7 +339,7 @@ protected:
void CleanUp();
void ClearControllers();
void FreeInnerObjects(JSContext *cx);
void FreeInnerObjects(nsIScriptContext *cx);
nsresult SetNewDocument(nsIDocument *aDocument,
nsISupports *aState,
@ -380,7 +407,7 @@ protected:
PRBool aDialog,
PRBool aCalledNoScript,
PRBool aDoJSFixups,
jsval *argv, PRUint32 argc,
nsIArray *argv,
nsISupports *aExtraArgument,
nsIDOMWindow **aReturn);
@ -388,9 +415,19 @@ protected:
static void ClearWindowScope(nsISupports* aWindow);
// Timeout Functions
// Language agnostic timeout function (all args passed)
nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
PRInt32 interval,
PRBool aIsInterval, PRInt32 *aReturn);
nsresult ClearTimeoutOrInterval(PRInt32 aTimerID);
// JS specific timeout functions (JS args grabbed from context).
nsresult SetTimeoutOrInterval(PRBool aIsInterval, PRInt32* aReturn);
void RunTimeout(nsTimeout *aTimeout);
nsresult ClearTimeoutOrInterval();
// The timeout implementation functions.
void RunTimeout(nsTimeout *aTimeout);
void ClearAllTimeouts();
void InsertTimeoutIntoList(nsTimeout **aInsertionPoint, nsTimeout *aTimeout);
static void TimerCallback(nsITimer *aTimer, void *aClosure);
@ -500,7 +537,8 @@ protected:
nsCOMPtr<nsIScriptContext> mContext;
nsCOMPtr<nsIDOMWindowInternal> mOpener;
nsCOMPtr<nsIControllers> mControllers;
JSObject* mArguments;
nsCOMPtr<nsIArray> mArguments;
nsCOMPtr<nsIArray> mArgumentsLast;
nsRefPtr<nsNavigator> mNavigator;
nsRefPtr<nsScreen> mScreen;
nsRefPtr<nsHistory> mHistory;
@ -515,15 +553,19 @@ protected:
nsRefPtr<nsLocation> mLocation;
nsString mStatus;
nsString mDefaultStatus;
// index 0->language_id 1, so index MAX-1 == language_id MAX
nsCOMPtr<nsIScriptContext> mScriptContexts[NS_STID_ARRAY_UBOUND];
void * mScriptGlobals[NS_STID_ARRAY_UBOUND];
nsGlobalWindowObserver* mObserver;
nsIScriptGlobalObjectOwner* mGlobalObjectOwner; // Weak Reference
nsCOMPtr<nsIDOMCrypto> mCrypto;
nsCOMPtr<nsIDOMPkcs11> mPkcs11;
nsCOMPtr<nsIDOMStorageList> gGlobalStorageList;
nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
nsCOMPtr<nsISupports> mInnerWindowHolders[NS_STID_ARRAY_UBOUND];
nsCOMPtr<nsIPrincipal> mOpenerScriptPrincipal; // strong; used to determine
// whether to clear scope
@ -576,8 +618,9 @@ protected:
};
/*
* Timeout struct that holds information about each JavaScript
* timeout.
* Timeout struct that holds information about each script
* timeout. Holds a strong reference to an nsIScriptTimeoutHandler, which
* abstracts the language specific cruft.
*/
struct nsTimeout
{
@ -609,23 +652,15 @@ struct nsTimeout
MOZ_COUNT_DTOR(nsTimeout);
}
void Release(nsIScriptContext* aContext);
void AddRef();
nsrefcnt Release();
nsrefcnt AddRef();
// Window for which this timeout fires
nsGlobalWindow *mWindow;
// The JS expression to evaluate or function to call, if !mExpr
JSString *mExpr;
JSObject *mFunObj;
nsRefPtr<nsGlobalWindow> mWindow;
// The actual timer object
nsCOMPtr<nsITimer> mTimer;
// Function actual arguments and argument count
jsval *mArgv;
PRUint16 mArgc;
// True if the timeout was cleared
PRPackedBool mCleared;
@ -645,12 +680,6 @@ struct nsTimeout
// Principal with which to execute
nsCOMPtr<nsIPrincipal> mPrincipal;
// filename, line number and JS language version string of the
// caller of setTimeout()
char *mFileName;
PRUint32 mLineNo;
const char *mVersion;
// stack depth at which timeout is firing
PRUint32 mFiringDepth;
@ -662,6 +691,9 @@ struct nsTimeout
// another timeout
PopupControlState mPopupState;
// The language-specific information about the callback.
nsCOMPtr<nsIScriptTimeoutHandler> mScriptHandler;
private:
// reference count for shared usage
PRInt32 mRefCnt;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -38,9 +38,9 @@
#define nsJSEnvironment_h___
#include "nsIScriptContext.h"
#include "nsIScriptRuntime.h"
#include "nsCOMPtr.h"
#include "jsapi.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXPCScriptNotify.h"
@ -58,12 +58,15 @@ public:
NS_DECL_ISUPPORTS
virtual PRUint32 GetScriptTypeID()
{ return nsIProgrammingLanguage::JAVASCRIPT; }
virtual nsresult EvaluateString(const nsAString& aScript,
void *aScopeObject,
nsIPrincipal *principal,
const char *aURL,
PRUint32 aLineNo,
const char* aVersion,
PRUint32 aVersion,
nsAString *aRetValue,
PRBool* aIsUndefined);
virtual nsresult EvaluateStringWithValue(const nsAString& aScript,
@ -71,7 +74,7 @@ public:
nsIPrincipal *aPrincipal,
const char *aURL,
PRUint32 aLineNo,
const char* aVersion,
PRUint32 aVersion,
void* aRetValue,
PRBool* aIsUndefined);
@ -81,25 +84,29 @@ public:
nsIPrincipal *principal,
const char *aURL,
PRUint32 aLineNo,
const char* aVersion,
void** aScriptObject);
PRUint32 aVersion,
nsScriptObjectHolder &aScriptObject);
virtual nsresult ExecuteScript(void* aScriptObject,
void *aScopeObject,
nsAString* aRetValue,
PRBool* aIsUndefined);
virtual nsresult CompileEventHandler(void *aTarget,
nsIAtom *aName,
const char *aEventName,
virtual nsresult CompileEventHandler(nsIAtom *aName,
PRUint32 aArgCount,
const char** aArgNames,
const nsAString& aBody,
const char *aURL,
PRUint32 aLineNo,
PRBool aShared,
void** aHandler);
virtual nsresult CallEventHandler(JSObject *aTarget, JSObject *aHandler,
uintN argc, jsval *argv, jsval* rval);
virtual nsresult BindCompiledEventHandler(void *aTarget,
const char *aURL, PRUint32 aLineNo,
nsScriptObjectHolder &aHandler);
virtual nsresult CallEventHandler(nsISupports* aTarget, void *aScope,
void* aHandler,
nsIArray *argv, nsIVariant **rv);
virtual nsresult BindCompiledEventHandler(nsISupports *aTarget,
void *aScope,
nsIAtom *aName,
void *aHandler);
virtual nsresult GetBoundEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom* aName,
nsScriptObjectHolder &aHandler);
virtual nsresult CompileFunction(void* aTarget,
const nsACString& aName,
PRUint32 aArgCount,
@ -110,11 +117,21 @@ public:
PRBool aShared,
void** aFunctionObject);
virtual void SetDefaultLanguageVersion(const char* aVersion);
virtual void SetDefaultLanguageVersion(PRUint32 aVersion);
virtual nsIScriptGlobalObject *GetGlobalObject();
virtual void *GetNativeContext();
virtual void *GetNativeGlobal();
virtual nsresult CreateNativeGlobalForInner(
nsIScriptGlobalObject *aGlobal,
PRBool aIsChrome,
void **aNativeGlobal,
nsISupports **aHolder);
virtual nsresult ConnectToInner(nsIScriptGlobalObject *aNewInner,
void *aOuterGlobal);
virtual nsresult InitContext(nsIScriptGlobalObject *aGlobalObject);
virtual PRBool IsContextInitialized();
virtual void FinalizeContext();
virtual void GC();
virtual void ScriptEvaluated(PRBool aTerminated);
@ -125,15 +142,26 @@ public:
virtual PRBool GetScriptsEnabled();
virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
virtual nsresult SetProperty(void *aTarget, const char *aPropName, nsISupports *aVal);
virtual PRBool GetProcessingScriptTag();
virtual void SetProcessingScriptTag(PRBool aResult);
virtual void SetGCOnDestruction(PRBool aGCOnDestruction);
virtual nsresult InitClasses(JSObject *aGlobalObj);
virtual nsresult InitClasses(void *aGlobalObj);
virtual void ClearScope(void* aGlobalObj, PRBool bClearPolluters);
virtual void WillInitializeContext();
virtual void DidInitializeContext();
virtual void DidSetDocument(nsIDOMDocument *aDocdoc, void *aGlobal) {;}
virtual nsresult Serialize(nsIObjectOutputStream* aStream, void *aScriptObject);
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
nsScriptObjectHolder &aResult);
virtual nsresult DropScriptObject(void *object);
virtual nsresult HoldScriptObject(void *object);
NS_DECL_NSIXPCSCRIPTNOTIFY
@ -145,8 +173,21 @@ protected:
// aHolder should be holding our global object
nsresult FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder);
// Helper to convert xpcom datatypes to jsvals.
nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
void *aScope,
PRUint32 *aArgc, void **aArgv,
void **aMarkp);
nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
void FireGCTimer();
// given an nsISupports object (presumably an event target or some other
// DOM object), get (or create) the JSObject wrapping it.
nsresult JSObjectFromInterface(nsISupports *aSup, void *aScript,
JSObject **aRet);
private:
JSContext *mContext;
PRUint32 mNumEvaluations;
@ -232,25 +273,60 @@ private:
class nsIJSRuntimeService;
class nsJSEnvironment
class nsJSRuntime : public nsIScriptRuntime
{
private:
public:
// let people who can see us use our runtime for convenience.
static JSRuntime *sRuntime;
public:
// called from the module Ctor to initialize statics
// nsISupports
NS_DECL_ISUPPORTS
// nsIScriptRuntime
virtual void ShutDown();
virtual PRUint32 GetScriptTypeID() {
return nsIProgrammingLanguage::JAVASCRIPT;
}
virtual nsresult CreateContext(nsIScriptContext **ret);
virtual nsresult ParseVersion(const nsString &aVersionStr, PRUint32 *flags);
virtual nsresult DropScriptObject(void *object);
virtual nsresult HoldScriptObject(void *object);
// Private stuff.
// called by the nsDOMScriptObjectFactory to initialize statics
static void Startup();
// Setup all the statics etc - safe to call multiple times after Startup()
static nsresult Init();
static nsresult CreateNewContext(nsIScriptContext **aContext);
static void ShutDown();
};
/* factory function */
nsresult NS_CreateScriptContext(nsIScriptGlobalObject *aGlobal,
nsIScriptContext **aContext);
// An interface for fast and native conversion to/from nsIArray. If an object
// supports this interface, JS can reach directly in for the argv, and avoid
// nsISupports conversion. If this interface is not supported, the object will
// be queried for nsIArray, and everything converted via xpcom objects.
#define NS_IJSARGARRAY_IID \
{ /*{E96FB2AE-CB4F-44a0-81F8-D91C80AFE9A3} */ \
0xe96fb2ae, 0xcb4f, 0x44a0, \
{ 0x81, 0xf8, 0xd9, 0x1c, 0x80, 0xaf, 0xe9, 0xa3 } }
class nsIJSArgArray: public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSARGARRAY_IID)
// Bug 312003 describes why this must be "void **", but after calling argv
// may be cast to jsval* and the args found at:
// ((jsval*)argv)[0], ..., ((jsval*)argv)[argc - 1]
virtual nsresult GetArgs(PRUint32 *argc, void **argv) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID)
/* factory functions */
nsresult NS_CreateJSRuntime(nsIScriptRuntime **aRuntime);
/* prototypes */
void JS_DLL_CALLBACK NS_ScriptErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);

Просмотреть файл

@ -0,0 +1,338 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=80: */
/* ***** 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
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Hammond <mhammond@skippinet.com.au>
*
* 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 "nsCOMPtr.h"
#include "nsIScriptContext.h"
#include "nsIArray.h"
#include "nsIScriptTimeoutHandler.h"
#include "nsIXPConnect.h"
#include "nsIJSRuntimeService.h"
#include "nsJSUtils.h"
#include "nsDOMJSUtils.h"
#include "nsContentUtils.h"
#include "nsJSEnvironment.h"
#include "nsServiceManagerUtils.h"
static const char kSetIntervalStr[] = "setInterval";
static const char kSetTimeoutStr[] = "setTimeout";
// Our JS nsIScriptTimeoutHandler implementation.
class nsJSScriptTimeoutHandler: public nsIScriptTimeoutHandler
{
public:
// nsISupports
NS_DECL_ISUPPORTS
nsJSScriptTimeoutHandler();
~nsJSScriptTimeoutHandler();
virtual const PRUnichar *GetHandlerText();
virtual void *GetScriptObject() {
return mFunObj;
}
virtual void GetLocation(const char **aFileName, PRUint32 *aLineNo) {
*aFileName = mFileName.get();
*aLineNo = mLineNo;
}
virtual PRUint32 GetScriptTypeID() {
return nsIProgrammingLanguage::JAVASCRIPT;
}
virtual PRUint32 GetScriptVersion() {
return mVersion;
}
virtual nsIArray *GetArgv() {
return mArgv;
}
// Called by the timeout mechanism so the secret 'lateness' arg can be
// added.
virtual void SetLateness(PRIntervalTime aHowLate);
nsresult Init(nsIScriptContext *aContext, PRBool aIsInterval,
PRInt32 *aInterval);
private:
nsCOMPtr<nsIScriptContext> mContext;
// filename, line number and JS language version string of the
// caller of setTimeout()
nsCAutoString mFileName;
PRUint32 mLineNo;
PRUint32 mVersion;
nsCOMPtr<nsIArray> mArgv;
// The JS expression to evaluate or function to call, if !mExpr
JSString *mExpr;
JSObject *mFunObj;
};
// nsJSScriptTimeoutHandler
// QueryInterface implementation for nsJSScriptTimeoutHandler
NS_INTERFACE_MAP_BEGIN(nsJSScriptTimeoutHandler)
NS_INTERFACE_MAP_ENTRY(nsIScriptTimeoutHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsJSScriptTimeoutHandler)
NS_IMPL_RELEASE(nsJSScriptTimeoutHandler)
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler() :
mLineNo(0),
mVersion(nsnull),
mExpr(nsnull),
mFunObj(nsnull)
{
}
nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler()
{
if (mExpr || mFunObj) {
nsIScriptContext *scx = mContext;
JSRuntime *rt = nsnull;
if (scx) {
JSContext *cx;
cx = (JSContext *)scx->GetNativeContext();
rt = ::JS_GetRuntime(cx);
} else {
// XXX The timeout *must* be unrooted, even if !scx. This can be
// done without a JS context using the JSRuntime. This is safe
// enough, but it would be better to drop all a window's
// timeouts before its context is cleared. Bug 50705 describes a
// situation where we're not. In that case, at the time the
// context is cleared, a timeout (actually an Interval) is still
// active, but temporarily removed from the window's list of
// timers (placed instead on the timer manager's list). This
// makes the nearly handy ClearAllTimeouts routine useless, so
// we settled on using the JSRuntime rather than relying on the
// window having a context. It would be good to remedy this
// workable but clumsy situation someday.
nsCOMPtr<nsIJSRuntimeService> rtsvc =
do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
if (rtsvc) {
rtsvc->GetRuntime(&rt);
}
}
if (!rt) {
// most unexpected. not much choice but to bail.
NS_ERROR("nsTimeout::Release() with no JSRuntime. eek!");
return;
}
if (mExpr) {
::JS_RemoveRootRT(rt, &mExpr);
} else if (mFunObj) {
::JS_RemoveRootRT(rt, &mFunObj);
} else {
NS_WARNING("No func and no expr - roots may not have been removed");
}
}
}
nsresult
nsJSScriptTimeoutHandler::Init(nsIScriptContext *aContext, PRBool aIsInterval,
PRInt32 *aInterval)
{
if (!aContext) {
// This window was already closed, or never properly initialized,
// don't let a timer be scheduled on such a window.
return NS_ERROR_NOT_INITIALIZED;
}
mContext = aContext;
nsCOMPtr<nsIXPCNativeCallContext> ncc;
nsresult rv = nsContentUtils::XPConnect()->
GetCurrentNativeCallContext(getter_AddRefs(ncc));
NS_ENSURE_SUCCESS(rv, rv);
if (!ncc)
return NS_ERROR_NOT_AVAILABLE;
JSContext *cx = nsnull;
rv = ncc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 argc;
jsval *argv = nsnull;
ncc->GetArgc(&argc);
ncc->GetArgvPtr(&argv);
JSString *expr = nsnull;
JSObject *funobj = nsnull;
int32 interval = 0;
JSAutoRequest ar(cx);
if (argc < 1) {
::JS_ReportError(cx, "Function %s requires at least 1 parameter",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
return ncc->SetExceptionWasThrown(PR_TRUE);
}
if (argc > 1 && !::JS_ValueToECMAInt32(cx, argv[1], &interval)) {
::JS_ReportError(cx,
"Second argument to %s must be a millisecond interval",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
return ncc->SetExceptionWasThrown(PR_TRUE);
}
switch (::JS_TypeOfValue(cx, argv[0])) {
case JSTYPE_FUNCTION:
funobj = JSVAL_TO_OBJECT(argv[0]);
break;
case JSTYPE_STRING:
case JSTYPE_OBJECT:
expr = ::JS_ValueToString(cx, argv[0]);
if (!expr)
return NS_ERROR_OUT_OF_MEMORY;
argv[0] = STRING_TO_JSVAL(expr);
break;
default:
::JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
return ncc->SetExceptionWasThrown(PR_TRUE);
}
if (expr) {
if (!::JS_AddNamedRoot(cx, &mExpr, "timeout.mExpr")) {
return NS_ERROR_OUT_OF_MEMORY;
}
mExpr = expr;
} else if (funobj) {
if (!::JS_AddNamedRoot(cx, &mFunObj, "timeout.mFunObj")) {
return NS_ERROR_OUT_OF_MEMORY;
}
mFunObj = funobj;
/* Create our arg array - leave an extra slot for a secret final argument
that indicates to the called function how "late" the timeout is. We
will fill that in when SetLateness is called.
*/
nsCOMPtr<nsIArray> array;
rv = NS_CreateJSArgv(cx, argc-1, nsnull, getter_AddRefs(array));
if (NS_FAILED(rv)) {
return NS_ERROR_OUT_OF_MEMORY;
}
PRUint32 dummy;
jsval *jsargv = nsnull;
nsCOMPtr<nsIJSArgArray> jsarray(do_QueryInterface(array));
jsarray->GetArgs(&dummy, NS_REINTERPRET_CAST(void **, &jsargv));
// must have worked - we own the impl! :)
NS_ASSERTION(jsargv, "No argv!");
for (PRInt32 i = 2; (PRUint32)i < argc; ++i) {
jsargv[i - 2] = argv[i];
}
// final arg slot remains null, array has rooted vals.
mArgv = array;
// Get the calling location.
const char *filename;
if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
mFileName.Assign(filename);
if (mFileName.IsEmpty()) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
} else {
NS_WARNING("No func and no expr - why are we here?");
}
*aInterval = interval;
return NS_OK;
}
void nsJSScriptTimeoutHandler::SetLateness(PRIntervalTime aHowLate)
{
nsCOMPtr<nsIJSArgArray> jsarray(do_QueryInterface(mArgv));
if (jsarray) {
PRUint32 argc;
jsval *jsargv;
jsarray->GetArgs(&argc, NS_REINTERPRET_CAST(void **, &jsargv));
if (jsargv && argc)
jsargv[argc-1] = INT_TO_JSVAL((jsint) aHowLate);
} else {
NS_ERROR("How can our argv not handle this?");
}
}
const PRUnichar *
nsJSScriptTimeoutHandler::GetHandlerText()
{
NS_ASSERTION(mExpr, "No expression, so no handler text!");
return NS_REINTERPRET_CAST(const PRUnichar *,
::JS_GetStringChars(mExpr));
}
nsresult NS_CreateJSTimeoutHandler(nsIScriptContext *aContext,
PRBool aIsInterval,
PRInt32 *aInterval,
nsIScriptTimeoutHandler **aRet)
{
*aRet = nsnull;
nsJSScriptTimeoutHandler *handler = new nsJSScriptTimeoutHandler();
if (!handler)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = handler->Init(aContext, aIsInterval, aInterval);
if (NS_FAILED(rv)) {
delete handler;
return rv;
}
return handler->QueryInterface(NS_GET_IID(nsIScriptTimeoutHandler),
NS_REINTERPRET_CAST(void **, aRet));
}

Просмотреть файл

@ -59,6 +59,7 @@
#include "nsIDOMGCParticipant.h"
#include "nsIWeakReference.h"
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
JSBool
nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
@ -198,7 +199,7 @@ nsJSUtils::GetStaticScriptContext(JSContext* aContext, JSObject* aObj)
if (!nativeGlobal)
return nsnull;
return nativeGlobal->GetContext();
return nativeGlobal->GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT);
}
nsIScriptGlobalObject *

Просмотреть файл

@ -269,6 +269,20 @@ nsWindowRoot::GetFocusController(nsIFocusController** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsWindowRoot::GetScriptTypeID(PRUint32 *aScriptType)
{
NS_ERROR("No default script type here - ask some element");
return nsIProgrammingLanguage::UNKNOWN;
}
NS_IMETHODIMP
nsWindowRoot::SetScriptTypeID(PRUint32 aScriptType)
{
NS_ERROR("Can't change default script type for a document");
return NS_ERROR_NOT_IMPLEMENTED;
}
///////////////////////////////////////////////////////////////////////////////////
nsresult

Просмотреть файл

@ -39,42 +39,56 @@
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsIServiceManager.h"
#include "nsIJSContextStack.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptRuntime.h"
#include "nsIXPConnect.h"
#include "nsIPrivateDOMEvent.h"
#include "nsGUIEvent.h"
#include "nsContentUtils.h"
#include "nsDOMScriptObjectHolder.h"
#include "nsIMutableArray.h"
#include "nsVariant.h"
#ifdef NS_DEBUG
#include "nspr.h" // PR_fprintf
PRInt32 nsIJSEventListener::sNumJSEventListeners = 0;
class EventListenerCounter
{
public:
~EventListenerCounter() {
if (nsIJSEventListener::sNumJSEventListeners) {
PR_fprintf(PR_STDERR,"WARNING: LEAKED %d nsIJSEventListeners\n",
nsIJSEventListener::sNumJSEventListeners);
}
}
};
static EventListenerCounter sEventListenerCounter;
#endif
/*
* nsJSEventListener implementation
*/
nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
JSObject *aScopeObject,
nsISupports *aObject)
: nsIJSEventListener(aContext, aScopeObject, aObject),
void *aScopeObject,
nsISupports *aTarget)
: nsIJSEventListener(aContext, aScopeObject, aTarget),
mReturnResult(nsReturnResult_eNotSet)
{
if (aScopeObject && aContext) {
JSContext *cx = (JSContext *)aContext->GetNativeContext();
JSAutoRequest ar(cx);
::JS_LockGCThing(cx, aScopeObject);
}
// mScopeObject is the "script global" for a context - this
// does not need explicit memory management so long we we don't
// outlive the context - which we don't.
}
nsJSEventListener::~nsJSEventListener()
{
if (mScopeObject && mContext) {
JSContext *cx = (JSContext *)mContext->GetNativeContext();
JSAutoRequest ar(cx);
::JS_UnlockGCThing(cx, mScopeObject);
}
// as above, no need to "drop" our reference...
}
NS_INTERFACE_MAP_BEGIN(nsJSEventListener)
@ -98,16 +112,15 @@ nsJSEventListener::SetEventName(nsIAtom* aName)
nsresult
nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
{
jsval funval;
jsval arg;
jsval *argv = &arg;
nsresult rv;
nsCOMPtr<nsIArray> iargv;
PRInt32 argc = 0;
void *stackPtr; // For JS_[Push|Pop]Arguments()
nsAutoString eventString;
// XXX This doesn't seem like the correct context on which to execute
// the event handler. Might need to get one from the JS thread context
// stack.
JSContext* cx = (JSContext*)mContext->GetNativeContext();
nsCOMPtr<nsIAtom> atomName;
if (!mEventName) {
if (NS_OK != aEvent->GetType(eventString)) {
@ -124,36 +137,20 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
}
//}
eventString.Assign(NS_LITERAL_STRING("on") + eventString);
atomName = do_GetAtom(eventString);
}
else {
mEventName->ToString(eventString);
atomName = mEventName;
}
nsresult rv;
nsIXPConnect *xpc = nsContentUtils::XPConnect();
// root
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
rv = xpc->WrapNative(cx, mScopeObject, mTarget, NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
nsScriptObjectHolder funcval(mContext);
rv = mContext->GetBoundEventHandler(mTarget, mScopeObject, atomName,
funcval);
NS_ENSURE_SUCCESS(rv, rv);
JSObject* obj = nsnull;
rv = wrapper->GetJSObject(&obj);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
if (!JS_LookupUCProperty(cx, obj,
NS_REINTERPRET_CAST(const jschar *,
eventString.get()),
eventString.Length(), &funval)) {
return NS_ERROR_FAILURE;
}
if (JS_TypeOfValue(cx, funval) != JSTYPE_FUNCTION) {
if (!funcval)
return NS_OK;
}
PRBool handledScriptError = PR_FALSE;
if (eventString.EqualsLiteral("onerror")) {
@ -165,36 +162,58 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
if (event->message == NS_SCRIPT_ERROR) {
nsScriptErrorEvent *scriptEvent =
NS_STATIC_CAST(nsScriptErrorEvent*, event);
// Create a temp argv for the error event.
nsCOMPtr<nsIMutableArray> tempargv =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
// Append the event args.
nsCOMPtr<nsIWritableVariant>
var(do_CreateInstance(NS_VARIANT_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = var->SetAsWString(scriptEvent->errorMsg);
NS_ENSURE_SUCCESS(rv, rv);
rv = tempargv->AppendElement(var, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// filename
var = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = var->SetAsWString(scriptEvent->fileName);
NS_ENSURE_SUCCESS(rv, rv);
rv = tempargv->AppendElement(var, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// line number
var = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = var->SetAsUint32(scriptEvent->lineNr);
NS_ENSURE_SUCCESS(rv, rv);
rv = tempargv->AppendElement(var, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// And set the real argv
iargv = do_QueryInterface(tempargv);
argv = ::JS_PushArguments(cx, &stackPtr, "WWi", scriptEvent->errorMsg,
scriptEvent->fileName, scriptEvent->lineNr);
NS_ENSURE_TRUE(argv, NS_ERROR_OUT_OF_MEMORY);
argc = 3;
handledScriptError = PR_TRUE;
}
}
if (!handledScriptError) {
rv = xpc->WrapNative(cx, obj, aEvent, NS_GET_IID(nsIDOMEvent),
getter_AddRefs(wrapper));
nsCOMPtr<nsIMutableArray> tempargv =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
NS_ENSURE_TRUE(tempargv != nsnull, NS_ERROR_OUT_OF_MEMORY);
rv = tempargv->AppendElement(aEvent, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
JSObject *eventObj = nsnull;
rv = wrapper->GetJSObject(&eventObj);
NS_ENSURE_SUCCESS(rv, rv);
argv[0] = OBJECT_TO_JSVAL(eventObj);
argc = 1;
iargv = do_QueryInterface(tempargv);
}
jsval rval;
rv = mContext->CallEventHandler(obj, JSVAL_TO_OBJECT(funval), argc, argv,
&rval);
if (argv != &arg)
::JS_PopArguments(cx, stackPtr);
nsCOMPtr<nsIVariant> vrv;
rv = mContext->CallEventHandler(mTarget, mScopeObject, funcval, iargv,
getter_AddRefs(vrv));
if (NS_SUCCEEDED(rv)) {
PRUint16 dataType = nsIDataType::VTYPE_VOID;
if (vrv)
vrv->GetDataType(&dataType);
if (eventString.EqualsLiteral("onbeforeunload")) {
nsCOMPtr<nsIPrivateDOMEvent> priv(do_QueryInterface(aEvent));
NS_ENSURE_TRUE(priv, NS_ERROR_UNEXPECTED);
@ -207,24 +226,38 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
nsBeforePageUnloadEvent *beforeUnload =
NS_STATIC_CAST(nsBeforePageUnloadEvent *, event);
if (!JSVAL_IS_VOID(rval)) {
if (dataType != nsIDataType::VTYPE_VOID) {
aEvent->PreventDefault();
// Set the text in the beforeUnload event as long as it wasn't
// already set (through event.returnValue, which takes
// precedence over a value returned from a JS function in IE)
if (JSVAL_IS_STRING(rval) && beforeUnload->text.IsEmpty()) {
beforeUnload->text = nsDependentJSString(JSVAL_TO_STRING(rval));
if ((dataType == nsIDataType::VTYPE_DOMSTRING ||
dataType == nsIDataType::VTYPE_CHAR_STR ||
dataType == nsIDataType::VTYPE_WCHAR_STR ||
dataType == nsIDataType::VTYPE_STRING_SIZE_IS ||
dataType == nsIDataType::VTYPE_WSTRING_SIZE_IS ||
dataType == nsIDataType::VTYPE_CSTRING ||
dataType == nsIDataType::VTYPE_ASTRING)
&& beforeUnload->text.IsEmpty()) {
vrv->GetAsDOMString(beforeUnload->text);
}
}
} else if (JSVAL_IS_BOOLEAN(rval)) {
} else if (dataType == nsIDataType::VTYPE_BOOL ||
dataType == nsIDataType::VTYPE_INT8 ||
dataType == nsIDataType::VTYPE_INT16 ||
dataType == nsIDataType::VTYPE_INT32 ||
dataType == nsIDataType::VTYPE_UINT8 ||
dataType == nsIDataType::VTYPE_UINT16 ||
dataType == nsIDataType::VTYPE_UINT32) {
// If the handler returned false and its sense is not reversed,
// or the handler returned true and its sense is reversed from
// the usual (false means cancel), then prevent default.
if (JSVAL_TO_BOOLEAN(rval) ==
(mReturnResult == nsReturnResult_eReverseReturnResult))
PRBool brv;
if (NS_SUCCEEDED(vrv->GetAsBool(&brv)) &&
brv == (mReturnResult == nsReturnResult_eReverseReturnResult)) {
aEvent->PreventDefault();
}
}
}
@ -236,15 +269,14 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
*/
nsresult
NS_NewJSEventListener(nsIScriptContext *aContext, JSObject *aScopeObject,
nsISupports *aObject, nsIDOMEventListener ** aReturn)
NS_NewJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports*aTarget, nsIDOMEventListener ** aReturn)
{
nsJSEventListener* it =
new nsJSEventListener(aContext, aScopeObject, aObject);
new nsJSEventListener(aContext, aScopeObject, aTarget);
if (!it) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aReturn = it);
return NS_OK;

Просмотреть файл

@ -46,12 +46,13 @@
#include "nsIAtom.h"
#include "nsIScriptContext.h"
//nsIDOMMouseListener interface
// nsJSEventListener interface
// misnamed - JS no longer has exclusive rights over this interface!
class nsJSEventListener : public nsIDOMEventListener,
public nsIJSEventListener
{
public:
nsJSEventListener(nsIScriptContext *aContext, JSObject *aScopeObject,
nsJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports* aObject);
virtual ~nsJSEventListener();

Просмотреть файл

@ -66,7 +66,6 @@
#include "nsXPIDLString.h"
#include "prprf.h"
#include "nsEscape.h"
#include "nsIJSContextStack.h"
#include "nsIWebNavigation.h"
#include "nsIDocShell.h"
#include "nsIContentViewer.h"

Просмотреть файл

@ -46,6 +46,7 @@ interface nsIDOMWindow;
interface nsISimpleEnumerator;
interface nsIWebBrowserChrome;
interface nsIDocShellTreeItem;
interface nsIArray;
%{C++
#include "jspubtd.h"
@ -84,9 +85,7 @@ interface nsPIWindowWatcher : nsISupports
aUrl in it (if aUrl is not null) and return it.
@param aFeatures window features from JS window.open. can be null.
@param aDialog use dialog defaults (see nsIDOMWindowInternal::openDialog)
@param argc count of argv arguments
@param argv extra JS arguments, if any
(see nsIDOMWindowInternal::openDialog)
@param aArgs Window argument
@return the new window
@note This method may examine the JS context stack for purposes of
@ -99,7 +98,7 @@ interface nsPIWindowWatcher : nsISupports
*/
nsIDOMWindow openWindowJS(in nsIDOMWindow aParent, in string aUrl,
in string aName, in string aFeatures, in boolean aDialog,
in PRUint32 argc, in jsvalptr argv);
in nsIArray aArgs);
/**
* Find a named docshell tree item amongst all windows registered

Просмотреть файл

@ -44,6 +44,7 @@
#include "nsIScriptGlobalObject.h"
#include "nsWWJSUtils.h"
#include "nsIXPConnect.h"
#include "nsDOMJSUtils.h"
nsIScriptGlobalObject *
nsWWJSUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj)

Просмотреть файл

@ -66,9 +66,7 @@
#include "nsIObserverService.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
#include "nsISupportsArray.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsIURI.h"
#include "nsIWebBrowser.h"
#include "nsIWebBrowserChrome.h"
@ -81,6 +79,7 @@
#include "nsIContentViewer.h"
#include "nsIDocumentViewer.h"
#include "nsIWindowProvider.h"
#include "nsIMutableArray.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
@ -316,25 +315,6 @@ nsresult JSContextAutoPopper::Push(JSContext *cx)
return mContext ? NS_OK : NS_ERROR_FAILURE;
}
/****************************************************************
************************** AutoFree ****************************
****************************************************************/
class AutoFree {
public:
AutoFree(void *aPtr) : mPtr(aPtr) {
}
~AutoFree() {
if (mPtr)
nsMemory::Free(mPtr);
}
void Invalidate() {
mPtr = 0;
}
private:
void *mPtr;
};
/****************************************************************
*********************** nsWindowWatcher ************************
****************************************************************/
@ -378,29 +358,26 @@ nsWindowWatcher::OpenWindow(nsIDOMWindow *aParent,
nsISupports *aArguments,
nsIDOMWindow **_retval)
{
PRUint32 argc;
jsval *argv = nsnull;
JSContext *cx;
void *mark;
// This kungFuDeathGrip is filled when we are using aParent's context. It
// prevents the context from being destroyed before we're truly done with
// it.
nsCOMPtr<nsIScriptContext> kungFuDeathGrip;
nsresult rv = ConvertSupportsTojsvals(aParent, aArguments, &argc, &argv, &cx,
&mark, getter_AddRefs(kungFuDeathGrip));
if (NS_SUCCEEDED(rv)) {
PRBool dialog = argc == 0 ? PR_FALSE : PR_TRUE;
rv = OpenWindowJSInternal(aParent, aUrl, aName, aFeatures, dialog, argc,
argv, PR_FALSE, _retval);
if (argv) {
js_FreeStack(cx, mark);
nsCOMPtr<nsIArray> argsArray;
PRUint32 argc = 0;
if (aArguments) {
// If aArguments is not already an array, make it one.
argsArray = do_QueryInterface(aArguments);
if (argsArray == nsnull) {
nsresult rv;
nsCOMPtr<nsIMutableArray> tempArray =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
tempArray->AppendElement(aArguments, PR_FALSE);
argsArray = do_QueryInterface(tempArray);
NS_ENSURE_TRUE(argsArray != nsnull, NS_ERROR_UNEXPECTED);
}
argsArray->GetLength(&argc);
}
return rv;
PRBool dialog = argc == 0 ? PR_FALSE : PR_TRUE;
return OpenWindowJSInternal(aParent, aUrl, aName, aFeatures, dialog,
argsArray, PR_FALSE, _retval);
}
struct SizeSpec {
@ -450,11 +427,10 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
const char *aName,
const char *aFeatures,
PRBool aDialog,
PRUint32 argc,
jsval *argv,
nsIArray *argv,
nsIDOMWindow **_retval)
{
return OpenWindowJSInternal(aParent, aUrl, aName, aFeatures, aDialog, argc,
return OpenWindowJSInternal(aParent, aUrl, aName, aFeatures, aDialog,
argv, PR_TRUE, _retval);
}
@ -464,8 +440,7 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
const char *aName,
const char *aFeatures,
PRBool aDialog,
PRUint32 argc,
jsval *argv,
nsIArray *argv,
PRBool aCalledFromJS,
nsIDOMWindow **_retval)
{
@ -692,12 +667,12 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
}
}
if (aDialog && argc > 0) {
rv = AttachArguments(*_retval, argc, argv);
if (NS_FAILED(rv)) {
return rv;
}
if (aDialog && argv > 0) {
// Set the args on the new object.
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_QueryInterface(*_retval));
NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_UNEXPECTED);
rv = scriptGlobal->SetNewArguments(argv);
NS_ENSURE_SUCCESS(rv, rv);
}
/* allow a window that we found by name to keep its name (important for cases
@ -1842,342 +1817,6 @@ nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
treeOwnerAsWin->SetVisibility(PR_TRUE);
}
// attach the given array of JS values to the given window, as a property array
// named "arguments"
nsresult
nsWindowWatcher::AttachArguments(nsIDOMWindow *aWindow,
PRUint32 argc, jsval *argv)
{
if (argc == 0)
return NS_OK;
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_QueryInterface(aWindow));
NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_UNEXPECTED);
// Just ask the global to attach the args for us
return scriptGlobal->SetNewArguments(argc, NS_STATIC_CAST(void*, argv));
}
nsresult
nsWindowWatcher::ConvertSupportsTojsvals(nsIDOMWindow *aWindow,
nsISupports *aArgs,
PRUint32 *aArgc, jsval **aArgv,
JSContext **aUsedContext,
void **aMarkp,
nsIScriptContext **aScriptContext)
{
nsresult rv = NS_OK;
*aArgv = nsnull;
*aArgc = 0;
// copy the elements in aArgsArray into the JS array
// window.arguments in the new window
if (!aArgs)
return NS_OK;
PRUint32 argCtr, argCount;
nsCOMPtr<nsISupportsArray> argsArray(do_QueryInterface(aArgs));
if (argsArray) {
argsArray->Count(&argCount);
if (argCount == 0)
return NS_OK;
} else
argCount = 1; // the nsISupports which is not an array
JSContext *cx;
JSContextAutoPopper contextGuard;
cx = GetJSContextFromWindow(aWindow);
if (cx) {
// Our caller needs to hold a strong ref to keep this context alive.
*aScriptContext = GetScriptContextFromJSContext(cx);
NS_ASSERTION(*aScriptContext,
"The window's context doesn't have a script context?");
NS_ADDREF(*aScriptContext);
} else {
*aScriptContext = nsnull;
}
if (!cx)
cx = GetJSContextFromCallStack();
if (!cx) {
rv = contextGuard.Push();
if (NS_FAILED(rv))
return rv;
cx = contextGuard.get();
}
jsval *argv = js_AllocStack(cx, argCount, aMarkp);
NS_ENSURE_TRUE(argv, NS_ERROR_OUT_OF_MEMORY);
if (argsArray)
for (argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
nsCOMPtr<nsISupports> s(dont_AddRef(argsArray->ElementAt(argCtr)));
rv = AddSupportsTojsvals(s, cx, argv + argCtr);
}
else
rv = AddSupportsTojsvals(aArgs, cx, argv);
if (NS_FAILED(rv)) {
js_FreeStack(cx, *aMarkp);
return rv;
}
*aUsedContext = cx;
*aArgv = argv;
*aArgc = argCount;
return NS_OK;
}
nsresult
nsWindowWatcher::AddInterfaceTojsvals(nsISupports *aArg,
JSContext *cx,
jsval *aArgv)
{
nsresult rv;
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
rv = xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), aArg,
NS_GET_IID(nsISupports), getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
JSObject *obj;
rv = wrapper->GetJSObject(&obj);
NS_ENSURE_SUCCESS(rv, rv);
*aArgv = OBJECT_TO_JSVAL(obj);
return NS_OK;
}
nsresult
nsWindowWatcher::AddSupportsTojsvals(nsISupports *aArg,
JSContext *cx, jsval *aArgv)
{
if (!aArg) {
*aArgv = JSVAL_NULL;
return NS_OK;
}
nsCOMPtr<nsISupportsPrimitive> argPrimitive(do_QueryInterface(aArg));
if (!argPrimitive)
return AddInterfaceTojsvals(aArg, cx, aArgv);
PRUint16 type;
argPrimitive->GetType(&type);
switch(type) {
case nsISupportsPrimitive::TYPE_CSTRING : {
nsCOMPtr<nsISupportsCString> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
nsCAutoString data;
p->GetData(data);
JSAutoRequest ar(cx);
JSString *str = ::JS_NewStringCopyN(cx, data.get(), data.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
break;
}
case nsISupportsPrimitive::TYPE_STRING : {
nsCOMPtr<nsISupportsString> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
nsAutoString data;
p->GetData(data);
JSAutoRequest ar(cx);
// cast is probably safe since wchar_t and jschar are expected
// to be equivalent; both unsigned 16-bit entities
JSString *str =
::JS_NewUCStringCopyN(cx,
NS_REINTERPRET_CAST(const jschar *,data.get()),
data.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
break;
}
case nsISupportsPrimitive::TYPE_PRBOOL : {
nsCOMPtr<nsISupportsPRBool> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
PRBool data;
p->GetData(&data);
*aArgv = BOOLEAN_TO_JSVAL(data);
break;
}
case nsISupportsPrimitive::TYPE_PRUINT8 : {
nsCOMPtr<nsISupportsPRUint8> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
PRUint8 data;
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
break;
}
case nsISupportsPrimitive::TYPE_PRUINT16 : {
nsCOMPtr<nsISupportsPRUint16> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
PRUint16 data;
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
break;
}
case nsISupportsPrimitive::TYPE_PRUINT32 : {
nsCOMPtr<nsISupportsPRUint32> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
PRUint32 data;
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
break;
}
case nsISupportsPrimitive::TYPE_CHAR : {
nsCOMPtr<nsISupportsChar> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
char data;
p->GetData(&data);
JSAutoRequest ar(cx);
JSString *str = ::JS_NewStringCopyN(cx, &data, 1);
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
break;
}
case nsISupportsPrimitive::TYPE_PRINT16 : {
nsCOMPtr<nsISupportsPRInt16> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
PRInt16 data;
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
break;
}
case nsISupportsPrimitive::TYPE_PRINT32 : {
nsCOMPtr<nsISupportsPRInt32> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
PRInt32 data;
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
break;
}
case nsISupportsPrimitive::TYPE_FLOAT : {
nsCOMPtr<nsISupportsFloat> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
float data;
p->GetData(&data);
JSAutoRequest ar(cx);
jsdouble *d = ::JS_NewDouble(cx, data);
*aArgv = DOUBLE_TO_JSVAL(d);
break;
}
case nsISupportsPrimitive::TYPE_DOUBLE : {
nsCOMPtr<nsISupportsDouble> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
double data;
p->GetData(&data);
JSAutoRequest ar(cx);
jsdouble *d = ::JS_NewDouble(cx, data);
*aArgv = DOUBLE_TO_JSVAL(d);
break;
}
case nsISupportsPrimitive::TYPE_INTERFACE_POINTER : {
nsCOMPtr<nsISupportsInterfacePointer> p(do_QueryInterface(argPrimitive));
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsISupports> data;
nsIID *iid = nsnull;
p->GetData(getter_AddRefs(data));
p->GetDataIID(&iid);
NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
AutoFree iidGuard(iid); // Free iid upon destruction.
nsresult rv;
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
rv = xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), data,
*iid, getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
JSObject *obj;
rv = wrapper->GetJSObject(&obj);
NS_ENSURE_SUCCESS(rv, rv);
*aArgv = OBJECT_TO_JSVAL(obj);
break;
}
case nsISupportsPrimitive::TYPE_ID :
case nsISupportsPrimitive::TYPE_PRUINT64 :
case nsISupportsPrimitive::TYPE_PRINT64 :
case nsISupportsPrimitive::TYPE_PRTIME :
case nsISupportsPrimitive::TYPE_VOID : {
NS_WARNING("Unsupported primitive type used");
*aArgv = JSVAL_NULL;
break;
}
default : {
NS_WARNING("Unknown primitive type used");
*aArgv = JSVAL_NULL;
break;
}
}
return NS_OK;
}
void
nsWindowWatcher::GetWindowTreeItem(nsIDOMWindow *inWindow,
nsIDocShellTreeItem **outTreeItem)

Просмотреть файл

@ -104,8 +104,7 @@ private:
const char *aName,
const char *aFeatures,
PRBool aDialog,
PRUint32 argc,
jsval *argv,
nsIArray *argv,
PRBool aCalledFromJS,
nsIDOMWindow **_retval);
@ -134,18 +133,6 @@ private:
static void SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
nsIDOMWindow *aParent,
const SizeSpec & aSizeSpec);
static nsresult AttachArguments(nsIDOMWindow *aWindow,
PRUint32 argc, jsval *argv);
static nsresult ConvertSupportsTojsvals(nsIDOMWindow *aWindow,
nsISupports *aArgs,
PRUint32 *aArgc, jsval **aArgv,
JSContext **aUsedContext,
void **aMarkp,
nsIScriptContext **aScriptContext);
static nsresult AddSupportsTojsvals(nsISupports *aArg,
JSContext *cx, jsval *aArgv);
static nsresult AddInterfaceTojsvals(nsISupports *aArg,
JSContext *cx, jsval *aArgv);
static void GetWindowTreeItem(nsIDOMWindow *inWindow,
nsIDocShellTreeItem **outTreeItem);
static void GetWindowTreeOwner(nsIDOMWindow *inWindow,

Просмотреть файл

@ -55,6 +55,7 @@
#include "nsICSSStyleSheet.h"
#include "nsDOMAttribute.h"
#include "nsDOMClassInfo.h"
#include "nsDOMScriptObjectFactory.h"
#include "nsEventListenerManager.h"
#include "nsFrame.h"
#include "nsGenericElement.h" // for nsDOMEventRTTearoff
@ -62,7 +63,6 @@
#include "nsGlobalWindow.h"
#include "nsHTMLAtoms.h"
#include "nsImageFrame.h"
#include "nsJSEnvironment.h"
#include "nsLayoutAtoms.h"
#include "nsLayoutStylesheetCache.h"
#include "nsNodeInfo.h"
@ -118,7 +118,7 @@ nsLayoutStatics::Initialize()
nsresult rv;
nsJSEnvironment::Startup();
nsDOMScriptObjectFactory::Startup();
rv = nsContentUtils::Init();
if (NS_FAILED(rv)) {
NS_ERROR("Could not initialize nsContentUtils");

Просмотреть файл

@ -49,6 +49,7 @@
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
#include "nsNetUtil.h"
#include "nsDOMJSUtils.h"
static NS_DEFINE_CID(kJVMManagerCID, NS_JVMMANAGER_CID);

Просмотреть файл

@ -62,6 +62,7 @@
#include "nsIDocument.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsDOMJSUtils.h"
#include "nsIXPConnect.h"

Просмотреть файл

@ -59,6 +59,7 @@
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsDOMJSUtils.h"
#include "nsIXPConnect.h"
#include "nsIRunnable.h"
#include "nsIWindowWatcher.h"

Просмотреть файл

@ -65,6 +65,10 @@ interface nsIProgrammingLanguage : nsISupports
const PRUint32 JAVA = 5;
const PRUint32 ZX81_BASIC = 6; // it could happen :)
const PRUint32 JAVASCRIPT2 = 7;
const PRUint32 RUBY = 8;
const PRUint32 PHP = 9;
const PRUint32 TCL = 10;
// This list can grow indefinitely. Just don't ever change an existing item.
const PRUint32 MAX = 10; // keep this as the largest index.
};

Просмотреть файл

@ -141,7 +141,7 @@ typedef PRUint32 NSFastLoadOID; // nsFastLoadFooter::mObjectMap index
#define MFL_FILE_VERSION_0 0
#define MFL_FILE_VERSION_1 1000
#define MFL_FILE_VERSION 4 // fix to note singletons in object map
#define MFL_FILE_VERSION 5 // multiple script languages
/**
* Compute Fletcher's 16-bit checksum over aLength bytes starting at aBuffer,

Просмотреть файл

@ -51,6 +51,7 @@
#include "nsIObserverService.h"
#include "nsInstallTrigger.h"
#include "nsXPITriggerInfo.h"
#include "nsDOMJSUtils.h"
#include "nsIComponentManager.h"
#include "nsNetUtil.h"