Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/CustomElementRegistry.h
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
#ifndef mozilla_dom_CustomElementRegistry_h
8
#define mozilla_dom_CustomElementRegistry_h
9
10
#include "js/GCHashTable.h"
11
#include "js/TypeDecls.h"
12
#include "mozilla/Attributes.h"
13
#include "mozilla/CycleCollectedJSContext.h" // for MicroTaskRunnable
14
#include "mozilla/ErrorResult.h"
15
#include "mozilla/dom/BindingDeclarations.h"
16
#include "mozilla/dom/CustomElementRegistryBinding.h"
17
#include "mozilla/dom/Element.h"
18
#include "mozilla/dom/FunctionBinding.h"
19
#include "mozilla/dom/WebComponentsBinding.h"
20
#include "nsCycleCollectionParticipant.h"
21
#include "nsGenericHTMLElement.h"
22
#include "nsWrapperCache.h"
23
#include "nsContentUtils.h"
24
25
class nsDocument;
26
27
namespace mozilla {
28
namespace dom {
29
30
struct CustomElementData;
31
struct ElementDefinitionOptions;
32
class CallbackFunction;
33
class CustomElementReaction;
34
class DocGroup;
35
class Function;
36
class Promise;
37
38
struct LifecycleCallbackArgs
39
{
40
  nsString name;
41
  nsString oldValue;
42
  nsString newValue;
43
  nsString namespaceURI;
44
45
  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
46
};
47
48
struct LifecycleAdoptedCallbackArgs
49
{
50
  nsCOMPtr<nsIDocument> mOldDocument;
51
  nsCOMPtr<nsIDocument> mNewDocument;
52
};
53
54
class CustomElementCallback
55
{
56
public:
57
  CustomElementCallback(Element* aThisObject,
58
                        nsIDocument::ElementCallbackType aCallbackType,
59
                        CallbackFunction* aCallback);
60
  void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
61
  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
62
  void Call();
63
  void SetArgs(LifecycleCallbackArgs& aArgs)
64
0
  {
65
0
    MOZ_ASSERT(mType == nsIDocument::eAttributeChanged,
66
0
               "Arguments are only used by attribute changed callback.");
67
0
    mArgs = aArgs;
68
0
  }
69
70
  void SetAdoptedCallbackArgs(LifecycleAdoptedCallbackArgs& aAdoptedCallbackArgs)
71
0
  {
72
0
    MOZ_ASSERT(mType == nsIDocument::eAdopted,
73
0
      "Arguments are only used by adopted callback.");
74
0
    mAdoptedCallbackArgs = aAdoptedCallbackArgs;
75
0
  }
76
77
private:
78
  // The this value to use for invocation of the callback.
79
  RefPtr<Element> mThisObject;
80
  RefPtr<CallbackFunction> mCallback;
81
  // The type of callback (eCreated, eAttached, etc.)
82
  nsIDocument::ElementCallbackType mType;
83
  // Arguments to be passed to the callback,
84
  // used by the attribute changed callback.
85
  LifecycleCallbackArgs mArgs;
86
  LifecycleAdoptedCallbackArgs mAdoptedCallbackArgs;
87
};
88
89
class CustomElementConstructor final : public CallbackFunction
90
{
91
public:
92
  explicit CustomElementConstructor(CallbackFunction* aOther)
93
    : CallbackFunction(aOther)
94
0
  {
95
0
    MOZ_ASSERT(JS::IsConstructor(mCallback));
96
0
  }
97
98
  already_AddRefed<Element> Construct(const char* aExecutionReason, ErrorResult& aRv);
99
};
100
101
// Each custom element has an associated callback queue and an element is
102
// being created flag.
103
struct CustomElementData
104
{
105
  NS_INLINE_DECL_REFCOUNTING(CustomElementData)
106
107
  // https://dom.spec.whatwg.org/#concept-element-custom-element-state
108
  // CustomElementData is only created on the element which is a custom element
109
  // or an upgrade candidate, so the state of an element without
110
  // CustomElementData is "uncustomized".
111
  enum class State {
112
    eUndefined,
113
    eFailed,
114
    eCustom
115
  };
116
117
  explicit CustomElementData(nsAtom* aType);
118
  CustomElementData(nsAtom* aType, State aState);
119
120
  // Custom element state as described in the custom element spec.
121
  State mState;
122
  // custom element reaction queue as described in the custom element spec.
123
  // There is 1 reaction in reaction queue, when 1) it becomes disconnected,
124
  // 2) it’s adopted into a new document, 3) its attributes are changed,
125
  // appended, removed, or replaced.
126
  // There are 3 reactions in reaction queue when doing upgrade operation,
127
  // e.g., create an element, insert a node.
128
  AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
129
130
  void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
131
  CustomElementDefinition* GetCustomElementDefinition();
132
  nsAtom* GetCustomElementType() const
133
  {
134
    return mType;
135
  }
136
137
  void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
138
  void Unlink();
139
  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
140
141
  nsAtom* GetIs(const Element* aElement) const
142
  {
143
    // If mType isn't the same as name atom, this is a customized built-in
144
    // element, which has 'is' value set.
145
    return aElement->NodeInfo()->NameAtom() == mType ? nullptr : mType.get();
146
  }
147
private:
148
0
  virtual ~CustomElementData() {}
149
150
  // Custom element type, for <button is="x-button"> or <x-button>
151
  // this would be x-button.
152
  RefPtr<nsAtom> mType;
153
  RefPtr<CustomElementDefinition> mCustomElementDefinition;
154
};
155
156
0
#define ALREADY_CONSTRUCTED_MARKER nullptr
157
158
// The required information for a custom element as defined in:
159
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition
160
struct CustomElementDefinition
161
{
162
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CustomElementDefinition)
163
  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CustomElementDefinition)
164
165
  CustomElementDefinition(nsAtom* aType,
166
                          nsAtom* aLocalName,
167
                          int32_t aNamespaceID,
168
                          Function* aConstructor,
169
                          nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
170
                          UniquePtr<LifecycleCallbacks>&& aCallbacks);
171
172
  // The type (name) for this custom element, for <button is="x-foo"> or <x-foo>
173
  // this would be x-foo.
174
  RefPtr<nsAtom> mType;
175
176
  // The localname to (e.g. <button is=type> -- this would be button).
177
  RefPtr<nsAtom> mLocalName;
178
179
  // The namespace for this custom element
180
  int32_t mNamespaceID;
181
182
  // The custom element constructor.
183
  RefPtr<CustomElementConstructor> mConstructor;
184
185
  // The list of attributes that this custom element observes.
186
  nsTArray<RefPtr<nsAtom>> mObservedAttributes;
187
188
  // The lifecycle callbacks to call for this custom element.
189
  UniquePtr<LifecycleCallbacks> mCallbacks;
190
191
  // A construction stack. Use nullptr to represent an "already constructed marker".
192
  nsTArray<RefPtr<Element>> mConstructionStack;
193
194
  // See step 6.1.10 of https://dom.spec.whatwg.org/#concept-create-element
195
  // which set up the prefix after a custom element is created. However, In Gecko,
196
  // the prefix isn't allowed to be changed in NodeInfo, so we store the prefix
197
  // information here and propagate to where NodeInfo is assigned to a custom
198
  // element instead.
199
  nsTArray<RefPtr<nsAtom>> mPrefixStack;
200
201
  // This basically is used for distinguishing the custom element constructor
202
  // is invoked from document.createElement or directly from JS, i.e.
203
  // `new CustomElementConstructor()`.
204
  uint32_t mConstructionDepth = 0;
205
206
  bool IsCustomBuiltIn()
207
  {
208
    return mType != mLocalName;
209
  }
210
211
  bool IsInObservedAttributeList(nsAtom* aName)
212
0
  {
213
0
    if (mObservedAttributes.IsEmpty()) {
214
0
      return false;
215
0
    }
216
0
217
0
    return mObservedAttributes.Contains(aName);
218
0
  }
219
220
private:
221
0
  ~CustomElementDefinition() {}
222
};
223
224
class CustomElementReaction
225
{
226
public:
227
0
  virtual ~CustomElementReaction() = default;
228
  virtual void Invoke(Element* aElement, ErrorResult& aRv) = 0;
229
  virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const = 0;
230
  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const = 0;
231
232
  bool IsUpgradeReaction()
233
0
  {
234
0
    return mIsUpgradeReaction;
235
0
  }
236
237
protected:
238
  bool mIsUpgradeReaction = false;
239
};
240
241
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reactions-stack
242
class CustomElementReactionsStack
243
{
244
public:
245
  NS_INLINE_DECL_REFCOUNTING(CustomElementReactionsStack)
246
247
  CustomElementReactionsStack()
248
    : mIsBackupQueueProcessing(false)
249
    , mRecursionDepth(0)
250
    , mIsElementQueuePushedForCurrentRecursionDepth(false)
251
0
  {
252
0
  }
253
254
  // Hold a strong reference of Element so that it does not get cycle collected
255
  // before the reactions in its reaction queue are invoked.
256
  // The element reaction queues are stored in CustomElementData.
257
  // We need to lookup ElementReactionQueueMap again to get relevant reaction queue.
258
  // The choice of 3 for the auto size here is based on running Custom Elements
259
  // wpt tests.
260
  typedef AutoTArray<RefPtr<Element>, 3> ElementQueue;
261
262
  /**
263
   * Enqueue a custom element upgrade reaction
264
   * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction
265
   */
266
  void EnqueueUpgradeReaction(Element* aElement,
267
                              CustomElementDefinition* aDefinition);
268
269
  /**
270
   * Enqueue a custom element callback reaction
271
   * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-callback-reaction
272
   */
273
  void EnqueueCallbackReaction(Element* aElement,
274
                               UniquePtr<CustomElementCallback> aCustomElementCallback);
275
276
  /**
277
   * [CEReactions] Before executing the algorithm's steps.
278
   * Increase the current recursion depth, and the element queue is pushed
279
   * lazily when we really enqueue reactions.
280
   *
281
   * @return true if the element queue is pushed for "previous" recursion depth.
282
   */
283
  bool EnterCEReactions()
284
0
  {
285
0
    bool temp = mIsElementQueuePushedForCurrentRecursionDepth;
286
0
    mRecursionDepth++;
287
0
    // The is-element-queue-pushed flag is initially false when entering a new
288
0
    // recursion level. The original value will be cached in AutoCEReaction
289
0
    // and restored after leaving this recursion level.
290
0
    mIsElementQueuePushedForCurrentRecursionDepth = false;
291
0
    return temp;
292
0
  }
293
294
  /**
295
   * [CEReactions] After executing the algorithm's steps.
296
   * Pop and invoke the element queue if it is created and pushed for current
297
   * recursion depth, then decrease the current recursion depth.
298
   *
299
   * @param aCx JSContext used for handling exception thrown by algorithm's
300
   *            steps, this could be a nullptr.
301
   *        aWasElementQueuePushed used for restoring status after leaving
302
   *                               current recursion.
303
   */
304
  void LeaveCEReactions(JSContext* aCx, bool aWasElementQueuePushed)
305
0
  {
306
0
    MOZ_ASSERT(mRecursionDepth);
307
0
308
0
    if (mIsElementQueuePushedForCurrentRecursionDepth) {
309
0
      Maybe<JS::AutoSaveExceptionState> ases;
310
0
      if (aCx) {
311
0
        ases.emplace(aCx);
312
0
      }
313
0
      PopAndInvokeElementQueue();
314
0
    }
315
0
    mRecursionDepth--;
316
0
    // Restore the is-element-queue-pushed flag cached in AutoCEReaction when
317
0
    // leaving the recursion level.
318
0
    mIsElementQueuePushedForCurrentRecursionDepth = aWasElementQueuePushed;
319
0
320
0
    MOZ_ASSERT_IF(!mRecursionDepth, mReactionsStack.IsEmpty());
321
0
  }
322
323
private:
324
0
  ~CustomElementReactionsStack() {};
325
326
  /**
327
   * Push a new element queue onto the custom element reactions stack.
328
   */
329
  void CreateAndPushElementQueue();
330
331
  /**
332
   * Pop the element queue from the custom element reactions stack, and invoke
333
   * custom element reactions in that queue.
334
   */
335
  void PopAndInvokeElementQueue();
336
337
  // The choice of 8 for the auto size here is based on gut feeling.
338
  AutoTArray<UniquePtr<ElementQueue>, 8> mReactionsStack;
339
  ElementQueue mBackupQueue;
340
  // https://html.spec.whatwg.org/#enqueue-an-element-on-the-appropriate-element-queue
341
  bool mIsBackupQueueProcessing;
342
343
  void InvokeBackupQueue();
344
345
  /**
346
   * Invoke custom element reactions
347
   * https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions
348
   */
349
  void InvokeReactions(ElementQueue* aElementQueue, nsIGlobalObject* aGlobal);
350
351
  void Enqueue(Element* aElement, CustomElementReaction* aReaction);
352
353
  // Current [CEReactions] recursion depth.
354
  uint32_t mRecursionDepth;
355
  // True if the element queue is pushed into reaction stack for current
356
  // recursion depth. This will be cached in AutoCEReaction when entering a new
357
  // CEReaction recursion and restored after leaving the recursion.
358
  bool mIsElementQueuePushedForCurrentRecursionDepth;
359
360
private:
361
  class BackupQueueMicroTask final : public mozilla::MicroTaskRunnable {
362
    public:
363
      explicit BackupQueueMicroTask(
364
        CustomElementReactionsStack* aReactionStack)
365
        : MicroTaskRunnable()
366
        , mReactionStack(aReactionStack)
367
0
      {
368
0
        MOZ_ASSERT(!mReactionStack->mIsBackupQueueProcessing,
369
0
                   "mIsBackupQueueProcessing should be initially false");
370
0
        mReactionStack->mIsBackupQueueProcessing = true;
371
0
      }
372
373
      virtual void Run(AutoSlowOperation& aAso) override
374
0
      {
375
0
        mReactionStack->InvokeBackupQueue();
376
0
        mReactionStack->mIsBackupQueueProcessing = false;
377
0
      }
378
379
    private:
380
      RefPtr<CustomElementReactionsStack> mReactionStack;
381
  };
382
};
383
384
class CustomElementRegistry final : public nsISupports,
385
                                    public nsWrapperCache
386
{
387
  // Allow nsDocument to access mCustomDefinitions and mCandidatesMap.
388
  friend class ::nsDocument;
389
390
public:
391
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
392
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CustomElementRegistry)
393
394
public:
395
  static bool IsCustomElementEnabled(JSContext* aCx, JSObject* aObject);
396
  static bool IsCustomElementEnabled(nsIDocument* aDoc);
397
398
  explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow);
399
400
private:
401
  class RunCustomElementCreationCallback : public mozilla::Runnable
402
  {
403
  public:
404
    NS_DECL_NSIRUNNABLE
405
    explicit RunCustomElementCreationCallback(CustomElementRegistry* aRegistry,
406
                                              nsAtom* aAtom,
407
                                              CustomElementCreationCallback* aCallback)
408
      : mozilla::Runnable("CustomElementRegistry::RunCustomElementCreationCallback")
409
      , mRegistry(aRegistry)
410
      , mAtom(aAtom)
411
      , mCallback(aCallback)
412
0
    {
413
0
    }
414
    private:
415
      RefPtr<CustomElementRegistry> mRegistry;
416
      RefPtr<nsAtom> mAtom;
417
      RefPtr<CustomElementCreationCallback> mCallback;
418
  };
419
420
public:
421
  /**
422
   * Returns whether there's a definition that is likely to match this type
423
   * atom. This is not exact, so should only be used for optimization, but it's
424
   * good enough to prove that the chrome code doesn't need an XBL binding.
425
   */
