michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "WebVTTListener.h" michael@0: #include "mozilla/dom/TextTrackCue.h" michael@0: #include "mozilla/dom/TextTrackRegion.h" michael@0: #include "mozilla/dom/VTTRegionBinding.h" michael@0: #include "mozilla/dom/HTMLTrackElement.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIWebVTTParserWrapper.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION(WebVTTListener, mElement, mParserWrapper) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebVTTListener) michael@0: NS_INTERFACE_MAP_ENTRY(nsIWebVTTListener) michael@0: NS_INTERFACE_MAP_ENTRY(nsIStreamListener) michael@0: NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) michael@0: NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebVTTListener) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(WebVTTListener) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(WebVTTListener) michael@0: michael@0: #ifdef PR_LOGGING michael@0: PRLogModuleInfo* gTextTrackLog; michael@0: # define VTT_LOG(...) PR_LOG(gTextTrackLog, PR_LOG_DEBUG, (__VA_ARGS__)) michael@0: #else michael@0: # define VTT_LOG(msg) michael@0: #endif michael@0: michael@0: WebVTTListener::WebVTTListener(HTMLTrackElement* aElement) michael@0: : mElement(aElement) michael@0: { michael@0: MOZ_ASSERT(mElement, "Must pass an element to the callback"); michael@0: #ifdef PR_LOGGING michael@0: if (!gTextTrackLog) { michael@0: gTextTrackLog = PR_NewLogModule("TextTrack"); michael@0: } michael@0: #endif michael@0: VTT_LOG("WebVTTListener created."); michael@0: } michael@0: michael@0: WebVTTListener::~WebVTTListener() michael@0: { michael@0: VTT_LOG("WebVTTListener destroyed."); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::GetInterface(const nsIID &aIID, michael@0: void** aResult) michael@0: { michael@0: return QueryInterface(aIID, aResult); michael@0: } michael@0: michael@0: nsresult michael@0: WebVTTListener::LoadResource() michael@0: { michael@0: if (!HTMLTrackElement::IsWebVTTEnabled()) { michael@0: NS_WARNING("WebVTT support disabled." michael@0: " See media.webvtt.enabled in about:config. "); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: nsresult rv; michael@0: mParserWrapper = do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsPIDOMWindow* window = mElement->OwnerDoc()->GetWindow(); michael@0: rv = mParserWrapper->LoadParser(window); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = mParserWrapper->Watch(this); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mElement->SetReadyState(TextTrackReadyState::Loading); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::AsyncOnChannelRedirect(nsIChannel* aOldChannel, michael@0: nsIChannel* aNewChannel, michael@0: uint32_t aFlags, michael@0: nsIAsyncVerifyRedirectCallback* cb) michael@0: { michael@0: if (mElement) { michael@0: mElement->OnChannelRedirect(aOldChannel, aNewChannel, aFlags); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::OnStartRequest(nsIRequest* aRequest, michael@0: nsISupports* aContext) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::OnStopRequest(nsIRequest* aRequest, michael@0: nsISupports* aContext, michael@0: nsresult aStatus) michael@0: { michael@0: if (NS_FAILED(aStatus)) { michael@0: mElement->SetReadyState(TextTrackReadyState::FailedToLoad); michael@0: } michael@0: // Attempt to parse any final data the parser might still have. michael@0: mParserWrapper->Flush(); michael@0: if (mElement->ReadyState() != TextTrackReadyState::FailedToLoad) { michael@0: mElement->SetReadyState(TextTrackReadyState::Loaded); michael@0: } michael@0: return aStatus; michael@0: } michael@0: michael@0: NS_METHOD michael@0: WebVTTListener::ParseChunk(nsIInputStream* aInStream, void* aClosure, michael@0: const char* aFromSegment, uint32_t aToOffset, michael@0: uint32_t aCount, uint32_t* aWriteCount) michael@0: { michael@0: nsCString buffer(aFromSegment, aCount); michael@0: WebVTTListener* listener = static_cast(aClosure); michael@0: michael@0: if (NS_FAILED(listener->mParserWrapper->Parse(buffer))) { michael@0: VTT_LOG("Unable to parse chunk of WEBVTT text. Aborting."); michael@0: *aWriteCount = 0; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: *aWriteCount = aCount; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::OnDataAvailable(nsIRequest* aRequest, michael@0: nsISupports* aContext, michael@0: nsIInputStream* aStream, michael@0: uint64_t aOffset, michael@0: uint32_t aCount) michael@0: { michael@0: uint32_t count = aCount; michael@0: while (count > 0) { michael@0: uint32_t read; michael@0: nsresult rv = aStream->ReadSegments(ParseChunk, this, count, &read); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (!read) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: count -= read; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::OnCue(JS::Handle aCue, JSContext* aCx) michael@0: { michael@0: if (!aCue.isObject()) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: TextTrackCue* cue; michael@0: nsresult rv = UNWRAP_OBJECT(VTTCue, &aCue.toObject(), cue); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: cue->SetTrackElement(mElement); michael@0: mElement->mTrack->AddCue(*cue); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::OnRegion(JS::Handle aRegion, JSContext* aCx) michael@0: { michael@0: // Nothing for this callback to do. michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebVTTListener::OnParsingError(int32_t errorCode, JSContext* cx) michael@0: { michael@0: // We only care about files that have a bad WebVTT file signature right now michael@0: // as that means the file failed to load. michael@0: if (errorCode == ErrorCodes::BadSignature) { michael@0: mElement->SetReadyState(TextTrackReadyState::FailedToLoad); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla