Coverage Report

Created: 2018-09-25 14:53

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