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"
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"
43 static PRLogModuleInfo
* gTrackElementLog
;
44 #define LOG(type, msg) PR_LOG(gTrackElementLog, type, msg)
46 #define LOG(type, msg)
49 // Replace the usual NS_IMPL_NS_NEW_HTML_ELEMENT(Track) so
50 // we can return an UnknownElement instead when pref'd off.
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
);
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
) },
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
)
83 if (!gTrackElementLog
) {
84 gTrackElementLog
= PR_NewLogModule("nsTrackElement");
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
)
105 HTMLTrackElement::GetKind(DOMString
& aKind
) const
107 GetEnumAttr(nsGkAtoms::kind
, kKindTableDefaultString
, aKind
);
111 HTMLTrackElement::OnChannelRedirect(nsIChannel
* aChannel
,
112 nsIChannel
* aNewChannel
,
115 NS_ASSERTION(aChannel
== mChannel
, "Channels should match!");
116 mChannel
= aNewChannel
;
120 HTMLTrackElement::WrapNode(JSContext
* aCx
)
122 return HTMLTrackElementBinding::Wrap(aCx
, this);
126 HTMLTrackElement::IsWebVTTEnabled()
128 // Our callee does not use its arguments.
129 return HTMLTrackElementBinding::ConstructorEnabled(nullptr, JS::NullPtr());
133 HTMLTrackElement::GetTrack()
143 HTMLTrackElement::CreateTextTrack()
145 nsString label
, srcLang
;
150 if (const nsAttrValue
* value
= GetParsedAttr(nsGkAtoms::kind
)) {
151 kind
= static_cast<TextTrackKind
>(value
->GetEnumValue());
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);
169 mMediaParent
->AddTextTrack(mTrack
);
174 HTMLTrackElement::ParseAttribute(int32_t aNamespaceID
,
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
,
192 HTMLTrackElement::LoadResource()
194 // Find our 'src' url
196 if (!GetAttr(kNameSpaceID_None
, nsGkAtoms::src
, src
)) {
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()));
207 mChannel
->Cancel(NS_BINDING_ABORTED
);
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
,
220 static_cast<Element
*>(this),
221 NS_LITERAL_CSTRING("text/vtt"), // mime type
224 nsContentUtils::GetContentPolicy(),
225 nsContentUtils::GetSecurityManager());
226 NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv
));
227 if (NS_CP_REJECTED(shouldLoad
)) {
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.
238 nsCOMPtr
<nsIChannel
> channel
;
239 nsCOMPtr
<nsILoadGroup
> loadGroup
= OwnerDoc()->GetDocumentLoadGroup();
240 rv
= NS_NewChannel(getter_AddRefs(channel
),
242 static_cast<Element
*>(this),
243 nsILoadInfo::SEC_NORMAL
,
244 nsIContentPolicy::TYPE_MEDIA
,
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
));
262 HTMLTrackElement::BindToTree(nsIDocument
* aDocument
,
264 nsIContent
* aBindingParent
,
265 bool aCompileEventHandlers
)
267 nsresult rv
= nsGenericHTMLElement::BindToTree(aDocument
,
270 aCompileEventHandlers
);
271 NS_ENSURE_SUCCESS(rv
, rv
);
277 LOG(PR_LOG_DEBUG
, ("Track Element bound to tree."));
278 if (!aParent
|| !aParent
->IsNodeOfType(nsINode::eMEDIA
)) {
282 // Store our parent so we can look up its frame for display.
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
));
299 HTMLTrackElement::UnbindFromTree(bool aDeep
, bool aNullParent
)
302 // mTrack can be null if HTMLTrackElement::LoadResource has never been
305 mMediaParent
->RemoveTextTrack(mTrack
);
308 mMediaParent
= nullptr;
312 nsGenericHTMLElement::UnbindFromTree(aDeep
, aNullParent
);
316 HTMLTrackElement::ReadyState() const
319 return TextTrackReadyState::NotLoaded
;
322 return mTrack
->ReadyState();
326 HTMLTrackElement::SetReadyState(uint16_t aReadyState
)
329 switch (aReadyState
) {
330 case TextTrackReadyState::Loaded
:
331 DispatchTrackRunnable(NS_LITERAL_STRING("load"));
333 case TextTrackReadyState::FailedToLoad
:
334 DispatchTrackRunnable(NS_LITERAL_STRING("error"));
337 mTrack
->SetReadyState(aReadyState
);
342 HTMLTrackElement::DispatchTrackRunnable(const nsString
& aEventName
)
344 nsCOMPtr
<nsIRunnable
> runnable
=
345 NS_NewRunnableMethodWithArg
346 <const nsString
>(this,
347 &HTMLTrackElement::DispatchTrustedEvent
,
349 NS_DispatchToMainThread(runnable
);
353 HTMLTrackElement::DispatchTrustedEvent(const nsAString
& aName
)
355 nsIDocument
* doc
= OwnerDoc();
359 nsContentUtils::DispatchTrustedEvent(doc
, static_cast<nsIContent
*>(this),
360 aName
, false, false);
364 HTMLTrackElement::DropChannel()
370 } // namespace mozilla