summaryrefslogtreecommitdiffstats
path: root/dom/base/DocumentOrShadowRoot.h
blob: 2092cd54f2a9b820fbc3706d3ec1fee006e0dcb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_DocumentOrShadowRoot_h__
#define mozilla_dom_DocumentOrShadowRoot_h__

#include "nsTArray.h"
#include "nsIdentifierMapEntry.h"
#include "nsContentListDeclarations.h"
#include "nsNameSpaceManager.h"
#include "mozilla/dom/NameSpaceConstants.h"

class nsContentList;
class nsINode;

namespace mozilla {
class StyleSheet;

namespace dom {

class StyleSheetList;
class ShadowRoot;

/**
 * A class meant to be shared by ShadowRoot and Document, that holds a list of
 * stylesheets.
 *
 * TODO(emilio, bug 1418159): In the future this should hold most of the
 * relevant style state, this should allow us to fix bug 548397.
 */
class DocumentOrShadowRoot
{
  enum class Kind {
    Document,
    ShadowRoot,
  };

public:
  explicit DocumentOrShadowRoot(nsIDocument*);
  explicit DocumentOrShadowRoot(mozilla::dom::ShadowRoot*);

  nsINode& AsNode()
  {
    return *mAsNode;
  }

  const nsINode& AsNode() const
  {
    return *mAsNode;
  }

  StyleSheet* SheetAt(size_t aIndex) const
  {
    return mStyleSheets.SafeElementAt(aIndex);
  }

  size_t SheetCount() const
  {
    return mStyleSheets.Length();
  }

  int32_t IndexOfSheet(const StyleSheet& aSheet) const
  {
    return mStyleSheets.IndexOf(&aSheet);
  }

  void InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
  {
    mStyleSheets.InsertElementAt(aIndex, &aSheet);
  }

  void RemoveSheet(StyleSheet& aSheet)
  {
    mStyleSheets.RemoveElement(&aSheet);
  }

  void AppendStyleSheet(StyleSheet& aSheet)
  {
    mStyleSheets.AppendElement(&aSheet);
  }

  StyleSheetList& EnsureDOMStyleSheets();

  Element* GetElementById(const nsAString& aElementId);

  /**
   * This method returns _all_ the elements in this scope which have id
   * aElementId, if there are any.  Otherwise it returns null.
   *
   * This is useful for stuff like QuerySelector optimization and such.
   */
  inline const nsTArray<Element*>*
  GetAllElementsForId(const nsAString& aElementId) const;

  already_AddRefed<nsContentList>
  GetElementsByTagName(const nsAString& aTagName)
  {
    return NS_GetContentList(&AsNode(), kNameSpaceID_Unknown, aTagName);
  }

  already_AddRefed<nsContentList>
  GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                         const nsAString& aLocalName);

  already_AddRefed<nsContentList>
  GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                         const nsAString& aLocalName,
                         mozilla::ErrorResult&);

  already_AddRefed<nsContentList>
  GetElementsByClassName(const nsAString& aClasses);

  ~DocumentOrShadowRoot() = default;

protected:
  nsIContent* Retarget(nsIContent* aContent) const;

  /**
   * If focused element's subtree root is this document or shadow root, return
   * focused element, otherwise, get the shadow host recursively until the
   * shadow host's subtree root is this document or shadow root.
   */
  Element* GetRetargetedFocusedElement();

  nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
  RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;

  /*
   * mIdentifierMap works as follows for IDs:
   * 1) Attribute changes affect the table immediately (removing and adding
   *    entries as needed).
   * 2) Removals from the DOM affect the table immediately
   * 3) Additions to the DOM always update existing entries for names, and add
   *    new ones for IDs.
   */
  nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;

  nsINode* mAsNode;
  const Kind mKind;
};

inline const nsTArray<Element*>*
DocumentOrShadowRoot::GetAllElementsForId(const nsAString& aElementId) const
{
  if (aElementId.IsEmpty()) {
    return nullptr;
  }

  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aElementId);
  return entry ? &entry->GetIdElements() : nullptr;
}

}

}

#endif