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
|