dom/xbl/nsXBLProtoImpl.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial