Bumping gaia.json for 8 gaia revision(s) a=gaia-bump
[gecko.git] / dom / html / HTMLTrackElement.cpp
blob315687789c412f3422cbf5a1ad820b0eab62569c
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/dom/Element.h"
7 #include "mozilla/dom/HTMLMediaElement.h"
8 #include "mozilla/dom/HTMLTrackElement.h"
9 #include "mozilla/dom/HTMLTrackElementBinding.h"
10 #include "mozilla/dom/HTMLUnknownElement.h"
11 #include "nsIContentPolicy.h"
12 #include "mozilla/LoadInfo.h"
13 #include "WebVTTListener.h"
14 #include "nsAttrValueInlines.h"
15 #include "nsCOMPtr.h"
16 #include "nsContentPolicyUtils.h"
17 #include "nsContentUtils.h"
18 #include "nsCycleCollectionParticipant.h"
19 #include "nsGenericHTMLElement.h"
20 #include "nsGkAtoms.h"
21 #include "nsIAsyncVerifyRedirectCallback.h"
22 #include "nsICachingChannel.h"
23 #include "nsIChannelEventSink.h"
24 #include "nsIContentPolicy.h"
25 #include "nsIContentSecurityPolicy.h"
26 #include "nsIDocument.h"
27 #include "nsIDOMEventTarget.h"
28 #include "nsIDOMHTMLMediaElement.h"
29 #include "nsIHttpChannel.h"
30 #include "nsIInterfaceRequestor.h"
31 #include "nsILoadGroup.h"
32 #include "nsIObserver.h"
33 #include "nsIStreamListener.h"
34 #include "nsISupportsImpl.h"
35 #include "nsMappedAttributes.h"
36 #include "nsNetUtil.h"
37 #include "nsRuleData.h"
38 #include "nsStyleConsts.h"
39 #include "nsThreadUtils.h"
40 #include "nsVideoFrame.h"
42 #ifdef PR_LOGGING
43 static PRLogModuleInfo* gTrackElementLog;
44 #define LOG(type, msg) PR_LOG(gTrackElementLog, type, msg)
45 #else
46 #define LOG(type, msg)
47 #endif
49 // Replace the usual NS_IMPL_NS_NEW_HTML_ELEMENT(Track) so
50 // we can return an UnknownElement instead when pref'd off.
51 nsGenericHTMLElement*
52 NS_NewHTMLTrackElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
53 mozilla::dom::FromParser aFromParser)
55 if (!mozilla::dom::HTMLTrackElement::IsWebVTTEnabled()) {
56 return new mozilla::dom::HTMLUnknownElement(aNodeInfo);
59 return new mozilla::dom::HTMLTrackElement(aNodeInfo);
62 namespace mozilla {
63 namespace dom {
65 // Map html attribute string values to TextTrackKind enums.
66 static MOZ_CONSTEXPR nsAttrValue::EnumTable kKindTable[] = {
67 { "subtitles", static_cast<int16_t>(TextTrackKind::Subtitles) },
68 { "captions", static_cast<int16_t>(TextTrackKind::Captions) },
69 { "descriptions", static_cast<int16_t>(TextTrackKind::Descriptions) },
70 { "chapters", static_cast<int16_t>(TextTrackKind::Chapters) },
71 { "metadata", static_cast<int16_t>(TextTrackKind::Metadata) },
72 { 0 }
75 // The default value for kKindTable is "subtitles"
76 static MOZ_CONSTEXPR const char* kKindTableDefaultString = kKindTable->tag;
78 /** HTMLTrackElement */
79 HTMLTrackElement::HTMLTrackElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
80 : nsGenericHTMLElement(aNodeInfo)
82 #ifdef PR_LOGGING
83 if (!gTrackElementLog) {
84 gTrackElementLog = PR_NewLogModule("nsTrackElement");
86 #endif
89 HTMLTrackElement::~HTMLTrackElement()
93 NS_IMPL_ELEMENT_CLONE(HTMLTrackElement)
95 NS_IMPL_ADDREF_INHERITED(HTMLTrackElement, Element)
96 NS_IMPL_RELEASE_INHERITED(HTMLTrackElement, Element)
98 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLTrackElement, nsGenericHTMLElement,
99 mTrack, mMediaParent, mListener)
101 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTrackElement)
102 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
104 void
105 HTMLTrackElement::GetKind(DOMString& aKind) const
107 GetEnumAttr(nsGkAtoms::kind, kKindTableDefaultString, aKind);
110 void
111 HTMLTrackElement::OnChannelRedirect(nsIChannel* aChannel,
112 nsIChannel* aNewChannel,
113 uint32_t aFlags)
115 NS_ASSERTION(aChannel == mChannel, "Channels should match!");
116 mChannel = aNewChannel;
119 JSObject*
120 HTMLTrackElement::WrapNode(JSContext* aCx)
122 return HTMLTrackElementBinding::Wrap(aCx, this);
125 bool
126 HTMLTrackElement::IsWebVTTEnabled()
128 // Our callee does not use its arguments.
129 return HTMLTrackElementBinding::ConstructorEnabled(nullptr, JS::NullPtr());
132 TextTrack*
133 HTMLTrackElement::GetTrack()
135 if (!mTrack) {
136 CreateTextTrack();
139 return mTrack;
142 void
143 HTMLTrackElement::CreateTextTrack()
145 nsString label, srcLang;
146 GetSrclang(srcLang);
147 GetLabel(label);
149 TextTrackKind kind;
150 if (const nsAttrValue* value = GetParsedAttr(nsGkAtoms::kind)) {
151 kind = static_cast<TextTrackKind>(value->GetEnumValue());
152 } else {
153 kind = TextTrackKind::Subtitles;
156 nsISupports* parentObject =
157 OwnerDoc()->GetParentObject();
159 NS_ENSURE_TRUE_VOID(parentObject);
161 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(parentObject);
162 mTrack = new TextTrack(window, kind, label, srcLang,
163 TextTrackMode::Disabled,
164 TextTrackReadyState::NotLoaded,
165 TextTrackSource::Track);
166 mTrack->SetTrackElement(this);
168 if (mMediaParent) {
169 mMediaParent->AddTextTrack(mTrack);
173 bool
174 HTMLTrackElement::ParseAttribute(int32_t aNamespaceID,
175 nsIAtom* aAttribute,
176 const nsAString& aValue,
177 nsAttrValue& aResult)
179 if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::kind) {
180 // Case-insensitive lookup, with the first element as the default.
181 return aResult.ParseEnumValue(aValue, kKindTable, false, kKindTable);
184 // Otherwise call the generic implementation.
185 return nsGenericHTMLElement::ParseAttribute(aNamespaceID,
186 aAttribute,
187 aValue,
188 aResult);
191 void
192 HTMLTrackElement::LoadResource()
194 // Find our 'src' url
195 nsAutoString src;
196 if (!GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
197 return;
200 nsCOMPtr<nsIURI> uri;
201 nsresult rv = NewURIFromString(src, getter_AddRefs(uri));
202 NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
203 LOG(PR_LOG_ALWAYS, ("%p Trying to load from src=%s", this,
204 NS_ConvertUTF16toUTF8(src).get()));
206 if (mChannel) {
207 mChannel->Cancel(NS_BINDING_ABORTED);
208 mChannel = nullptr;
211 rv = nsContentUtils::GetSecurityManager()->
212 CheckLoadURIWithPrincipal(NodePrincipal(), uri,
213 nsIScriptSecurityManager::STANDARD);
214 NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
216 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
217 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_MEDIA,
218 uri,
219 NodePrincipal(),
220 static_cast<Element*>(this),
221 NS_LITERAL_CSTRING("text/vtt"), // mime type
222 nullptr, // extra
223 &shouldLoad,
224 nsContentUtils::GetContentPolicy(),
225 nsContentUtils::GetSecurityManager());
226 NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
227 if (NS_CP_REJECTED(shouldLoad)) {
228 return;
231 // We may already have a TextTrack at this point if GetTrack() has already
232 // been called. This happens, for instance, if script tries to get the
233 // TextTrack before its mTrackElement has been bound to the DOM tree.
234 if (!mTrack) {
235 CreateTextTrack();
238 nsCOMPtr<nsIChannel> channel;
239 nsCOMPtr<nsILoadGroup> loadGroup = OwnerDoc()->GetDocumentLoadGroup();
240 rv = NS_NewChannel(getter_AddRefs(channel),
241 uri,
242 static_cast<Element*>(this),
243 nsILoadInfo::SEC_NORMAL,
244 nsIContentPolicy::TYPE_MEDIA,
245 loadGroup);
247 NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
249 mListener = new WebVTTListener(this);
250 rv = mListener->LoadResource();
251 NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
252 channel->SetNotificationCallbacks(mListener);
254 LOG(PR_LOG_DEBUG, ("opening webvtt channel"));
255 rv = channel->AsyncOpen(mListener, nullptr);
256 NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
258 mChannel = channel;
261 nsresult
262 HTMLTrackElement::BindToTree(nsIDocument* aDocument,
263 nsIContent* aParent,
264 nsIContent* aBindingParent,
265 bool aCompileEventHandlers)
267 nsresult rv = nsGenericHTMLElement::BindToTree(aDocument,
268 aParent,
269 aBindingParent,
270 aCompileEventHandlers);
271 NS_ENSURE_SUCCESS(rv, rv);
273 if (!aDocument) {
274 return NS_OK;
277 LOG(PR_LOG_DEBUG, ("Track Element bound to tree."));
278 if (!aParent || !aParent->IsNodeOfType(nsINode::eMEDIA)) {
279 return NS_OK;
282 // Store our parent so we can look up its frame for display.
283 if (!mMediaParent) {
284 mMediaParent = static_cast<HTMLMediaElement*>(aParent);
286 HTMLMediaElement* media = static_cast<HTMLMediaElement*>(aParent);
287 // TODO: separate notification for 'alternate' tracks?
288 media->NotifyAddedSource();
289 LOG(PR_LOG_DEBUG, ("Track element sent notification to parent."));
291 mMediaParent->RunInStableState(
292 NS_NewRunnableMethod(this, &HTMLTrackElement::LoadResource));
295 return NS_OK;
298 void
299 HTMLTrackElement::UnbindFromTree(bool aDeep, bool aNullParent)
301 if (mMediaParent) {
302 // mTrack can be null if HTMLTrackElement::LoadResource has never been
303 // called.
304 if (mTrack) {
305 mMediaParent->RemoveTextTrack(mTrack);
307 if (aNullParent) {
308 mMediaParent = nullptr;
312 nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
315 uint16_t
316 HTMLTrackElement::ReadyState() const
318 if (!mTrack) {
319 return TextTrackReadyState::NotLoaded;
322 return mTrack->ReadyState();
325 void
326 HTMLTrackElement::SetReadyState(uint16_t aReadyState)
328 if (mTrack) {
329 switch (aReadyState) {
330 case TextTrackReadyState::Loaded:
331 DispatchTrackRunnable(NS_LITERAL_STRING("load"));
332 break;
333 case TextTrackReadyState::FailedToLoad:
334 DispatchTrackRunnable(NS_LITERAL_STRING("error"));
335 break;
337 mTrack->SetReadyState(aReadyState);
341 void
342 HTMLTrackElement::DispatchTrackRunnable(const nsString& aEventName)
344 nsCOMPtr<nsIRunnable> runnable =
345 NS_NewRunnableMethodWithArg
346 <const nsString>(this,
347 &HTMLTrackElement::DispatchTrustedEvent,
348 aEventName);
349 NS_DispatchToMainThread(runnable);
352 void
353 HTMLTrackElement::DispatchTrustedEvent(const nsAString& aName)
355 nsIDocument* doc = OwnerDoc();
356 if (!doc) {
357 return;
359 nsContentUtils::DispatchTrustedEvent(doc, static_cast<nsIContent*>(this),
360 aName, false, false);
363 void
364 HTMLTrackElement::DropChannel()
366 mChannel = nullptr;
369 } // namespace dom
370 } // namespace mozilla