dom/xbl/nsXBLPrototypeBinding.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/ArrayUtils.h"
michael@0 7
michael@0 8 #include "nsCOMPtr.h"
michael@0 9 #include "nsIAtom.h"
michael@0 10 #include "nsIInputStream.h"
michael@0 11 #include "nsNameSpaceManager.h"
michael@0 12 #include "nsIURI.h"
michael@0 13 #include "nsIURL.h"
michael@0 14 #include "nsIChannel.h"
michael@0 15 #include "nsXPIDLString.h"
michael@0 16 #include "nsReadableUtils.h"
michael@0 17 #include "nsNetUtil.h"
michael@0 18 #include "plstr.h"
michael@0 19 #include "nsContentCreatorFunctions.h"
michael@0 20 #include "nsIDocument.h"
michael@0 21 #include "nsIXMLContentSink.h"
michael@0 22 #include "nsContentCID.h"
michael@0 23 #include "mozilla/dom/XMLDocument.h"
michael@0 24 #include "nsXBLService.h"
michael@0 25 #include "nsXBLBinding.h"
michael@0 26 #include "nsXBLPrototypeBinding.h"
michael@0 27 #include "nsXBLContentSink.h"
michael@0 28 #include "xptinfo.h"
michael@0 29 #include "nsIInterfaceInfoManager.h"
michael@0 30 #include "nsIDocumentObserver.h"
michael@0 31 #include "nsGkAtoms.h"
michael@0 32 #include "nsXBLProtoImpl.h"
michael@0 33 #include "nsCRT.h"
michael@0 34 #include "nsContentUtils.h"
michael@0 35 #include "nsTextFragment.h"
michael@0 36 #include "nsTextNode.h"
michael@0 37 #include "nsIInterfaceInfo.h"
michael@0 38 #include "nsIScriptError.h"
michael@0 39
michael@0 40 #include "nsIStyleRuleProcessor.h"
michael@0 41 #include "nsXBLResourceLoader.h"
michael@0 42 #include "mozilla/dom/CDATASection.h"
michael@0 43 #include "mozilla/dom/Comment.h"
michael@0 44 #include "mozilla/dom/Element.h"
michael@0 45
michael@0 46 #ifdef MOZ_XUL
michael@0 47 #include "nsXULElement.h"
michael@0 48 #endif
michael@0 49
michael@0 50 using namespace mozilla;
michael@0 51 using namespace mozilla::dom;
michael@0 52
michael@0 53 // Helper Classes =====================================================================
michael@0 54
michael@0 55 // nsXBLAttributeEntry and helpers. This class is used to efficiently handle
michael@0 56 // attribute changes in anonymous content.
michael@0 57
michael@0 58 class nsXBLAttributeEntry {
michael@0 59 public:
michael@0 60 nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom,
michael@0 61 int32_t aDstNameSpace, nsIContent* aContent)
michael@0 62 : mElement(aContent),
michael@0 63 mSrcAttribute(aSrcAtom),
michael@0 64 mDstAttribute(aDstAtom),
michael@0 65 mDstNameSpace(aDstNameSpace),
michael@0 66 mNext(nullptr) { }
michael@0 67
michael@0 68 ~nsXBLAttributeEntry() {
michael@0 69 NS_CONTENT_DELETE_LIST_MEMBER(nsXBLAttributeEntry, this, mNext);
michael@0 70 }
michael@0 71
michael@0 72 nsIAtom* GetSrcAttribute() { return mSrcAttribute; }
michael@0 73 nsIAtom* GetDstAttribute() { return mDstAttribute; }
michael@0 74 int32_t GetDstNameSpace() { return mDstNameSpace; }
michael@0 75
michael@0 76 nsIContent* GetElement() { return mElement; }
michael@0 77
michael@0 78 nsXBLAttributeEntry* GetNext() { return mNext; }
michael@0 79 void SetNext(nsXBLAttributeEntry* aEntry) { mNext = aEntry; }
michael@0 80
michael@0 81 protected:
michael@0 82 nsIContent* mElement;
michael@0 83
michael@0 84 nsCOMPtr<nsIAtom> mSrcAttribute;
michael@0 85 nsCOMPtr<nsIAtom> mDstAttribute;
michael@0 86 int32_t mDstNameSpace;
michael@0 87 nsXBLAttributeEntry* mNext;
michael@0 88 };
michael@0 89
michael@0 90 // =============================================================================
michael@0 91
michael@0 92 // Implementation /////////////////////////////////////////////////////////////////
michael@0 93
michael@0 94 // Constructors/Destructors
michael@0 95 nsXBLPrototypeBinding::nsXBLPrototypeBinding()
michael@0 96 : mImplementation(nullptr),
michael@0 97 mBaseBinding(nullptr),
michael@0 98 mInheritStyle(true),
michael@0 99 mCheckedBaseProto(false),
michael@0 100 mKeyHandlersRegistered(false),
michael@0 101 mChromeOnlyContent(false),
michael@0 102 mResources(nullptr),
michael@0 103 mBaseNameSpaceID(kNameSpaceID_None)
michael@0 104 {
michael@0 105 MOZ_COUNT_CTOR(nsXBLPrototypeBinding);
michael@0 106 }
michael@0 107
michael@0 108 nsresult
michael@0 109 nsXBLPrototypeBinding::Init(const nsACString& aID,
michael@0 110 nsXBLDocumentInfo* aInfo,
michael@0 111 nsIContent* aElement,
michael@0 112 bool aFirstBinding)
michael@0 113 {
michael@0 114 nsresult rv = aInfo->DocumentURI()->Clone(getter_AddRefs(mBindingURI));
michael@0 115 NS_ENSURE_SUCCESS(rv, rv);
michael@0 116
michael@0 117 // The binding URI might be an immutable URI (e.g. for about: URIs). In that case,
michael@0 118 // we'll fail in SetRef below, but that doesn't matter much for now.
michael@0 119 if (aFirstBinding) {
michael@0 120 rv = mBindingURI->Clone(getter_AddRefs(mAlternateBindingURI));
michael@0 121 NS_ENSURE_SUCCESS(rv, rv);
michael@0 122 }
michael@0 123 mBindingURI->SetRef(aID);
michael@0 124
michael@0 125 mXBLDocInfoWeak = aInfo;
michael@0 126
michael@0 127 // aElement will be null when reading from the cache, but the element will
michael@0 128 // still be set later.
michael@0 129 if (aElement) {
michael@0 130 SetBindingElement(aElement);
michael@0 131 }
michael@0 132 return NS_OK;
michael@0 133 }
michael@0 134
michael@0 135 bool nsXBLPrototypeBinding::CompareBindingURI(nsIURI* aURI) const
michael@0 136 {
michael@0 137 bool equal = false;
michael@0 138 mBindingURI->Equals(aURI, &equal);
michael@0 139 if (!equal && mAlternateBindingURI) {
michael@0 140 mAlternateBindingURI->Equals(aURI, &equal);
michael@0 141 }
michael@0 142 return equal;
michael@0 143 }
michael@0 144
michael@0 145 void
michael@0 146 nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
michael@0 147 {
michael@0 148 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mBinding");
michael@0 149 cb.NoteXPCOMChild(mBinding);
michael@0 150 if (mResources) {
michael@0 151 mResources->Traverse(cb);
michael@0 152 }
michael@0 153 ImplCycleCollectionTraverse(cb, mInterfaceTable, "proto mInterfaceTable");
michael@0 154 }
michael@0 155
michael@0 156 void
michael@0 157 nsXBLPrototypeBinding::UnlinkJSObjects()
michael@0 158 {
michael@0 159 if (mImplementation)
michael@0 160 mImplementation->UnlinkJSObjects();
michael@0 161 }
michael@0 162
michael@0 163 void
michael@0 164 nsXBLPrototypeBinding::Trace(const TraceCallbacks& aCallbacks, void *aClosure) const
michael@0 165 {
michael@0 166 if (mImplementation)
michael@0 167 mImplementation->Trace(aCallbacks, aClosure);
michael@0 168 }
michael@0 169
michael@0 170 void
michael@0 171 nsXBLPrototypeBinding::Initialize()
michael@0 172 {
michael@0 173 nsIContent* content = GetImmediateChild(nsGkAtoms::content);
michael@0 174 if (content) {
michael@0 175 ConstructAttributeTable(content);
michael@0 176 }
michael@0 177 }
michael@0 178
michael@0 179 nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
michael@0 180 {
michael@0 181 delete mImplementation;
michael@0 182 MOZ_COUNT_DTOR(nsXBLPrototypeBinding);
michael@0 183 }
michael@0 184
michael@0 185 void
michael@0 186 nsXBLPrototypeBinding::SetBasePrototype(nsXBLPrototypeBinding* aBinding)
michael@0 187 {
michael@0 188 if (mBaseBinding == aBinding)
michael@0 189 return;
michael@0 190
michael@0 191 if (mBaseBinding) {
michael@0 192 NS_ERROR("Base XBL prototype binding is already defined!");
michael@0 193 return;
michael@0 194 }
michael@0 195
michael@0 196 mBaseBinding = aBinding;
michael@0 197 }
michael@0 198
michael@0 199 void
michael@0 200 nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
michael@0 201 {
michael@0 202 mBinding = aElement;
michael@0 203 if (mBinding->AttrValueIs(kNameSpaceID_None, nsGkAtoms::inheritstyle,
michael@0 204 nsGkAtoms::_false, eCaseMatters))
michael@0 205 mInheritStyle = false;
michael@0 206
michael@0 207 mChromeOnlyContent = mBinding->AttrValueIs(kNameSpaceID_None,
michael@0 208 nsGkAtoms::chromeOnlyContent,
michael@0 209 nsGkAtoms::_true, eCaseMatters);
michael@0 210 }
michael@0 211
michael@0 212 bool
michael@0 213 nsXBLPrototypeBinding::GetAllowScripts() const
michael@0 214 {
michael@0 215 return mXBLDocInfoWeak->GetScriptAccess();
michael@0 216 }
michael@0 217
michael@0 218 bool
michael@0 219 nsXBLPrototypeBinding::LoadResources()
michael@0 220 {
michael@0 221 if (mResources) {
michael@0 222 bool result;
michael@0 223 mResources->LoadResources(&result);
michael@0 224 return result;
michael@0 225 }
michael@0 226
michael@0 227 return true;
michael@0 228 }
michael@0 229
michael@0 230 nsresult
michael@0 231 nsXBLPrototypeBinding::AddResource(nsIAtom* aResourceType, const nsAString& aSrc)
michael@0 232 {
michael@0 233 if (!mResources) {
michael@0 234 mResources = new nsXBLPrototypeResources(this);
michael@0 235 }
michael@0 236
michael@0 237 mResources->AddResource(aResourceType, aSrc);
michael@0 238 return NS_OK;
michael@0 239 }
michael@0 240
michael@0 241 nsresult
michael@0 242 nsXBLPrototypeBinding::FlushSkinSheets()
michael@0 243 {
michael@0 244 if (mResources)
michael@0 245 return mResources->FlushSkinSheets();
michael@0 246 return NS_OK;
michael@0 247 }
michael@0 248
michael@0 249 nsresult
michael@0 250 nsXBLPrototypeBinding::BindingAttached(nsIContent* aBoundElement)
michael@0 251 {
michael@0 252 if (mImplementation && mImplementation->CompiledMembers() &&
michael@0 253 mImplementation->mConstructor)
michael@0 254 return mImplementation->mConstructor->Execute(aBoundElement);
michael@0 255 return NS_OK;
michael@0 256 }
michael@0 257
michael@0 258 nsresult
michael@0 259 nsXBLPrototypeBinding::BindingDetached(nsIContent* aBoundElement)
michael@0 260 {
michael@0 261 if (mImplementation && mImplementation->CompiledMembers() &&
michael@0 262 mImplementation->mDestructor)
michael@0 263 return mImplementation->mDestructor->Execute(aBoundElement);
michael@0 264 return NS_OK;
michael@0 265 }
michael@0 266
michael@0 267 nsXBLProtoImplAnonymousMethod*
michael@0 268 nsXBLPrototypeBinding::GetConstructor()
michael@0 269 {
michael@0 270 if (mImplementation)
michael@0 271 return mImplementation->mConstructor;
michael@0 272
michael@0 273 return nullptr;
michael@0 274 }
michael@0 275
michael@0 276 nsXBLProtoImplAnonymousMethod*
michael@0 277 nsXBLPrototypeBinding::GetDestructor()
michael@0 278 {
michael@0 279 if (mImplementation)
michael@0 280 return mImplementation->mDestructor;
michael@0 281
michael@0 282 return nullptr;
michael@0 283 }
michael@0 284
michael@0 285 nsresult
michael@0 286 nsXBLPrototypeBinding::SetConstructor(nsXBLProtoImplAnonymousMethod* aMethod)
michael@0 287 {
michael@0 288 if (!mImplementation)
michael@0 289 return NS_ERROR_FAILURE;
michael@0 290 mImplementation->mConstructor = aMethod;
michael@0 291 return NS_OK;
michael@0 292 }
michael@0 293
michael@0 294 nsresult
michael@0 295 nsXBLPrototypeBinding::SetDestructor(nsXBLProtoImplAnonymousMethod* aMethod)
michael@0 296 {
michael@0 297 if (!mImplementation)
michael@0 298 return NS_ERROR_FAILURE;
michael@0 299 mImplementation->mDestructor = aMethod;
michael@0 300 return NS_OK;
michael@0 301 }
michael@0 302
michael@0 303 nsresult
michael@0 304 nsXBLPrototypeBinding::InstallImplementation(nsXBLBinding* aBinding)
michael@0 305 {
michael@0 306 if (mImplementation)
michael@0 307 return mImplementation->InstallImplementation(this, aBinding);
michael@0 308 return NS_OK;
michael@0 309 }
michael@0 310
michael@0 311 // XXXbz this duplicates lots of SetAttrs
michael@0 312 void
michael@0 313 nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute,
michael@0 314 int32_t aNameSpaceID,
michael@0 315 bool aRemoveFlag,
michael@0 316 nsIContent* aChangedElement,
michael@0 317 nsIContent* aAnonymousContent,
michael@0 318 bool aNotify)
michael@0 319 {
michael@0 320 if (!mAttributeTable)
michael@0 321 return;
michael@0 322
michael@0 323 InnerAttributeTable *attributesNS = mAttributeTable->Get(aNameSpaceID);
michael@0 324 if (!attributesNS)
michael@0 325 return;
michael@0 326
michael@0 327 nsXBLAttributeEntry* xblAttr = attributesNS->Get(aAttribute);
michael@0 328 if (!xblAttr)
michael@0 329 return;
michael@0 330
michael@0 331 // Iterate over the elements in the array.
michael@0 332 nsCOMPtr<nsIContent> content = GetImmediateChild(nsGkAtoms::content);
michael@0 333 while (xblAttr) {
michael@0 334 nsIContent* element = xblAttr->GetElement();
michael@0 335
michael@0 336 nsCOMPtr<nsIContent> realElement = LocateInstance(aChangedElement, content,
michael@0 337 aAnonymousContent,
michael@0 338 element);
michael@0 339
michael@0 340 if (realElement) {
michael@0 341 // Hold a strong reference here so that the atom doesn't go away during
michael@0 342 // UnsetAttr.
michael@0 343 nsCOMPtr<nsIAtom> dstAttr = xblAttr->GetDstAttribute();
michael@0 344 int32_t dstNs = xblAttr->GetDstNameSpace();
michael@0 345
michael@0 346 if (aRemoveFlag)
michael@0 347 realElement->UnsetAttr(dstNs, dstAttr, aNotify);
michael@0 348 else {
michael@0 349 bool attrPresent = true;
michael@0 350 nsAutoString value;
michael@0 351 // Check to see if the src attribute is xbl:text. If so, then we need to obtain the
michael@0 352 // children of the real element and get the text nodes' values.
michael@0 353 if (aAttribute == nsGkAtoms::text && aNameSpaceID == kNameSpaceID_XBL) {
michael@0 354 if (!nsContentUtils::GetNodeTextContent(aChangedElement, false, value)) {
michael@0 355 NS_RUNTIMEABORT("OOM");
michael@0 356 }
michael@0 357 value.StripChar(char16_t('\n'));
michael@0 358 value.StripChar(char16_t('\r'));
michael@0 359 nsAutoString stripVal(value);
michael@0 360 stripVal.StripWhitespace();
michael@0 361 if (stripVal.IsEmpty())
michael@0 362 attrPresent = false;
michael@0 363 }
michael@0 364 else {
michael@0 365 attrPresent = aChangedElement->GetAttr(aNameSpaceID, aAttribute, value);
michael@0 366 }
michael@0 367
michael@0 368 if (attrPresent)
michael@0 369 realElement->SetAttr(dstNs, dstAttr, value, aNotify);
michael@0 370 }
michael@0 371
michael@0 372 // See if we're the <html> tag in XUL, and see if value is being
michael@0 373 // set or unset on us. We may also be a tag that is having
michael@0 374 // xbl:text set on us.
michael@0 375
michael@0 376 if ((dstAttr == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
michael@0 377 (realElement->NodeInfo()->Equals(nsGkAtoms::html,
michael@0 378 kNameSpaceID_XUL) &&
michael@0 379 dstAttr == nsGkAtoms::value)) {
michael@0 380 // Flush out all our kids.
michael@0 381 uint32_t childCount = realElement->GetChildCount();
michael@0 382 for (uint32_t i = 0; i < childCount; i++)
michael@0 383 realElement->RemoveChildAt(0, aNotify);
michael@0 384
michael@0 385 if (!aRemoveFlag) {
michael@0 386 // Construct a new text node and insert it.
michael@0 387 nsAutoString value;
michael@0 388 aChangedElement->GetAttr(aNameSpaceID, aAttribute, value);
michael@0 389 if (!value.IsEmpty()) {
michael@0 390 nsRefPtr<nsTextNode> textContent =
michael@0 391 new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
michael@0 392
michael@0 393 textContent->SetText(value, true);
michael@0 394 realElement->AppendChildTo(textContent, true);
michael@0 395 }
michael@0 396 }
michael@0 397 }
michael@0 398 }
michael@0 399
michael@0 400 xblAttr = xblAttr->GetNext();
michael@0 401 }
michael@0 402 }
michael@0 403
michael@0 404 void
michael@0 405 nsXBLPrototypeBinding::SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag)
michael@0 406 {
michael@0 407 mBaseNameSpaceID = aNamespaceID;
michael@0 408 mBaseTag = aTag;
michael@0 409 }
michael@0 410
michael@0 411 nsIAtom*
michael@0 412 nsXBLPrototypeBinding::GetBaseTag(int32_t* aNamespaceID)
michael@0 413 {
michael@0 414 if (mBaseTag) {
michael@0 415 *aNamespaceID = mBaseNameSpaceID;
michael@0 416 return mBaseTag;
michael@0 417 }
michael@0 418
michael@0 419 return nullptr;
michael@0 420 }
michael@0 421
michael@0 422 bool
michael@0 423 nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID) const
michael@0 424 {
michael@0 425 // Check our IID table.
michael@0 426 return !!mInterfaceTable.GetWeak(aIID);
michael@0 427 }
michael@0 428
michael@0 429 // Internal helpers ///////////////////////////////////////////////////////////////////////
michael@0 430
michael@0 431 nsIContent*
michael@0 432 nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag)
michael@0 433 {
michael@0 434 for (nsIContent* child = mBinding->GetFirstChild();
michael@0 435 child;
michael@0 436 child = child->GetNextSibling()) {
michael@0 437 if (child->NodeInfo()->Equals(aTag, kNameSpaceID_XBL)) {
michael@0 438 return child;
michael@0 439 }
michael@0 440 }
michael@0 441
michael@0 442 return nullptr;
michael@0 443 }
michael@0 444
michael@0 445 nsresult
michael@0 446 nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
michael@0 447 JSContext * aContext,
michael@0 448 JS::Handle<JSObject*> aScriptObject,
michael@0 449 JS::MutableHandle<JSObject*> aClassObject,
michael@0 450 bool* aNew)
michael@0 451 {
michael@0 452 return nsXBLBinding::DoInitJSClass(aContext, aScriptObject,
michael@0 453 aClassName, this, aClassObject, aNew);
michael@0 454 }
michael@0 455
michael@0 456 nsIContent*
michael@0 457 nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
michael@0 458 nsIContent* aTemplRoot,
michael@0 459 nsIContent* aCopyRoot,
michael@0 460 nsIContent* aTemplChild)
michael@0 461 {
michael@0 462 // XXX We will get in trouble if the binding instantiation deviates from the template
michael@0 463 // in the prototype.
michael@0 464 if (aTemplChild == aTemplRoot || !aTemplChild)
michael@0 465 return nullptr;
michael@0 466
michael@0 467 nsIContent* templParent = aTemplChild->GetParent();
michael@0 468
michael@0 469 // We may be disconnected from our parent during cycle collection.
michael@0 470 if (!templParent)
michael@0 471 return nullptr;
michael@0 472
michael@0 473 nsIContent *copyParent =
michael@0 474 templParent == aTemplRoot ? aCopyRoot :
michael@0 475 LocateInstance(aBoundElement, aTemplRoot, aCopyRoot, templParent);
michael@0 476
michael@0 477 if (!copyParent)
michael@0 478 return nullptr;
michael@0 479
michael@0 480 return copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
michael@0 481 }
michael@0 482
michael@0 483 struct nsXBLAttrChangeData
michael@0 484 {
michael@0 485 nsXBLPrototypeBinding* mProto;
michael@0 486 nsIContent* mBoundElement;
michael@0 487 nsIContent* mContent;
michael@0 488 int32_t mSrcNamespace;
michael@0 489
michael@0 490 nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
michael@0 491 nsIContent* aElt, nsIContent* aContent)
michael@0 492 :mProto(aProto), mBoundElement(aElt), mContent(aContent) {}
michael@0 493 };
michael@0 494
michael@0 495 // XXXbz this duplicates lots of AttributeChanged
michael@0 496 static PLDHashOperator
michael@0 497 SetAttrs(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
michael@0 498 {
michael@0 499 nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
michael@0 500
michael@0 501 nsIAtom* src = aEntry->GetSrcAttribute();
michael@0 502 int32_t srcNs = changeData->mSrcNamespace;
michael@0 503 nsAutoString value;
michael@0 504 bool attrPresent = true;
michael@0 505
michael@0 506 if (src == nsGkAtoms::text && srcNs == kNameSpaceID_XBL) {
michael@0 507 if (!nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false,
michael@0 508 value)) {
michael@0 509 NS_RUNTIMEABORT("OOM");
michael@0 510 }
michael@0 511 value.StripChar(char16_t('\n'));
michael@0 512 value.StripChar(char16_t('\r'));
michael@0 513 nsAutoString stripVal(value);
michael@0 514 stripVal.StripWhitespace();
michael@0 515
michael@0 516 if (stripVal.IsEmpty())
michael@0 517 attrPresent = false;
michael@0 518 }
michael@0 519 else {
michael@0 520 attrPresent = changeData->mBoundElement->GetAttr(srcNs, src, value);
michael@0 521 }
michael@0 522
michael@0 523 if (attrPresent) {
michael@0 524 nsIContent* content =
michael@0 525 changeData->mProto->GetImmediateChild(nsGkAtoms::content);
michael@0 526
michael@0 527 nsXBLAttributeEntry* curr = aEntry;
michael@0 528 while (curr) {
michael@0 529 nsIAtom* dst = curr->GetDstAttribute();
michael@0 530 int32_t dstNs = curr->GetDstNameSpace();
michael@0 531 nsIContent* element = curr->GetElement();
michael@0 532
michael@0 533 nsIContent *realElement =
michael@0 534 changeData->mProto->LocateInstance(changeData->mBoundElement, content,
michael@0 535 changeData->mContent, element);
michael@0 536
michael@0 537 if (realElement) {
michael@0 538 realElement->SetAttr(dstNs, dst, value, false);
michael@0 539
michael@0 540 // XXXndeakin shouldn't this be done in lieu of SetAttr?
michael@0 541 if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
michael@0 542 (realElement->NodeInfo()->Equals(nsGkAtoms::html,
michael@0 543 kNameSpaceID_XUL) &&
michael@0 544 dst == nsGkAtoms::value && !value.IsEmpty())) {
michael@0 545
michael@0 546 nsRefPtr<nsTextNode> textContent =
michael@0 547 new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
michael@0 548
michael@0 549 textContent->SetText(value, false);
michael@0 550 realElement->AppendChildTo(textContent, false);
michael@0 551 }
michael@0 552 }
michael@0 553
michael@0 554 curr = curr->GetNext();
michael@0 555 }
michael@0 556 }
michael@0 557
michael@0 558 return PL_DHASH_NEXT;
michael@0 559 }
michael@0 560
michael@0 561 static PLDHashOperator
michael@0 562 SetAttrsNS(const uint32_t &aNamespace,
michael@0 563 nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
michael@0 564 void* aClosure)
michael@0 565 {
michael@0 566 if (aXBLAttributes && aClosure) {
michael@0 567 nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
michael@0 568 changeData->mSrcNamespace = aNamespace;
michael@0 569 aXBLAttributes->EnumerateRead(SetAttrs, aClosure);
michael@0 570 }
michael@0 571 return PL_DHASH_NEXT;
michael@0 572 }
michael@0 573
michael@0 574 void
michael@0 575 nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
michael@0 576 {
michael@0 577 if (mAttributeTable) {
michael@0 578 nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
michael@0 579 mAttributeTable->EnumerateRead(SetAttrsNS, &data);
michael@0 580 }
michael@0 581 }
michael@0 582
michael@0 583 nsIStyleRuleProcessor*
michael@0 584 nsXBLPrototypeBinding::GetRuleProcessor()
michael@0 585 {
michael@0 586 if (mResources) {
michael@0 587 return mResources->mRuleProcessor;
michael@0 588 }
michael@0 589
michael@0 590 return nullptr;
michael@0 591 }
michael@0 592
michael@0 593 nsXBLPrototypeResources::sheet_array_type*
michael@0 594 nsXBLPrototypeBinding::GetOrCreateStyleSheets()
michael@0 595 {
michael@0 596 if (!mResources) {
michael@0 597 mResources = new nsXBLPrototypeResources(this);
michael@0 598 }
michael@0 599
michael@0 600 return &mResources->mStyleSheetList;
michael@0 601 }
michael@0 602
michael@0 603 nsXBLPrototypeResources::sheet_array_type*
michael@0 604 nsXBLPrototypeBinding::GetStyleSheets()
michael@0 605 {
michael@0 606 if (mResources) {
michael@0 607 return &mResources->mStyleSheetList;
michael@0 608 }
michael@0 609
michael@0 610 return nullptr;
michael@0 611 }
michael@0 612
michael@0 613 void
michael@0 614 nsXBLPrototypeBinding::EnsureAttributeTable()
michael@0 615 {
michael@0 616 if (!mAttributeTable) {
michael@0 617 mAttributeTable = new nsClassHashtable<nsUint32HashKey, InnerAttributeTable>(4);
michael@0 618 }
michael@0 619 }
michael@0 620
michael@0 621 void
michael@0 622 nsXBLPrototypeBinding::AddToAttributeTable(int32_t aSourceNamespaceID, nsIAtom* aSourceTag,
michael@0 623 int32_t aDestNamespaceID, nsIAtom* aDestTag,
michael@0 624 nsIContent* aContent)
michael@0 625 {
michael@0 626 InnerAttributeTable* attributesNS = mAttributeTable->Get(aSourceNamespaceID);
michael@0 627 if (!attributesNS) {
michael@0 628 attributesNS = new InnerAttributeTable(4);
michael@0 629 mAttributeTable->Put(aSourceNamespaceID, attributesNS);
michael@0 630 }
michael@0 631
michael@0 632 nsXBLAttributeEntry* xblAttr =
michael@0 633 new nsXBLAttributeEntry(aSourceTag, aDestTag, aDestNamespaceID, aContent);
michael@0 634
michael@0 635 nsXBLAttributeEntry* entry = attributesNS->Get(aSourceTag);
michael@0 636 if (!entry) {
michael@0 637 attributesNS->Put(aSourceTag, xblAttr);
michael@0 638 } else {
michael@0 639 while (entry->GetNext())
michael@0 640 entry = entry->GetNext();
michael@0 641 entry->SetNext(xblAttr);
michael@0 642 }
michael@0 643 }
michael@0 644
michael@0 645 void
michael@0 646 nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
michael@0 647 {
michael@0 648 // Don't add entries for <children> elements, since those will get
michael@0 649 // removed from the DOM when we construct the insertion point table.
michael@0 650 if (!aElement->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
michael@0 651 nsAutoString inherits;
michael@0 652 aElement->GetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, inherits);
michael@0 653
michael@0 654 if (!inherits.IsEmpty()) {
michael@0 655 EnsureAttributeTable();
michael@0 656
michael@0 657 // The user specified at least one attribute.
michael@0 658 char* str = ToNewCString(inherits);
michael@0 659 char* newStr;
michael@0 660 // XXX We should use a strtok function that tokenizes PRUnichars
michael@0 661 // so that we don't have to convert from Unicode to ASCII and then back
michael@0 662
michael@0 663 char* token = nsCRT::strtok( str, ", ", &newStr );
michael@0 664 while( token != nullptr ) {
michael@0 665 // Build an atom out of this attribute.
michael@0 666 nsCOMPtr<nsIAtom> atom;
michael@0 667 int32_t atomNsID = kNameSpaceID_None;
michael@0 668 nsCOMPtr<nsIAtom> attribute;
michael@0 669 int32_t attributeNsID = kNameSpaceID_None;
michael@0 670
michael@0 671 // Figure out if this token contains a :.
michael@0 672 nsAutoString attrTok; attrTok.AssignWithConversion(token);
michael@0 673 int32_t index = attrTok.Find("=", true);
michael@0 674 nsresult rv;
michael@0 675 if (index != -1) {
michael@0 676 // This attribute maps to something different.
michael@0 677 nsAutoString left, right;
michael@0 678 attrTok.Left(left, index);
michael@0 679 attrTok.Right(right, attrTok.Length()-index-1);
michael@0 680
michael@0 681 rv = nsContentUtils::SplitQName(aElement, left, &attributeNsID,
michael@0 682 getter_AddRefs(attribute));
michael@0 683 if (NS_FAILED(rv))
michael@0 684 return;
michael@0 685
michael@0 686 rv = nsContentUtils::SplitQName(aElement, right, &atomNsID,
michael@0 687 getter_AddRefs(atom));
michael@0 688 if (NS_FAILED(rv))
michael@0 689 return;
michael@0 690 }
michael@0 691 else {
michael@0 692 nsAutoString tok;
michael@0 693 tok.AssignWithConversion(token);
michael@0 694 rv = nsContentUtils::SplitQName(aElement, tok, &atomNsID,
michael@0 695 getter_AddRefs(atom));
michael@0 696 if (NS_FAILED(rv))
michael@0 697 return;
michael@0 698 attribute = atom;
michael@0 699 attributeNsID = atomNsID;
michael@0 700 }
michael@0 701
michael@0 702 AddToAttributeTable(atomNsID, atom, attributeNsID, attribute, aElement);
michael@0 703
michael@0 704 // Now remove the inherits attribute from the element so that it doesn't
michael@0 705 // show up on clones of the element. It is used
michael@0 706 // by the template only, and we don't need it anymore.
michael@0 707 // XXXdwh Don't do this for XUL elements, since it faults them into heavyweight
michael@0 708 // elements. Should nuke from the prototype instead.
michael@0 709 // aElement->UnsetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, false);
michael@0 710
michael@0 711 token = nsCRT::strtok( newStr, ", ", &newStr );
michael@0 712 }
michael@0 713
michael@0 714 nsMemory::Free(str);
michael@0 715 }
michael@0 716 }
michael@0 717
michael@0 718 // Recur into our children.
michael@0 719 for (nsIContent* child = aElement->GetFirstChild();
michael@0 720 child;
michael@0 721 child = child->GetNextSibling()) {
michael@0 722 ConstructAttributeTable(child);
michael@0 723 }
michael@0 724 }
michael@0 725
michael@0 726 nsresult
michael@0 727 nsXBLPrototypeBinding::ConstructInterfaceTable(const nsAString& aImpls)
michael@0 728 {
michael@0 729 if (!aImpls.IsEmpty()) {
michael@0 730 // Obtain the interface info manager that can tell us the IID
michael@0 731 // for a given interface name.
michael@0 732 nsCOMPtr<nsIInterfaceInfoManager>
michael@0 733 infoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
michael@0 734 if (!infoManager)
michael@0 735 return NS_ERROR_FAILURE;
michael@0 736
michael@0 737 // The user specified at least one attribute.
michael@0 738 NS_ConvertUTF16toUTF8 utf8impl(aImpls);
michael@0 739 char* str = utf8impl.BeginWriting();
michael@0 740 char* newStr;
michael@0 741 // XXX We should use a strtok function that tokenizes PRUnichars
michael@0 742 // so that we don't have to convert from Unicode to ASCII and then back
michael@0 743
michael@0 744 char* token = nsCRT::strtok( str, ", ", &newStr );
michael@0 745 while( token != nullptr ) {
michael@0 746 // get the InterfaceInfo for the name
michael@0 747 nsCOMPtr<nsIInterfaceInfo> iinfo;
michael@0 748 infoManager->GetInfoForName(token, getter_AddRefs(iinfo));
michael@0 749
michael@0 750 if (iinfo) {
michael@0 751 // obtain an IID.
michael@0 752 const nsIID* iid = nullptr;
michael@0 753 iinfo->GetIIDShared(&iid);
michael@0 754
michael@0 755 if (iid) {
michael@0 756 // We found a valid iid. Add it to our table.
michael@0 757 mInterfaceTable.Put(*iid, mBinding);
michael@0 758
michael@0 759 // this block adds the parent interfaces of each interface
michael@0 760 // defined in the xbl definition (implements="nsI...")
michael@0 761 nsCOMPtr<nsIInterfaceInfo> parentInfo;
michael@0 762 // if it has a parent, add it to the table
michael@0 763 while (NS_SUCCEEDED(iinfo->GetParent(getter_AddRefs(parentInfo))) && parentInfo) {
michael@0 764 // get the iid
michael@0 765 parentInfo->GetIIDShared(&iid);
michael@0 766
michael@0 767 // don't add nsISupports to the table
michael@0 768 if (!iid || iid->Equals(NS_GET_IID(nsISupports)))
michael@0 769 break;
michael@0 770
michael@0 771 // add the iid to the table
michael@0 772 mInterfaceTable.Put(*iid, mBinding);
michael@0 773
michael@0 774 // look for the next parent
michael@0 775 iinfo = parentInfo;
michael@0 776 }
michael@0 777 }
michael@0 778 }
michael@0 779
michael@0 780 token = nsCRT::strtok( newStr, ", ", &newStr );
michael@0 781 }
michael@0 782 }
michael@0 783
michael@0 784 return NS_OK;
michael@0 785 }
michael@0 786
michael@0 787 nsresult
michael@0 788 nsXBLPrototypeBinding::AddResourceListener(nsIContent* aBoundElement)
michael@0 789 {
michael@0 790 if (!mResources)
michael@0 791 return NS_ERROR_FAILURE; // Makes no sense to add a listener when the binding
michael@0 792 // has no resources.
michael@0 793
michael@0 794 mResources->AddResourceListener(aBoundElement);
michael@0 795 return NS_OK;
michael@0 796 }
michael@0 797
michael@0 798 void
michael@0 799 nsXBLPrototypeBinding::CreateKeyHandlers()
michael@0 800 {
michael@0 801 nsXBLPrototypeHandler* curr = mPrototypeHandler;
michael@0 802 while (curr) {
michael@0 803 nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
michael@0 804 if (eventAtom == nsGkAtoms::keyup ||
michael@0 805 eventAtom == nsGkAtoms::keydown ||
michael@0 806 eventAtom == nsGkAtoms::keypress) {
michael@0 807 uint8_t phase = curr->GetPhase();
michael@0 808 uint8_t type = curr->GetType();
michael@0 809
michael@0 810 int32_t count = mKeyHandlers.Count();
michael@0 811 int32_t i;
michael@0 812 nsXBLKeyEventHandler* handler = nullptr;
michael@0 813 for (i = 0; i < count; ++i) {
michael@0 814 handler = mKeyHandlers[i];
michael@0 815 if (handler->Matches(eventAtom, phase, type))
michael@0 816 break;
michael@0 817 }
michael@0 818
michael@0 819 if (i == count) {
michael@0 820 nsRefPtr<nsXBLKeyEventHandler> newHandler;
michael@0 821 NS_NewXBLKeyEventHandler(eventAtom, phase, type,
michael@0 822 getter_AddRefs(newHandler));
michael@0 823 if (newHandler)
michael@0 824 mKeyHandlers.AppendObject(newHandler);
michael@0 825 handler = newHandler;
michael@0 826 }
michael@0 827
michael@0 828 if (handler)
michael@0 829 handler->AddProtoHandler(curr);
michael@0 830 }
michael@0 831
michael@0 832 curr = curr->GetNextHandler();
michael@0 833 }
michael@0 834 }
michael@0 835
michael@0 836 class XBLPrototypeSetupCleanup
michael@0 837 {
michael@0 838 public:
michael@0 839 XBLPrototypeSetupCleanup(nsXBLDocumentInfo* aDocInfo, const nsACString& aID)
michael@0 840 : mDocInfo(aDocInfo), mID(aID) {}
michael@0 841
michael@0 842 ~XBLPrototypeSetupCleanup()
michael@0 843 {
michael@0 844 if (mDocInfo) {
michael@0 845 mDocInfo->RemovePrototypeBinding(mID);
michael@0 846 }
michael@0 847 }
michael@0 848
michael@0 849 void Disconnect()
michael@0 850 {
michael@0 851 mDocInfo = nullptr;
michael@0 852 }
michael@0 853
michael@0 854 nsXBLDocumentInfo* mDocInfo;
michael@0 855 nsAutoCString mID;
michael@0 856 };
michael@0 857
michael@0 858 nsresult
michael@0 859 nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
michael@0 860 nsXBLDocumentInfo* aDocInfo,
michael@0 861 nsIDocument* aDocument,
michael@0 862 uint8_t aFlags)
michael@0 863 {
michael@0 864 mInheritStyle = (aFlags & XBLBinding_Serialize_InheritStyle) ? true : false;
michael@0 865 mChromeOnlyContent =
michael@0 866 (aFlags & XBLBinding_Serialize_ChromeOnlyContent) ? true : false;
michael@0 867
michael@0 868 // nsXBLContentSink::ConstructBinding doesn't create a binding with an empty
michael@0 869 // id, so we don't here either.
michael@0 870 nsAutoCString id;
michael@0 871 nsresult rv = aStream->ReadCString(id);
michael@0 872
michael@0 873 NS_ENSURE_SUCCESS(rv, rv);
michael@0 874 NS_ENSURE_TRUE(!id.IsEmpty(), NS_ERROR_FAILURE);
michael@0 875
michael@0 876 nsAutoCString baseBindingURI;
michael@0 877 rv = aStream->ReadCString(baseBindingURI);
michael@0 878 NS_ENSURE_SUCCESS(rv, rv);
michael@0 879 mCheckedBaseProto = true;
michael@0 880
michael@0 881 if (!baseBindingURI.IsEmpty()) {
michael@0 882 rv = NS_NewURI(getter_AddRefs(mBaseBindingURI), baseBindingURI);
michael@0 883 NS_ENSURE_SUCCESS(rv, rv);
michael@0 884 }
michael@0 885
michael@0 886 rv = ReadNamespace(aStream, mBaseNameSpaceID);
michael@0 887 NS_ENSURE_SUCCESS(rv, rv);
michael@0 888
michael@0 889 nsAutoString baseTag;
michael@0 890 rv = aStream->ReadString(baseTag);
michael@0 891 NS_ENSURE_SUCCESS(rv, rv);
michael@0 892 if (!baseTag.IsEmpty()) {
michael@0 893 mBaseTag = do_GetAtom(baseTag);
michael@0 894 }
michael@0 895
michael@0 896 aDocument->CreateElem(NS_LITERAL_STRING("binding"), nullptr, kNameSpaceID_XBL,
michael@0 897 getter_AddRefs(mBinding));
michael@0 898
michael@0 899 nsCOMPtr<nsIContent> child;
michael@0 900 rv = ReadContentNode(aStream, aDocument, aDocument->NodeInfoManager(), getter_AddRefs(child));
michael@0 901 NS_ENSURE_SUCCESS(rv, rv);
michael@0 902
michael@0 903 Element* rootElement = aDocument->GetRootElement();
michael@0 904 if (rootElement)
michael@0 905 rootElement->AppendChildTo(mBinding, false);
michael@0 906
michael@0 907 if (child) {
michael@0 908 mBinding->AppendChildTo(child, false);
michael@0 909 }
michael@0 910
michael@0 911 uint32_t interfaceCount;
michael@0 912 rv = aStream->Read32(&interfaceCount);
michael@0 913 NS_ENSURE_SUCCESS(rv, rv);
michael@0 914
michael@0 915 for (; interfaceCount > 0; interfaceCount--) {
michael@0 916 nsIID iid;
michael@0 917 aStream->ReadID(&iid);
michael@0 918 mInterfaceTable.Put(iid, mBinding);
michael@0 919 }
michael@0 920
michael@0 921 AutoSafeJSContext cx;
michael@0 922 JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope());
michael@0 923 NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
michael@0 924 JSAutoCompartment ac(cx, compilationGlobal);
michael@0 925
michael@0 926 bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding;
michael@0 927 rv = Init(id, aDocInfo, nullptr, isFirstBinding);
michael@0 928 NS_ENSURE_SUCCESS(rv, rv);
michael@0 929
michael@0 930 // We need to set the prototype binding before reading the nsXBLProtoImpl,
michael@0 931 // as it may be retrieved within.
michael@0 932 rv = aDocInfo->SetPrototypeBinding(id, this);
michael@0 933 NS_ENSURE_SUCCESS(rv, rv);
michael@0 934
michael@0 935 XBLPrototypeSetupCleanup cleanup(aDocInfo, id);
michael@0 936
michael@0 937 nsAutoCString className;
michael@0 938 rv = aStream->ReadCString(className);
michael@0 939 NS_ENSURE_SUCCESS(rv, rv);
michael@0 940
michael@0 941 if (!className.IsEmpty()) {
michael@0 942 nsXBLProtoImpl* impl; // NS_NewXBLProtoImpl will set mImplementation for us
michael@0 943 NS_NewXBLProtoImpl(this, NS_ConvertUTF8toUTF16(className).get(), &impl);
michael@0 944
michael@0 945 // This needs to happen after SetPrototypeBinding as calls are made to
michael@0 946 // retrieve the mapped bindings from within here. However, if an error
michael@0 947 // occurs, the mapping should be removed again so that we don't keep an
michael@0 948 // invalid binding around.
michael@0 949 rv = mImplementation->Read(aStream, this);
michael@0 950 NS_ENSURE_SUCCESS(rv, rv);
michael@0 951 }
michael@0 952
michael@0 953 // Next read in the handlers.
michael@0 954 nsXBLPrototypeHandler* previousHandler = nullptr;
michael@0 955
michael@0 956 do {
michael@0 957 XBLBindingSerializeDetails type;
michael@0 958 rv = aStream->Read8(&type);
michael@0 959 NS_ENSURE_SUCCESS(rv, rv);
michael@0 960
michael@0 961 if (type == XBLBinding_Serialize_NoMoreItems)
michael@0 962 break;
michael@0 963
michael@0 964 NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Handler,
michael@0 965 "invalid handler type");
michael@0 966
michael@0 967 nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(this);
michael@0 968 rv = handler->Read(aStream);
michael@0 969 if (NS_FAILED(rv)) {
michael@0 970 delete handler;
michael@0 971 return rv;
michael@0 972 }
michael@0 973
michael@0 974 if (previousHandler) {
michael@0 975 previousHandler->SetNextHandler(handler);
michael@0 976 }
michael@0 977 else {
michael@0 978 SetPrototypeHandlers(handler);
michael@0 979 }
michael@0 980 previousHandler = handler;
michael@0 981 } while (1);
michael@0 982
michael@0 983 if (mBinding) {
michael@0 984 while (true) {
michael@0 985 XBLBindingSerializeDetails type;
michael@0 986 rv = aStream->Read8(&type);
michael@0 987 NS_ENSURE_SUCCESS(rv, rv);
michael@0 988
michael@0 989 if (type != XBLBinding_Serialize_Attribute) {
michael@0 990 break;
michael@0 991 }
michael@0 992
michael@0 993 int32_t attrNamespace;
michael@0 994 rv = ReadNamespace(aStream, attrNamespace);
michael@0 995 NS_ENSURE_SUCCESS(rv, rv);
michael@0 996
michael@0 997 nsAutoString attrPrefix, attrName, attrValue;
michael@0 998 rv = aStream->ReadString(attrPrefix);
michael@0 999 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1000
michael@0 1001 rv = aStream->ReadString(attrName);
michael@0 1002 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1003
michael@0 1004 rv = aStream->ReadString(attrValue);
michael@0 1005 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1006
michael@0 1007 nsCOMPtr<nsIAtom> atomPrefix = do_GetAtom(attrPrefix);
michael@0 1008 nsCOMPtr<nsIAtom> atomName = do_GetAtom(attrName);
michael@0 1009 mBinding->SetAttr(attrNamespace, atomName, atomPrefix, attrValue, false);
michael@0 1010 }
michael@0 1011 }
michael@0 1012
michael@0 1013 // Finally, read in the resources.
michael@0 1014 while (true) {
michael@0 1015 XBLBindingSerializeDetails type;
michael@0 1016 rv = aStream->Read8(&type);
michael@0 1017 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1018
michael@0 1019 if (type == XBLBinding_Serialize_NoMoreItems)
michael@0 1020 break;
michael@0 1021
michael@0 1022 NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Stylesheet ||
michael@0 1023 (type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Image, "invalid resource type");
michael@0 1024
michael@0 1025 nsAutoString src;
michael@0 1026 rv = aStream->ReadString(src);
michael@0 1027 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1028
michael@0 1029 AddResource(type == XBLBinding_Serialize_Stylesheet ? nsGkAtoms::stylesheet :
michael@0 1030 nsGkAtoms::image, src);
michael@0 1031 }
michael@0 1032
michael@0 1033 if (isFirstBinding) {
michael@0 1034 aDocInfo->SetFirstPrototypeBinding(this);
michael@0 1035 }
michael@0 1036
michael@0 1037 cleanup.Disconnect();
michael@0 1038 return NS_OK;
michael@0 1039 }
michael@0 1040
michael@0 1041 // static
michael@0 1042 nsresult
michael@0 1043 nsXBLPrototypeBinding::ReadNewBinding(nsIObjectInputStream* aStream,
michael@0 1044 nsXBLDocumentInfo* aDocInfo,
michael@0 1045 nsIDocument* aDocument,
michael@0 1046 uint8_t aFlags)
michael@0 1047 {
michael@0 1048 // If the Read() succeeds, |binding| will end up being owned by aDocInfo's
michael@0 1049 // binding table. Otherwise, we must manually delete it.
michael@0 1050 nsXBLPrototypeBinding* binding = new nsXBLPrototypeBinding();
michael@0 1051 nsresult rv = binding->Read(aStream, aDocInfo, aDocument, aFlags);
michael@0 1052 if (NS_FAILED(rv)) {
michael@0 1053 delete binding;
michael@0 1054 }
michael@0 1055 return rv;
michael@0 1056 }
michael@0 1057
michael@0 1058 static PLDHashOperator
michael@0 1059 WriteInterfaceID(const nsIID& aKey, nsIContent* aData, void* aClosure)
michael@0 1060 {
michael@0 1061 // We can just write out the ids. The cache will be invalidated when a
michael@0 1062 // different build is used, so we don't need to worry about ids changing.
michael@0 1063 static_cast<nsIObjectOutputStream *>(aClosure)->WriteID(aKey);
michael@0 1064 return PL_DHASH_NEXT;
michael@0 1065 }
michael@0 1066
michael@0 1067 nsresult
michael@0 1068 nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
michael@0 1069 {
michael@0 1070 // This writes out the binding. Note that mCheckedBaseProto,
michael@0 1071 // mKeyHandlersRegistered and mKeyHandlers are not serialized as they are
michael@0 1072 // computed on demand.
michael@0 1073
michael@0 1074 AutoSafeJSContext cx;
michael@0 1075 JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope());
michael@0 1076 NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
michael@0 1077 JSAutoCompartment ac(cx, compilationGlobal);
michael@0 1078
michael@0 1079 uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0;
michael@0 1080
michael@0 1081 // mAlternateBindingURI is only set on the first binding.
michael@0 1082 if (mAlternateBindingURI) {
michael@0 1083 flags |= XBLBinding_Serialize_IsFirstBinding;
michael@0 1084 }
michael@0 1085
michael@0 1086 if (mChromeOnlyContent) {
michael@0 1087 flags |= XBLBinding_Serialize_ChromeOnlyContent;
michael@0 1088 }
michael@0 1089
michael@0 1090 nsresult rv = aStream->Write8(flags);
michael@0 1091 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1092
michael@0 1093 nsAutoCString id;
michael@0 1094 mBindingURI->GetRef(id);
michael@0 1095 rv = aStream->WriteStringZ(id.get());
michael@0 1096 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1097
michael@0 1098 // write out the extends and display attribute values
michael@0 1099 nsAutoCString extends;
michael@0 1100 ResolveBaseBinding();
michael@0 1101 if (mBaseBindingURI)
michael@0 1102 mBaseBindingURI->GetSpec(extends);
michael@0 1103
michael@0 1104 rv = aStream->WriteStringZ(extends.get());
michael@0 1105 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1106
michael@0 1107 rv = WriteNamespace(aStream, mBaseNameSpaceID);
michael@0 1108 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1109
michael@0 1110 nsAutoString baseTag;
michael@0 1111 if (mBaseTag) {
michael@0 1112 mBaseTag->ToString(baseTag);
michael@0 1113 }
michael@0 1114 rv = aStream->WriteWStringZ(baseTag.get());
michael@0 1115 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1116
michael@0 1117 nsIContent* content = GetImmediateChild(nsGkAtoms::content);
michael@0 1118 if (content) {
michael@0 1119 rv = WriteContentNode(aStream, content);
michael@0 1120 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1121 }
michael@0 1122 else {
michael@0 1123 // Write a marker to indicate that there is no content.
michael@0 1124 rv = aStream->Write8(XBLBinding_Serialize_NoContent);
michael@0 1125 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1126 }
michael@0 1127
michael@0 1128 // Enumerate and write out the implemented interfaces.
michael@0 1129 rv = aStream->Write32(mInterfaceTable.Count());
michael@0 1130 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1131
michael@0 1132 mInterfaceTable.EnumerateRead(WriteInterfaceID, aStream);
michael@0 1133
michael@0 1134 // Write out the implementation details.
michael@0 1135 if (mImplementation) {
michael@0 1136 rv = mImplementation->Write(aStream, this);
michael@0 1137 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1138 }
michael@0 1139 else {
michael@0 1140 // Write out an empty classname. This indicates that the binding does not
michael@0 1141 // define an implementation.
michael@0 1142 rv = aStream->WriteWStringZ(EmptyString().get());
michael@0 1143 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1144 }
michael@0 1145
michael@0 1146 // Write out the handlers.
michael@0 1147 nsXBLPrototypeHandler* handler = mPrototypeHandler;
michael@0 1148 while (handler) {
michael@0 1149 rv = handler->Write(aStream);
michael@0 1150 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1151
michael@0 1152 handler = handler->GetNextHandler();
michael@0 1153 }
michael@0 1154
michael@0 1155 aStream->Write8(XBLBinding_Serialize_NoMoreItems);
michael@0 1156 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1157
michael@0 1158 if (mBinding) {
michael@0 1159 uint32_t attributes = mBinding->GetAttrCount();
michael@0 1160 nsAutoString attrValue;
michael@0 1161 for (uint32_t i = 0; i < attributes; ++i) {
michael@0 1162 const nsAttrName* attr = mBinding->GetAttrNameAt(i);
michael@0 1163 nsDependentAtomString attrName = attr->LocalName();
michael@0 1164 mBinding->GetAttr(attr->NamespaceID(), attr->LocalName(), attrValue);
michael@0 1165 rv = aStream->Write8(XBLBinding_Serialize_Attribute);
michael@0 1166 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1167
michael@0 1168 rv = WriteNamespace(aStream, attr->NamespaceID());
michael@0 1169 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1170
michael@0 1171 nsIAtom* prefix = attr->GetPrefix();
michael@0 1172 nsAutoString prefixString;
michael@0 1173 if (prefix) {
michael@0 1174 prefix->ToString(prefixString);
michael@0 1175 }
michael@0 1176
michael@0 1177 rv = aStream->WriteWStringZ(prefixString.get());
michael@0 1178 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1179
michael@0 1180 rv = aStream->WriteWStringZ(attrName.get());
michael@0 1181 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1182
michael@0 1183 rv = aStream->WriteWStringZ(attrValue.get());
michael@0 1184 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1185 }
michael@0 1186 }
michael@0 1187
michael@0 1188 aStream->Write8(XBLBinding_Serialize_NoMoreItems);
michael@0 1189 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1190
michael@0 1191 // Write out the resources
michael@0 1192 if (mResources) {
michael@0 1193 rv = mResources->Write(aStream);
michael@0 1194 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1195 }
michael@0 1196
michael@0 1197 // Write out an end mark at the end.
michael@0 1198 return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
michael@0 1199 }
michael@0 1200
michael@0 1201 nsresult
michael@0 1202 nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
michael@0 1203 nsIDocument* aDocument,
michael@0 1204 nsNodeInfoManager* aNim,
michael@0 1205 nsIContent** aContent)
michael@0 1206 {
michael@0 1207 *aContent = nullptr;
michael@0 1208
michael@0 1209 int32_t namespaceID;
michael@0 1210 nsresult rv = ReadNamespace(aStream, namespaceID);
michael@0 1211 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1212
michael@0 1213 // There is no content to read so just return.
michael@0 1214 if (namespaceID == XBLBinding_Serialize_NoContent)
michael@0 1215 return NS_OK;
michael@0 1216
michael@0 1217 nsCOMPtr<nsIContent> content;
michael@0 1218
michael@0 1219 // If this is a text type, just read the string and return.
michael@0 1220 if (namespaceID == XBLBinding_Serialize_TextNode ||
michael@0 1221 namespaceID == XBLBinding_Serialize_CDATANode ||
michael@0 1222 namespaceID == XBLBinding_Serialize_CommentNode) {
michael@0 1223 switch (namespaceID) {
michael@0 1224 case XBLBinding_Serialize_TextNode:
michael@0 1225 content = new nsTextNode(aNim);
michael@0 1226 break;
michael@0 1227 case XBLBinding_Serialize_CDATANode:
michael@0 1228 content = new CDATASection(aNim);
michael@0 1229 break;
michael@0 1230 case XBLBinding_Serialize_CommentNode:
michael@0 1231 content = new Comment(aNim);
michael@0 1232 break;
michael@0 1233 default:
michael@0 1234 break;
michael@0 1235 }
michael@0 1236
michael@0 1237 nsAutoString text;
michael@0 1238 rv = aStream->ReadString(text);
michael@0 1239 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1240
michael@0 1241 content->SetText(text, false);
michael@0 1242 content.swap(*aContent);
michael@0 1243 return NS_OK;
michael@0 1244 }
michael@0 1245
michael@0 1246 // Otherwise, it's an element, so read its tag, attributes and children.
michael@0 1247 nsAutoString prefix, tag;
michael@0 1248 rv = aStream->ReadString(prefix);
michael@0 1249 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1250
michael@0 1251 nsCOMPtr<nsIAtom> prefixAtom;
michael@0 1252 if (!prefix.IsEmpty())
michael@0 1253 prefixAtom = do_GetAtom(prefix);
michael@0 1254
michael@0 1255 rv = aStream->ReadString(tag);
michael@0 1256 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1257
michael@0 1258 nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(tag);
michael@0 1259 nsCOMPtr<nsINodeInfo> nodeInfo =
michael@0 1260 aNim->GetNodeInfo(tagAtom, prefixAtom, namespaceID, nsIDOMNode::ELEMENT_NODE);
michael@0 1261
michael@0 1262 uint32_t attrCount;
michael@0 1263 rv = aStream->Read32(&attrCount);
michael@0 1264 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1265
michael@0 1266 // Create XUL prototype elements, or regular elements for other namespaces.
michael@0 1267 // This needs to match the code in nsXBLContentSink::CreateElement.
michael@0 1268 #ifdef MOZ_XUL
michael@0 1269 if (namespaceID == kNameSpaceID_XUL) {
michael@0 1270 nsIURI* documentURI = aDocument->GetDocumentURI();
michael@0 1271
michael@0 1272 nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
michael@0 1273 NS_ENSURE_TRUE(prototype, NS_ERROR_OUT_OF_MEMORY);
michael@0 1274
michael@0 1275 prototype->mNodeInfo = nodeInfo;
michael@0 1276
michael@0 1277 nsXULPrototypeAttribute* attrs = nullptr;
michael@0 1278 if (attrCount > 0) {
michael@0 1279 attrs = new nsXULPrototypeAttribute[attrCount];
michael@0 1280 }
michael@0 1281
michael@0 1282 prototype->mAttributes = attrs;
michael@0 1283 prototype->mNumAttributes = attrCount;
michael@0 1284
michael@0 1285 for (uint32_t i = 0; i < attrCount; i++) {
michael@0 1286 rv = ReadNamespace(aStream, namespaceID);
michael@0 1287 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1288
michael@0 1289 nsAutoString prefix, name, val;
michael@0 1290 rv = aStream->ReadString(prefix);
michael@0 1291 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1292 rv = aStream->ReadString(name);
michael@0 1293 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1294 rv = aStream->ReadString(val);
michael@0 1295 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1296
michael@0 1297 nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name);
michael@0 1298 if (namespaceID == kNameSpaceID_None) {
michael@0 1299 attrs[i].mName.SetTo(nameAtom);
michael@0 1300 }
michael@0 1301 else {
michael@0 1302 nsCOMPtr<nsIAtom> prefixAtom;
michael@0 1303 if (!prefix.IsEmpty())
michael@0 1304 prefixAtom = do_GetAtom(prefix);
michael@0 1305
michael@0 1306 nsCOMPtr<nsINodeInfo> ni =
michael@0 1307 aNim->GetNodeInfo(nameAtom, prefixAtom,
michael@0 1308 namespaceID, nsIDOMNode::ATTRIBUTE_NODE);
michael@0 1309 attrs[i].mName.SetTo(ni);
michael@0 1310 }
michael@0 1311
michael@0 1312 rv = prototype->SetAttrAt(i, val, documentURI);
michael@0 1313 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1314 }
michael@0 1315
michael@0 1316 nsCOMPtr<Element> result;
michael@0 1317 nsresult rv =
michael@0 1318 nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(result));
michael@0 1319 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1320 content = result;
michael@0 1321 }
michael@0 1322 else {
michael@0 1323 #endif
michael@0 1324 nsCOMPtr<Element> element;
michael@0 1325 NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), NOT_FROM_PARSER);
michael@0 1326 content = element;
michael@0 1327
michael@0 1328 for (uint32_t i = 0; i < attrCount; i++) {
michael@0 1329 rv = ReadNamespace(aStream, namespaceID);
michael@0 1330 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1331
michael@0 1332 nsAutoString prefix, name, val;
michael@0 1333 rv = aStream->ReadString(prefix);
michael@0 1334 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1335 rv = aStream->ReadString(name);
michael@0 1336 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1337 rv = aStream->ReadString(val);
michael@0 1338 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1339
michael@0 1340 nsCOMPtr<nsIAtom> prefixAtom;
michael@0 1341 if (!prefix.IsEmpty())
michael@0 1342 prefixAtom = do_GetAtom(prefix);
michael@0 1343
michael@0 1344 nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name);
michael@0 1345 content->SetAttr(namespaceID, nameAtom, prefixAtom, val, false);
michael@0 1346 }
michael@0 1347
michael@0 1348 #ifdef MOZ_XUL
michael@0 1349 }
michael@0 1350 #endif
michael@0 1351
michael@0 1352 // Now read the attribute forwarding entries (xbl:inherits)
michael@0 1353
michael@0 1354 int32_t srcNamespaceID, destNamespaceID;
michael@0 1355 rv = ReadNamespace(aStream, srcNamespaceID);
michael@0 1356 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1357
michael@0 1358 while (srcNamespaceID != XBLBinding_Serialize_NoMoreAttributes) {
michael@0 1359 nsAutoString srcAttribute, destAttribute;
michael@0 1360 rv = aStream->ReadString(srcAttribute);
michael@0 1361 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1362 rv = ReadNamespace(aStream, destNamespaceID);
michael@0 1363 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1364 rv = aStream->ReadString(destAttribute);
michael@0 1365 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1366
michael@0 1367 nsCOMPtr<nsIAtom> srcAtom = do_GetAtom(srcAttribute);
michael@0 1368 nsCOMPtr<nsIAtom> destAtom = do_GetAtom(destAttribute);
michael@0 1369
michael@0 1370 EnsureAttributeTable();
michael@0 1371 AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, content);
michael@0 1372
michael@0 1373 rv = ReadNamespace(aStream, srcNamespaceID);
michael@0 1374 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1375 }
michael@0 1376
michael@0 1377 // Finally, read in the child nodes.
michael@0 1378 uint32_t childCount;
michael@0 1379 rv = aStream->Read32(&childCount);
michael@0 1380 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1381
michael@0 1382 for (uint32_t i = 0; i < childCount; i++) {
michael@0 1383 nsCOMPtr<nsIContent> child;
michael@0 1384 ReadContentNode(aStream, aDocument, aNim, getter_AddRefs(child));
michael@0 1385
michael@0 1386 // Child may be null if this was a comment for example and can just be ignored.
michael@0 1387 if (child) {
michael@0 1388 content->AppendChildTo(child, false);
michael@0 1389 }
michael@0 1390 }
michael@0 1391
michael@0 1392 content.swap(*aContent);
michael@0 1393 return NS_OK;
michael@0 1394 }
michael@0 1395
michael@0 1396 // This structure holds information about a forwarded attribute that needs to be
michael@0 1397 // written out. This is used because we need several fields passed within the
michael@0 1398 // enumeration closure.
michael@0 1399 struct WriteAttributeData
michael@0 1400 {
michael@0 1401 nsXBLPrototypeBinding* binding;
michael@0 1402 nsIObjectOutputStream* stream;
michael@0 1403 nsIContent* content;
michael@0 1404 int32_t srcNamespace;
michael@0 1405
michael@0 1406 WriteAttributeData(nsXBLPrototypeBinding* aBinding,
michael@0 1407 nsIObjectOutputStream* aStream,
michael@0 1408 nsIContent* aContent)
michael@0 1409 : binding(aBinding), stream(aStream), content(aContent)
michael@0 1410 { }
michael@0 1411 };
michael@0 1412
michael@0 1413 static PLDHashOperator
michael@0 1414 WriteAttribute(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
michael@0 1415 {
michael@0 1416 WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
michael@0 1417 nsIObjectOutputStream* stream = data->stream;
michael@0 1418 const int32_t srcNamespace = data->srcNamespace;
michael@0 1419
michael@0 1420 do {
michael@0 1421 if (aEntry->GetElement() == data->content) {
michael@0 1422 data->binding->WriteNamespace(stream, srcNamespace);
michael@0 1423 stream->WriteWStringZ(nsDependentAtomString(aEntry->GetSrcAttribute()).get());
michael@0 1424 data->binding->WriteNamespace(stream, aEntry->GetDstNameSpace());
michael@0 1425 stream->WriteWStringZ(nsDependentAtomString(aEntry->GetDstAttribute()).get());
michael@0 1426 }
michael@0 1427
michael@0 1428 aEntry = aEntry->GetNext();
michael@0 1429 } while (aEntry);
michael@0 1430
michael@0 1431 return PL_DHASH_NEXT;
michael@0 1432 }
michael@0 1433
michael@0 1434 // WriteAttributeNS is the callback to enumerate over the attribute
michael@0 1435 // forwarding entries. Since these are stored in a hash of hashes,
michael@0 1436 // we need to iterate over the inner hashes, calling WriteAttribute
michael@0 1437 // to do the actual work.
michael@0 1438 static PLDHashOperator
michael@0 1439 WriteAttributeNS(const uint32_t &aNamespace,
michael@0 1440 nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
michael@0 1441 void* aClosure)
michael@0 1442 {
michael@0 1443 WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
michael@0 1444 data->srcNamespace = aNamespace;
michael@0 1445 aXBLAttributes->EnumerateRead(WriteAttribute, data);
michael@0 1446
michael@0 1447 return PL_DHASH_NEXT;
michael@0 1448 }
michael@0 1449
michael@0 1450 nsresult
michael@0 1451 nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
michael@0 1452 nsIContent* aNode)
michael@0 1453 {
michael@0 1454 nsresult rv;
michael@0 1455
michael@0 1456 if (!aNode->IsElement()) {
michael@0 1457 // Text is writen out as a single byte for the type, followed by the text.
michael@0 1458 uint8_t type = XBLBinding_Serialize_NoContent;
michael@0 1459 switch (aNode->NodeType()) {
michael@0 1460 case nsIDOMNode::TEXT_NODE:
michael@0 1461 type = XBLBinding_Serialize_TextNode;
michael@0 1462 break;
michael@0 1463 case nsIDOMNode::CDATA_SECTION_NODE:
michael@0 1464 type = XBLBinding_Serialize_CDATANode;
michael@0 1465 break;
michael@0 1466 case nsIDOMNode::COMMENT_NODE:
michael@0 1467 type = XBLBinding_Serialize_CommentNode;
michael@0 1468 break;
michael@0 1469 default:
michael@0 1470 break;
michael@0 1471 }
michael@0 1472
michael@0 1473 rv = aStream->Write8(type);
michael@0 1474 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1475
michael@0 1476 nsAutoString content;
michael@0 1477 aNode->GetText()->AppendTo(content);
michael@0 1478 return aStream->WriteWStringZ(content.get());
michael@0 1479 }
michael@0 1480
michael@0 1481 // Otherwise, this is an element.
michael@0 1482
michael@0 1483 // Write the namespace id followed by the tag name
michael@0 1484 rv = WriteNamespace(aStream, aNode->GetNameSpaceID());
michael@0 1485 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1486
michael@0 1487 nsAutoString prefixStr;
michael@0 1488 aNode->NodeInfo()->GetPrefix(prefixStr);
michael@0 1489 rv = aStream->WriteWStringZ(prefixStr.get());
michael@0 1490 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1491
michael@0 1492 rv = aStream->WriteWStringZ(nsDependentAtomString(aNode->Tag()).get());
michael@0 1493 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1494
michael@0 1495 // Write attributes
michael@0 1496 uint32_t count = aNode->GetAttrCount();
michael@0 1497 rv = aStream->Write32(count);
michael@0 1498 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1499
michael@0 1500 uint32_t i;
michael@0 1501 for (i = 0; i < count; i++) {
michael@0 1502 // Write out the namespace id, the namespace prefix, the local tag name,
michael@0 1503 // and the value, in that order.
michael@0 1504
michael@0 1505 const nsAttrName* attr = aNode->GetAttrNameAt(i);
michael@0 1506
michael@0 1507 // XXXndeakin don't write out xbl:inherits?
michael@0 1508 int32_t namespaceID = attr->NamespaceID();
michael@0 1509 rv = WriteNamespace(aStream, namespaceID);
michael@0 1510 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1511
michael@0 1512 nsAutoString prefixStr;
michael@0 1513 nsIAtom* prefix = attr->GetPrefix();
michael@0 1514 if (prefix)
michael@0 1515 prefix->ToString(prefixStr);
michael@0 1516 rv = aStream->WriteWStringZ(prefixStr.get());
michael@0 1517 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1518
michael@0 1519 rv = aStream->WriteWStringZ(nsDependentAtomString(attr->LocalName()).get());
michael@0 1520 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1521
michael@0 1522 nsAutoString val;
michael@0 1523 aNode->GetAttr(attr->NamespaceID(), attr->LocalName(), val);
michael@0 1524 rv = aStream->WriteWStringZ(val.get());
michael@0 1525 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1526 }
michael@0 1527
michael@0 1528 // Write out the attribute fowarding information
michael@0 1529 if (mAttributeTable) {
michael@0 1530 WriteAttributeData data(this, aStream, aNode);
michael@0 1531 mAttributeTable->EnumerateRead(WriteAttributeNS, &data);
michael@0 1532 }
michael@0 1533 rv = aStream->Write8(XBLBinding_Serialize_NoMoreAttributes);
michael@0 1534 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1535
michael@0 1536 // Finally, write out the child nodes.
michael@0 1537 count = aNode->GetChildCount();
michael@0 1538 rv = aStream->Write32(count);
michael@0 1539 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1540
michael@0 1541 for (i = 0; i < count; i++) {
michael@0 1542 rv = WriteContentNode(aStream, aNode->GetChildAt(i));
michael@0 1543 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1544 }
michael@0 1545
michael@0 1546 return NS_OK;
michael@0 1547 }
michael@0 1548
michael@0 1549 nsresult
michael@0 1550 nsXBLPrototypeBinding::ReadNamespace(nsIObjectInputStream* aStream,
michael@0 1551 int32_t& aNameSpaceID)
michael@0 1552 {
michael@0 1553 uint8_t namespaceID;
michael@0 1554 nsresult rv = aStream->Read8(&namespaceID);
michael@0 1555 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1556
michael@0 1557 if (namespaceID == XBLBinding_Serialize_CustomNamespace) {
michael@0 1558 nsAutoString namesp;
michael@0 1559 rv = aStream->ReadString(namesp);
michael@0 1560 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1561
michael@0 1562 nsContentUtils::NameSpaceManager()->RegisterNameSpace(namesp, aNameSpaceID);
michael@0 1563 }
michael@0 1564 else {
michael@0 1565 aNameSpaceID = namespaceID;
michael@0 1566 }
michael@0 1567
michael@0 1568 return NS_OK;
michael@0 1569 }
michael@0 1570
michael@0 1571 nsresult
michael@0 1572 nsXBLPrototypeBinding::WriteNamespace(nsIObjectOutputStream* aStream,
michael@0 1573 int32_t aNameSpaceID)
michael@0 1574 {
michael@0 1575 // Namespaces are stored as a single byte id for well-known namespaces.
michael@0 1576 // This saves time and space as other namespaces aren't very common in
michael@0 1577 // XBL. If another namespace is used however, the namespace id will be
michael@0 1578 // XBLBinding_Serialize_CustomNamespace and the string namespace written
michael@0 1579 // out directly afterwards.
michael@0 1580 nsresult rv;
michael@0 1581
michael@0 1582 if (aNameSpaceID <= kNameSpaceID_LastBuiltin) {
michael@0 1583 rv = aStream->Write8((int8_t)aNameSpaceID);
michael@0 1584 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1585 }
michael@0 1586 else {
michael@0 1587 rv = aStream->Write8(XBLBinding_Serialize_CustomNamespace);
michael@0 1588 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1589
michael@0 1590 nsAutoString namesp;
michael@0 1591 nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, namesp);
michael@0 1592 aStream->WriteWStringZ(namesp.get());
michael@0 1593 }
michael@0 1594
michael@0 1595 return NS_OK;
michael@0 1596 }
michael@0 1597
michael@0 1598
michael@0 1599 bool CheckTagNameWhiteList(int32_t aNameSpaceID, nsIAtom *aTagName)
michael@0 1600 {
michael@0 1601 static nsIContent::AttrValuesArray kValidXULTagNames[] = {
michael@0 1602 &nsGkAtoms::autorepeatbutton, &nsGkAtoms::box, &nsGkAtoms::browser,
michael@0 1603 &nsGkAtoms::button, &nsGkAtoms::hbox, &nsGkAtoms::image, &nsGkAtoms::menu,
michael@0 1604 &nsGkAtoms::menubar, &nsGkAtoms::menuitem, &nsGkAtoms::menupopup,
michael@0 1605 &nsGkAtoms::row, &nsGkAtoms::slider, &nsGkAtoms::spacer,
michael@0 1606 &nsGkAtoms::splitter, &nsGkAtoms::text, &nsGkAtoms::tree, nullptr};
michael@0 1607
michael@0 1608 uint32_t i;
michael@0 1609 if (aNameSpaceID == kNameSpaceID_XUL) {
michael@0 1610 for (i = 0; kValidXULTagNames[i]; ++i) {
michael@0 1611 if (aTagName == *(kValidXULTagNames[i])) {
michael@0 1612 return true;
michael@0 1613 }
michael@0 1614 }
michael@0 1615 }
michael@0 1616 else if (aNameSpaceID == kNameSpaceID_SVG &&
michael@0 1617 aTagName == nsGkAtoms::generic_) {
michael@0 1618 return true;
michael@0 1619 }
michael@0 1620
michael@0 1621 return false;
michael@0 1622 }
michael@0 1623
michael@0 1624 nsresult
michael@0 1625 nsXBLPrototypeBinding::ResolveBaseBinding()
michael@0 1626 {
michael@0 1627 if (mCheckedBaseProto)
michael@0 1628 return NS_OK;
michael@0 1629 mCheckedBaseProto = true;
michael@0 1630
michael@0 1631 nsCOMPtr<nsIDocument> doc = mXBLDocInfoWeak->GetDocument();
michael@0 1632
michael@0 1633 // Check for the presence of 'extends' and 'display' attributes
michael@0 1634 nsAutoString display, extends;
michael@0 1635 mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::extends, extends);
michael@0 1636 if (extends.IsEmpty())
michael@0 1637 return NS_OK;
michael@0 1638
michael@0 1639 mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::display, display);
michael@0 1640 bool hasDisplay = !display.IsEmpty();
michael@0 1641
michael@0 1642 nsAutoString value(extends);
michael@0 1643
michael@0 1644 // Now slice 'em up to see what we've got.
michael@0 1645 nsAutoString prefix;
michael@0 1646 int32_t offset;
michael@0 1647 if (hasDisplay) {
michael@0 1648 offset = display.FindChar(':');
michael@0 1649 if (-1 != offset) {
michael@0 1650 display.Left(prefix, offset);
michael@0 1651 display.Cut(0, offset+1);
michael@0 1652 }
michael@0 1653 }
michael@0 1654 else {
michael@0 1655 offset = extends.FindChar(':');
michael@0 1656 if (-1 != offset) {
michael@0 1657 extends.Left(prefix, offset);
michael@0 1658 extends.Cut(0, offset+1);
michael@0 1659 display = extends;
michael@0 1660 }
michael@0 1661 }
michael@0 1662
michael@0 1663 nsAutoString nameSpace;
michael@0 1664
michael@0 1665 if (!prefix.IsEmpty()) {
michael@0 1666 mBinding->LookupNamespaceURI(prefix, nameSpace);
michael@0 1667 if (!nameSpace.IsEmpty()) {
michael@0 1668 int32_t nameSpaceID =
michael@0 1669 nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace);
michael@0 1670
michael@0 1671 nsCOMPtr<nsIAtom> tagName = do_GetAtom(display);
michael@0 1672 // Check the white list
michael@0 1673 if (!CheckTagNameWhiteList(nameSpaceID, tagName)) {
michael@0 1674 const char16_t* params[] = { display.get() };
michael@0 1675 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
michael@0 1676 NS_LITERAL_CSTRING("XBL"), nullptr,
michael@0 1677 nsContentUtils::eXBL_PROPERTIES,
michael@0 1678 "InvalidExtendsBinding",
michael@0 1679 params, ArrayLength(params),
michael@0 1680 doc->GetDocumentURI());
michael@0 1681 NS_ASSERTION(!nsXBLService::IsChromeOrResourceURI(doc->GetDocumentURI()),
michael@0 1682 "Invalid extends value");
michael@0 1683 return NS_ERROR_ILLEGAL_VALUE;
michael@0 1684 }
michael@0 1685
michael@0 1686 SetBaseTag(nameSpaceID, tagName);
michael@0 1687 }
michael@0 1688 }
michael@0 1689
michael@0 1690 if (hasDisplay || nameSpace.IsEmpty()) {
michael@0 1691 mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, false);
michael@0 1692 mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::display, false);
michael@0 1693
michael@0 1694 return NS_NewURI(getter_AddRefs(mBaseBindingURI), value,
michael@0 1695 doc->GetDocumentCharacterSet().get(),
michael@0 1696 doc->GetDocBaseURI());
michael@0 1697 }
michael@0 1698
michael@0 1699 return NS_OK;
michael@0 1700 }

mercurial