426
  bool IsLikelyToBeCustomElement(nsAtom* aTypeAtom) const
427
0
  {
428
0
    return mCustomDefinitions.GetWeak(aTypeAtom) ||
429
0
      mElementCreationCallbacks.GetWeak(aTypeAtom);
430
0
  }
431
432
  /**
433
   * Looking up a custom element definition.
434
   * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
435
   */
436
  CustomElementDefinition* LookupCustomElementDefinition(
437
    nsAtom* aNameAtom, int32_t aNameSpaceID, nsAtom* aTypeAtom);
438
439
  CustomElementDefinition* LookupCustomElementDefinition(
440
    JSContext* aCx, JSObject *aConstructor) const;
441
442
  static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
443
                                       Element* aCustomElement,
444
                                       LifecycleCallbackArgs* aArgs,
445
                                       LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
446
                                       CustomElementDefinition* aDefinition);
447
448
  /**
449
   * Upgrade an element.
450
   * https://html.spec.whatwg.org/multipage/scripting.html#upgrades
451
   */
452
  static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv);
453
454
  /**
455
   * To allow native code to call methods of chrome-implemented custom elements,
456
   * a helper method may be defined in the custom element called
457
   * 'getCustomInterfaceCallback'. This method takes an IID and returns an
458
   * object which implements an XPCOM interface.
459
   *
460
   * This returns null if aElement is not from a chrome document.
461
   */
462
  static already_AddRefed<nsISupports> CallGetCustomInterface(
463
    Element* aElement, const nsIID& aIID);
464
465
  /**
466
   * Registers an unresolved custom element that is a candidate for
467
   * upgrade. |aTypeName| is the name of the custom element type, if it is not
468
   * provided, then element name is used. |aTypeName| should be provided
469
   * when registering a custom element that extends an existing
470
   * element. e.g. <button is="x-button">.
471
   */
472
  void RegisterUnresolvedElement(Element* aElement,
473
                                 nsAtom* aTypeName = nullptr);
474
475
  /**
476
   * Unregister an unresolved custom element that is a candidate for
477
   * upgrade when a custom element is removed from tree.
478
   */
479
  void UnregisterUnresolvedElement(Element* aElement,
480
                                   nsAtom* aTypeName = nullptr);
481
482
  /**
483
   * Register an element to be upgraded when the custom element creation
484
   * callback is executed.
485
   *
486
   * To be used when LookupCustomElementDefinition() didn't return a definition,
487
   * but with the callback scheduled to be run.
488
   */
489
  inline void RegisterCallbackUpgradeElement(Element* aElement,
490
                                             nsAtom* aTypeName = nullptr)
491
  {
492
    if (mElementCreationCallbacksUpgradeCandidatesMap.IsEmpty()) {
493
      return;
494
    }
495
496
    RefPtr<nsAtom> typeName = aTypeName;
497
    if (!typeName) {
498
      typeName = aElement->NodeInfo()->NameAtom();
499
    }
500
501
    nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>* elements =
502
      mElementCreationCallbacksUpgradeCandidatesMap.Get(typeName);
503
504
    // If there isn't a table, there won't be a definition added by the callback.
505
    if (!elements) {
506
      return;
507
    }
508
509
    nsWeakPtr elem = do_GetWeakReference(aElement);
510
    elements->PutEntry(elem);
511
  }
