nsXBLContentSink.cpp 30 KB

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