LCOV - code coverage report
Current view: directory - content/xbl/src - nsXBLProtoImplMethod.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 164 0 0.0 %
Date: 2012-06-02 Functions: 13 0 0.0 %

       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
       4                 :  *
       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/
       9                 :  *
      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
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      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.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   David Hyatt <hyatt@netscape.com> (Original Author)
      24                 :  *
      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.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsIAtom.h"
      40                 : #include "nsString.h"
      41                 : #include "jsapi.h"
      42                 : #include "nsIContent.h"
      43                 : #include "nsIDocument.h"
      44                 : #include "nsIScriptGlobalObject.h"
      45                 : #include "nsString.h"
      46                 : #include "mozilla/FunctionTimer.h"
      47                 : #include "nsUnicharUtils.h"
      48                 : #include "nsReadableUtils.h"
      49                 : #include "nsXBLProtoImplMethod.h"
      50                 : #include "nsIScriptContext.h"
      51                 : #include "nsContentUtils.h"
      52                 : #include "nsIScriptSecurityManager.h"
      53                 : #include "nsIXPConnect.h"
      54                 : #include "nsXBLPrototypeBinding.h"
      55                 : 
      56               0 : nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) :
      57                 :   nsXBLProtoImplMember(aName), 
      58               0 :   mUncompiledMethod(BIT_UNCOMPILED)
      59                 : {
      60               0 :   MOZ_COUNT_CTOR(nsXBLProtoImplMethod);
      61               0 : }
      62                 : 
      63               0 : nsXBLProtoImplMethod::~nsXBLProtoImplMethod()
      64                 : {
      65               0 :   MOZ_COUNT_DTOR(nsXBLProtoImplMethod);
      66                 : 
      67               0 :   if (!IsCompiled()) {
      68               0 :     delete GetUncompiledMethod();
      69                 :   }
      70               0 : }
      71                 : 
      72                 : void 
      73               0 : nsXBLProtoImplMethod::AppendBodyText(const nsAString& aText)
      74                 : {
      75               0 :   NS_PRECONDITION(!IsCompiled(),
      76                 :                   "Must not be compiled when accessing uncompiled method");
      77                 : 
      78               0 :   nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
      79               0 :   if (!uncompiledMethod) {
      80               0 :     uncompiledMethod = new nsXBLUncompiledMethod();
      81               0 :     if (!uncompiledMethod)
      82               0 :       return;
      83               0 :     SetUncompiledMethod(uncompiledMethod);
      84                 :   }
      85                 : 
      86               0 :   uncompiledMethod->AppendBodyText(aText);
      87                 : }
      88                 : 
      89                 : void 
      90               0 : nsXBLProtoImplMethod::AddParameter(const nsAString& aText)
      91                 : {
      92               0 :   NS_PRECONDITION(!IsCompiled(),
      93                 :                   "Must not be compiled when accessing uncompiled method");
      94                 : 
      95               0 :   nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
      96               0 :   if (!uncompiledMethod) {
      97               0 :     uncompiledMethod = new nsXBLUncompiledMethod();
      98               0 :     if (!uncompiledMethod)
      99               0 :       return;
     100               0 :     SetUncompiledMethod(uncompiledMethod);
     101                 :   }
     102                 : 
     103               0 :   uncompiledMethod->AddParameter(aText);
     104                 : }
     105                 : 
     106                 : void
     107               0 : nsXBLProtoImplMethod::SetLineNumber(PRUint32 aLineNumber)
     108                 : {
     109               0 :   NS_PRECONDITION(!IsCompiled(),
     110                 :                   "Must not be compiled when accessing uncompiled method");
     111                 : 
     112               0 :   nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
     113               0 :   if (!uncompiledMethod) {
     114               0 :     uncompiledMethod = new nsXBLUncompiledMethod();
     115               0 :     if (!uncompiledMethod)
     116               0 :       return;
     117               0 :     SetUncompiledMethod(uncompiledMethod);
     118                 :   }
     119                 : 
     120               0 :   uncompiledMethod->SetLineNumber(aLineNumber);
     121                 : }
     122                 : 
     123                 : nsresult
     124               0 : nsXBLProtoImplMethod::InstallMember(nsIScriptContext* aContext,
     125                 :                                     nsIContent* aBoundElement, 
     126                 :                                     void* aScriptObject,
     127                 :                                     void* aTargetClassObject,
     128                 :                                     const nsCString& aClassStr)
     129                 : {
     130               0 :   NS_PRECONDITION(IsCompiled(),
     131                 :                   "Should not be installing an uncompiled method");
     132               0 :   JSContext* cx = aContext->GetNativeContext();
     133                 : 
     134               0 :   nsIDocument *ownerDoc = aBoundElement->OwnerDoc();
     135                 :   nsIScriptGlobalObject *sgo;
     136                 : 
     137               0 :   if (!(sgo = ownerDoc->GetScopeObject())) {
     138               0 :     return NS_ERROR_UNEXPECTED;
     139                 :   }
     140                 : 
     141               0 :   JSObject * scriptObject = (JSObject *) aScriptObject;
     142               0 :   NS_ASSERTION(scriptObject, "uh-oh, script Object should NOT be null or bad things will happen");
     143               0 :   if (!scriptObject)
     144               0 :     return NS_ERROR_FAILURE;
     145                 : 
     146               0 :   JSObject * targetClassObject = (JSObject *) aTargetClassObject;
     147               0 :   JSObject * globalObject = sgo->GetGlobalJSObject();
     148                 : 
     149                 :   // now we want to reevaluate our property using aContext and the script object for this window...
     150               0 :   if (mJSMethodObject && targetClassObject) {
     151               0 :     nsDependentString name(mName);
     152               0 :     JSAutoRequest ar(cx);
     153               0 :     JSAutoEnterCompartment ac;
     154                 : 
     155               0 :     if (!ac.enter(cx, globalObject)) {
     156               0 :       return NS_ERROR_UNEXPECTED;
     157                 :     }
     158                 : 
     159               0 :     JSObject * method = ::JS_CloneFunctionObject(cx, mJSMethodObject, globalObject);
     160               0 :     if (!method) {
     161               0 :       return NS_ERROR_OUT_OF_MEMORY;
     162                 :     }
     163                 : 
     164               0 :     if (!::JS_DefineUCProperty(cx, targetClassObject,
     165                 :                                reinterpret_cast<const jschar*>(mName), 
     166                 :                                name.Length(), OBJECT_TO_JSVAL(method),
     167               0 :                                NULL, NULL, JSPROP_ENUMERATE)) {
     168               0 :       return NS_ERROR_OUT_OF_MEMORY;
     169                 :     }
     170                 :   }
     171               0 :   return NS_OK;
     172                 : }
     173                 : 
     174                 : nsresult 
     175               0 : nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
     176                 :                                     JSObject* aClassObject)
     177                 : {
     178                 :   NS_TIME_FUNCTION_MIN(5);
     179               0 :   NS_PRECONDITION(!IsCompiled(),
     180                 :                   "Trying to compile an already-compiled method");
     181               0 :   NS_PRECONDITION(aClassObject,
     182                 :                   "Must have class object to compile");
     183                 : 
     184               0 :   nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
     185                 : 
     186                 :   // No parameters or body was supplied, so don't install method.
     187               0 :   if (!uncompiledMethod) {
     188                 :     // Early return after which we consider ourselves compiled.
     189               0 :     mJSMethodObject = nsnull;
     190                 : 
     191               0 :     return NS_OK;
     192                 :   }
     193                 : 
     194                 :   // Don't install method if no name was supplied.
     195               0 :   if (!mName) {
     196               0 :     delete uncompiledMethod;
     197                 : 
     198                 :     // Early return after which we consider ourselves compiled.
     199               0 :     mJSMethodObject = nsnull;
     200                 : 
     201               0 :     return NS_OK;
     202                 :   }
     203                 : 
     204                 :   // We have a method.
     205                 :   // Allocate an array for our arguments.
     206               0 :   PRInt32 paramCount = uncompiledMethod->GetParameterCount();
     207               0 :   char** args = nsnull;
     208               0 :   if (paramCount > 0) {
     209               0 :     args = new char*[paramCount];
     210               0 :     if (!args)
     211               0 :       return NS_ERROR_OUT_OF_MEMORY;
     212                 : 
     213                 :     // Add our parameters to our args array.
     214               0 :     PRInt32 argPos = 0; 
     215               0 :     for (nsXBLParameter* curr = uncompiledMethod->mParameters; 
     216                 :          curr; 
     217                 :          curr = curr->mNext) {
     218               0 :       args[argPos] = curr->mName;
     219               0 :       argPos++;
     220                 :     }
     221                 :   }
     222                 : 
     223                 :   // Get the body
     224               0 :   nsDependentString body;
     225               0 :   PRUnichar *bodyText = uncompiledMethod->mBodyText.GetText();
     226               0 :   if (bodyText)
     227               0 :     body.Rebind(bodyText);
     228                 : 
     229                 :   // Now that we have a body and args, compile the function
     230                 :   // and then define it.
     231               0 :   NS_ConvertUTF16toUTF8 cname(mName);
     232               0 :   nsCAutoString functionUri(aClassStr);
     233               0 :   PRInt32 hash = functionUri.RFindChar('#');
     234               0 :   if (hash != kNotFound) {
     235               0 :     functionUri.Truncate(hash);
     236                 :   }
     237                 : 
     238               0 :   JSObject* methodObject = nsnull;
     239                 :   nsresult rv = aContext->CompileFunction(aClassObject,
     240                 :                                           cname,
     241                 :                                           paramCount,
     242                 :                                           const_cast<const char**>(args),
     243                 :                                           body, 
     244                 :                                           functionUri.get(),
     245                 :                                           uncompiledMethod->mBodyText.GetLineNumber(),
     246                 :                                           JSVERSION_LATEST,
     247                 :                                           true,
     248               0 :                                           &methodObject);
     249                 : 
     250                 :   // Destroy our uncompiled method and delete our arg list.
     251               0 :   delete uncompiledMethod;
     252               0 :   delete [] args;
     253               0 :   if (NS_FAILED(rv)) {
     254               0 :     SetUncompiledMethod(nsnull);
     255               0 :     return rv;
     256                 :   }
     257                 : 
     258               0 :   mJSMethodObject = methodObject;
     259                 : 
     260               0 :   return NS_OK;
     261                 : }
     262                 : 
     263                 : void
     264               0 : nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const
     265                 : {
     266               0 :   if (IsCompiled() && mJSMethodObject) {
     267               0 :     aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject, "mJSMethodObject", aClosure);
     268                 :   }
     269               0 : }
     270                 : 
     271                 : nsresult
     272               0 : nsXBLProtoImplMethod::Read(nsIScriptContext* aContext,
     273                 :                            nsIObjectInputStream* aStream)
     274                 : {
     275               0 :   nsresult rv = XBL_DeserializeFunction(aContext, aStream, &mJSMethodObject);
     276               0 :   if (NS_FAILED(rv)) {
     277               0 :     SetUncompiledMethod(nsnull);
     278               0 :     return rv;
     279                 :   }
     280                 : 
     281                 : #ifdef DEBUG
     282               0 :   mIsCompiled = true;
     283                 : #endif
     284                 : 
     285               0 :   return NS_OK;
     286                 : }
     287                 : 
     288                 : nsresult
     289               0 : nsXBLProtoImplMethod::Write(nsIScriptContext* aContext,
     290                 :                             nsIObjectOutputStream* aStream)
     291                 : {
     292               0 :   if (mJSMethodObject) {
     293               0 :     nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
     294               0 :     NS_ENSURE_SUCCESS(rv, rv);
     295                 : 
     296               0 :     rv = aStream->WriteWStringZ(mName);
     297               0 :     NS_ENSURE_SUCCESS(rv, rv);
     298                 : 
     299               0 :     return XBL_SerializeFunction(aContext, aStream, mJSMethodObject);
     300                 :   }
     301                 : 
     302               0 :   return NS_OK;
     303                 : }
     304                 : 
     305                 : nsresult
     306               0 : nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
     307                 : {
     308               0 :   NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
     309                 :   
     310               0 :   if (!mJSMethodObject) {
     311                 :     // Nothing to do here
     312               0 :     return NS_OK;
     313                 :   }
     314                 : 
     315                 :   // Get the script context the same way
     316                 :   // nsXBLProtoImpl::InstallImplementation does.
     317               0 :   nsIDocument* document = aBoundElement->OwnerDoc();
     318                 : 
     319               0 :   nsIScriptGlobalObject* global = document->GetScriptGlobalObject();
     320               0 :   if (!global) {
     321               0 :     return NS_OK;
     322                 :   }
     323                 : 
     324               0 :   nsCOMPtr<nsIScriptContext> context = global->GetContext();
     325               0 :   if (!context) {
     326               0 :     return NS_OK;
     327                 :   }
     328                 :   
     329               0 :   JSContext* cx = context->GetNativeContext();
     330                 : 
     331               0 :   JSObject* globalObject = global->GetGlobalJSObject();
     332                 : 
     333               0 :   nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
     334                 :   jsval v;
     335                 :   nsresult rv =
     336                 :     nsContentUtils::WrapNative(cx, globalObject, aBoundElement, &v,
     337               0 :                                getter_AddRefs(wrapper));
     338               0 :   NS_ENSURE_SUCCESS(rv, rv);
     339                 : 
     340               0 :   JSObject* thisObject = JSVAL_TO_OBJECT(v);
     341                 : 
     342               0 :   JSAutoRequest ar(cx);
     343               0 :   JSAutoEnterCompartment ac;
     344                 : 
     345               0 :   if (!ac.enter(cx, thisObject))
     346               0 :     return NS_ERROR_UNEXPECTED;
     347                 : 
     348                 :   // Clone the function object, using thisObject as the parent so "this" is in
     349                 :   // the scope chain of the resulting function (for backwards compat to the
     350                 :   // days when this was an event handler).
     351               0 :   JSObject* method = ::JS_CloneFunctionObject(cx, mJSMethodObject, thisObject);
     352               0 :   if (!method)
     353               0 :     return NS_ERROR_OUT_OF_MEMORY;
     354                 : 
     355                 :   // Now call the method
     356                 : 
     357                 :   // Use nsCxPusher to make sure we call ScriptEvaluated when we're done.
     358               0 :   nsCxPusher pusher;
     359               0 :   NS_ENSURE_STATE(pusher.Push(aBoundElement));
     360                 : 
     361                 :   // Check whether it's OK to call the method.
     362               0 :   rv = nsContentUtils::GetSecurityManager()->CheckFunctionAccess(cx, method,
     363               0 :                                                                  thisObject);
     364                 : 
     365               0 :   JSBool ok = JS_TRUE;
     366               0 :   if (NS_SUCCEEDED(rv)) {
     367                 :     jsval retval;
     368                 :     ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method),
     369               0 :                                 0 /* argc */, nsnull /* argv */, &retval);
     370                 :   }
     371                 : 
     372               0 :   if (!ok) {
     373                 :     // If a constructor or destructor threw an exception, it doesn't stop
     374                 :     // anything else.  We just report it.  Note that we need to set aside the
     375                 :     // frame chain here, since the constructor invocation is not related to
     376                 :     // whatever is on the stack right now, really.
     377               0 :     JSBool saved = JS_SaveFrameChain(cx);
     378               0 :     JS_ReportPendingException(cx);
     379               0 :     if (saved)
     380               0 :         JS_RestoreFrameChain(cx);
     381               0 :     return NS_ERROR_FAILURE;
     382                 :   }
     383                 : 
     384               0 :   return NS_OK;
     385                 : }
     386                 : 
     387                 : nsresult
     388               0 : nsXBLProtoImplAnonymousMethod::Write(nsIScriptContext* aContext,
     389                 :                                      nsIObjectOutputStream* aStream,
     390                 :                                      XBLBindingSerializeDetails aType)
     391                 : {
     392               0 :   if (mJSMethodObject) {
     393               0 :     nsresult rv = aStream->Write8(aType);
     394               0 :     NS_ENSURE_SUCCESS(rv, rv);
     395                 : 
     396               0 :     rv = XBL_SerializeFunction(aContext, aStream, mJSMethodObject);
     397               0 :     NS_ENSURE_SUCCESS(rv, rv);
     398                 :   }
     399                 : 
     400               0 :   return NS_OK;
     401                 : }

Generated by: LCOV version 1.7