512
513
private:
514
  ~CustomElementRegistry();
515
516
  static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
517
    nsIDocument::ElementCallbackType aType, Element* aCustomElement,
518
    LifecycleCallbackArgs* aArgs,
519
    LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
520
    CustomElementDefinition* aDefinition);
521
522
  void UpgradeCandidates(nsAtom* aKey,
523
                         CustomElementDefinition* aDefinition,
524
                         ErrorResult& aRv);
525
526
  typedef nsRefPtrHashtable<nsRefPtrHashKey<nsAtom>, CustomElementDefinition>
527
    DefinitionMap;
528
  typedef nsRefPtrHashtable<nsRefPtrHashKey<nsAtom>, CustomElementCreationCallback>
529
    ElementCreationCallbackMap;
530
  typedef nsClassHashtable<nsRefPtrHashKey<nsAtom>,
531
                           nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>>
532
    CandidateMap;
533
  typedef JS::GCHashMap<JS::Heap<JSObject*>,
534
                        RefPtr<nsAtom>,
535
                        js::MovableCellHasher<JS::Heap<JSObject*>>,
536
                        js::SystemAllocPolicy> ConstructorMap;
537
538
  // Hashtable for custom element definitions in web components.
539
  // Custom prototypes are stored in the compartment where definition was
540
  // defined.
541
  DefinitionMap mCustomDefinitions;
542
543
  // Hashtable for chrome-only callbacks that is called *before* we return
544
  // a CustomElementDefinition, when the typeAtom matches.
