2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2013-05-21 20:14:00 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2018-12-13 23:06:02 +03:00
|
|
|
#include "mozilla/dom/HTMLTrackElement.h"
|
2013-05-21 20:14:00 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
|
|
|
#include "mozilla/dom/HTMLMediaElement.h"
|
2020-11-09 18:47:07 +03:00
|
|
|
#include "mozilla/dom/WebVTTListener.h"
|
2018-12-13 23:06:02 +03:00
|
|
|
#include "mozilla/LoadInfo.h"
|
2019-07-26 04:10:23 +03:00
|
|
|
#include "mozilla/StaticPrefs_media.h"
|
2013-05-21 20:14:00 +04:00
|
|
|
#include "mozilla/dom/HTMLTrackElementBinding.h"
|
|
|
|
#include "mozilla/dom/HTMLUnknownElement.h"
|
|
|
|
#include "nsAttrValueInlines.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsContentPolicyUtils.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsCycleCollectionParticipant.h"
|
|
|
|
#include "nsGenericHTMLElement.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsIContentPolicy.h"
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2013-05-21 20:14:00 +04:00
|
|
|
#include "nsILoadGroup.h"
|
|
|
|
#include "nsIObserver.h"
|
2020-02-11 03:41:14 +03:00
|
|
|
#include "nsIScriptError.h"
|
2013-05-21 20:14:00 +04:00
|
|
|
#include "nsISupportsImpl.h"
|
2016-08-05 10:13:36 +03:00
|
|
|
#include "nsISupportsPrimitives.h"
|
2013-05-21 20:14:00 +04:00
|
|
|
#include "nsMappedAttributes.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsVideoFrame.h"
|
|
|
|
|
2019-07-03 09:50:04 +03:00
|
|
|
extern mozilla::LazyLogModule gTextTrackLog;
|
|
|
|
#define LOG(msg, ...) \
|
|
|
|
MOZ_LOG(gTextTrackLog, LogLevel::Verbose, \
|
2019-05-24 03:41:21 +03:00
|
|
|
("TextTrackElement=%p, " msg, this, ##__VA_ARGS__))
|
2013-05-21 20:14:00 +04:00
|
|
|
|
|
|
|
// Replace the usual NS_IMPL_NS_NEW_HTML_ELEMENT(Track) so
|
|
|
|
// we can return an UnknownElement instead when pref'd off.
|
2014-06-20 06:01:40 +04:00
|
|
|
nsGenericHTMLElement* NS_NewHTMLTrackElement(
|
|
|
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
2013-05-21 20:14:00 +04:00
|
|
|
mozilla::dom::FromParser aFromParser) {
|
2020-03-17 17:53:08 +03:00
|
|
|
RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
|
|
|
|
auto* nim = nodeInfo->NodeInfoManager();
|
|
|
|
return new (nim) mozilla::dom::HTMLTrackElement(nodeInfo.forget());
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
2020-11-04 20:04:01 +03:00
|
|
|
namespace mozilla::dom {
|
2013-05-21 20:14:00 +04:00
|
|
|
|
2014-02-22 07:06:48 +04:00
|
|
|
// Map html attribute string values to TextTrackKind enums.
|
2016-07-09 00:39:53 +03:00
|
|
|
static constexpr nsAttrValue::EnumTable kKindTable[] = {
|
2014-02-22 07:06:48 +04:00
|
|
|
{"subtitles", static_cast<int16_t>(TextTrackKind::Subtitles)},
|
|
|
|
{"captions", static_cast<int16_t>(TextTrackKind::Captions)},
|
|
|
|
{"descriptions", static_cast<int16_t>(TextTrackKind::Descriptions)},
|
|
|
|
{"chapters", static_cast<int16_t>(TextTrackKind::Chapters)},
|
|
|
|
{"metadata", static_cast<int16_t>(TextTrackKind::Metadata)},
|
2016-09-07 05:20:17 +03:00
|
|
|
{nullptr, 0}};
|
2014-02-22 07:06:48 +04:00
|
|
|
|
2016-05-08 14:46:20 +03:00
|
|
|
// Invalid values are treated as "metadata" in ParseAttribute, but if no value
|
|
|
|
// at all is specified, it's treated as "subtitles" in GetKind
|
2017-10-15 04:09:05 +03:00
|
|
|
static const nsAttrValue::EnumTable* const kKindTableInvalidValueDefault =
|
|
|
|
&kKindTable[4];
|
2013-07-04 22:16:05 +04:00
|
|
|
|
2016-08-05 10:13:36 +03:00
|
|
|
class WindowDestroyObserver final : public nsIObserver {
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit WindowDestroyObserver(HTMLTrackElement* aElement, uint64_t aWinID)
|
|
|
|
: mTrackElement(aElement), mInnerID(aWinID) {
|
|
|
|
RegisterWindowDestroyObserver();
|
|
|
|
}
|
|
|
|
void RegisterWindowDestroyObserver() {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->AddObserver(this, "inner-window-destroyed", false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void UnRegisterWindowDestroyObserver() {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->RemoveObserver(this, "inner-window-destroyed");
|
|
|
|
}
|
|
|
|
mTrackElement = nullptr;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData) override {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (strcmp(aTopic, "inner-window-destroyed") == 0) {
|
|
|
|
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
|
|
|
|
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
|
|
|
|
uint64_t innerID;
|
|
|
|
nsresult rv = wrapper->GetData(&innerID);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (innerID == mInnerID) {
|
|
|
|
if (mTrackElement) {
|
2019-07-04 02:27:12 +03:00
|
|
|
mTrackElement->CancelChannelAndListener();
|
2016-08-05 10:13:36 +03:00
|
|
|
}
|
|
|
|
UnRegisterWindowDestroyObserver();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-02-20 19:19:15 +03:00
|
|
|
~WindowDestroyObserver() = default;
|
|
|
|
|
2016-08-05 10:13:36 +03:00
|
|
|
HTMLTrackElement* mTrackElement;
|
|
|
|
uint64_t mInnerID;
|
|
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(WindowDestroyObserver, nsIObserver);
|
|
|
|
|
2013-05-21 20:14:00 +04:00
|
|
|
/** HTMLTrackElement */
|
2018-09-21 23:45:49 +03:00
|
|
|
HTMLTrackElement::HTMLTrackElement(
|
|
|
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
|
|
|
|
: nsGenericHTMLElement(std::move(aNodeInfo)),
|
2020-05-11 10:47:22 +03:00
|
|
|
mLoadResourceDispatched(false),
|
2016-10-12 12:26:20 +03:00
|
|
|
mWindowDestroyObserver(nullptr) {
|
2016-08-17 04:11:42 +03:00
|
|
|
nsISupports* parentObject = OwnerDoc()->GetParentObject();
|
|
|
|
NS_ENSURE_TRUE_VOID(parentObject);
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(parentObject);
|
2016-10-12 12:26:20 +03:00
|
|
|
if (window) {
|
|
|
|
mWindowDestroyObserver =
|
|
|
|
new WindowDestroyObserver(this, window->WindowID());
|
|
|
|
}
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
HTMLTrackElement::~HTMLTrackElement() {
|
2016-08-05 10:13:36 +03:00
|
|
|
if (mWindowDestroyObserver) {
|
|
|
|
mWindowDestroyObserver->UnRegisterWindowDestroyObserver();
|
|
|
|
}
|
2019-07-04 02:27:12 +03:00
|
|
|
CancelChannelAndListener();
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ELEMENT_CLONE(HTMLTrackElement)
|
|
|
|
|
2014-04-25 20:49:00 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLTrackElement, nsGenericHTMLElement,
|
2014-06-19 00:10:24 +04:00
|
|
|
mTrack, mMediaParent, mListener)
|
2013-05-21 20:14:00 +04:00
|
|
|
|
2017-10-03 02:42:09 +03:00
|
|
|
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLTrackElement,
|
|
|
|
nsGenericHTMLElement)
|
2013-05-21 20:14:00 +04:00
|
|
|
|
2013-07-04 22:16:05 +04:00
|
|
|
void HTMLTrackElement::GetKind(DOMString& aKind) const {
|
2016-05-08 14:46:20 +03:00
|
|
|
GetEnumAttr(nsGkAtoms::kind, kKindTable[0].tag, aKind);
|
2013-07-04 22:16:05 +04:00
|
|
|
}
|
|
|
|
|
2013-06-10 19:30:00 +04:00
|
|
|
void HTMLTrackElement::OnChannelRedirect(nsIChannel* aChannel,
|
|
|
|
nsIChannel* aNewChannel,
|
|
|
|
uint32_t aFlags) {
|
|
|
|
NS_ASSERTION(aChannel == mChannel, "Channels should match!");
|
|
|
|
mChannel = aNewChannel;
|
|
|
|
}
|
|
|
|
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
JSObject* HTMLTrackElement::WrapNode(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGivenProto) {
|
2018-06-26 00:20:54 +03:00
|
|
|
return HTMLTrackElement_Binding::Wrap(aCx, this, aGivenProto);
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
2014-04-07 21:58:38 +04:00
|
|
|
TextTrack* HTMLTrackElement::GetTrack() {
|
2013-05-21 20:14:00 +04:00
|
|
|
if (!mTrack) {
|
2014-01-28 00:17:20 +04:00
|
|
|
CreateTextTrack();
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
return mTrack;
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLTrackElement::CreateTextTrack() {
|
2020-02-11 03:41:14 +03:00
|
|
|
nsISupports* parentObject = OwnerDoc()->GetParentObject();
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(parentObject);
|
|
|
|
if (!parentObject) {
|
|
|
|
nsContentUtils::ReportToConsole(
|
2020-07-01 11:29:29 +03:00
|
|
|
nsIScriptError::errorFlag, "Media"_ns, OwnerDoc(),
|
2020-02-11 03:41:14 +03:00
|
|
|
nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"Using track element in non-window context");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-24 06:57:00 +04:00
|
|
|
nsString label, srcLang;
|
2013-05-21 20:14:00 +04:00
|
|
|
GetSrclang(srcLang);
|
|
|
|
GetLabel(label);
|
|
|
|
|
2013-07-04 22:16:05 +04:00
|
|
|
TextTrackKind kind;
|
|
|
|
if (const nsAttrValue* value = GetParsedAttr(nsGkAtoms::kind)) {
|
|
|
|
kind = static_cast<TextTrackKind>(value->GetEnumValue());
|
|
|
|
} else {
|
|
|
|
kind = TextTrackKind::Subtitles;
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
2020-02-11 03:41:14 +03:00
|
|
|
MOZ_ASSERT(!mTrack, "No need to recreate a text track!");
|
2014-04-07 21:58:38 +04:00
|
|
|
mTrack =
|
|
|
|
new TextTrack(window, kind, label, srcLang, TextTrackMode::Disabled,
|
2014-03-13 22:41:21 +04:00
|
|
|
TextTrackReadyState::NotLoaded, TextTrackSource::Track);
|
2014-02-27 23:07:39 +04:00
|
|
|
mTrack->SetTrackElement(this);
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HTMLTrackElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
|
|
|
const nsAString& aValue,
|
2017-11-02 06:35:52 +03:00
|
|
|
nsIPrincipal* aMaybeScriptedPrincipal,
|
2013-05-21 20:14:00 +04:00
|
|
|
nsAttrValue& aResult) {
|
|
|
|
if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::kind) {
|
|
|
|
// Case-insensitive lookup, with the first element as the default.
|
2016-05-08 14:46:20 +03:00
|
|
|
return aResult.ParseEnumValue(aValue, kKindTable, false,
|
|
|
|
kKindTableInvalidValueDefault);
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise call the generic implementation.
|
|
|
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
2017-11-02 06:35:52 +03:00
|
|
|
aMaybeScriptedPrincipal, aResult);
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
2016-07-21 11:49:24 +03:00
|
|
|
void HTMLTrackElement::SetSrc(const nsAString& aSrc, ErrorResult& aError) {
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Set src=%s", NS_ConvertUTF16toUTF8(aSrc).get());
|
2019-05-24 03:41:23 +03:00
|
|
|
|
|
|
|
nsAutoString src;
|
|
|
|
if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src) && src == aSrc) {
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("No need to reload for same src url");
|
2019-05-24 03:41:23 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-21 11:49:24 +03:00
|
|
|
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
|
|
|
|
SetReadyState(TextTrackReadyState::NotLoaded);
|
|
|
|
if (!mMediaParent) {
|
|
|
|
return;
|
|
|
|
}
|
2019-05-24 03:41:29 +03:00
|
|
|
|
2016-07-21 11:49:24 +03:00
|
|
|
// Stop WebVTTListener.
|
|
|
|
mListener = nullptr;
|
|
|
|
if (mChannel) {
|
|
|
|
mChannel->Cancel(NS_BINDING_ABORTED);
|
|
|
|
mChannel = nullptr;
|
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:40 +03:00
|
|
|
MaybeDispatchLoadResource();
|
2016-07-21 11:49:24 +03:00
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:29 +03:00
|
|
|
void HTMLTrackElement::MaybeClearAllCues() {
|
|
|
|
// Empty track's cue list whenever the track element's `src` attribute set,
|
|
|
|
// changed, or removed,
|
|
|
|
// https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:attr-track-src
|
|
|
|
if (!mTrack) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mTrack->ClearAllCues();
|
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:40 +03:00
|
|
|
// This function will run partial steps from `start-the-track-processing-model`
|
|
|
|
// and finish the rest of steps in `LoadResource()` during the stable state.
|
|
|
|
// https://html.spec.whatwg.org/multipage/media.html#start-the-track-processing-model
|
|
|
|
void HTMLTrackElement::MaybeDispatchLoadResource() {
|
|
|
|
MOZ_ASSERT(mTrack, "Should have already created text track!");
|
|
|
|
|
|
|
|
// step2, if the text track's text track mode is not set to one of hidden or
|
|
|
|
// showing, then return.
|
|
|
|
if (mTrack->Mode() == TextTrackMode::Disabled) {
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Do not load resource for disable track");
|
2019-05-24 03:41:40 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// step3, if the text track's track element does not have a media element as a
|
|
|
|
// parent, return.
|
|
|
|
if (!mMediaParent) {
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Do not load resource for track without media element");
|
2019-05-24 03:41:40 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:38 +03:00
|
|
|
if (ReadyState() == TextTrackReadyState::Loaded) {
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Has already loaded resource");
|
2019-05-24 03:41:38 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:40 +03:00
|
|
|
// step5, await a stable state and run the rest of steps.
|
2020-05-11 10:47:22 +03:00
|
|
|
if (!mLoadResourceDispatched) {
|
|
|
|
RefPtr<WebVTTListener> listener = new WebVTTListener(this);
|
|
|
|
RefPtr<Runnable> r = NewRunnableMethod<RefPtr<WebVTTListener>>(
|
|
|
|
"dom::HTMLTrackElement::LoadResource", this,
|
|
|
|
&HTMLTrackElement::LoadResource, std::move(listener));
|
|
|
|
nsContentUtils::RunInStableState(r.forget());
|
|
|
|
mLoadResourceDispatched = true;
|
|
|
|
}
|
2016-07-21 11:49:24 +03:00
|
|
|
}
|
|
|
|
|
2018-12-13 23:06:02 +03:00
|
|
|
void HTMLTrackElement::LoadResource(RefPtr<WebVTTListener>&& aWebVTTListener) {
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("LoadResource");
|
2020-05-11 10:47:22 +03:00
|
|
|
mLoadResourceDispatched = false;
|
2016-07-21 11:49:24 +03:00
|
|
|
|
2013-06-10 19:30:00 +04:00
|
|
|
nsAutoString src;
|
Bug 1550633 - part7 : change ready state to 'FAILED_TO_LOAD' and dispatch 'error' event when we have no 'src' or have an empty url. r=jya
`Failed to load` [1] indicates that the text track was enabled, but when the user agent attempted to obtain it, this failed in some way.
According to the spec [2], if fetching fails for any reason (network error, the server returns an error code, CORS fails, etc), or if URL is the empty string, then queue a task to first change the text track readiness state to `failed to load` and then fire an event named `error` at the track element. And spec [3] also mention that, if the track URL changes so that it is no longer equal to URL while fetching is ongoing, we also need to change the text track readiness state to`failed to load` and dispatch `error`.
[1] https://html.spec.whatwg.org/multipage/media.html#text-track-readiness-state
[2] https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:text-track-failed-to-load
[3] https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:text-track-failed-to-load-3
Differential Revision: https://phabricator.services.mozilla.com/D31556
--HG--
extra : moz-landing-system : lando
2019-05-24 03:41:27 +03:00
|
|
|
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::src, src) || src.IsEmpty()) {
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Fail to load because no src");
|
Bug 1550633 - part7 : change ready state to 'FAILED_TO_LOAD' and dispatch 'error' event when we have no 'src' or have an empty url. r=jya
`Failed to load` [1] indicates that the text track was enabled, but when the user agent attempted to obtain it, this failed in some way.
According to the spec [2], if fetching fails for any reason (network error, the server returns an error code, CORS fails, etc), or if URL is the empty string, then queue a task to first change the text track readiness state to `failed to load` and then fire an event named `error` at the track element. And spec [3] also mention that, if the track URL changes so that it is no longer equal to URL while fetching is ongoing, we also need to change the text track readiness state to`failed to load` and dispatch `error`.
[1] https://html.spec.whatwg.org/multipage/media.html#text-track-readiness-state
[2] https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:text-track-failed-to-load
[3] https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:text-track-failed-to-load-3
Differential Revision: https://phabricator.services.mozilla.com/D31556
--HG--
extra : moz-landing-system : lando
2019-05-24 03:41:27 +03:00
|
|
|
SetReadyState(TextTrackReadyState::FailedToLoad);
|
2013-06-10 19:30:00 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NewURIFromString(src, getter_AddRefs(uri));
|
|
|
|
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Trying to load from src=%s", NS_ConvertUTF16toUTF8(src).get());
|
2013-06-10 19:30:00 +04:00
|
|
|
|
2019-07-04 02:27:12 +03:00
|
|
|
CancelChannelAndListener();
|
2019-07-04 02:23:29 +03:00
|
|
|
|
2017-02-14 06:47:14 +03:00
|
|
|
// According to
|
|
|
|
// https://www.w3.org/TR/html5/embedded-content-0.html#sourcing-out-of-band-text-tracks
|
|
|
|
//
|
|
|
|
// "8: If the track element's parent is a media element then let CORS mode
|
|
|
|
// be the state of the parent media element's crossorigin content attribute.
|
|
|
|
// Otherwise, let CORS mode be No CORS."
|
|
|
|
//
|
2019-06-14 20:56:33 +03:00
|
|
|
CORSMode corsMode =
|
|
|
|
mMediaParent ? AttrValueToCORSMode(
|
|
|
|
mMediaParent->GetParsedAttr(nsGkAtoms::crossorigin))
|
|
|
|
: CORS_NONE;
|
2017-02-14 06:47:14 +03:00
|
|
|
|
|
|
|
// Determine the security flag based on corsMode.
|
|
|
|
nsSecurityFlags secFlags;
|
|
|
|
if (CORS_NONE == corsMode) {
|
|
|
|
// Same-origin is required for track element.
|
2020-07-15 14:20:45 +03:00
|
|
|
secFlags = nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT;
|
2017-02-14 06:47:14 +03:00
|
|
|
} else {
|
2020-07-15 14:20:45 +03:00
|
|
|
secFlags = nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
|
2017-02-14 06:47:14 +03:00
|
|
|
if (CORS_ANONYMOUS == corsMode) {
|
|
|
|
secFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
|
|
|
|
} else if (CORS_USE_CREDENTIALS == corsMode) {
|
|
|
|
secFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
|
|
|
|
} else {
|
|
|
|
NS_WARNING("Unknown CORS mode.");
|
2020-07-15 14:20:45 +03:00
|
|
|
secFlags = nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT;
|
2017-02-14 06:47:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-13 23:06:02 +03:00
|
|
|
mListener = std::move(aWebVTTListener);
|
|
|
|
// This will do 6. Set the text track readiness state to loading.
|
2013-09-19 19:26:00 +04:00
|
|
|
rv = mListener->LoadResource();
|
2013-06-10 19:30:00 +04:00
|
|
|
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
|
2017-02-14 06:47:14 +03:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = OwnerDoc();
|
2018-12-13 23:06:02 +03:00
|
|
|
if (!doc) {
|
2017-02-14 06:47:14 +03:00
|
|
|
return;
|
|
|
|
}
|
2013-06-10 19:30:00 +04:00
|
|
|
|
2018-12-13 23:06:02 +03:00
|
|
|
// 9. End the synchronous section, continuing the remaining steps in parallel.
|
|
|
|
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
|
|
|
|
"dom::HTMLTrackElement::LoadResource",
|
2019-05-24 03:41:25 +03:00
|
|
|
[self = RefPtr<HTMLTrackElement>(this), this, uri, secFlags]() {
|
|
|
|
if (!mListener) {
|
2018-12-19 23:25:55 +03:00
|
|
|
// Shutdown got called, abort.
|
|
|
|
return;
|
|
|
|
}
|
2018-12-13 23:06:02 +03:00
|
|
|
nsCOMPtr<nsIChannel> channel;
|
2019-05-24 03:41:25 +03:00
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = OwnerDoc()->GetDocumentLoadGroup();
|
2019-03-25 15:47:57 +03:00
|
|
|
nsresult rv = NS_NewChannel(getter_AddRefs(channel), uri,
|
2019-05-24 03:41:25 +03:00
|
|
|
static_cast<Element*>(this), secFlags,
|
2019-03-25 15:47:57 +03:00
|
|
|
nsIContentPolicy::TYPE_INTERNAL_TRACK,
|
|
|
|
nullptr, // PerformanceStorage
|
|
|
|
loadGroup);
|
2018-12-13 23:06:02 +03:00
|
|
|
|
2019-05-24 03:40:58 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
LOG("create channel failed.");
|
|
|
|
SetReadyState(TextTrackReadyState::FailedToLoad);
|
|
|
|
return;
|
|
|
|
}
|
2018-12-13 23:06:02 +03:00
|
|
|
|
2019-05-24 03:41:25 +03:00
|
|
|
channel->SetNotificationCallbacks(mListener);
|
2018-12-13 23:06:02 +03:00
|
|
|
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("opening webvtt channel");
|
2019-05-24 03:41:25 +03:00
|
|
|
rv = channel->AsyncOpen(mListener);
|
2018-12-13 23:06:02 +03:00
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
2019-05-24 03:41:25 +03:00
|
|
|
SetReadyState(TextTrackReadyState::FailedToLoad);
|
2018-12-13 23:06:02 +03:00
|
|
|
return;
|
|
|
|
}
|
2019-05-24 03:41:25 +03:00
|
|
|
mChannel = channel;
|
2018-12-13 23:06:02 +03:00
|
|
|
});
|
|
|
|
doc->Dispatch(TaskCategory::Other, runnable.forget());
|
2013-06-10 19:30:00 +04:00
|
|
|
}
|
|
|
|
|
Bug 1555216 - Change the signature of BindToTree to be (BindContext&, nsINode& aParentNode). r=bzbarsky
BindContext was going to have way more information at first, but then I realized
that most of the things I wanted to know were basically a flag away using the
parent node.
Still I think it's worth it, now experimenting with BindToTree will only mean
adding a field to a struct that's included from a couple cpp files, instead of a
massive pain.
I also think this is clearer, and doing this highlights quite a few
inconsistencies in our code which I've left untouched, but commented with
FIXMEs.
Steps are:
$ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsresult BindToTree(Document\* aDocument, nsIContent\* aParent,#nsresult BindToTree(BindContext\&, nsINode\& aParent)#g' $file; done
$ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's# nsIContent\* aBindingParent) override#override#g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(Document\* aDocument, nsIContent\* aParent,#::BindToTree(BindContext\& aContext, nsINode\& aParent)#g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsIContent\* aBindingParent)##g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(aDocument, aParent, aBindingParent)#::BindToTree(aContext, aParent)#g' $file; done
$ ./mach clang-format
Then manual fixups.
Depends on D32948
Differential Revision: https://phabricator.services.mozilla.com/D32949
2019-05-29 07:27:04 +03:00
|
|
|
nsresult HTMLTrackElement::BindToTree(BindContext& aContext, nsINode& aParent) {
|
|
|
|
nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
|
2013-05-21 20:14:00 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Track Element bound to tree.");
|
Bug 1555216 - Change the signature of BindToTree to be (BindContext&, nsINode& aParentNode). r=bzbarsky
BindContext was going to have way more information at first, but then I realized
that most of the things I wanted to know were basically a flag away using the
parent node.
Still I think it's worth it, now experimenting with BindToTree will only mean
adding a field to a struct that's included from a couple cpp files, instead of a
massive pain.
I also think this is clearer, and doing this highlights quite a few
inconsistencies in our code which I've left untouched, but commented with
FIXMEs.
Steps are:
$ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsresult BindToTree(Document\* aDocument, nsIContent\* aParent,#nsresult BindToTree(BindContext\&, nsINode\& aParent)#g' $file; done
$ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's# nsIContent\* aBindingParent) override#override#g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(Document\* aDocument, nsIContent\* aParent,#::BindToTree(BindContext\& aContext, nsINode\& aParent)#g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsIContent\* aBindingParent)##g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(aDocument, aParent, aBindingParent)#::BindToTree(aContext, aParent)#g' $file; done
$ ./mach clang-format
Then manual fixups.
Depends on D32948
Differential Revision: https://phabricator.services.mozilla.com/D32949
2019-05-29 07:27:04 +03:00
|
|
|
auto* parent = HTMLMediaElement::FromNode(aParent);
|
2018-04-15 13:29:46 +03:00
|
|
|
if (!parent) {
|
2013-05-21 20:14:00 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store our parent so we can look up its frame for display.
|
|
|
|
if (!mMediaParent) {
|
2018-04-15 13:29:46 +03:00
|
|
|
mMediaParent = parent;
|
2013-05-21 20:14:00 +04:00
|
|
|
|
|
|
|
// TODO: separate notification for 'alternate' tracks?
|
2016-06-02 10:37:14 +03:00
|
|
|
mMediaParent->NotifyAddedSource();
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("Track element sent notification to parent.");
|
2013-05-21 20:14:00 +04:00
|
|
|
|
2016-06-02 10:37:14 +03:00
|
|
|
// We may already have a TextTrack at this point if GetTrack() has already
|
|
|
|
// been called. This happens, for instance, if script tries to get the
|
|
|
|
// TextTrack before its mTrackElement has been bound to the DOM tree.
|
|
|
|
if (!mTrack) {
|
|
|
|
CreateTextTrack();
|
|
|
|
}
|
2020-02-11 03:41:14 +03:00
|
|
|
// As `CreateTextTrack()` might fail, so we have to check it again.
|
|
|
|
if (mTrack) {
|
|
|
|
LOG("Add text track to media parent");
|
|
|
|
mMediaParent->AddTextTrack(mTrack);
|
|
|
|
}
|
2019-05-24 03:41:40 +03:00
|
|
|
MaybeDispatchLoadResource();
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2019-05-29 01:47:08 +03:00
|
|
|
void HTMLTrackElement::UnbindFromTree(bool aNullParent) {
|
2016-04-26 11:38:24 +03:00
|
|
|
if (mMediaParent && aNullParent) {
|
2013-06-24 19:35:58 +04:00
|
|
|
// mTrack can be null if HTMLTrackElement::LoadResource has never been
|
|
|
|
// called.
|
|
|
|
if (mTrack) {
|
|
|
|
mMediaParent->RemoveTextTrack(mTrack);
|
2017-02-21 10:44:10 +03:00
|
|
|
mMediaParent->UpdateReadyState();
|
2013-06-24 19:35:58 +04:00
|
|
|
}
|
2016-04-26 11:38:24 +03:00
|
|
|
mMediaParent = nullptr;
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
2019-05-29 01:47:08 +03:00
|
|
|
nsGenericHTMLElement::UnbindFromTree(aNullParent);
|
2013-05-21 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
2019-12-02 22:13:11 +03:00
|
|
|
TextTrackReadyState HTMLTrackElement::ReadyState() const {
|
2013-10-25 08:14:36 +04:00
|
|
|
if (!mTrack) {
|
2014-03-13 22:29:32 +04:00
|
|
|
return TextTrackReadyState::NotLoaded;
|
2013-10-25 08:14:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return mTrack->ReadyState();
|
|
|
|
}
|
|
|
|
|
2019-12-02 22:13:11 +03:00
|
|
|
void HTMLTrackElement::SetReadyState(TextTrackReadyState aReadyState) {
|
2016-08-18 14:10:31 +03:00
|
|
|
if (ReadyState() == aReadyState) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-14 20:13:41 +04:00
|
|
|
if (mTrack) {
|
|
|
|
switch (aReadyState) {
|
|
|
|
case TextTrackReadyState::Loaded:
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("dispatch 'load' event");
|
2020-07-01 11:29:29 +03:00
|
|
|
DispatchTrackRunnable(u"load"_ns);
|
2014-03-14 20:13:41 +04:00
|
|
|
break;
|
|
|
|
case TextTrackReadyState::FailedToLoad:
|
2019-05-24 03:41:21 +03:00
|
|
|
LOG("dispatch 'error' event");
|
2020-07-01 11:29:29 +03:00
|
|
|
DispatchTrackRunnable(u"error"_ns);
|
2014-03-14 20:13:41 +04:00
|
|
|
break;
|
2019-12-02 22:13:11 +03:00
|
|
|
default:
|
|
|
|
break;
|
2014-03-14 20:13:41 +04:00
|
|
|
}
|
|
|
|
mTrack->SetReadyState(aReadyState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLTrackElement::DispatchTrackRunnable(const nsString& aEventName) {
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = OwnerDoc();
|
2017-03-08 05:10:35 +03:00
|
|
|
if (!doc) {
|
|
|
|
return;
|
|
|
|
}
|
2017-06-12 22:34:10 +03:00
|
|
|
nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<const nsString>(
|
|
|
|
"dom::HTMLTrackElement::DispatchTrustedEvent", this,
|
|
|
|
&HTMLTrackElement::DispatchTrustedEvent, aEventName);
|
2017-07-26 11:13:35 +03:00
|
|
|
doc->Dispatch(TaskCategory::Other, runnable.forget());
|
2014-03-14 20:13:41 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLTrackElement::DispatchTrustedEvent(const nsAString& aName) {
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = OwnerDoc();
|
2014-03-14 20:13:41 +04:00
|
|
|
if (!doc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsContentUtils::DispatchTrustedEvent(doc, static_cast<nsIContent*>(this),
|
2018-06-25 19:23:50 +03:00
|
|
|
aName, CanBubble::eNo, Cancelable::eNo);
|
2014-03-14 20:13:41 +04:00
|
|
|
}
|
|
|
|
|
2019-07-04 02:27:12 +03:00
|
|
|
void HTMLTrackElement::CancelChannelAndListener() {
|
2016-08-05 10:13:36 +03:00
|
|
|
if (mChannel) {
|
|
|
|
mChannel->Cancel(NS_BINDING_ABORTED);
|
2019-07-04 02:27:12 +03:00
|
|
|
mChannel->SetNotificationCallbacks(nullptr);
|
|
|
|
mChannel = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mListener) {
|
|
|
|
mListener->Cancel();
|
|
|
|
mListener = nullptr;
|
2016-08-05 10:13:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:29 +03:00
|
|
|
nsresult HTMLTrackElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
|
|
|
const nsAttrValue* aValue,
|
|
|
|
const nsAttrValue* aOldValue,
|
|
|
|
nsIPrincipal* aMaybeScriptedPrincipal,
|
|
|
|
bool aNotify) {
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
|
|
|
|
MaybeClearAllCues();
|
Bug 1550633 - part7 : change ready state to 'FAILED_TO_LOAD' and dispatch 'error' event when we have no 'src' or have an empty url. r=jya
`Failed to load` [1] indicates that the text track was enabled, but when the user agent attempted to obtain it, this failed in some way.
According to the spec [2], if fetching fails for any reason (network error, the server returns an error code, CORS fails, etc), or if URL is the empty string, then queue a task to first change the text track readiness state to `failed to load` and then fire an event named `error` at the track element. And spec [3] also mention that, if the track URL changes so that it is no longer equal to URL while fetching is ongoing, we also need to change the text track readiness state to`failed to load` and dispatch `error`.
[1] https://html.spec.whatwg.org/multipage/media.html#text-track-readiness-state
[2] https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:text-track-failed-to-load
[3] https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:text-track-failed-to-load-3
Differential Revision: https://phabricator.services.mozilla.com/D31556
--HG--
extra : moz-landing-system : lando
2019-05-24 03:41:27 +03:00
|
|
|
// In spec, `start the track processing model` step10, while fetching is
|
|
|
|
// ongoing, if the track URL changes, then we have to set the `FailedToLoad`
|
|
|
|
// state.
|
|
|
|
// https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks:text-track-failed-to-load-3
|
|
|
|
if (ReadyState() == TextTrackReadyState::Loading && aValue != aOldValue) {
|
|
|
|
SetReadyState(TextTrackReadyState::FailedToLoad);
|
|
|
|
}
|
2019-05-24 03:41:29 +03:00
|
|
|
}
|
|
|
|
return nsGenericHTMLElement::AfterSetAttr(
|
|
|
|
aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
|
|
|
|
}
|
|
|
|
|
2019-07-04 02:28:31 +03:00
|
|
|
void HTMLTrackElement::DispatchTestEvent(const nsAString& aName) {
|
|
|
|
if (!StaticPrefs::media_webvtt_testing_events()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DispatchTrustedEvent(aName);
|
|
|
|
}
|
|
|
|
|
2020-11-04 20:04:01 +03:00
|
|
|
} // namespace mozilla::dom
|