Fix for bug 163810 (Option Object created, own properties added, but Mozilla "forgets" them after some time.). r=sicking, sr=jst.

This commit is contained in:
peterv%netscape.com 2002-09-20 13:40:53 +00:00
parent f997bfaf78
commit 7a93a8cbf1
6 changed files with 91 additions and 139 deletions

View File

@ -184,8 +184,22 @@ public:
// Check if the (JS) caller can access aNode. // Check if the (JS) caller can access aNode.
static PRBool CanCallerAccess(nsIDOMNode *aNode); static PRBool CanCallerAccess(nsIDOMNode *aNode);
/**
* Get the docshell through the JS context that's currently on the stack.
* If there's no JS context currently on the stack aDocShell will be null.
*
* @param aDocShell The docshell or null if no JS context
*/
static void GetDocShellFromCaller(nsIDocShell** aDocShell); static void GetDocShellFromCaller(nsIDocShell** aDocShell);
/**
* Get the document through the JS context that's currently on the stack.
* If there's no JS context currently on the stack aDocument will be null.
*
* @param aDocument The document or null if no JS context
*/
static void GetDocumentFromCaller(nsIDOMDocument** aDocument);
// Check if a node is in the document prolog, i.e. before the document // Check if a node is in the document prolog, i.e. before the document
// element. // element.
static PRBool InProlog(nsIDOMNode *aNode); static PRBool InProlog(nsIDOMNode *aNode);

View File

