dom/xbl/nsXBLContentSink.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/ArrayUtils.h"
     8 #include "nsXBLContentSink.h"
     9 #include "nsIDocument.h"
    10 #include "nsBindingManager.h"
    11 #include "nsIDOMNode.h"
    12 #include "nsGkAtoms.h"
    13 #include "nsNameSpaceManager.h"
    14 #include "nsIURI.h"
    15 #include "nsTextFragment.h"
    16 #ifdef MOZ_XUL
    17 #include "nsXULElement.h"
    18 #endif
    19 #include "nsXBLProtoImplProperty.h"
    20 #include "nsXBLProtoImplMethod.h"
    21 #include "nsXBLProtoImplField.h"
    22 #include "nsXBLPrototypeBinding.h"
    23 #include "nsContentUtils.h"
    24 #include "nsIConsoleService.h"
    25 #include "nsIScriptError.h"
    26 #include "nsNodeInfoManager.h"
    27 #include "nsINodeInfo.h"
    28 #include "nsIPrincipal.h"
    29 #include "mozilla/dom/Element.h"
    31 using namespace mozilla;
    32 using namespace mozilla::dom;
    34 nsresult
    35 NS_NewXBLContentSink(nsIXMLContentSink** aResult,
    36                      nsIDocument* aDoc,
    37                      nsIURI* aURI,
    38                      nsISupports* aContainer)
    39 {
    40   NS_ENSURE_ARG_POINTER(aResult);
    42   nsXBLContentSink* it = new nsXBLContentSink();
    43   NS_ENSURE_TRUE(it, NS_ERROR_OUT_OF_MEMORY);
    45   nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
    46   nsresult rv = it->Init(aDoc, aURI, aContainer);
    47   NS_ENSURE_SUCCESS(rv, rv);
    49   return CallQueryInterface(it, aResult);
    50 }
    52 nsXBLContentSink::nsXBLContentSink()
    53   : mState(eXBL_InDocument),
    54     mSecondaryState(eXBL_None),
    55     mDocInfo(nullptr),
    56     mIsChromeOrResource(false),
    57     mFoundFirstBinding(false),
    58     mBinding(nullptr),
    59     mHandler(nullptr),
    60     mImplementation(nullptr),
    61     mImplMember(nullptr),
    62     mImplField(nullptr),
    63     mProperty(nullptr),
    64     mMethod(nullptr),
    65     mField(nullptr)
    66 {
    67   mPrettyPrintXML = false;
    68 }
    70 nsXBLContentSink::~nsXBLContentSink()
    71 {
    72 }
    74 nsresult
    75 nsXBLContentSink::Init(nsIDocument* aDoc,
    76                        nsIURI* aURI,
    77                        nsISupports* aContainer)
    78 {
    79   nsresult rv;
    80   rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nullptr);
    81   return rv;
    82 }
    84 void
    85 nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
    86 {
    87   return;
    88 }
    90 nsresult
    91 nsXBLContentSink::FlushText(bool aReleaseTextNode)
    92 {
    93   if (mTextLength != 0) {
    94     const nsASingleFragmentString& text = Substring(mText, mText+mTextLength);
    95     if (mState == eXBL_InHandlers) {
    96       NS_ASSERTION(mBinding, "Must have binding here");
    97       // Get the text and add it to the event handler.
    98       if (mSecondaryState == eXBL_InHandler)
    99         mHandler->AppendHandlerText(text);
   100       mTextLength = 0;
   101       return NS_OK;
   102     }
   103     else if (mState == eXBL_InImplementation) {
   104       NS_ASSERTION(mBinding, "Must have binding here");
   105       if (mSecondaryState == eXBL_InConstructor ||
   106           mSecondaryState == eXBL_InDestructor) {
   107         // Construct a method for the constructor/destructor.
   108         nsXBLProtoImplMethod* method;
   109         if (mSecondaryState == eXBL_InConstructor)
   110           method = mBinding->GetConstructor();
   111         else
   112           method = mBinding->GetDestructor();
   114         // Get the text and add it to the constructor/destructor.
   115         method->AppendBodyText(text);
   116       }
   117       else if (mSecondaryState == eXBL_InGetter ||
   118                mSecondaryState == eXBL_InSetter) {
   119         // Get the text and add it to the getter/setter
   120         if (mSecondaryState == eXBL_InGetter)
   121           mProperty->AppendGetterText(text);
   122         else
   123           mProperty->AppendSetterText(text);
   124       }
   125       else if (mSecondaryState == eXBL_InBody) {
   126         // Get the text and add it to the method
   127         if (mMethod)
   128           mMethod->AppendBodyText(text);
   129       }
   130       else if (mSecondaryState == eXBL_InField) {
   131         // Get the text and add it to the method
   132         if (mField)
   133           mField->AppendFieldText(text);
   134       }
   135       mTextLength = 0;
   136       return NS_OK;
   137     }
   139     nsIContent* content = GetCurrentContent();
   140     if (content &&
   141         (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) ||
   142          (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XUL) &&
   143           content->Tag() != nsGkAtoms::label &&
   144           content->Tag() != nsGkAtoms::description))) {
   146       bool isWS = true;
   147       if (mTextLength > 0) {
   148         const char16_t* cp = mText;
   149         const char16_t* end = mText + mTextLength;
   150         while (cp < end) {
   151           char16_t ch = *cp++;
   152           if (!dom::IsSpaceCharacter(ch)) {
   153             isWS = false;
   154             break;
   155           }
   156         }
   157       }
   159       if (isWS && mTextLength > 0) {
   160         mTextLength = 0;
   161         // Make sure to drop the textnode, if any
   162         return nsXMLContentSink::FlushText(aReleaseTextNode);
   163       }
   164     }
   165   }
   167   return nsXMLContentSink::FlushText(aReleaseTextNode);
   168 }
   170 NS_IMETHODIMP
   171 nsXBLContentSink::ReportError(const char16_t* aErrorText, 
   172                               const char16_t* aSourceText,
   173                               nsIScriptError *aError,
   174                               bool *_retval)
   175 {
   176   NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
   178   // XXX FIXME This function overrides and calls on
   179   // nsXMLContentSink::ReportError, and probably should die.  See bug 347826.
   181   // XXX We should make sure the binding has no effect, but that it also
   182   // gets destroyed properly without leaking.  Perhaps we should even
   183   // ensure that the content that was bound is displayed with no
   184   // binding.
   186 #ifdef DEBUG
   187   // Report the error to stderr.
   188   fprintf(stderr,
   189           "\n%s\n%s\n\n",
   190           NS_LossyConvertUTF16toASCII(aErrorText).get(),
   191           NS_LossyConvertUTF16toASCII(aSourceText).get());
   192 #endif
   194   // Most of what this does won't be too useful, but whatever...
   195   // nsXMLContentSink::ReportError will handle the console logging.
   196   return nsXMLContentSink::ReportError(aErrorText, 
   197                                        aSourceText, 
   198                                        aError,
   199                                        _retval);
   200 }
   202 nsresult
   203 nsXBLContentSink::ReportUnexpectedElement(nsIAtom* aElementName,
   204                                           uint32_t aLineNumber)
   205 {
   206   // XXX we should really somehow stop the parse and drop the binding
   207   // instead of just letting the XML sink build the content model like
   208   // we do...
   209   mState = eXBL_Error;
   210   nsAutoString elementName;
   211   aElementName->ToString(elementName);
   213   const char16_t* params[] = { elementName.get() };
   215   return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
   216                                          NS_LITERAL_CSTRING("XBL Content Sink"),
   217                                          mDocument,
   218                                          nsContentUtils::eXBL_PROPERTIES,
   219                                          "UnexpectedElement",
   220                                          params, ArrayLength(params),
   221                                          nullptr,
   222                                          EmptyString() /* source line */,
   223                                          aLineNumber);
   224 }
   226 void
   227 nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember)
   228 {
   229   // Add this member to our chain.
   230   if (mImplMember)
   231     mImplMember->SetNext(aMember); // Already have a chain. Just append to the end.
   232   else
   233     mImplementation->SetMemberList(aMember); // We're the first member in the chain.
   235   mImplMember = aMember; // Adjust our pointer to point to the new last member in the chain.
   236 }
   238 void
   239 nsXBLContentSink::AddField(nsXBLProtoImplField* aField)
   240 {
   241   // Add this field to our chain.
   242   if (mImplField)
   243     mImplField->SetNext(aField); // Already have a chain. Just append to the end.
   244   else
   245     mImplementation->SetFieldList(aField); // We're the first member in the chain.
   247   mImplField = aField; // Adjust our pointer to point to the new last field in the chain.
   248 }
   250 NS_IMETHODIMP 
   251 nsXBLContentSink::HandleStartElement(const char16_t *aName, 
   252                                      const char16_t **aAtts, 
   253                                      uint32_t aAttsCount, 
   254                                      int32_t aIndex, 
   255                                      uint32_t aLineNumber)
   256 {
   257   nsresult rv = nsXMLContentSink::HandleStartElement(aName,aAtts,aAttsCount,aIndex,aLineNumber);
   258   if (NS_FAILED(rv))
   259     return rv;
   261   if (mState == eXBL_InBinding && !mBinding) {
   262     rv = ConstructBinding(aLineNumber);
   263     if (NS_FAILED(rv))
   264       return rv;
   266     // mBinding may still be null, if the binding had no id.  If so,
   267     // we'll deal with that later in the sink.
   268   }
   270   return rv;
   271 }
   273 NS_IMETHODIMP 
   274 nsXBLContentSink::HandleEndElement(const char16_t *aName)
   275 {
   276   FlushText();
   278   if (mState != eXBL_InDocument) {
   279     int32_t nameSpaceID;
   280     nsCOMPtr<nsIAtom> prefix, localName;
   281     nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
   282                                    getter_AddRefs(localName), &nameSpaceID);
   284     if (nameSpaceID == kNameSpaceID_XBL) {
   285       if (mState == eXBL_Error) {
   286         // Check whether we've opened this tag before; we may not have if
   287         // it was a real XBL tag before the error occurred.
   288         if (!GetCurrentContent()->NodeInfo()->Equals(localName,
   289                                                      nameSpaceID)) {
   290           // OK, this tag was never opened as far as the XML sink is
   291           // concerned.  Just drop the HandleEndElement
   292           return NS_OK;
   293         }
   294       }
   295       else if (mState == eXBL_InHandlers) {
   296         if (localName == nsGkAtoms::handlers) {
   297           mState = eXBL_InBinding;
   298           mHandler = nullptr;
   299         }
   300         else if (localName == nsGkAtoms::handler)
   301           mSecondaryState = eXBL_None;
   302         return NS_OK;
   303       }
   304       else if (mState == eXBL_InResources) {
   305         if (localName == nsGkAtoms::resources)
   306           mState = eXBL_InBinding;
   307         return NS_OK;
   308       }
   309       else if (mState == eXBL_InImplementation) {
   310         if (localName == nsGkAtoms::implementation)
   311           mState = eXBL_InBinding;
   312         else if (localName == nsGkAtoms::property) {
   313           mSecondaryState = eXBL_None;
   314           mProperty = nullptr;
   315         }
   316         else if (localName == nsGkAtoms::method) {
   317           mSecondaryState = eXBL_None;
   318           mMethod = nullptr;
   319         }
   320         else if (localName == nsGkAtoms::field) {
   321           mSecondaryState = eXBL_None;
   322           mField = nullptr;
   323         }
   324         else if (localName == nsGkAtoms::constructor ||
   325                  localName == nsGkAtoms::destructor)
   326           mSecondaryState = eXBL_None;
   327         else if (localName == nsGkAtoms::getter ||
   328                  localName == nsGkAtoms::setter)
   329           mSecondaryState = eXBL_InProperty;
   330         else if (localName == nsGkAtoms::parameter ||
   331                  localName == nsGkAtoms::body)
   332           mSecondaryState = eXBL_InMethod;
   333         return NS_OK;
   334       }
   335       else if (mState == eXBL_InBindings &&
   336                localName == nsGkAtoms::bindings) {
   337         mState = eXBL_InDocument;
   338       }
   340       nsresult rv = nsXMLContentSink::HandleEndElement(aName);
   341       if (NS_FAILED(rv))
   342         return rv;
   344       if (mState == eXBL_InBinding && localName == nsGkAtoms::binding) {
   345         mState = eXBL_InBindings;
   346         if (mBinding) {  // See comment in HandleStartElement()
   347           mBinding->Initialize();
   348           mBinding = nullptr; // Clear our current binding ref.
   349         }
   350       }
   352       return NS_OK;
   353     }
   354   }
   356   return nsXMLContentSink::HandleEndElement(aName);
   357 }
   359 NS_IMETHODIMP 
   360 nsXBLContentSink::HandleCDataSection(const char16_t *aData, 
   361                                      uint32_t aLength)
   362 {
   363   if (mState == eXBL_InHandlers || mState == eXBL_InImplementation)
   364     return AddText(aData, aLength);
   365   return nsXMLContentSink::HandleCDataSection(aData, aLength);
   366 }
   368 #define ENSURE_XBL_STATE(_cond)                                                       \
   369   PR_BEGIN_MACRO                                                                      \
   370     if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return true; } \
   371   PR_END_MACRO
   373 bool 
   374 nsXBLContentSink::OnOpenContainer(const char16_t **aAtts, 
   375                                   uint32_t aAttsCount, 
   376                                   int32_t aNameSpaceID, 
   377                                   nsIAtom* aTagName,
   378                                   uint32_t aLineNumber)
   379 {
   380   if (mState == eXBL_Error) {
   381     return true;
   382   }
   384   if (aNameSpaceID != kNameSpaceID_XBL) {
   385     // Construct non-XBL nodes
   386     return true;
   387   }
   389   bool ret = true;
   390   if (aTagName == nsGkAtoms::bindings) {
   391     ENSURE_XBL_STATE(mState == eXBL_InDocument);
   393     NS_ASSERTION(mDocument, "Must have a document!");
   394     nsRefPtr<nsXBLDocumentInfo> info = new nsXBLDocumentInfo(mDocument);
   396     // We keep a weak ref. We're creating a cycle between doc/binding manager/doc info.
   397     mDocInfo = info;
   399     if (!mDocInfo) {
   400       mState = eXBL_Error;
   401       return true;
   402     }
   404     mDocument->BindingManager()->PutXBLDocumentInfo(mDocInfo);
   406     nsIURI *uri = mDocument->GetDocumentURI();
   408     bool isChrome = false;
   409     bool isRes = false;
   411     uri->SchemeIs("chrome", &isChrome);
   412     uri->SchemeIs("resource", &isRes);
   413     mIsChromeOrResource = isChrome || isRes;
   415     mState = eXBL_InBindings;
   416   }
   417   else if (aTagName == nsGkAtoms::binding) {
   418     ENSURE_XBL_STATE(mState == eXBL_InBindings);
   419     mState = eXBL_InBinding;
   420   }
   421   else if (aTagName == nsGkAtoms::handlers) {
   422     ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
   423     mState = eXBL_InHandlers;
   424     ret = false;
   425   }
   426   else if (aTagName == nsGkAtoms::handler) {
   427     ENSURE_XBL_STATE(mState == eXBL_InHandlers);
   428     mSecondaryState = eXBL_InHandler;
   429     ConstructHandler(aAtts, aLineNumber);
   430     ret = false;
   431   }
   432   else if (aTagName == nsGkAtoms::resources) {
   433     ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
   434     mState = eXBL_InResources;
   435     // Note that this mState will cause us to return false, so no need
   436     // to set ret to false.
   437   }
   438   else if (aTagName == nsGkAtoms::stylesheet || aTagName == nsGkAtoms::image) {
   439     ENSURE_XBL_STATE(mState == eXBL_InResources);
   440     NS_ASSERTION(mBinding, "Must have binding here");
   441     ConstructResource(aAtts, aTagName);
   442   }
   443   else if (aTagName == nsGkAtoms::implementation) {
   444     ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
   445     mState = eXBL_InImplementation;
   446     ConstructImplementation(aAtts);
   447     // Note that this mState will cause us to return false, so no need
   448     // to set ret to false.
   449   }
   450   else if (aTagName == nsGkAtoms::constructor) {
   451     ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
   452                      mSecondaryState == eXBL_None);
   453     NS_ASSERTION(mBinding, "Must have binding here");
   455     mSecondaryState = eXBL_InConstructor;
   456     nsAutoString name;
   457     if (!mCurrentBindingID.IsEmpty()) {
   458       name.Assign(mCurrentBindingID);
   459       name.AppendLiteral("_XBL_Constructor");
   460     } else {
   461       name.AppendLiteral("XBL_Constructor");
   462     }
   463     nsXBLProtoImplAnonymousMethod* newMethod =
   464       new nsXBLProtoImplAnonymousMethod(name.get());
   465     if (newMethod) {
   466       newMethod->SetLineNumber(aLineNumber);
   467       mBinding->SetConstructor(newMethod);
   468       AddMember(newMethod);
   469     }
   470   }
   471   else if (aTagName == nsGkAtoms::destructor) {
   472     ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
   473                      mSecondaryState == eXBL_None);
   474     NS_ASSERTION(mBinding, "Must have binding here");
   475     mSecondaryState = eXBL_InDestructor;
   476     nsAutoString name;
   477     if (!mCurrentBindingID.IsEmpty()) {
   478       name.Assign(mCurrentBindingID);
   479       name.AppendLiteral("_XBL_Destructor");
   480     } else {
   481       name.AppendLiteral("XBL_Destructor");
   482     }
   483     nsXBLProtoImplAnonymousMethod* newMethod =
   484       new nsXBLProtoImplAnonymousMethod(name.get());
   485     if (newMethod) {
   486       newMethod->SetLineNumber(aLineNumber);
   487       mBinding->SetDestructor(newMethod);
   488       AddMember(newMethod);
   489     }
   490   }
   491   else if (aTagName == nsGkAtoms::field) {
   492     ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
   493                      mSecondaryState == eXBL_None);
   494     NS_ASSERTION(mBinding, "Must have binding here");
   495     mSecondaryState = eXBL_InField;
   496     ConstructField(aAtts, aLineNumber);
   497   }
   498   else if (aTagName == nsGkAtoms::property) {
   499     ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
   500                      mSecondaryState == eXBL_None);
   501     NS_ASSERTION(mBinding, "Must have binding here");
   502     mSecondaryState = eXBL_InProperty;
   503     ConstructProperty(aAtts, aLineNumber);
   504   }
   505   else if (aTagName == nsGkAtoms::getter) {
   506     ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty);
   507     NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
   508     mProperty->SetGetterLineNumber(aLineNumber);
   509     mSecondaryState = eXBL_InGetter;
   510   }
   511   else if (aTagName == nsGkAtoms::setter) {
   512     ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty);
   513     NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
   514     mProperty->SetSetterLineNumber(aLineNumber);
   515     mSecondaryState = eXBL_InSetter;
   516   }
   517   else if (aTagName == nsGkAtoms::method) {
   518     ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
   519                      mSecondaryState == eXBL_None);
   520     NS_ASSERTION(mBinding, "Must have binding here");
   521     mSecondaryState = eXBL_InMethod;
   522     ConstructMethod(aAtts);
   523   }
   524   else if (aTagName == nsGkAtoms::parameter) {
   525     ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod);
   526     NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
   527     ConstructParameter(aAtts);
   528   }
   529   else if (aTagName == nsGkAtoms::body) {
   530     ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod);
   531     NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
   532     // stash away the line number
   533     mMethod->SetLineNumber(aLineNumber);
   534     mSecondaryState = eXBL_InBody;
   535   }
   537   return ret && mState != eXBL_InResources && mState != eXBL_InImplementation;
   538 }
   540 #undef ENSURE_XBL_STATE
   542 nsresult
   543 nsXBLContentSink::ConstructBinding(uint32_t aLineNumber)
   544 {
   545   nsCOMPtr<nsIContent> binding = GetCurrentContent();
   546   binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID);
   547   NS_ConvertUTF16toUTF8 cid(mCurrentBindingID);
   549   nsresult rv = NS_OK;
   551   // Don't create a binding with no id. nsXBLPrototypeBinding::Read also
   552   // performs this check.
   553   if (!cid.IsEmpty()) {
   554     mBinding = new nsXBLPrototypeBinding();
   555     if (!mBinding)
   556       return NS_ERROR_OUT_OF_MEMORY;
   558     rv = mBinding->Init(cid, mDocInfo, binding, !mFoundFirstBinding);
   559     if (NS_SUCCEEDED(rv) &&
   560         NS_SUCCEEDED(mDocInfo->SetPrototypeBinding(cid, mBinding))) {
   561       if (!mFoundFirstBinding) {
   562         mFoundFirstBinding = true;
   563         mDocInfo->SetFirstPrototypeBinding(mBinding);
   564       }
   565       binding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::id, false);
   566     } else {
   567       delete mBinding;
   568       mBinding = nullptr;
   569     }
   570   } else {
   571     nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
   572                                     NS_LITERAL_CSTRING("XBL Content Sink"), nullptr,
   573                                     nsContentUtils::eXBL_PROPERTIES,
   574                                     "MissingIdAttr", nullptr, 0,
   575                                     mDocumentURI,
   576                                     EmptyString(),
   577                                     aLineNumber);
   578   }
   580   return rv;
   581 }
   583 static bool
   584 FindValue(const char16_t **aAtts, nsIAtom *aAtom, const char16_t **aResult)
   585 {
   586   nsCOMPtr<nsIAtom> prefix, localName;
   587   for (; *aAtts; aAtts += 2) {
   588     int32_t nameSpaceID;
   589     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
   590                                    getter_AddRefs(localName), &nameSpaceID);
   592     // Is this attribute one of the ones we care about?
   593     if (nameSpaceID == kNameSpaceID_None && localName == aAtom) {
   594       *aResult = aAtts[1];
   596       return true;
   597     }
   598   }
   600   return false;
   601 }
   603 void
   604 nsXBLContentSink::ConstructHandler(const char16_t **aAtts, uint32_t aLineNumber)
   605 {
   606   const char16_t* event          = nullptr;
   607   const char16_t* modifiers      = nullptr;
   608   const char16_t* button         = nullptr;
   609   const char16_t* clickcount     = nullptr;
   610   const char16_t* keycode        = nullptr;
   611   const char16_t* charcode       = nullptr;
   612   const char16_t* phase          = nullptr;
   613   const char16_t* command        = nullptr;
   614   const char16_t* action         = nullptr;
   615   const char16_t* group          = nullptr;
   616   const char16_t* preventdefault = nullptr;
   617   const char16_t* allowuntrusted = nullptr;
   619   nsCOMPtr<nsIAtom> prefix, localName;
   620   for (; *aAtts; aAtts += 2) {
   621     int32_t nameSpaceID;
   622     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
   623                                    getter_AddRefs(localName), &nameSpaceID);
   625     if (nameSpaceID != kNameSpaceID_None) {
   626       continue;
   627     }
   629     // Is this attribute one of the ones we care about?
   630     if (localName == nsGkAtoms::event)
   631       event = aAtts[1];
   632     else if (localName == nsGkAtoms::modifiers)
   633       modifiers = aAtts[1];
   634     else if (localName == nsGkAtoms::button)
   635       button = aAtts[1];
   636     else if (localName == nsGkAtoms::clickcount)
   637       clickcount = aAtts[1];
   638     else if (localName == nsGkAtoms::keycode)
   639       keycode = aAtts[1];
   640     else if (localName == nsGkAtoms::key || localName == nsGkAtoms::charcode)
   641       charcode = aAtts[1];
   642     else if (localName == nsGkAtoms::phase)
   643       phase = aAtts[1];
   644     else if (localName == nsGkAtoms::command)
   645       command = aAtts[1];
   646     else if (localName == nsGkAtoms::action)
   647       action = aAtts[1];
   648     else if (localName == nsGkAtoms::group)
   649       group = aAtts[1];
   650     else if (localName == nsGkAtoms::preventdefault)
   651       preventdefault = aAtts[1];
   652     else if (localName == nsGkAtoms::allowuntrusted)
   653       allowuntrusted = aAtts[1];
   654   }
   656   if (command && !mIsChromeOrResource) {
   657     // Make sure the XBL doc is chrome or resource if we have a command
   658     // shorthand syntax.
   659     mState = eXBL_Error;
   660     nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
   661                                     NS_LITERAL_CSTRING("XBL Content Sink"),
   662                                     mDocument,
   663                                     nsContentUtils::eXBL_PROPERTIES,
   664                                     "CommandNotInChrome", nullptr, 0,
   665                                     nullptr,
   666                                     EmptyString() /* source line */,
   667                                     aLineNumber);
   668     return; // Don't even make this handler.
   669   }
   671   // All of our pointers are now filled in. Construct our handler with all of
   672   // these parameters.
   673   nsXBLPrototypeHandler* newHandler;
   674   newHandler = new nsXBLPrototypeHandler(event, phase, action, command,
   675                                          keycode, charcode, modifiers, button,
   676                                          clickcount, group, preventdefault,
   677                                          allowuntrusted, mBinding, aLineNumber);
   679   if (newHandler) {
   680     // Add this handler to our chain of handlers.
   681     if (mHandler) {
   682       // Already have a chain. Just append to the end.
   683       mHandler->SetNextHandler(newHandler);
   684     }
   685     else {
   686       // We're the first handler in the chain.
   687       mBinding->SetPrototypeHandlers(newHandler);
   688     }
   689     // Adjust our mHandler pointer to point to the new last handler in the
   690     // chain.
   691     mHandler = newHandler;
   692   } else {
   693     mState = eXBL_Error;
   694   }
   695 }
   697 void
   698 nsXBLContentSink::ConstructResource(const char16_t **aAtts,
   699                                     nsIAtom* aResourceType)
   700 {
   701   if (!mBinding)
   702     return;
   704   const char16_t* src = nullptr;
   705   if (FindValue(aAtts, nsGkAtoms::src, &src)) {
   706     mBinding->AddResource(aResourceType, nsDependentString(src));
   707   }
   708 }
   710 void
   711 nsXBLContentSink::ConstructImplementation(const char16_t **aAtts)
   712 {
   713   mImplementation = nullptr;
   714   mImplMember = nullptr;
   715   mImplField = nullptr;
   717   if (!mBinding)
   718     return;
   720   const char16_t* name = nullptr;
   722   nsCOMPtr<nsIAtom> prefix, localName;
   723   for (; *aAtts; aAtts += 2) {
   724     int32_t nameSpaceID;
   725     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
   726                                    getter_AddRefs(localName), &nameSpaceID);
   728     if (nameSpaceID != kNameSpaceID_None) {
   729       continue;
   730     }
   732     // Is this attribute one of the ones we care about?
   733     if (localName == nsGkAtoms::name) {
   734       name = aAtts[1];
   735     }
   736     else if (localName == nsGkAtoms::implements) {
   737       // Only allow implementation of interfaces via XBL if the principal of
   738       // our XBL document is the system principal.
   739       if (nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) {
   740         mBinding->ConstructInterfaceTable(nsDependentString(aAtts[1]));
   741       }
   742     }
   743   }
   745   NS_NewXBLProtoImpl(mBinding, name, &mImplementation);
   746 }
   748 void
   749 nsXBLContentSink::ConstructField(const char16_t **aAtts, uint32_t aLineNumber)
   750 {
   751   const char16_t* name     = nullptr;
   752   const char16_t* readonly = nullptr;
   754   nsCOMPtr<nsIAtom> prefix, localName;
   755   for (; *aAtts; aAtts += 2) {
   756     int32_t nameSpaceID;
   757     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
   758                                    getter_AddRefs(localName), &nameSpaceID);
   760     if (nameSpaceID != kNameSpaceID_None) {
   761       continue;
   762     }
   764     // Is this attribute one of the ones we care about?
   765     if (localName == nsGkAtoms::name) {
   766       name = aAtts[1];
   767     }
   768     else if (localName == nsGkAtoms::readonly) {
   769       readonly = aAtts[1];
   770     }
   771   }
   773   if (name) {
   774     // All of our pointers are now filled in. Construct our field with all of
   775     // these parameters.
   776     mField = new nsXBLProtoImplField(name, readonly);
   777     if (mField) {
   778       mField->SetLineNumber(aLineNumber);
   779       AddField(mField);
   780     }
   781   }
   782 }
   784 void
   785 nsXBLContentSink::ConstructProperty(const char16_t **aAtts, uint32_t aLineNumber)
   786 {
   787   const char16_t* name     = nullptr;
   788   const char16_t* readonly = nullptr;
   789   const char16_t* onget    = nullptr;
   790   const char16_t* onset    = nullptr;
   791   bool exposeToUntrustedContent = false;
   793   nsCOMPtr<nsIAtom> prefix, localName;
   794   for (; *aAtts; aAtts += 2) {
   795     int32_t nameSpaceID;
   796     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
   797                                    getter_AddRefs(localName), &nameSpaceID);
   799     if (nameSpaceID != kNameSpaceID_None) {
   800       continue;
   801     }
   803     // Is this attribute one of the ones we care about?
   804     if (localName == nsGkAtoms::name) {
   805       name = aAtts[1];
   806     }
   807     else if (localName == nsGkAtoms::readonly) {
   808       readonly = aAtts[1];
   809     }
   810     else if (localName == nsGkAtoms::onget) {
   811       onget = aAtts[1];
   812     }
   813     else if (localName == nsGkAtoms::onset) {
   814       onset = aAtts[1];
   815     }
   816     else if (localName == nsGkAtoms::exposeToUntrustedContent &&
   817              nsDependentString(aAtts[1]).EqualsLiteral("true"))
   818     {
   819       exposeToUntrustedContent = true;
   820     }
   821   }
   823   if (name) {
   824     // All of our pointers are now filled in. Construct our property with all of
   825     // these parameters.
   826     mProperty = new nsXBLProtoImplProperty(name, onget, onset, readonly, aLineNumber);
   827     if (exposeToUntrustedContent) {
   828       mProperty->SetExposeToUntrustedContent(true);
   829     }
   830     AddMember(mProperty);
   831   }
   832 }
   834 void
   835 nsXBLContentSink::ConstructMethod(const char16_t **aAtts)
   836 {
   837   mMethod = nullptr;
   839   const char16_t* name = nullptr;
   840   const char16_t* expose = nullptr;
   841   if (FindValue(aAtts, nsGkAtoms::name, &name)) {
   842     mMethod = new nsXBLProtoImplMethod(name);
   843     if (FindValue(aAtts, nsGkAtoms::exposeToUntrustedContent, &expose) &&
   844         nsDependentString(expose).EqualsLiteral("true"))
   845     {
   846       mMethod->SetExposeToUntrustedContent(true);
   847     }
   848   }
   850   if (mMethod) {
   851     AddMember(mMethod);
   852   }
   853 }
   855 void
   856 nsXBLContentSink::ConstructParameter(const char16_t **aAtts)
   857 {
   858   if (!mMethod)
   859     return;
   861   const char16_t* name = nullptr;
   862   if (FindValue(aAtts, nsGkAtoms::name, &name)) {
   863     mMethod->AddParameter(nsDependentString(name));
   864   }
   865 }
   867 nsresult
   868 nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
   869                                 nsINodeInfo* aNodeInfo, uint32_t aLineNumber,
   870                                 nsIContent** aResult, bool* aAppendContent,
   871                                 FromParser aFromParser)
   872 {
   873 #ifdef MOZ_XUL
   874   if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
   875 #endif
   876     return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
   877                                            aLineNumber, aResult,
   878                                            aAppendContent, aFromParser);
   879 #ifdef MOZ_XUL
   880   }
   882   // Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode.
   884   *aAppendContent = true;
   885   nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
   886   if (!prototype)
   887     return NS_ERROR_OUT_OF_MEMORY;
   889   prototype->mNodeInfo = aNodeInfo;
   891   AddAttributesToXULPrototype(aAtts, aAttsCount, prototype);
   893   Element* result;
   894   nsresult rv = nsXULElement::Create(prototype, mDocument, false, false, &result);
   895   *aResult = result;
   896   return rv;
   897 #endif
   898 }
   900 nsresult 
   901 nsXBLContentSink::AddAttributes(const char16_t** aAtts,
   902                                 nsIContent* aContent)
   903 {
   904   if (aContent->IsXUL())
   905     return NS_OK; // Nothing to do, since the proto already has the attrs.
   907   return nsXMLContentSink::AddAttributes(aAtts, aContent);
   908 }
   910 #ifdef MOZ_XUL
   911 nsresult
   912 nsXBLContentSink::AddAttributesToXULPrototype(const char16_t **aAtts, 
   913                                               uint32_t aAttsCount, 
   914                                               nsXULPrototypeElement* aElement)
   915 {
   916   // Add tag attributes to the element
   917   nsresult rv;
   919   // Create storage for the attributes
   920   nsXULPrototypeAttribute* attrs = nullptr;
   921   if (aAttsCount > 0) {
   922     attrs = new nsXULPrototypeAttribute[aAttsCount];
   923     if (!attrs)
   924       return NS_ERROR_OUT_OF_MEMORY;
   925   }
   927   aElement->mAttributes    = attrs;
   928   aElement->mNumAttributes = aAttsCount;
   930   // Copy the attributes into the prototype
   931   nsCOMPtr<nsIAtom> prefix, localName;
   933   uint32_t i;  
   934   for (i = 0; i < aAttsCount; ++i) {
   935     int32_t nameSpaceID;
   936     nsContentUtils::SplitExpatName(aAtts[i * 2], getter_AddRefs(prefix),
   937                                    getter_AddRefs(localName), &nameSpaceID);
   939     if (nameSpaceID == kNameSpaceID_None) {
   940       attrs[i].mName.SetTo(localName);
   941     }
   942     else {
   943       nsCOMPtr<nsINodeInfo> ni;
   944       ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
   945                                          nsIDOMNode::ATTRIBUTE_NODE);
   946       attrs[i].mName.SetTo(ni);
   947     }
   949     rv = aElement->SetAttrAt(i, nsDependentString(aAtts[i * 2 + 1]),
   950                              mDocumentURI); 
   951     NS_ENSURE_SUCCESS(rv, rv);
   952   }
   954   return NS_OK;
   955 }
   956 #endif

mercurial