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 "WebVTTListener.h"
7 #include "mozilla/CycleCollectedJSContext.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/HTMLTrackElement.h"
10 #include "mozilla/dom/TextTrackCue.h"
11 #include "mozilla/dom/TextTrackRegion.h"
12 #include "mozilla/dom/VTTRegionBinding.h"
13 #include "nsComponentManagerUtils.h"
14 #include "nsIAsyncVerifyRedirectCallback.h"
15 #include "nsIInputStream.h"
17 extern mozilla::LazyLogModule gTextTrackLog
;
18 #define LOG(msg, ...) \
19 MOZ_LOG(gTextTrackLog, LogLevel::Debug, \
20 ("WebVTTListener=%p, " msg, this, ##__VA_ARGS__))
21 #define LOG_WIHTOUT_ADDRESS(msg, ...) \
22 MOZ_LOG(gTextTrackLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
24 namespace mozilla::dom
{
26 NS_IMPL_CYCLE_COLLECTION(WebVTTListener
, mElement
, mParserWrapper
)
28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebVTTListener
)
29 NS_INTERFACE_MAP_ENTRY(nsIWebVTTListener
)
30 NS_INTERFACE_MAP_ENTRY(nsIStreamListener
)
31 NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink
)
32 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
33 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIWebVTTListener
)
36 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebVTTListener
)
37 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebVTTListener
)
39 WebVTTListener::WebVTTListener(HTMLTrackElement
* aElement
)
40 : mElement(aElement
), mParserWrapperError(NS_OK
) {
41 MOZ_ASSERT(mElement
, "Must pass an element to the callback");
42 LOG("Created listener for track element %p", aElement
);
43 MOZ_DIAGNOSTIC_ASSERT(
44 CycleCollectedJSContext::Get() &&
45 !CycleCollectedJSContext::Get()->IsInStableOrMetaStableState());
46 mParserWrapper
= do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID
,
47 &mParserWrapperError
);
48 if (NS_SUCCEEDED(mParserWrapperError
)) {
49 nsPIDOMWindowInner
* window
= mElement
->OwnerDoc()->GetInnerWindow();
50 mParserWrapperError
= mParserWrapper
->LoadParser(window
);
52 if (NS_SUCCEEDED(mParserWrapperError
)) {
53 mParserWrapperError
= mParserWrapper
->Watch(this);
57 WebVTTListener::~WebVTTListener() { LOG("destroyed."); }
60 WebVTTListener::GetInterface(const nsIID
& aIID
, void** aResult
) {
61 return QueryInterface(aIID
, aResult
);
64 nsresult
WebVTTListener::LoadResource() {
68 // Exit if we failed to create the WebVTTParserWrapper (vtt.sys.mjs)
69 NS_ENSURE_SUCCESS(mParserWrapperError
, mParserWrapperError
);
71 mElement
->SetReadyState(TextTrackReadyState::Loading
);
76 WebVTTListener::AsyncOnChannelRedirect(nsIChannel
* aOldChannel
,
77 nsIChannel
* aNewChannel
, uint32_t aFlags
,
78 nsIAsyncVerifyRedirectCallback
* cb
) {
83 mElement
->OnChannelRedirect(aOldChannel
, aNewChannel
, aFlags
);
85 cb
->OnRedirectVerifyCallback(NS_OK
);
90 WebVTTListener::OnStartRequest(nsIRequest
* aRequest
) {
95 LOG("OnStartRequest");
96 mElement
->DispatchTestEvent(u
"mozStartedLoadingTextTrack"_ns
);
101 WebVTTListener::OnStopRequest(nsIRequest
* aRequest
, nsresult aStatus
) {
106 LOG("OnStopRequest");
107 if (NS_FAILED(aStatus
)) {
108 LOG("Got error status");
109 mElement
->SetReadyState(TextTrackReadyState::FailedToLoad
);
111 // Attempt to parse any final data the parser might still have.
112 mParserWrapper
->Flush();
113 if (mElement
->ReadyState() != TextTrackReadyState::FailedToLoad
) {
114 mElement
->SetReadyState(TextTrackReadyState::Loaded
);
117 // Prevent canceling the channel and listener if RFP is enabled.
118 mElement
->CancelChannelAndListener(true);
123 nsresult
WebVTTListener::ParseChunk(nsIInputStream
* aInStream
, void* aClosure
,
124 const char* aFromSegment
,
125 uint32_t aToOffset
, uint32_t aCount
,
126 uint32_t* aWriteCount
) {
127 nsCString
buffer(aFromSegment
, aCount
);
128 WebVTTListener
* listener
= static_cast<WebVTTListener
*>(aClosure
);
129 MOZ_ASSERT(!listener
->IsCanceled());
131 if (NS_FAILED(listener
->mParserWrapper
->Parse(buffer
))) {
133 "WebVTTListener=%p, Unable to parse chunk of WEBVTT text. Aborting.",
136 return NS_ERROR_FAILURE
;
139 *aWriteCount
= aCount
;
144 WebVTTListener::OnDataAvailable(nsIRequest
* aRequest
, nsIInputStream
* aStream
,
145 uint64_t aOffset
, uint32_t aCount
) {
150 LOG("OnDataAvailable");
151 uint32_t count
= aCount
;
154 nsresult rv
= aStream
->ReadSegments(ParseChunk
, this, count
, &read
);
155 NS_ENSURE_SUCCESS(rv
, rv
);
157 return NS_ERROR_FAILURE
;
166 WebVTTListener::OnCue(JS::Handle
<JS::Value
> aCue
, JSContext
* aCx
) {
167 MOZ_ASSERT(!IsCanceled());
168 if (!aCue
.isObject()) {
169 return NS_ERROR_FAILURE
;
172 JS::Rooted
<JSObject
*> obj(aCx
, &aCue
.toObject());
173 TextTrackCue
* cue
= nullptr;
174 nsresult rv
= UNWRAP_OBJECT(VTTCue
, &obj
, cue
);
175 NS_ENSURE_SUCCESS(rv
, rv
);
177 cue
->SetTrackElement(mElement
);
178 mElement
->mTrack
->AddCue(*cue
);
184 WebVTTListener::OnRegion(JS::Handle
<JS::Value
> aRegion
, JSContext
* aCx
) {
185 MOZ_ASSERT(!IsCanceled());
186 // Nothing for this callback to do.
191 WebVTTListener::OnParsingError(int32_t errorCode
, JSContext
* cx
) {
192 MOZ_ASSERT(!IsCanceled());
193 // We only care about files that have a bad WebVTT file signature right now
194 // as that means the file failed to load.
195 if (errorCode
== ErrorCodes::BadSignature
) {
196 LOG("parsing error");
197 mElement
->SetReadyState(TextTrackReadyState::FailedToLoad
);
202 bool WebVTTListener::IsCanceled() const { return mCancel
; }
204 void WebVTTListener::Cancel() {
205 MOZ_ASSERT(!IsCanceled(), "Do not cancel canceled listener again!");
206 LOG("Cancel listen to channel's response.");
208 mParserWrapper
->Cancel();
209 mParserWrapper
= nullptr;
213 } // namespace mozilla::dom