LCOV - code coverage report
Current view: top level - dom/xbl - nsXBLProtoImplField.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 161 232 69.4 %
Date: 2017-07-14 16:53:18 Functions: 11 15 73.3 %
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 "nsIAtom.h"
       8             : #include "nsIContent.h"
       9             : #include "nsString.h"
      10             : #include "nsJSUtils.h"
      11             : #include "jsapi.h"
      12             : #include "js/CharacterEncoding.h"
      13             : #include "nsUnicharUtils.h"
      14             : #include "nsReadableUtils.h"
      15             : #include "nsXBLProtoImplField.h"
      16             : #include "nsIScriptContext.h"
      17             : #include "nsIURI.h"
      18             : #include "nsXBLSerialize.h"
      19             : #include "nsXBLPrototypeBinding.h"
      20             : #include "mozilla/AddonPathService.h"
      21             : #include "mozilla/dom/BindingUtils.h"
      22             : #include "mozilla/dom/ElementBinding.h"
      23             : #include "mozilla/dom/ScriptSettings.h"
      24             : #include "nsGlobalWindow.h"
      25             : #include "xpcpublic.h"
      26             : #include "WrapperFactory.h"
      27             : 
      28             : using namespace mozilla;
      29             : using namespace mozilla::dom;
      30             : 
      31           0 : nsXBLProtoImplField::nsXBLProtoImplField(const char16_t* aName, const char16_t* aReadOnly)
      32             :   : mNext(nullptr),
      33             :     mFieldText(nullptr),
      34             :     mFieldTextLength(0),
      35           0 :     mLineNumber(0)
      36             : {
      37           0 :   MOZ_COUNT_CTOR(nsXBLProtoImplField);
      38           0 :   mName = NS_strdup(aName);  // XXXbz make more sense to use a stringbuffer?
      39             : 
      40           0 :   mJSAttributes = JSPROP_ENUMERATE;
      41           0 :   if (aReadOnly) {
      42           0 :     nsAutoString readOnly; readOnly.Assign(aReadOnly);
      43           0 :     if (readOnly.LowerCaseEqualsLiteral("true"))
      44           0 :       mJSAttributes |= JSPROP_READONLY;
      45             :   }
      46           0 : }
      47             : 
      48             : 
      49         331 : nsXBLProtoImplField::nsXBLProtoImplField(const bool aIsReadOnly)
      50             :   : mNext(nullptr),
      51             :     mFieldText(nullptr),
      52             :     mFieldTextLength(0),
      53         331 :     mLineNumber(0)
      54             : {
      55         331 :   MOZ_COUNT_CTOR(nsXBLProtoImplField);
      56             : 
      57         331 :   mJSAttributes = JSPROP_ENUMERATE;
      58         331 :   if (aIsReadOnly)
      59          56 :     mJSAttributes |= JSPROP_READONLY;
      60         331 : }
      61             : 
      62           0 : nsXBLProtoImplField::~nsXBLProtoImplField()
      63             : {
      64           0 :   MOZ_COUNT_DTOR(nsXBLProtoImplField);
      65           0 :   if (mFieldText)
      66           0 :     free(mFieldText);
      67           0 :   free(mName);
      68           0 :   NS_CONTENT_DELETE_LIST_MEMBER(nsXBLProtoImplField, this, mNext);
      69           0 : }
      70             : 
      71             : void
      72           0 : nsXBLProtoImplField::AppendFieldText(const nsAString& aText)
      73             : {
      74           0 :   if (mFieldText) {
      75           0 :     nsDependentString fieldTextStr(mFieldText, mFieldTextLength);
      76           0 :     nsAutoString newFieldText = fieldTextStr + aText;
      77           0 :     char16_t* temp = mFieldText;
      78           0 :     mFieldText = ToNewUnicode(newFieldText);
      79           0 :     mFieldTextLength = newFieldText.Length();
      80           0 :     free(temp);
      81             :   }
      82             :   else {
      83           0 :     mFieldText = ToNewUnicode(aText);
      84           0 :     mFieldTextLength = aText.Length();
      85             :   }
      86           0 : }
      87             : 
      88             : // XBL fields are represented on elements inheriting that field a bit trickily.
      89             : // When setting up the XBL prototype object, we install accessors for the fields
      90             : // on the prototype object. Those accessors, when used, will then (via
      91             : // InstallXBLField below) reify a property for the field onto the actual XBL-backed
      92             : // element.
      93             : //
      94             : // The accessor property is a plain old property backed by a getter function and
      95             : // a setter function.  These properties are backed by the FieldGetter and
      96             : // FieldSetter natives; they're created by InstallAccessors.  The precise field to be
      97             : // reified is identified using two extra slots on the getter/setter functions.
      98             : // XBLPROTO_SLOT stores the XBL prototype object that provides the field.
      99             : // FIELD_SLOT stores the name of the field, i.e. its JavaScript property name.
     100             : //
     101             : // This two-step field installation process -- creating an accessor on the
     102             : // prototype, then have that reify an own property on the actual element -- is
     103             : // admittedly convoluted.  Better would be for XBL-backed elements to be proxies
     104             : // that could resolve fields onto themselves.  But given that XBL bindings are
     105             : // associated with elements mutably -- you can add/remove/change -moz-binding
     106             : // whenever you want, alas -- doing so would require all elements to be proxies,
     107             : // which isn't performant now.  So we do this two-step instead.
     108             : static const uint32_t XBLPROTO_SLOT = 0;
     109             : static const uint32_t FIELD_SLOT = 1;
     110             : 
     111             : bool
     112         336 : ValueHasISupportsPrivate(JS::Handle<JS::Value> v)
     113             : {
     114         336 :   if (!v.isObject()) {
     115           0 :     return false;
     116             :   }
     117             : 
     118         336 :   const DOMJSClass* domClass = GetDOMClass(&v.toObject());
     119         336 :   if (domClass) {
     120         336 :     return domClass->mDOMObjectIsISupports;
     121             :   }
     122             : 
     123           0 :   const JSClass* clasp = ::JS_GetClass(&v.toObject());
     124             :   const uint32_t HAS_PRIVATE_NSISUPPORTS =
     125           0 :     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
     126           0 :   return (clasp->flags & HAS_PRIVATE_NSISUPPORTS) == HAS_PRIVATE_NSISUPPORTS;
     127             : }
     128             : 
     129             : #ifdef DEBUG
     130             : static bool
     131         112 : ValueHasISupportsPrivate(JSContext* cx, const JS::Value& aVal)
     132             : {
     133         224 :     JS::Rooted<JS::Value> v(cx, aVal);
     134         224 :     return ValueHasISupportsPrivate(v);
     135             : }
     136             : #endif
     137             : 
     138             : // Define a shadowing property on |this| for the XBL field defined by the
     139             : // contents of the callee's reserved slots.  If the property was defined,
     140             : // *installed will be true, and idp will be set to the property name that was
     141             : // defined.
     142             : static bool
     143         112 : InstallXBLField(JSContext* cx,
     144             :                 JS::Handle<JSObject*> callee, JS::Handle<JSObject*> thisObj,
     145             :                 JS::MutableHandle<jsid> idp, bool* installed)
     146             : {
     147         112 :   *installed = false;
     148             : 
     149             :   // First ensure |this| is a reasonable XBL bound node.
     150             :   //
     151             :   // FieldAccessorGuard already determined whether |thisObj| was acceptable as
     152             :   // |this| in terms of not throwing a TypeError.  Assert this for good measure.
     153         112 :   MOZ_ASSERT(ValueHasISupportsPrivate(cx, JS::ObjectValue(*thisObj)));
     154             : 
     155             :   // But there are some cases where we must accept |thisObj| but not install a
     156             :   // property on it, or otherwise touch it.  Hence this split of |this|-vetting
     157             :   // duties.
     158         224 :   nsCOMPtr<nsISupports> native = xpc::UnwrapReflectorToISupports(thisObj);
     159         112 :   if (!native) {
     160             :     // Looks like whatever |thisObj| is it's not our nsIContent.  It might well
     161             :     // be the proto our binding installed, however, where the private is the
     162             :     // nsXBLDocumentInfo, so just baul out quietly.  Do NOT throw an exception
     163             :     // here.
     164             :     //
     165             :     // We could make this stricter by checking the class maybe, but whatever.
     166           0 :     return true;
     167             :   }
     168             : 
     169         224 :   nsCOMPtr<nsIContent> xblNode = do_QueryInterface(native);
     170         112 :   if (!xblNode) {
     171           0 :     xpc::Throw(cx, NS_ERROR_UNEXPECTED);
     172           0 :     return false;
     173             :   }
     174             : 
     175             :   // Now that |this| is okay, actually install the field.
     176             : 
     177             :   // Because of the possibility (due to XBL binding inheritance, because each
     178             :   // XBL binding lives in its own global object) that |this| might be in a
     179             :   // different compartment from the callee (not to mention that this method can
     180             :   // be called with an arbitrary |this| regardless of how insane XBL is), and
     181             :   // because in this method we've entered |this|'s compartment (see in
     182             :   // Field[GS]etter where we attempt a cross-compartment call), we must enter
     183             :   // the callee's compartment to access its reserved slots.
     184             :   nsXBLPrototypeBinding* protoBinding;
     185         224 :   nsAutoJSString fieldName;
     186             :   {
     187         224 :     JSAutoCompartment ac(cx, callee);
     188             : 
     189         224 :     JS::Rooted<JSObject*> xblProto(cx);
     190         112 :     xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();
     191             : 
     192         224 :     JS::Rooted<JS::Value> name(cx, js::GetFunctionNativeReserved(callee, FIELD_SLOT));
     193         112 :     if (!fieldName.init(cx, name.toString())) {
     194           0 :       return false;
     195             :     }
     196             : 
     197         112 :     MOZ_ALWAYS_TRUE(JS_ValueToId(cx, name, idp));
     198             : 
     199             :     // If a separate XBL scope is being used, the callee is not same-compartment
     200             :     // with the xbl prototype, and the object is a cross-compartment wrapper.
     201         112 :     xblProto = js::UncheckedUnwrap(xblProto);
     202         224 :     JSAutoCompartment ac2(cx, xblProto);
     203         112 :     JS::Value slotVal = ::JS_GetReservedSlot(xblProto, 0);
     204         112 :     protoBinding = static_cast<nsXBLPrototypeBinding*>(slotVal.toPrivate());
     205         112 :     MOZ_ASSERT(protoBinding);
     206             :   }
     207             : 
     208         112 :   nsXBLProtoImplField* field = protoBinding->FindField(fieldName);
     209         112 :   MOZ_ASSERT(field);
     210             : 
     211         112 :   nsresult rv = field->InstallField(thisObj, protoBinding->DocURI(), installed);
     212         112 :   if (NS_SUCCEEDED(rv)) {
     213         112 :     return true;
     214             :   }
     215             : 
     216           0 :   if (!::JS_IsExceptionPending(cx)) {
     217           0 :     xpc::Throw(cx, rv);
     218             :   }
     219           0 :   return false;
     220             : }
     221             : 
     222             : bool
     223          68 : FieldGetterImpl(JSContext *cx, const JS::CallArgs& args)
     224             : {
     225          68 :   JS::Handle<JS::Value> thisv = args.thisv();
     226          68 :   MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
     227             : 
     228         136 :   JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
     229             : 
     230             :   // We should be in the compartment of |this|. If we got here via nativeCall,
     231             :   // |this| is not same-compartment with |callee|, and it's possible via
     232             :   // asymmetric security semantics that |args.calleev()| is actually a security
     233             :   // wrapper. In this case, we know we want to do an unsafe unwrap, and
     234             :   // InstallXBLField knows how to handle cross-compartment pointers.
     235          68 :   bool installed = false;
     236         136 :   JS::Rooted<JSObject*> callee(cx, js::UncheckedUnwrap(&args.calleev().toObject()));
     237         136 :   JS::Rooted<jsid> id(cx);
     238          68 :   if (!InstallXBLField(cx, callee, thisObj, &id, &installed)) {
     239           0 :     return false;
     240             :   }
     241             : 
     242          68 :   if (!installed) {
     243           0 :     args.rval().setUndefined();
     244           0 :     return true;
     245             :   }
     246             : 
     247          68 :   return JS_GetPropertyById(cx, thisObj, id, args.rval());
     248             : }
     249             : 
     250             : static bool
     251          68 : FieldGetter(JSContext *cx, unsigned argc, JS::Value *vp)
     252             : {
     253          68 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     254             :   return JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldGetterImpl>
     255          68 :                                  (cx, args);
     256             : }
     257             : 
     258             : bool
     259          44 : FieldSetterImpl(JSContext *cx, const JS::CallArgs& args)
     260             : {
     261          44 :   JS::Handle<JS::Value> thisv = args.thisv();
     262          44 :   MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
     263             : 
     264          88 :   JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
     265             : 
     266             :   // We should be in the compartment of |this|. If we got here via nativeCall,
     267             :   // |this| is not same-compartment with |callee|, and it's possible via
     268             :   // asymmetric security semantics that |args.calleev()| is actually a security
     269             :   // wrapper. In this case, we know we want to do an unsafe unwrap, and
     270             :   // InstallXBLField knows how to handle cross-compartment pointers.
     271          44 :   bool installed = false;
     272          88 :   JS::Rooted<JSObject*> callee(cx, js::UncheckedUnwrap(&args.calleev().toObject()));
     273          88 :   JS::Rooted<jsid> id(cx);
     274          44 :   if (!InstallXBLField(cx, callee, thisObj, &id, &installed)) {
     275           0 :     return false;
     276             :   }
     277             : 
     278          44 :   if (installed) {
     279          44 :     if (!::JS_SetPropertyById(cx, thisObj, id, args.get(0))) {
     280           0 :       return false;
     281             :     }
     282             :   }
     283          44 :   args.rval().setUndefined();
     284          44 :   return true;
     285             : }
     286             : 
     287             : static bool
     288          44 : FieldSetter(JSContext *cx, unsigned argc, JS::Value *vp)
     289             : {
     290          44 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     291             :   return JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldSetterImpl>
     292          44 :                                  (cx, args);
     293             : }
     294             : 
     295             : nsresult
     296         282 : nsXBLProtoImplField::InstallAccessors(JSContext* aCx,
     297             :                                       JS::Handle<JSObject*> aTargetClassObject)
     298             : {
     299         282 :   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
     300         564 :   JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
     301         564 :   JS::Rooted<JSObject*> scopeObject(aCx, xpc::GetXBLScopeOrGlobal(aCx, globalObject));
     302         282 :   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
     303             : 
     304             :   // Don't install it if the field is empty; see also InstallField which also must
     305             :   // implement the not-empty requirement.
     306         282 :   if (IsEmpty()) {
     307           2 :     return NS_OK;
     308             :   }
     309             : 
     310             :   // Install a getter/setter pair which will resolve the field onto the actual
     311             :   // object, when invoked.
     312             : 
     313             :   // Get the field name as an id.
     314         560 :   JS::Rooted<jsid> id(aCx);
     315         280 :   JS::TwoByteChars chars(mName, NS_strlen(mName));
     316         280 :   if (!JS_CharsToId(aCx, chars, &id))
     317           0 :     return NS_ERROR_OUT_OF_MEMORY;
     318             : 
     319             :   // Properties/Methods have historically taken precendence over fields. We
     320             :   // install members first, so just bounce here if the property is already
     321             :   // defined.
     322         280 :   bool found = false;
     323         280 :   if (!JS_AlreadyHasOwnPropertyById(aCx, aTargetClassObject, id, &found))
     324           0 :     return NS_ERROR_FAILURE;
     325         280 :   if (found)
     326           1 :     return NS_OK;
     327             : 
     328             :   // FieldGetter and FieldSetter need to run in the XBL scope so that they can
     329             :   // see through any SOWs on their targets.
     330             : 
     331             :   // First, enter the XBL scope, and compile the functions there.
     332         558 :   JSAutoCompartment ac(aCx, scopeObject);
     333         558 :   JS::Rooted<JS::Value> wrappedClassObj(aCx, JS::ObjectValue(*aTargetClassObject));
     334         279 :   if (!JS_WrapValue(aCx, &wrappedClassObj))
     335           0 :     return NS_ERROR_OUT_OF_MEMORY;
     336             : 
     337             :   JS::Rooted<JSObject*> get(aCx,
     338         558 :     JS_GetFunctionObject(js::NewFunctionByIdWithReserved(aCx, FieldGetter,
     339         837 :                                                          0, 0, id)));
     340         279 :   if (!get) {
     341           0 :     return NS_ERROR_OUT_OF_MEMORY;
     342             :   }
     343         279 :   js::SetFunctionNativeReserved(get, XBLPROTO_SLOT, wrappedClassObj);
     344         279 :   js::SetFunctionNativeReserved(get, FIELD_SLOT,
     345         558 :                                 JS::StringValue(JSID_TO_STRING(id)));
     346             : 
     347             :   JS::Rooted<JSObject*> set(aCx,
     348         558 :     JS_GetFunctionObject(js::NewFunctionByIdWithReserved(aCx, FieldSetter,
     349         837 :                                                           1, 0, id)));
     350         279 :   if (!set) {
     351           0 :     return NS_ERROR_OUT_OF_MEMORY;
     352             :   }
     353         279 :   js::SetFunctionNativeReserved(set, XBLPROTO_SLOT, wrappedClassObj);
     354         279 :   js::SetFunctionNativeReserved(set, FIELD_SLOT,
     355         558 :                                 JS::StringValue(JSID_TO_STRING(id)));
     356             : 
     357             :   // Now, re-enter the class object's scope, wrap the getters/setters, and define
     358             :   // them there.
     359         558 :   JSAutoCompartment ac2(aCx, aTargetClassObject);
     360         279 :   if (!JS_WrapObject(aCx, &get) || !JS_WrapObject(aCx, &set)) {
     361           0 :     return NS_ERROR_OUT_OF_MEMORY;
     362             :   }
     363             : 
     364         558 :   if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, JS::UndefinedHandleValue,
     365             :                                AccessorAttributes(),
     366         279 :                                JS_DATA_TO_FUNC_PTR(JSNative, get.get()),
     367         279 :                                JS_DATA_TO_FUNC_PTR(JSNative, set.get()))) {
     368           0 :     return NS_ERROR_OUT_OF_MEMORY;
     369             :   }
     370             : 
     371         279 :   return NS_OK;
     372             : }
     373             : 
     374             : nsresult
     375         112 : nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
     376             :                                   nsIURI* aBindingDocURI,
     377             :                                   bool* aDidInstall) const
     378             : {
     379         112 :   NS_PRECONDITION(aBoundNode,
     380             :                   "uh-oh, bound node should NOT be null or bad things will "
     381             :                   "happen");
     382             : 
     383         112 :   *aDidInstall = false;
     384             : 
     385             :   // Empty fields are treated as not actually present.
     386         112 :   if (IsEmpty()) {
     387           0 :     return NS_OK;
     388             :   }
     389             : 
     390         224 :   nsAutoMicroTask mt;
     391             : 
     392         224 :   nsAutoCString uriSpec;
     393         112 :   nsresult rv = aBindingDocURI->GetSpec(uriSpec);
     394         112 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     395           0 :     return rv;
     396             :   }
     397             : 
     398         112 :   nsIGlobalObject* globalObject = xpc::WindowGlobalOrNull(aBoundNode);
     399         112 :   if (!globalObject) {
     400           0 :     return NS_OK;
     401             :   }
     402             : 
     403             :   // We are going to run script via EvaluateString, so we need a script entry
     404             :   // point, but as this is XBL related it does not appear in the HTML spec.
     405             :   // We need an actual JSContext to do GetScopeForXBLExecution, and it needs to
     406             :   // be in the compartment of globalObject.  But we want our XBL execution scope
     407             :   // to be our entry global.
     408         224 :   AutoJSAPI jsapi;
     409         112 :   if (!jsapi.Init(globalObject)) {
     410           0 :     return NS_ERROR_UNEXPECTED;
     411             :   }
     412         112 :   MOZ_ASSERT(!::JS_IsExceptionPending(jsapi.cx()),
     413             :              "Shouldn't get here when an exception is pending!");
     414             : 
     415         112 :   JSAddonId* addonId = MapURIToAddonID(aBindingDocURI);
     416             : 
     417             :   // Note: the UNWRAP_OBJECT may mutate boundNode; don't use it after that call.
     418         224 :   JS::Rooted<JSObject*> boundNode(jsapi.cx(), aBoundNode);
     419         112 :   Element* boundElement = nullptr;
     420         112 :   rv = UNWRAP_OBJECT(Element, &boundNode, boundElement);
     421         112 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     422           0 :     return rv;
     423             :   }
     424             : 
     425             :   // First, enter the xbl scope, build the element's scope chain, and use
     426             :   // that as the scope chain for the evaluation.
     427         224 :   JS::Rooted<JSObject*> scopeObject(jsapi.cx(),
     428         448 :     xpc::GetScopeForXBLExecution(jsapi.cx(), aBoundNode, addonId));
     429         112 :   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
     430             : 
     431         224 :   AutoEntryScript aes(scopeObject, "XBL <field> initialization", true);
     432         112 :   JSContext* cx = aes.cx();
     433             : 
     434         224 :   JS::Rooted<JS::Value> result(cx);
     435         224 :   JS::CompileOptions options(cx);
     436         112 :   options.setFileAndLine(uriSpec.get(), mLineNumber)
     437         112 :          .setVersion(JSVERSION_LATEST);
     438         224 :   JS::AutoObjectVector scopeChain(cx);
     439         112 :   if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, scopeChain)) {
     440           0 :     return NS_ERROR_OUT_OF_MEMORY;
     441             :   }
     442         112 :   rv = NS_OK;
     443             :   {
     444         224 :     nsJSUtils::ExecutionContext exec(cx, scopeObject);
     445         112 :     exec.SetScopeChain(scopeChain);
     446         224 :     exec.CompileAndExec(options, nsDependentString(mFieldText,
     447         224 :                                                    mFieldTextLength));
     448         112 :     rv = exec.ExtractReturnValue(&result);
     449             :   }
     450             : 
     451         112 :   if (NS_FAILED(rv)) {
     452           0 :     return rv;
     453             :   }
     454             : 
     455         112 :   if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW) {
     456             :     // Report the exception now, before we try using the JSContext for
     457             :     // the JS_DefineUCProperty call.  Note that this reports in our current
     458             :     // compartment, which is the XBL scope.
     459           0 :     aes.ReportException();
     460             :   }
     461             : 
     462             :   // Now, enter the node's compartment, wrap the eval result, and define it on
     463             :   // the bound node.
     464         224 :   JSAutoCompartment ac2(cx, aBoundNode);
     465         224 :   nsDependentString name(mName);
     466         448 :   if (!JS_WrapValue(cx, &result) ||
     467         448 :       !::JS_DefineUCProperty(cx, aBoundNode,
     468         112 :                              reinterpret_cast<const char16_t*>(mName),
     469         224 :                              name.Length(), result, mJSAttributes)) {
     470           0 :     return NS_ERROR_OUT_OF_MEMORY;
     471             :   }
     472             : 
     473         112 :   *aDidInstall = true;
     474         112 :   return NS_OK;
     475             : }
     476             : 
     477             : nsresult
     478         331 : nsXBLProtoImplField::Read(nsIObjectInputStream* aStream)
     479             : {
     480         662 :   nsAutoString name;
     481         331 :   nsresult rv = aStream->ReadString(name);
     482         331 :   NS_ENSURE_SUCCESS(rv, rv);
     483         331 :   mName = ToNewUnicode(name);
     484             : 
     485         331 :   rv = aStream->Read32(&mLineNumber);
     486         331 :   NS_ENSURE_SUCCESS(rv, rv);
     487             : 
     488         662 :   nsAutoString fieldText;
     489         331 :   rv = aStream->ReadString(fieldText);
     490         331 :   NS_ENSURE_SUCCESS(rv, rv);
     491         331 :   mFieldTextLength = fieldText.Length();
     492         331 :   if (mFieldTextLength)
     493         328 :     mFieldText = ToNewUnicode(fieldText);
     494             : 
     495         331 :   return NS_OK;
     496             : }
     497             : 
     498             : nsresult
     499           0 : nsXBLProtoImplField::Write(nsIObjectOutputStream* aStream)
     500             : {
     501           0 :   XBLBindingSerializeDetails type = XBLBinding_Serialize_Field;
     502             : 
     503           0 :   if (mJSAttributes & JSPROP_READONLY) {
     504           0 :     type |= XBLBinding_Serialize_ReadOnly;
     505             :   }
     506             : 
     507           0 :   nsresult rv = aStream->Write8(type);
     508           0 :   NS_ENSURE_SUCCESS(rv, rv);
     509           0 :   rv = aStream->WriteWStringZ(mName);
     510           0 :   NS_ENSURE_SUCCESS(rv, rv);
     511           0 :   rv = aStream->Write32(mLineNumber);
     512           0 :   NS_ENSURE_SUCCESS(rv, rv);
     513             : 
     514           0 :   return aStream->WriteWStringZ(mFieldText ? mFieldText : u"");
     515             : }

Generated by: LCOV version 1.13