Shaka Player Embedded
document.cc
Go to the documentation of this file.
1 // Copyright 2016 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/js/dom/document.h"
16 
17 #include "src/js/dom/attr.h"
18 #include "src/js/dom/comment.h"
19 #include "src/js/dom/element.h"
20 #include "src/js/dom/text.h"
22 #include "src/memory/heap_tracer.h"
23 #include "src/util/clock.h"
24 
25 namespace shaka {
26 namespace js {
27 namespace dom {
28 
29 namespace {
30 
31 constexpr const char* kXmlNamespace = "http://www.w3.org/XML/1998/namespace";
32 constexpr const char* kXmlNsNamespace = "http://www.w3.org/2000/xmlns/";
33 
34 } // namespace
35 
36 std::atomic<Document*> Document::instance_{nullptr};
37 
39  : ContainerNode(DOCUMENT_NODE, nullptr),
40  created_at_(util::Clock::Instance.GetMonotonicTime()) {}
41 
42 // \cond Doxygen_Skip
43 Document::~Document() {
44  // If "instance_" equals "this", replace with nullptr.
45  Document* temp = this;
46  instance_.compare_exchange_strong(temp, nullptr, std::memory_order_relaxed);
47 }
48 // \endcond Doxygen_Skip
49 
50 // static
52  Document* ret = instance_.load(std::memory_order_relaxed);
53  if (!ret) {
54  RefPtr<Document> doc = new Document();
55  // If "instance_" wasn't updated, this will change it to our new value. If
56  // "instance_" was changed, "ret" will be updated to match the new value.
57  if (instance_.compare_exchange_strong(ret, doc.get(),
58  std::memory_order_relaxed)) {
59  ret = doc.get();
60  }
61  }
62  return ret;
63 }
64 
65 std::string Document::node_name() const {
66  return "#document";
67 }
68 
70  return nullopt;
71 }
72 
74  return nullopt;
75 }
76 
78  for (auto& child : child_nodes()) {
79  if (child->is_element())
80  return static_cast<Element*>(child.get());
81  }
82  return nullptr;
83 }
84 
85 std::vector<RefPtr<Element>> Document::GetElementsByTagName(
86  const std::string& name) const {
87  // This exists so Shaka Player can request an arbitrary video element as part
88  // of shaka.util.Platform.
89  // TODO: Remove once we upgrade Shaka Player to avoid this.
90  if (name == "video")
93 }
94 
96  if (name == "video") {
97  // This should only be used in Shaka Player integration tests.
98  return new mse::HTMLVideoElement(this, nullptr);
99  }
100  return new Element(this, name, nullopt, nullopt);
101 }
102 
103 RefPtr<Comment> Document::CreateComment(const std::string& data) {
104  return new Comment(this, data);
105 }
106 
107 RefPtr<Text> Document::CreateTextNode(const std::string& data) {
108  return new Text(this, data);
109 }
110 
112  // TODO: Validate valid XML characters.
113  if (name.empty())
115 
116  return new Attr(this, nullptr, util::ToAsciiLower(name), nullopt, nullopt,
117  "");
118 }
119 
121  const std::string& namespace_uri, const std::string& qualified_name) {
122  // 1. If namespace is the empty string, set it to null.
124  !namespace_uri.empty() ? optional<std::string>(namespace_uri) : nullopt;
125 
126  // 2. Validate qualifiedName.
127  // TODO: Validate valid XML characters.
128  if (qualified_name.empty())
130 
131  // 3. Let prefix be null.
132  optional<std::string> prefix;
133 
134  // 4. Let localName be qualifiedName.
135  std::string local_name = qualified_name;
136 
137  // 5. If qualifiedName contains a ":" (U+003E), then split the string on it
138  // and set prefix to the part before and localName to the part after.
139  auto pos = local_name.find(':');
140  if (pos != std::string::npos) {
141  prefix = local_name.substr(0, pos);
142  local_name = local_name.substr(pos + 1);
143  }
144 
145  // 6. If prefix is non-null and namespace is null, then throw a
146  // "NamespaceError" DOMException.
147  if (prefix.has_value() && !ns.has_value())
149 
150  // 7. If prefix is "xml" and namespace is not the XML namespace, then throw a
151  // "NamespaceError" DOMException.
152  if (prefix == "xml" && namespace_uri != kXmlNamespace)
154 
155  // 8. If either qualifiedName or prefix is "xmlns" and namespace is not the
156  // XMLNS namespace, then throw a "NamespaceError" DOMException.
157  if (prefix == "xmlns" && namespace_uri != kXmlNsNamespace)
159 
160  // 9. If namespace is the XMLNS namespace and neither qualifiedName nor prefix
161  // is "xmlns", then throw a "NamespaceError" DOMException.
162  if (namespace_uri == kXmlNsNamespace && qualified_name != "xmlns" &&
163  prefix != "xmlns") {
165  }
166 
167  // 10. Return namespace, prefix, and localName.
168  return new Attr(this, nullptr, local_name, ns, prefix, "");
169 }
170 
171 
173  AddMemberFunction("createElement", &Document::CreateElement);
174  AddMemberFunction("createComment", &Document::CreateComment);
175  AddMemberFunction("createTextNode", &Document::CreateTextNode);
176  AddMemberFunction("createAttribute", &Document::CreateAttribute);
177  AddMemberFunction("createAttributeNS", &Document::CreateAttributeNS);
178 
179  AddGenericProperty("documentElement", &Document::DocumentElement);
180 
181  // TODO: Consider adding createEvent. Shaka Player only uses it in the
182  // Microsoft EME polyfill and the unit tests.
183  NotImplemented("createEvent");
184 
185  NotImplemented("createElementNS");
186  NotImplemented("createDocumentFragment");
187  NotImplemented("createCDATASection");
188  NotImplemented("createProcessingInstruction");
189 
190  NotImplemented("createRange");
191  NotImplemented("createNodeIterator");
192  NotImplemented("createTreeWalker");
193 
194  NotImplemented("importNode");
195  NotImplemented("adoptNode");
196 }
197 
198 } // namespace dom
199 } // namespace js
200 } // namespace shaka
std::string ToAsciiLower(const std::string &source)
Definition: utils.cc:76
std::vector< RefPtr< Element > > GetElementsByTagName(const std::string &name) const override
Definition: document.cc:85
RefPtr< Element > CreateElement(const std::string &name)
Definition: document.cc:95
RefPtr< Comment > CreateComment(const std::string &data)
Definition: document.cc:103
const nullopt_t nullopt
Definition: optional.cc:22
optional< std::string > TextContent() const override
Definition: document.cc:73
T * get() const
Definition: ref_ptr.h:125
RefPtr< Text > CreateTextNode(const std::string &data)
Definition: document.cc:107
static RefPtr< Document > EnsureGlobalDocument()
Definition: document.cc:51
virtual std::vector< RefPtr< Element > > GetElementsByTagName(const std::string &name) const
optional< std::string > NodeValue() const override
Definition: document.cc:69
RefPtr< Element > DocumentElement() const
Definition: document.cc:77
std::string node_name() const override
Definition: document.cc:65
static JsError DOMException(ExceptionCode code)
Definition: js_error.cc:115
std::vector< RefPtr< Node > > child_nodes() const
Definition: node.cc:55
ExceptionOr< RefPtr< Attr > > CreateAttribute(const std::string &name)
Definition: document.cc:111
static RefPtr< HTMLVideoElement > AnyVideoElement()
bool has_value() const
Definition: optional.h:143
ExceptionOr< RefPtr< Attr > > CreateAttributeNS(const std::string &namespace_uri, const std::string &qualified_name)
Definition: document.cc:120
std::string name() const