LCOV - code coverage report
Current view: top level - dom/xbl - nsXBLProtoImpl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 138 245 56.3 %
Date: 2017-07-14 16:53:18 Functions: 7 13 53.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/DebugOnly.h"
       8             : 
       9             : #include "nsXBLProtoImpl.h"
      10             : #include "nsIContent.h"
      11             : #include "nsIDocument.h"
      12             : #include "nsContentUtils.h"
      13             : #include "nsIXPConnect.h"
      14             : #include "nsIServiceManager.h"
      15             : #include "nsIDOMNode.h"
      16             : #include "nsXBLPrototypeBinding.h"
      17             : #include "nsXBLProtoImplProperty.h"
      18             : #include "nsIURI.h"
      19             : #include "mozilla/AddonPathService.h"
      20             : #include "mozilla/dom/ScriptSettings.h"
      21             : #include "mozilla/dom/XULElementBinding.h"
      22             : #include "xpcpublic.h"
      23             : #include "js/CharacterEncoding.h"
      24             : 
      25             : using namespace mozilla;
      26             : using namespace mozilla::dom;
      27             : using js::GetGlobalForObjectCrossCompartment;
      28             : using js::AssertSameCompartment;
      29             : 
      30             : nsresult
      31         523 : nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
      32             :                                       nsXBLBinding* aBinding)
      33             : {
      34             :   // This function is called to install a concrete implementation on a bound element using
      35             :   // this prototype implementation as a guide.  The prototype implementation is compiled lazily,
      36             :   // so for the first bound element that needs a concrete implementation, we also build the
      37             :   // prototype implementation.
      38         523 :   if (!mMembers && !mFields)  // Constructor and destructor also live in mMembers
      39           0 :     return NS_OK; // Nothing to do, so let's not waste time.
      40             : 
      41             :   // If the way this gets the script context changes, fix
      42             :   // nsXBLProtoImplAnonymousMethod::Execute
      43         523 :   nsIDocument* document = aBinding->GetBoundElement()->OwnerDoc();
      44             : 
      45             :   // This sometimes gets called when we have no outer window and if we don't
      46             :   // catch this, we get leaks during crashtests and reftests.
      47         523 :   if (NS_WARN_IF(!document->GetWindow())) {
      48           0 :     return NS_OK;
      49             :   }
      50             : 
      51             :   // |propertyHolder| (below) can be an existing object, so in theory we might
      52             :   // hit something that could end up running script. We never want that to
      53             :   // happen here, so we use an AutoJSAPI instead of an AutoEntryScript.
      54        1046 :   dom::AutoJSAPI jsapi;
      55         523 :   if (NS_WARN_IF(!jsapi.Init(document->GetScopeObject()))) {
      56           0 :     return NS_OK;
      57             :   }
      58         523 :   JSContext* cx = jsapi.cx();
      59             : 
      60             :   // InitTarget objects gives us back the JS object that represents the bound element and the
      61             :   // class object in the bound document that represents the concrete version of this implementation.
      62             :   // This function also has the side effect of building up the prototype implementation if it has
      63             :   // not been built already.
      64        1046 :   JS::Rooted<JSObject*> targetClassObject(cx, nullptr);
      65         523 :   bool targetObjectIsNew = false;
      66        1046 :   nsresult rv = InitTargetObjects(aPrototypeBinding,
      67             :                                   aBinding->GetBoundElement(),
      68             :                                   &targetClassObject,
      69         523 :                                   &targetObjectIsNew);
      70         523 :   NS_ENSURE_SUCCESS(rv, rv); // kick out if we were unable to properly intialize our target objects
      71         523 :   MOZ_ASSERT(targetClassObject);
      72             : 
      73             :   // If the prototype already existed, we don't need to install anything. return early.
      74         523 :   if (!targetObjectIsNew)
      75         463 :     return NS_OK;
      76             : 
      77             :   // We want to define the canonical set of members in a safe place. If we're
      78             :   // using a separate XBL scope, we want to define them there first (so that
      79             :   // they'll be available for Xray lookups, among other things), and then copy
      80             :   // the properties to the content-side prototype as needed. We don't need to
      81             :   // bother about the field accessors here, since we don't use/support those
      82             :   // for in-content bindings.
      83             : 
      84             :   // First, start by entering the compartment of the XBL scope. This may or may
      85             :   // not be the same compartment as globalObject.
      86          60 :   JSAddonId* addonId = MapURIToAddonID(aPrototypeBinding->BindingURI());
      87             :   JS::Rooted<JSObject*> globalObject(cx,
      88         120 :     GetGlobalForObjectCrossCompartment(targetClassObject));
      89         120 :   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
      90          60 :   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
      91          60 :   MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(scopeObject) == scopeObject);
      92         120 :   JSAutoCompartment ac(cx, scopeObject);
      93             : 
      94             :   // Determine the appropriate property holder.
      95             :   //
      96             :   // Note: If |targetIsNew| is false, we'll early-return above. However, that only
      97             :   // tells us if the content-side object is new, which may be the case even if
      98             :   // we've already set up the binding on the XBL side. For example, if we apply
      99             :   // a binding #foo to a <span> when we've already applied it to a <div>, we'll
     100             :   // end up with a different content prototype, but we'll already have a property
     101             :   // holder called |foo| in the XBL scope. Check for that to avoid wasteful and
     102             :   // weird property holder duplication.
     103          60 :   const char16_t* className = aPrototypeBinding->ClassName().get();
     104         120 :   JS::Rooted<JSObject*> propertyHolder(cx);
     105         120 :   JS::Rooted<JS::PropertyDescriptor> existingHolder(cx);
     106         180 :   if (scopeObject != globalObject &&
     107          60 :       !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, className, &existingHolder)) {
     108           0 :     return NS_ERROR_FAILURE;
     109             :   }
     110          60 :   bool propertyHolderIsNew = !existingHolder.object() || !existingHolder.value().isObject();
     111             : 
     112          60 :   if (!propertyHolderIsNew) {
     113           0 :     propertyHolder = &existingHolder.value().toObject();
     114          60 :   } else if (scopeObject != globalObject) {
     115             : 
     116             :     // This is just a property holder, so it doesn't need any special JSClass.
     117           0 :     propertyHolder = JS_NewObjectWithGivenProto(cx, nullptr, nullptr);
     118           0 :     NS_ENSURE_TRUE(propertyHolder, NS_ERROR_OUT_OF_MEMORY);
     119             : 
     120             :     // Define it as a property on the scopeObject, using the same name used on
     121             :     // the content side.
     122           0 :     bool ok = JS_DefineUCProperty(cx, scopeObject, className, -1, propertyHolder,
     123             :                                   JSPROP_PERMANENT | JSPROP_READONLY,
     124           0 :                                   JS_STUBGETTER, JS_STUBSETTER);
     125           0 :     NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
     126             :   } else {
     127          60 :     propertyHolder = targetClassObject;
     128             :   }
     129             : 
     130             :   // Walk our member list and install each one in turn on the XBL scope object.
     131          60 :   if (propertyHolderIsNew) {
     132         849 :     for (nsXBLProtoImplMember* curr = mMembers;
     133         849 :          curr;
     134             :          curr = curr->GetNext())
     135         789 :       curr->InstallMember(cx, propertyHolder);
     136             :   }
     137             : 
     138             :   // Now, if we're using a separate XBL scope, enter the compartment of the
     139             :   // bound node and copy exposable properties to the prototype there. This
     140             :   // rewraps them appropriately, which should result in cross-compartment
     141             :   // function wrappers.
     142          60 :   if (propertyHolder != targetClassObject) {
     143           0 :     AssertSameCompartment(propertyHolder, scopeObject);
     144           0 :     AssertSameCompartment(targetClassObject, globalObject);
     145           0 :     bool inContentXBLScope = xpc::IsInContentXBLScope(scopeObject);
     146           0 :     for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
     147           0 :       if (!inContentXBLScope || curr->ShouldExposeToUntrustedContent()) {
     148           0 :         JS::Rooted<jsid> id(cx);
     149           0 :         JS::TwoByteChars chars(curr->GetName(), NS_strlen(curr->GetName()));
     150           0 :         bool ok = JS_CharsToId(cx, chars, &id);
     151           0 :         NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
     152             : 
     153             :         bool found;
     154           0 :         ok = JS_HasPropertyById(cx, propertyHolder, id, &found);
     155           0 :         NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
     156           0 :         if (!found) {
     157             :           // Some members don't install anything in InstallMember (e.g.,
     158             :           // nsXBLProtoImplAnonymousMethod). We need to skip copying in
     159             :           // those cases.
     160           0 :           continue;
     161             :         }
     162             : 
     163           0 :         ok = JS_CopyPropertyFrom(cx, id, targetClassObject, propertyHolder);
     164           0 :         NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
     165             :       }
     166             :     }
     167             :   }
     168             : 
     169             :   // From here on out, work in the scope of the bound element.
     170         120 :   JSAutoCompartment ac2(cx, targetClassObject);
     171             : 
     172             :   // Install all of our field accessors.
     173         342 :   for (nsXBLProtoImplField* curr = mFields;
     174         342 :        curr;
     175             :        curr = curr->GetNext())
     176         282 :     curr->InstallAccessors(cx, targetClassObject);
     177             : 
     178          60 :   return NS_OK;
     179             : }
     180             : 
     181             : nsresult
     182         523 : nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
     183             :                                   nsIContent* aBoundElement,
     184             :                                   JS::MutableHandle<JSObject*> aTargetClassObject,
     185             :                                   bool* aTargetIsNew)
     186             : {
     187         523 :   nsresult rv = NS_OK;
     188             : 
     189         523 :   if (!mPrecompiledMemberHolder) {
     190           0 :     rv = CompilePrototypeMembers(aBinding); // This is the first time we've ever installed this binding on an element.
     191             :                                  // We need to go ahead and compile all methods and properties on a class
     192             :                                  // in our prototype binding.
     193           0 :     if (NS_FAILED(rv))
     194           0 :       return rv;
     195             : 
     196           0 :     MOZ_ASSERT(mPrecompiledMemberHolder);
     197             :   }
     198             : 
     199         523 :   nsIDocument *ownerDoc = aBoundElement->OwnerDoc();
     200             :   nsIGlobalObject *sgo;
     201             : 
     202         523 :   if (!(sgo = ownerDoc->GetScopeObject())) {
     203           0 :     return NS_ERROR_UNEXPECTED;
     204             :   }
     205             : 
     206             :   // Because our prototype implementation has a class, we need to build up a corresponding
     207             :   // class for the concrete implementation in the bound document.
     208        1046 :   AutoJSContext cx;
     209        1046 :   JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
     210        1046 :   JS::Rooted<JS::Value> v(cx);
     211             : 
     212        1046 :   JSAutoCompartment ac(cx, global);
     213             :   // Make sure the interface object is created before the prototype object
     214             :   // so that XULElement is hidden from content. See bug 909340.
     215         523 :   bool defineOnGlobal = dom::XULElementBinding::ConstructorEnabled(cx, global);
     216         523 :   dom::XULElementBinding::GetConstructorObjectHandle(cx, defineOnGlobal);
     217             : 
     218        1046 :   rv = nsContentUtils::WrapNative(cx, aBoundElement, &v,
     219         523 :                                   /* aAllowWrapping = */ false);
     220         523 :   NS_ENSURE_SUCCESS(rv, rv);
     221             : 
     222        1046 :   JS::Rooted<JSObject*> value(cx, &v.toObject());
     223        1046 :   JSAutoCompartment ac2(cx, value);
     224             : 
     225             :   // All of the above code was just obtaining the bound element's script object and its immediate
     226             :   // concrete base class.  We need to alter the object so that our concrete class is interposed
     227             :   // between the object and its base class.  We become the new base class of the object, and the
     228             :   // object's old base class becomes the new class' base class.
     229         523 :   rv = aBinding->InitClass(mClassName, cx, value, aTargetClassObject, aTargetIsNew);
     230         523 :   if (NS_FAILED(rv)) {
     231           0 :     return rv;
     232             :   }
     233             : 
     234         523 :   aBoundElement->PreserveWrapper(aBoundElement);
     235             : 
     236         523 :   return rv;
     237             : }
     238             : 
     239             : nsresult
     240           0 : nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding)
     241             : {
     242             :   // We want to pre-compile our implementation's members against a "prototype context". Then when we actually
     243             :   // bind the prototype to a real xbl instance, we'll clone the pre-compiled JS into the real instance's
     244             :   // context.
     245           0 :   AutoJSAPI jsapi;
     246           0 :   if (NS_WARN_IF(!jsapi.Init(xpc::CompilationScope())))
     247           0 :     return NS_ERROR_FAILURE;
     248           0 :   JSContext* cx = jsapi.cx();
     249             : 
     250           0 :   mPrecompiledMemberHolder = JS_NewObjectWithGivenProto(cx, nullptr, nullptr);
     251           0 :   if (!mPrecompiledMemberHolder)
     252           0 :     return NS_ERROR_OUT_OF_MEMORY;
     253             : 
     254             :   // Now that we have a class object installed, we walk our member list and compile each of our
     255             :   // properties and methods in turn.
     256           0 :   JS::Rooted<JSObject*> rootedHolder(cx, mPrecompiledMemberHolder);
     257           0 :   for (nsXBLProtoImplMember* curr = mMembers;
     258           0 :        curr;
     259             :        curr = curr->GetNext()) {
     260           0 :     nsresult rv = curr->CompileMember(jsapi, mClassName, rootedHolder);
     261           0 :     if (NS_FAILED(rv)) {
     262           0 :       DestroyMembers();
     263           0 :       return rv;
     264             :     }
     265             :   }
     266             : 
     267           0 :   return NS_OK;
     268             : }
     269             : 
     270             : bool
     271           0 : nsXBLProtoImpl::LookupMember(JSContext* aCx, nsString& aName,
     272             :                              JS::Handle<jsid> aNameAsId,
     273             :                              JS::MutableHandle<JS::PropertyDescriptor> aDesc,
     274             :                              JS::Handle<JSObject*> aClassObject)
     275             : {
     276           0 :   for (nsXBLProtoImplMember* m = mMembers; m; m = m->GetNext()) {
     277           0 :     if (aName.Equals(m->GetName())) {
     278           0 :       return JS_GetPropertyDescriptorById(aCx, aClassObject, aNameAsId, aDesc);
     279             :     }
     280             :   }
     281           0 :   return true;
     282             : }
     283             : 
     284             : void
     285          83 : nsXBLProtoImpl::Trace(const TraceCallbacks& aCallbacks, void *aClosure)
     286             : {
     287             :   // If we don't have a class object then we either didn't compile members
     288             :   // or we only have fields, in both cases there are no cycles through our
     289             :   // members.
     290          83 :   if (!mPrecompiledMemberHolder) {
     291           0 :     return;
     292             :   }
     293             : 
     294             :   nsXBLProtoImplMember *member;
     295        1017 :   for (member = mMembers; member; member = member->GetNext()) {
     296         934 :     member->Trace(aCallbacks, aClosure);
     297             :   }
     298             : }
     299             : 
     300             : void
     301           0 : nsXBLProtoImpl::UnlinkJSObjects()
     302             : {
     303           0 :   if (mPrecompiledMemberHolder) {
     304           0 :     DestroyMembers();
     305             :   }
     306           0 : }
     307             : 
     308             : nsXBLProtoImplField*
     309         112 : nsXBLProtoImpl::FindField(const nsString& aFieldName) const
     310             : {
     311        1096 :   for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
     312        1096 :     if (aFieldName.Equals(f->GetName())) {
     313         112 :       return f;
     314             :     }
     315             :   }
     316             : 
     317           0 :   return nullptr;
     318             : }
     319             : 
     320             : bool
     321           0 : nsXBLProtoImpl::ResolveAllFields(JSContext *cx, JS::Handle<JSObject*> obj) const
     322             : {
     323           0 :   for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
     324           0 :     nsDependentString name(f->GetName());
     325             :     bool dummy;
     326           0 :     if (!::JS_HasUCProperty(cx, obj, name.get(), name.Length(), &dummy)) {
     327           0 :       return false;
     328             :     }
     329             :   }
     330             : 
     331           0 :   return true;
     332             : }
     333             : 
     334             : void
     335          25 : nsXBLProtoImpl::UndefineFields(JSContext *cx, JS::Handle<JSObject*> obj) const
     336             : {
     337          50 :   JSAutoRequest ar(cx);
     338          63 :   for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
     339          76 :     nsDependentString name(f->GetName());
     340             : 
     341          38 :     const char16_t* s = name.get();
     342             :     bool hasProp;
     343          38 :     if (::JS_AlreadyHasOwnUCProperty(cx, obj, s, name.Length(), &hasProp) &&
     344             :         hasProp) {
     345          13 :       JS::ObjectOpResult ignored;
     346          13 :       ::JS_DeleteUCProperty(cx, obj, s, name.Length(), ignored);
     347             :     }
     348             :   }
     349          25 : }
     350             : 
     351             : void
     352           0 : nsXBLProtoImpl::DestroyMembers()
     353             : {
     354           0 :   MOZ_ASSERT(mPrecompiledMemberHolder);
     355             : 
     356           0 :   delete mMembers;
     357           0 :   mMembers = nullptr;
     358           0 :   mConstructor = nullptr;
     359           0 :   mDestructor = nullptr;
     360           0 : }
     361             : 
     362             : nsresult
     363          83 : nsXBLProtoImpl::Read(nsIObjectInputStream* aStream,
     364             :                      nsXBLPrototypeBinding* aBinding)
     365             : {
     366          83 :   AssertInCompilationScope();
     367         166 :   AutoJSContext cx;
     368             :   // Set up a class object first so that deserialization is possible
     369          83 :   mPrecompiledMemberHolder = JS_NewObjectWithGivenProto(cx, nullptr, nullptr);
     370          83 :   if (!mPrecompiledMemberHolder)
     371           0 :     return NS_ERROR_OUT_OF_MEMORY;
     372             : 
     373          83 :   nsXBLProtoImplField* previousField = nullptr;
     374          83 :   nsXBLProtoImplMember* previousMember = nullptr;
     375             : 
     376             :   do {
     377             :     XBLBindingSerializeDetails type;
     378        1348 :     nsresult rv = aStream->Read8(&type);
     379        1348 :     NS_ENSURE_SUCCESS(rv, rv);
     380        1348 :     if (type == XBLBinding_Serialize_NoMoreItems)
     381          83 :       break;
     382             : 
     383        1265 :     switch (type & XBLBinding_Serialize_Mask) {
     384             :       case XBLBinding_Serialize_Field:
     385             :       {
     386             :         nsXBLProtoImplField* field =
     387         331 :           new nsXBLProtoImplField(type & XBLBinding_Serialize_ReadOnly);
     388         331 :         rv = field->Read(aStream);
     389         331 :         if (NS_FAILED(rv)) {
     390           0 :           delete field;
     391           0 :           return rv;
     392             :         }
     393             : 
     394         331 :         if (previousField) {
     395         273 :           previousField->SetNext(field);
     396             :         }
     397             :         else {
     398          58 :           mFields = field;
     399             :         }
     400         331 :         previousField = field;
     401             : 
     402         331 :         break;
     403             :       }
     404             :       case XBLBinding_Serialize_GetterProperty:
     405             :       case XBLBinding_Serialize_SetterProperty:
     406             :       case XBLBinding_Serialize_GetterSetterProperty:
     407             :       {
     408         355 :         nsAutoString name;
     409         355 :         nsresult rv = aStream->ReadString(name);
     410         355 :         NS_ENSURE_SUCCESS(rv, rv);
     411             : 
     412             :         nsXBLProtoImplProperty* prop =
     413         710 :           new nsXBLProtoImplProperty(name.get(), type & XBLBinding_Serialize_ReadOnly);
     414         355 :         rv = prop->Read(aStream, type & XBLBinding_Serialize_Mask);
     415         355 :         if (NS_FAILED(rv)) {
     416           0 :           delete prop;
     417           0 :           return rv;
     418             :         }
     419             : 
     420         355 :         previousMember = AddMember(prop, previousMember);
     421         355 :         break;
     422             :       }
     423             :       case XBLBinding_Serialize_Method:
     424             :       {
     425         522 :         nsAutoString name;
     426         522 :         rv = aStream->ReadString(name);
     427         522 :         NS_ENSURE_SUCCESS(rv, rv);
     428             : 
     429        1044 :         nsXBLProtoImplMethod* method = new nsXBLProtoImplMethod(name.get());
     430         522 :         rv = method->Read(aStream);
     431         522 :         if (NS_FAILED(rv)) {
     432           0 :           delete method;
     433           0 :           return rv;
     434             :         }
     435             : 
     436         522 :         previousMember = AddMember(method, previousMember);
     437         522 :         break;
     438             :       }
     439             :       case XBLBinding_Serialize_Constructor:
     440             :       {
     441          39 :         nsAutoString name;
     442          39 :         rv = aStream->ReadString(name);
     443          39 :         NS_ENSURE_SUCCESS(rv, rv);
     444             : 
     445          78 :         mConstructor = new nsXBLProtoImplAnonymousMethod(name.get());
     446          39 :         rv = mConstructor->Read(aStream);
     447          39 :         if (NS_FAILED(rv)) {
     448           0 :           delete mConstructor;
     449           0 :           mConstructor = nullptr;
     450           0 :           return rv;
     451             :         }
     452             : 
     453          39 :         previousMember = AddMember(mConstructor, previousMember);
     454          39 :         break;
     455             :       }
     456             :       case XBLBinding_Serialize_Destructor:
     457             :       {
     458          18 :         nsAutoString name;
     459          18 :         rv = aStream->ReadString(name);
     460          18 :         NS_ENSURE_SUCCESS(rv, rv);
     461             : 
     462          36 :         mDestructor = new nsXBLProtoImplAnonymousMethod(name.get());
     463          18 :         rv = mDestructor->Read(aStream);
     464          18 :         if (NS_FAILED(rv)) {
     465           0 :           delete mDestructor;
     466           0 :           mDestructor = nullptr;
     467           0 :           return rv;
     468             :         }
     469             : 
     470          18 :         previousMember = AddMember(mDestructor, previousMember);
     471          18 :         break;
     472             :       }
     473             :       default:
     474           0 :         NS_ERROR("Unexpected binding member type");
     475           0 :         break;
     476        1265 :     }
     477             :   } while (1);
     478             : 
     479          83 :   return NS_OK;
     480             : }
     481             : 
     482             : nsresult
     483           0 : nsXBLProtoImpl::Write(nsIObjectOutputStream* aStream,
     484             :                       nsXBLPrototypeBinding* aBinding)
     485             : {
     486             :   nsresult rv;
     487             : 
     488           0 :   if (!mPrecompiledMemberHolder) {
     489           0 :     rv = CompilePrototypeMembers(aBinding);
     490           0 :     NS_ENSURE_SUCCESS(rv, rv);
     491             :   }
     492             : 
     493           0 :   rv = aStream->WriteUtf8Z(mClassName.get());
     494           0 :   NS_ENSURE_SUCCESS(rv, rv);
     495             : 
     496           0 :   for (nsXBLProtoImplField* curr = mFields; curr; curr = curr->GetNext()) {
     497           0 :     rv = curr->Write(aStream);
     498           0 :     NS_ENSURE_SUCCESS(rv, rv);
     499             :   }
     500           0 :   for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
     501           0 :     if (curr == mConstructor) {
     502           0 :       rv = mConstructor->Write(aStream, XBLBinding_Serialize_Constructor);
     503             :     }
     504           0 :     else if (curr == mDestructor) {
     505           0 :       rv = mDestructor->Write(aStream, XBLBinding_Serialize_Destructor);
     506             :     }
     507             :     else {
     508           0 :       rv = curr->Write(aStream);
     509             :     }
     510           0 :     NS_ENSURE_SUCCESS(rv, rv);
     511             :   }
     512             : 
     513           0 :   return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
     514             : }
     515             : 
     516             : void
     517          83 : NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding,
     518             :                    const char16_t* aClassName,
     519             :                    nsXBLProtoImpl** aResult)
     520             : {
     521          83 :   nsXBLProtoImpl* impl = new nsXBLProtoImpl();
     522          83 :   if (aClassName) {
     523          83 :     impl->mClassName = aClassName;
     524             :   } else {
     525           0 :     nsCString spec;
     526           0 :     nsresult rv = aBinding->BindingURI()->GetSpec(spec);
     527             :     // XXX: should handle this better
     528           0 :     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
     529           0 :     impl->mClassName = NS_ConvertUTF8toUTF16(spec);
     530             :   }
     531             : 
     532          83 :   aBinding->SetImplementation(impl);
     533          83 :   *aResult = impl;
     534          83 : }
     535             : 

Generated by: LCOV version 1.13