@ -53,12 +53,12 @@
#include "nsIURI.h" #include "nsIURI.h"
#include "nsIScriptSecurityManager.h" #include "nsIScriptSecurityManager.h"
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsIDOMWindowInternal.h"
#include "nsIJSContextStack.h" #include "nsIJSContextStack.h"
#include "nsIDocShell.h" #include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeItem.h"
static const char *sJSStackContractID = "@mozilla.org/js/xpc/ContextStack;1"; static const char *kJSStackContractID = "@mozilla.org/js/xpc/ContextStack;1";
nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull; nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull;
nsIXPConnect *nsContentUtils::sXPConnect = nsnull; nsIXPConnect *nsContentUtils::sXPConnect = nsnull;
@ -80,7 +80,7 @@ nsContentUtils::Init()
sSecurityManager = nsnull; sSecurityManager = nsnull;
} }
rv = CallGetService(sJSStackContractID, &sThreadJSContextStack); rv = CallGetService(kJSStackContractID, &sThreadJSContextStack);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
sThreadJSContextStack = nsnull; sThreadJSContextStack = nsnull;
} }
@ -91,7 +91,7 @@ nsContentUtils::Init()
// static // static
nsresult nsresult
nsContentUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj, nsContentUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj,
nsIScriptGlobalObject** aNativeGlobal) nsIScriptGlobalObject** aNativeGlobal)
{ {
if (!sXPConnect) { if (!sXPConnect) {
*aNativeGlobal = nsnull; *aNativeGlobal = nsnull;
@ -126,8 +126,8 @@ nsContentUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj,
//static //static
nsresult nsresult
nsContentUtils::GetStaticScriptContext(JSContext* aContext, nsContentUtils::GetStaticScriptContext(JSContext* aContext,
JSObject* aObj, JSObject* aObj,
nsIScriptContext** aScriptContext) nsIScriptContext** aScriptContext)
{ {
nsCOMPtr<nsIScriptGlobalObject> nativeGlobal; nsCOMPtr<nsIScriptGlobalObject> nativeGlobal;
GetStaticScriptGlobal(aContext, aObj, getter_AddRefs(nativeGlobal)); GetStaticScriptGlobal(aContext, aObj, getter_AddRefs(nativeGlobal));
@ -142,7 +142,7 @@ nsContentUtils::GetStaticScriptContext(JSContext* aContext,
//static //static
nsresult nsresult
nsContentUtils::GetDynamicScriptGlobal(JSContext* aContext, nsContentUtils::GetDynamicScriptGlobal(JSContext* aContext,
nsIScriptGlobalObject** aNativeGlobal) nsIScriptGlobalObject** aNativeGlobal)
{ {
nsCOMPtr<nsIScriptContext> scriptCX; nsCOMPtr<nsIScriptContext> scriptCX;
GetDynamicScriptContext(aContext, getter_AddRefs(scriptCX)); GetDynamicScriptContext(aContext, getter_AddRefs(scriptCX));
@ -156,7 +156,7 @@ nsContentUtils::GetDynamicScriptGlobal(JSContext* aContext,
//static //static
nsresult nsresult
nsContentUtils::GetDynamicScriptContext(JSContext *aContext, nsContentUtils::GetDynamicScriptContext(JSContext *aContext,
nsIScriptContext** aScriptContext) nsIScriptContext** aScriptContext)
{ {
*aScriptContext = nsnull; *aScriptContext = nsnull;
@ -617,7 +617,7 @@ nsContentUtils::InProlog(nsIDOMNode *aNode)
// Check that there are no elements before aNode to make sure we are not // Check that there are no elements before aNode to make sure we are not
// in the epilog // in the epilog
PRInt32 pos, i; PRInt32 pos;
doc->IndexOf(cont, pos); doc->IndexOf(cont, pos);
while (pos > 0) { while (pos > 0) {
--pos; --pos;
@ -826,6 +826,30 @@ nsContentUtils::GetDocShellFromCaller(nsIDocShell** aDocShell)
} }
} }
void
nsContentUtils::GetDocumentFromCaller(nsIDOMDocument** aDocument)
{
*aDocument = nsnull;
if (!sThreadJSContextStack) {
return;
}
JSContext *cx = nsnull;
sThreadJSContextStack->Peek(&cx);
if (cx) {
nsCOMPtr<nsIScriptGlobalObject> sgo;
GetDynamicScriptGlobal(cx, getter_AddRefs(sgo));
nsCOMPtr<nsIDOMWindowInternal> win(do_QueryInterface(sgo));
if (!win) {
return;
}
win->GetDocument(aDocument);
}
}
PRBool PRBool
nsContentUtils::IsCallerChrome() nsContentUtils::IsCallerChrome()
{ {
@ -1138,7 +1162,7 @@ nsCxPusher::Push(nsISupports *aCurrentTarget)
if (cx) { if (cx) {
if (!mStack) { if (!mStack) {
mStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1"); mStack = do_GetService(kJSStackContractID);
} }
if (mStack) { if (mStack) {

View File

@ -140,7 +140,6 @@ public:
protected: protected:
nsresult SetSrcInner(nsIURI* aBaseURL, const nsAString& aSrc); nsresult SetSrcInner(nsIURI* aBaseURL, const nsAString& aSrc);
static nsresult GetCallerSourceURL(nsIURI** sourceURL);
nsresult GetImageFrame(nsIImageFrame** aImageFrame); nsresult GetImageFrame(nsIImageFrame** aImageFrame);
nsresult GetXY(PRInt32* aX, PRInt32* aY); nsresult GetXY(PRInt32* aX, PRInt32* aY);
@ -158,31 +157,13 @@ NS_NewHTMLImageElement(nsIHTMLContent** aInstancePtrResult,
/* /*
* nsHTMLImageElement's will be created without a nsINodeInfo passed in * nsHTMLImageElement's will be created without a nsINodeInfo passed in
* if someone says "var img = new Image();" in JavaScript, in a case like * if someone says "var img = new Image();" in JavaScript, in a case like
* that we request the nsINodeInfo from the anonymous nodeinfo list. * that we request the nsINodeInfo from the document's nodeinfo list.
*/ */
nsresult rv;
nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo); nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo);
if (!nodeInfo) { if (!nodeInfo) {
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
NS_ENSURE_TRUE(stack, NS_ERROR_NOT_AVAILABLE);
JSContext *cx = nsnull;
nsresult rv = stack->Peek(&cx);
if (NS_FAILED(rv) || !cx)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIScriptGlobalObject> globalObject;
nsContentUtils::GetStaticScriptGlobal(cx, ::JS_GetGlobalObject(cx),
getter_AddRefs(globalObject));;
nsCOMPtr<nsIDOMWindowInternal> win(do_QueryInterface(globalObject));
NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDOMDocument> dom_doc; nsCOMPtr<nsIDOMDocument> dom_doc;
win->GetDocument(getter_AddRefs(dom_doc)); nsContentUtils::GetDocumentFromCaller(getter_AddRefs(dom_doc));
nsCOMPtr<nsIDocument> doc(do_QueryInterface(dom_doc)); nsCOMPtr<nsIDocument> doc(do_QueryInterface(dom_doc));
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
@ -203,7 +184,7 @@ NS_NewHTMLImageElement(nsIHTMLContent** aInstancePtrResult,
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
nsresult rv = it->Init(nodeInfo); rv = it->Init(nodeInfo);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
delete it; delete it;
@ -610,60 +591,6 @@ nsHTMLImageElement::HandleDOMEvent(nsIPresContext* aPresContext,
aEventStatus); aEventStatus);
} }
nsresult
nsHTMLImageElement::GetCallerSourceURL(nsIURI** sourceURL)
{
// XXX Code duplicated from nsHTMLDocument
// XXX Question, why does this return NS_OK on failure?
nsresult result = NS_OK;
// We need to use the dynamically scoped global and assume that the
// current JSContext is a DOM context with a nsIScriptGlobalObject so
// that we can get the url of the caller.
// XXX This will fail on non-DOM contexts :(
// Get JSContext from stack.
// XXX: This service should be cached.
nsCOMPtr<nsIJSContextStack>
stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result));
if (NS_FAILED(result))
return NS_ERROR_FAILURE;
JSContext *cx = nsnull;
// it's possible that there is not a JSContext on the stack.
// specifically this can happen when the DOM is being manipulated
// from native (non-JS) code.
if (NS_FAILED(stack->Peek(&cx)) || !cx)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIScriptGlobalObject> global;
nsContentUtils::GetDynamicScriptGlobal(cx, getter_AddRefs(global));
nsCOMPtr<nsIDOMWindowInternal> window(do_QueryInterface(global));
if (window) {
nsCOMPtr<nsIDOMDocument> domDoc;
result = window->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
if (doc) {
result = doc->GetBaseURL(*sourceURL);
if (!*sourceURL) {
doc->GetDocumentURL(sourceURL);
}
}
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLImageElement::Initialize(JSContext* aContext, JSObject *aObj, nsHTMLImageElement::Initialize(JSContext* aContext, JSObject *aObj,
PRUint32 argc, jsval *argv) PRUint32 argc, jsval *argv)
@ -926,13 +853,23 @@ nsHTMLImageElement::SetSrc(const nsAString& aSrc)
nsCOMPtr<nsIURI> baseURL; nsCOMPtr<nsIURI> baseURL;
nsresult rv = NS_OK; nsresult rv = NS_OK;
(void) GetCallerSourceURL(getter_AddRefs(baseURL)); nsCOMPtr<nsIDOMDocument> domDoc;
nsContentUtils::GetDocumentFromCaller(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc; nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
mNodeInfo->GetDocument(*getter_AddRefs(doc)); if (doc) {
// XXX GetBaseURL should do the GetDocumentURL for us
if (doc && !baseURL) {
rv = doc->GetBaseURL(*getter_AddRefs(baseURL)); rv = doc->GetBaseURL(*getter_AddRefs(baseURL));
if (!baseURL) {
rv = doc->GetDocumentURL(getter_AddRefs(baseURL));
}
}
if (!baseURL) {
mNodeInfo->GetDocument(*getter_AddRefs(doc));
if (doc) {
rv = doc->GetBaseURL(*getter_AddRefs(baseURL));
}
} }
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {

View File

@ -69,6 +69,7 @@
#include "nsLayoutAtoms.h" #include "nsLayoutAtoms.h"
#include "nsIEventStateManager.h" #include "nsIEventStateManager.h"
#include "nsXULAtoms.h" #include "nsXULAtoms.h"
#include "nsIDOMDocument.h"
/** /**
* Implementation of &lt;option&gt; * Implementation of &lt;option&gt;
@ -154,15 +155,21 @@ NS_NewHTMLOptionElement(nsIHTMLContent** aInstancePtrResult,
/* /*
* nsHTMLOptionElement's will be created without a nsINodeInfo passed in * nsHTMLOptionElement's will be created without a nsINodeInfo passed in
* if someone creates new option elements in JavaScript, in a case like * if someone says "var opt = new Option();" in JavaScript, in a case like
* that we request the nsINodeInfo from the anonymous nodeinfo list. * that we request the nsINodeInfo from the document's nodeinfo list.
*/ */
nsresult rv;
nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo); nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo);
if (!nodeInfo) { if (!nodeInfo) {
nsCOMPtr<nsIDOMDocument> dom_doc;
nsContentUtils::GetDocumentFromCaller(getter_AddRefs(dom_doc));
nsCOMPtr<nsIDocument> doc(do_QueryInterface(dom_doc));
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsINodeInfoManager> nodeInfoManager; nsCOMPtr<nsINodeInfoManager> nodeInfoManager;
nsresult rv; doc->GetNodeInfoManager(*getter_AddRefs(nodeInfoManager));
rv = nsNodeInfoManager::GetAnonymousManager(*getter_AddRefs(nodeInfoManager)); NS_ENSURE_TRUE(nodeInfoManager, NS_ERROR_UNEXPECTED);
NS_ENSURE_SUCCESS(rv, rv);
rv = nodeInfoManager->GetNodeInfo(nsHTMLAtoms::option, nsnull, rv = nodeInfoManager->GetNodeInfo(nsHTMLAtoms::option, nsnull,
kNameSpaceID_None, kNameSpaceID_None,
@ -176,7 +183,7 @@ NS_NewHTMLOptionElement(nsIHTMLContent** aInstancePtrResult,
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
nsresult rv = NS_STATIC_CAST(nsGenericElement *, it)->Init(nodeInfo); rv = NS_STATIC_CAST(nsGenericElement *, it)->Init(nodeInfo);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
delete it; delete it;

View File

@ -2335,8 +2335,7 @@ nsHTMLDocument::SetCookie(const nsAString& aCookie)
// static // static
nsresult nsresult
nsHTMLDocument::GetSourceDocumentURL(JSContext* cx, nsHTMLDocument::GetSourceDocumentURL(nsIURI** sourceURL)
nsIURI** sourceURL)
{ {
// XXX Tom said this reminded him of the "Six Degrees of // XXX Tom said this reminded him of the "Six Degrees of
// Kevin Bacon" game. We try to get from here to there using // Kevin Bacon" game. We try to get from here to there using
@ -2345,29 +2344,11 @@ nsHTMLDocument::GetSourceDocumentURL(JSContext* cx,
// I wish there were a better way. // I wish there were a better way.
*sourceURL = nsnull; *sourceURL = nsnull;
if (!cx) {
return NS_OK;
}
// We need to use the dynamically scoped global and assume that the
// current JSContext is a DOM context with a nsIScriptGlobalObject so
// that we can get the url of the caller.
// XXX This will fail on non-DOM contexts :( // XXX This will fail on non-DOM contexts :(
nsCOMPtr<nsIDOMDocument> domDoc;
nsContentUtils::GetDocumentFromCaller(getter_AddRefs(domDoc));
nsCOMPtr<nsIScriptGlobalObject> global; nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
nsContentUtils::GetDynamicScriptGlobal(cx, getter_AddRefs(global));
nsCOMPtr<nsIDOMWindowInternal> window(do_QueryInterface(global));
if (!window) {
return NS_OK; // Can't get the source URI if we can't get the window.
}
nsCOMPtr<nsIDOMDocument> dom_doc;
window->GetDocument(getter_AddRefs(dom_doc));
nsCOMPtr<nsIDocument> doc(do_QueryInterface(dom_doc));
if (!doc) { if (!doc) {
return NS_OK; // No document in the window return NS_OK; // No document in the window
} }
@ -2549,35 +2530,24 @@ nsHTMLDocument::Open()
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLDocument::Open(nsIDOMDocument** aReturn) nsHTMLDocument::Open(nsIDOMDocument** aReturn)
{ {
nsresult result = NS_OK;
nsCOMPtr<nsIURI> sourceURL;
// XXX The URL of the newly created document will match // XXX The URL of the newly created document will match
// that of the source document. Is this right? // that of the source document. Is this right?
// XXX: This service should be cached. // XXX This will fail on non-DOM contexts :(
nsCOMPtr<nsIJSContextStack> nsCOMPtr<nsIURI> sourceURL;
stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result)); nsresult result = GetSourceDocumentURL(getter_AddRefs(sourceURL));
if (NS_FAILED(result))
return NS_ERROR_FAILURE;
JSContext *cx;
if (NS_FAILED(stack->Peek(&cx)))
return NS_ERROR_FAILURE;
result = GetSourceDocumentURL(cx, getter_AddRefs(sourceURL));
// Recover if we had a problem obtaining the source URL // Recover if we had a problem obtaining the source URL
if (!sourceURL) { if (!sourceURL) {
result = NS_NewURI(getter_AddRefs(sourceURL), NS_LITERAL_CSTRING("about:blank")); result = NS_NewURI(getter_AddRefs(sourceURL),
NS_LITERAL_CSTRING("about:blank"));
} }
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
result = OpenCommon(sourceURL); result = OpenCommon(sourceURL);
} }
QueryInterface(NS_GET_IID(nsIDOMDocument), (void **)aReturn); CallQueryInterface(this, aReturn);
return result; return result;
} }

View File

@ -209,7 +209,7 @@ protected:
static PRBool MatchNameAttribute(nsIContent* aContent, nsString* aData); static PRBool MatchNameAttribute(nsIContent* aContent, nsString* aData);
static PRBool MatchFormControls(nsIContent* aContent, nsString* aData); static PRBool MatchFormControls(nsIContent* aContent, nsString* aData);
static nsresult GetSourceDocumentURL(JSContext* cx, nsIURI** sourceURL); static nsresult GetSourceDocumentURL(nsIURI** sourceURL);
static void DocumentWriteTerminationFunc(nsISupports *aRef); static void DocumentWriteTerminationFunc(nsISupports *aRef);