545
  // The callbacks are registered with the setElementCreationCallback method.
546
  ElementCreationCallbackMap mElementCreationCallbacks;
547
548
  // Hashtable for looking up definitions by using constructor as key.
549
  // Custom elements' name are stored here and we need to lookup
550
  // mCustomDefinitions again to get definitions.
551
  ConstructorMap mConstructors;
552
553
  typedef nsRefPtrHashtable<nsRefPtrHashKey<nsAtom>, Promise>
554
    WhenDefinedPromiseMap;
555
  WhenDefinedPromiseMap mWhenDefinedPromiseMap;
556
557
  // The "upgrade candidates map" from the web components spec. Maps from a
558
  // namespace id and local name to a list of elements to upgrade if that
559
  // element is registered as a custom element.
560
  CandidateMap mCandidatesMap;
561
562
  // If an element creation callback is found, the nsTHashtable for the
563
  // type is created here, and elements will later be upgraded.
564
  CandidateMap mElementCreationCallbacksUpgradeCandidatesMap;
565
566
  nsCOMPtr<nsPIDOMWindowInner> mWindow;
567
568
  // It is used to prevent reentrant invocations of element definition.
569
  bool mIsCustomDefinitionRunning;
570
571
private:
572
  class MOZ_RAII AutoSetRunningFlag final {
573
    public:
574
      explicit AutoSetRunningFlag(CustomElementRegistry* aRegistry)
575
        : mRegistry(aRegistry)
576
0
      {
577
0
        MOZ_ASSERT(!mRegistry->mIsCustomDefinitionRunning,
578
0
                   "IsCustomDefinitionRunning flag should be initially false");
579
0
        mRegistry->mIsCustomDefinitionRunning = true;
580
0
      }
581
582
0
      ~AutoSetRunningFlag() {
583
0
        mRegistry->mIsCustomDefinitionRunning = false;
584
0
      }
585
586
    private:
587
      CustomElementRegistry* mRegistry;
588
  };
589
590
  int32_t InferNamespace(JSContext* aCx, JS::Handle<JSObject*> constructor);
591
592
public:
593
  nsISupports* GetParentObject() const;
594
595
  DocGroup* GetDocGroup() const;
596
597
  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
598
599
  void Define(JSContext* aCx, const nsAString& aName,
600
              Function& aFunctionConstructor,
601
              const ElementDefinitionOptions& aOptions, ErrorResult& aRv);
602
603
  void Get(JSContext* cx, const nsAString& name,
604
           JS::MutableHandle<JS::Value> aRetVal);
605
606
  already_AddRefed<Promise> WhenDefined(const nsAString& aName, ErrorResult& aRv);
607
608
  // Chrome-only method that give JS an opportunity to only load the custom
609
  // element definition script when needed.
610
  void SetElementCreationCallback(const nsAString& aName, CustomElementCreationCallback& aCallback, ErrorResult& aRv);
611
612
  void Upgrade(nsINode& aRoot);
613
};
614
615
class MOZ_RAII AutoCEReaction final {
616
  public:
617
    // JSContext is allowed to be a nullptr if we are guaranteeing that we're
618
    // not doing something that might throw but not finish reporting a JS
619
    // exception during the lifetime of the AutoCEReaction.
620
    AutoCEReaction(CustomElementReactionsStack* aReactionsStack, JSContext* aCx)
621
      : mReactionsStack(aReactionsStack)
622
      , mCx(aCx)
623
0
    {
624
0
      mIsElementQueuePushedForPreviousRecursionDepth =
625
0
        mReactionsStack->EnterCEReactions();
626
0
    }
627
628
    ~AutoCEReaction()
629
0
    {
630
0
      mReactionsStack->LeaveCEReactions(
631
0
        mCx, mIsElementQueuePushedForPreviousRecursionDepth);
632
0
    }
633
634
  private:
635
    RefPtr<CustomElementReactionsStack> mReactionsStack;
636
    JSContext* mCx;
637
    bool mIsElementQueuePushedForPreviousRecursionDepth;
638
};
639
640
} // namespace dom
641
} // namespace mozilla
642
643
644
#endif // mozilla_dom_CustomElementRegistry_h