1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * David Hyatt <hyatt@netscape.com> (Original Author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
42 #include "nsIContent.h"
43 #include "nsIDocument.h"
44 #include "nsIScriptGlobalObject.h"
46 #include "nsUnicharUtils.h"
47 #include "nsReadableUtils.h"
48 #include "nsXBLProtoImplMethod.h"
49 #include "nsIScriptContext.h"
50 #include "nsContentUtils.h"
51 #include "nsIScriptSecurityManager.h"
52 #include "nsIXPConnect.h"
54 nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar
* aName
) :
55 nsXBLProtoImplMember(aName
),
56 mUncompiledMethod(BIT_UNCOMPILED
)
58 MOZ_COUNT_CTOR(nsXBLProtoImplMethod
);
61 nsXBLProtoImplMethod::~nsXBLProtoImplMethod()
63 MOZ_COUNT_DTOR(nsXBLProtoImplMethod
);
66 delete GetUncompiledMethod();
71 nsXBLProtoImplMethod::AppendBodyText(const nsAString
& aText
)
73 NS_PRECONDITION(!IsCompiled(),
74 "Must not be compiled when accessing uncompiled method");
76 nsXBLUncompiledMethod
* uncompiledMethod
= GetUncompiledMethod();
77 if (!uncompiledMethod
) {
78 uncompiledMethod
= new nsXBLUncompiledMethod();
79 if (!uncompiledMethod
)
81 SetUncompiledMethod(uncompiledMethod
);
84 uncompiledMethod
->AppendBodyText(aText
);
88 nsXBLProtoImplMethod::AddParameter(const nsAString
& aText
)
90 NS_PRECONDITION(!IsCompiled(),
91 "Must not be compiled when accessing uncompiled method");
93 nsXBLUncompiledMethod
* uncompiledMethod
= GetUncompiledMethod();
94 if (!uncompiledMethod
) {
95 uncompiledMethod
= new nsXBLUncompiledMethod();
96 if (!uncompiledMethod
)
98 SetUncompiledMethod(uncompiledMethod
);
101 uncompiledMethod
->AddParameter(aText
);
105 nsXBLProtoImplMethod::SetLineNumber(PRUint32 aLineNumber
)
107 NS_PRECONDITION(!IsCompiled(),
108 "Must not be compiled when accessing uncompiled method");
110 nsXBLUncompiledMethod
* uncompiledMethod
= GetUncompiledMethod();
111 if (!uncompiledMethod
) {
112 uncompiledMethod
= new nsXBLUncompiledMethod();
113 if (!uncompiledMethod
)
115 SetUncompiledMethod(uncompiledMethod
);
118 uncompiledMethod
->SetLineNumber(aLineNumber
);
122 nsXBLProtoImplMethod::InstallMember(nsIScriptContext
* aContext
,
123 nsIContent
* aBoundElement
,
125 void* aTargetClassObject
,
126 const nsCString
& aClassStr
)
128 NS_PRECONDITION(IsCompiled(),
129 "Should not be installing an uncompiled method");
130 JSContext
* cx
= (JSContext
*) aContext
->GetNativeContext();
132 nsIDocument
*ownerDoc
= aBoundElement
->GetOwnerDoc();
133 nsIScriptGlobalObject
*sgo
;
135 if (!ownerDoc
|| !(sgo
= ownerDoc
->GetScopeObject())) {
136 return NS_ERROR_UNEXPECTED
;
139 JSObject
* scriptObject
= (JSObject
*) aScriptObject
;
140 NS_ASSERTION(scriptObject
, "uh-oh, script Object should NOT be null or bad things will happen");
142 return NS_ERROR_FAILURE
;
144 JSObject
* targetClassObject
= (JSObject
*) aTargetClassObject
;
145 JSObject
* globalObject
= sgo
->GetGlobalJSObject();
147 // now we want to reevaluate our property using aContext and the script object for this window...
148 if (mJSMethodObject
&& targetClassObject
) {
149 nsDependentString
name(mName
);
150 JSAutoRequest
ar(cx
);
151 JSObject
* method
= ::JS_CloneFunctionObject(cx
, mJSMethodObject
, globalObject
);
153 return NS_ERROR_OUT_OF_MEMORY
;
157 nsAutoGCRoot
root(&method
, &rv
);
158 NS_ENSURE_SUCCESS(rv
, rv
);
160 if (!::JS_DefineUCProperty(cx
, targetClassObject
,
161 reinterpret_cast<const jschar
*>(mName
),
162 name
.Length(), OBJECT_TO_JSVAL(method
),
163 NULL
, NULL
, JSPROP_ENUMERATE
)) {
164 return NS_ERROR_OUT_OF_MEMORY
;
171 nsXBLProtoImplMethod::CompileMember(nsIScriptContext
* aContext
, const nsCString
& aClassStr
,
174 NS_PRECONDITION(!IsCompiled(),
175 "Trying to compile an already-compiled method");
176 NS_PRECONDITION(aClassObject
,
177 "Must have class object to compile");
179 nsXBLUncompiledMethod
* uncompiledMethod
= GetUncompiledMethod();
181 // No parameters or body was supplied, so don't install method.
182 if (!uncompiledMethod
) {
183 // Early return after which we consider ourselves compiled.
184 mJSMethodObject
= nsnull
;
189 // Don't install method if no name was supplied.
191 delete uncompiledMethod
;
193 // Early return after which we consider ourselves compiled.
194 mJSMethodObject
= nsnull
;
200 // Allocate an array for our arguments.
201 PRInt32 paramCount
= uncompiledMethod
->GetParameterCount();
202 char** args
= nsnull
;
203 if (paramCount
> 0) {
204 args
= new char*[paramCount
];
206 return NS_ERROR_OUT_OF_MEMORY
;
209 // Add our parameters to our args array.
211 for (nsXBLParameter
* curr
= uncompiledMethod
->mParameters
;
213 curr
= curr
->mNext
) {
214 args
[argPos
] = curr
->mName
;
219 nsDependentString body
;
220 PRUnichar
*bodyText
= uncompiledMethod
->mBodyText
.GetText();
222 body
.Rebind(bodyText
);
224 // Now that we have a body and args, compile the function
225 // and then define it.
226 NS_ConvertUTF16toUTF8
cname(mName
);
227 nsCAutoString
functionUri(aClassStr
);
228 PRInt32 hash
= functionUri
.RFindChar('#');
229 if (hash
!= kNotFound
) {
230 functionUri
.Truncate(hash
);
233 JSObject
* methodObject
= nsnull
;
234 nsresult rv
= aContext
->CompileFunction(aClassObject
,
240 uncompiledMethod
->mBodyText
.GetLineNumber(),
243 (void **) &methodObject
);
245 // Destroy our uncompiled method and delete our arg list.
246 delete uncompiledMethod
;
249 SetUncompiledMethod(nsnull
);
253 mJSMethodObject
= methodObject
;
259 nsXBLProtoImplMethod::Trace(TraceCallback aCallback
, void *aClosure
) const
261 if (IsCompiled() && mJSMethodObject
) {
262 aCallback(nsIProgrammingLanguage::JAVASCRIPT
, mJSMethodObject
, aClosure
);
267 nsXBLProtoImplAnonymousMethod::Execute(nsIContent
* aBoundElement
)
269 NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
271 if (!mJSMethodObject
) {
272 // Nothing to do here
276 // Get the script context the same way
277 // nsXBLProtoImpl::InstallImplementation does.
278 nsIDocument
* document
= aBoundElement
->GetOwnerDoc();
283 nsIScriptGlobalObject
* global
= document
->GetScriptGlobalObject();
288 nsCOMPtr
<nsIScriptContext
> context
= global
->GetContext();
293 JSContext
* cx
= (JSContext
*) context
->GetNativeContext();
295 JSObject
* globalObject
= global
->GetGlobalJSObject();
297 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
299 nsContentUtils::XPConnect()->WrapNative(cx
, globalObject
,
301 NS_GET_IID(nsISupports
),
302 getter_AddRefs(wrapper
));
303 NS_ENSURE_SUCCESS(rv
, rv
);
305 JSObject
* thisObject
;
306 rv
= wrapper
->GetJSObject(&thisObject
);
307 NS_ENSURE_SUCCESS(rv
, rv
);
309 JSAutoRequest
ar(cx
);
311 // Clone the function object, using thisObject as the parent so "this" is in
312 // the scope chain of the resulting function (for backwards compat to the
313 // days when this was an event handler).
314 JSObject
* method
= ::JS_CloneFunctionObject(cx
, mJSMethodObject
, thisObject
);
316 return NS_ERROR_OUT_OF_MEMORY
;
318 // Now call the method
320 // Use nsCxPusher to make sure we call ScriptEvaluated when we're done.
322 NS_ENSURE_STATE(pusher
.Push(aBoundElement
));
324 // Check whether it's OK to call the method.
325 rv
= nsContentUtils::GetSecurityManager()->CheckFunctionAccess(cx
, method
,
329 if (NS_SUCCEEDED(rv
)) {
331 ok
= ::JS_CallFunctionValue(cx
, thisObject
, OBJECT_TO_JSVAL(method
),
332 0 /* argc */, nsnull
/* argv */, &retval
);
336 // If a constructor or destructor threw an exception, it doesn't
337 // stop anything else. We just report it.
338 ::JS_ReportPendingException(cx
);
339 return NS_ERROR_FAILURE
;