LCOV - code coverage report
Current view: top level - dom/xbl - nsXBLContentSink.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 211 479 44.1 %
Date: 2017-07-14 16:53:18 Functions: 13 27 48.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13