dom/xbl/nsXBLContentSink.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:a8e130ad66bb
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/. */
5
6 #include "mozilla/ArrayUtils.h"
7
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"
30
31 using namespace mozilla;
32 using namespace mozilla::dom;
33
34 nsresult
35 NS_NewXBLContentSink(nsIXMLContentSink** aResult,
36 nsIDocument* aDoc,
37 nsIURI* aURI,
38 nsISupports* aContainer)
39 {
40 NS_ENSURE_ARG_POINTER(aResult);
41
42 nsXBLContentSink* it = new nsXBLContentSink();
43 NS_ENSURE_TRUE(it, NS_ERROR_OUT_OF_MEMORY);
44
45 nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
46 nsresult rv = it->Init(aDoc, aURI, aContainer);
47 NS_ENSURE_SUCCESS(rv, rv);
48
49 return CallQueryInterface(it, aResult);
50 }
51
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 }
69
70 nsXBLContentSink::~nsXBLContentSink()
71 {
72 }
73
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 }
83
84 void
85 nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
86 {
87 return;
88 }
89
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();
113
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 }
138
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))) {
145
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 }
158
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 }
166
167 return nsXMLContentSink::FlushText(aReleaseTextNode);
168 }
169
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!!!");
177
178 // XXX FIXME This function overrides and calls on
179 // nsXMLContentSink::ReportError, and probably should die. See bug 347826.
180
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.
185
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
193
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 }
201
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);
212
213 const char16_t* params[] = { elementName.get() };
214
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 }
225
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.
234
235 mImplMember = aMember; // Adjust our pointer to point to the new last member in the chain.
236 }
237
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.
246
247 mImplField = aField; // Adjust our pointer to point to the new last field in the chain.
248 }
249
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;
260
261 if (mState == eXBL_InBinding && !mBinding) {
262 rv = ConstructBinding(aLineNumber);
263 if (NS_FAILED(rv))
264 return rv;
265
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 }
269
270 return rv;
271 }
272
273 NS_IMETHODIMP
274 nsXBLContentSink::HandleEndElement(const char16_t *aName)
275 {
276 FlushText();
277
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);
283
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 }
339
340 nsresult rv = nsXMLContentSink::HandleEndElement(aName);
341 if (NS_FAILED(rv))
342 return rv;
343
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 }
351
352 return NS_OK;
353 }
354 }
355
356 return nsXMLContentSink::HandleEndElement(aName);
357 }
358
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 }
367
368 #define ENSURE_XBL_STATE(_cond) \
369 PR_BEGIN_MACRO \
370 if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return true; } \
371 PR_END_MACRO
372
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 }
383
384 if (aNameSpaceID != kNameSpaceID_XBL) {
385 // Construct non-XBL nodes
386 return true;
387 }
388
389 bool ret = true;
390 if (aTagName == nsGkAtoms::bindings) {
391 ENSURE_XBL_STATE(mState == eXBL_InDocument);
392
393 NS_ASSERTION(mDocument, "Must have a document!");
394 nsRefPtr<nsXBLDocumentInfo> info = new nsXBLDocumentInfo(mDocument);
395
396 // We keep a weak ref. We're creating a cycle between doc/binding manager/doc info.
397 mDocInfo = info;
398
399 if (!mDocInfo) {
400 mState = eXBL_Error;
401 return true;
402 }
403
404 mDocument->BindingManager()->PutXBLDocumentInfo(mDocInfo);
405
406 nsIURI *uri = mDocument->GetDocumentURI();
407
408 bool isChrome = false;
409 bool isRes = false;
410
411 uri->SchemeIs("chrome", &isChrome);
412 uri->SchemeIs("resource", &isRes);
413 mIsChromeOrResource = isChrome || isRes;
414
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");
454
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 }
536
537 return ret && mState != eXBL_InResources && mState != eXBL_InImplementation;
538 }
539
540 #undef ENSURE_XBL_STATE
541
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);
548
549 nsresult rv = NS_OK;
550
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;
557
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 }
579
580 return rv;
581 }
582
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);
591
592 // Is this attribute one of the ones we care about?
593 if (nameSpaceID == kNameSpaceID_None && localName == aAtom) {
594 *aResult = aAtts[1];
595
596 return true;
597 }
598 }
599
600 return false;
601 }
602
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;
618
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);
624
625 if (nameSpaceID != kNameSpaceID_None) {
626 continue;
627 }
628
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 }
655
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 }
670
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);
678
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 }
696
697 void
698 nsXBLContentSink::ConstructResource(const char16_t **aAtts,
699 nsIAtom* aResourceType)
700 {
701 if (!mBinding)
702 return;
703
704 const char16_t* src = nullptr;
705 if (FindValue(aAtts, nsGkAtoms::src, &src)) {
706 mBinding->AddResource(aResourceType, nsDependentString(src));
707 }
708 }
709
710 void
711 nsXBLContentSink::ConstructImplementation(const char16_t **aAtts)
712 {
713 mImplementation = nullptr;
714 mImplMember = nullptr;
715 mImplField = nullptr;
716
717 if (!mBinding)
718 return;
719
720 const char16_t* name = nullptr;
721
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);
727
728 if (nameSpaceID != kNameSpaceID_None) {
729 continue;
730 }
731
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 }
744
745 NS_NewXBLProtoImpl(mBinding, name, &mImplementation);
746 }
747
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;
753
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);
759
760 if (nameSpaceID != kNameSpaceID_None) {
761 continue;
762 }
763
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 }
772
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 }
783
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;
792
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);
798
799 if (nameSpaceID != kNameSpaceID_None) {
800 continue;
801 }
802
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 }
822
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 }
833
834 void
835 nsXBLContentSink::ConstructMethod(const char16_t **aAtts)
836 {
837 mMethod = nullptr;
838
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 }
849
850 if (mMethod) {
851 AddMember(mMethod);
852 }
853 }
854
855 void
856 nsXBLContentSink::ConstructParameter(const char16_t **aAtts)
857 {
858 if (!mMethod)
859 return;
860
861 const char16_t* name = nullptr;
862 if (FindValue(aAtts, nsGkAtoms::name, &name)) {
863 mMethod->AddParameter(nsDependentString(name));
864 }
865 }
866
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 }
881
882 // Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode.
883
884 *aAppendContent = true;
885 nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
886 if (!prototype)
887 return NS_ERROR_OUT_OF_MEMORY;
888
889 prototype->mNodeInfo = aNodeInfo;
890
891 AddAttributesToXULPrototype(aAtts, aAttsCount, prototype);
892
893 Element* result;
894 nsresult rv = nsXULElement::Create(prototype, mDocument, false, false, &result);
895 *aResult = result;
896 return rv;
897 #endif
898 }
899
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.
906
907 return nsXMLContentSink::AddAttributes(aAtts, aContent);
908 }
909
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;
918
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 }
926
927 aElement->mAttributes = attrs;
928 aElement->mNumAttributes = aAttsCount;
929
930 // Copy the attributes into the prototype
931 nsCOMPtr<nsIAtom> prefix, localName;
932
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);
938
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 }
948
949 rv = aElement->SetAttrAt(i, nsDependentString(aAtts[i * 2 + 1]),
950 mDocumentURI);
951 NS_ENSURE_SUCCESS(rv, rv);
952 }
953
954 return NS_OK;
955 }
956 #endif

mercurial