From cc2db4daf4a8b7ed914491fcc7658b3d953f37b7 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Wed, 22 May 2013 00:14:00 +0800 Subject: [PATCH] Bug 833385 - Implement HTMLTrackElement and TextTrack. r=bz,Ms2ger Add webidl interfaces and implementations of the HTML element and related TextTrack, TextTrackList, TextTrackCue, and TextTrackCueList dom objects. Visibility is controlled by the media.webvtt.enabled pref, which defaults to false. HTMLMediaElement:NewURIFromString() is hoisted to nsGenericHTMLElement so it's available to the track element as well. This patch is primarily work by Dale Karp, David Humphrey and others as Seneca College. --- content/base/src/nsGkAtomList.h | 5 + .../html/content/public/HTMLMediaElement.h | 20 +- content/html/content/src/HTMLMediaElement.cpp | 59 ++-- content/html/content/src/HTMLTrackElement.cpp | 257 ++++++++++++++++ content/html/content/src/HTMLTrackElement.h | 152 ++++++++++ content/html/content/src/Makefile.in | 5 +- content/html/content/src/moz.build | 1 + .../html/content/src/nsGenericHTMLElement.cpp | 34 +++ .../html/content/src/nsGenericHTMLElement.h | 8 + content/media/Makefile.in | 4 + content/media/TextTrack.cpp | 87 ++++++ content/media/TextTrack.h | 109 +++++++ content/media/TextTrackCue.cpp | 102 +++++++ content/media/TextTrackCue.h | 277 ++++++++++++++++++ content/media/TextTrackCueList.cpp | 79 +++++ content/media/TextTrackCueList.h | 60 ++++ content/media/TextTrackList.cpp | 55 ++++ content/media/TextTrackList.h | 69 +++++ content/media/moz.build | 5 +- dom/webidl/HTMLMediaElement.webidl | 8 +- dom/webidl/HTMLTrackElement.webidl | 30 ++ dom/webidl/TextTrack.webidl | 41 +++ dom/webidl/TextTrackCue.webidl | 46 +++ dom/webidl/TextTrackCueList.webidl | 15 + dom/webidl/TextTrackList.webidl | 19 ++ dom/webidl/WebIDL.mk | 5 + .../libeditor/base/nsEditPropertyAtomList.h | 1 + editor/libeditor/html/nsHTMLEditUtils.cpp | 1 + layout/media/symbols.def.in | 6 + modules/libpref/src/init/all.js | 2 + parser/htmlparser/public/nsHTMLTagList.h | 1 + parser/htmlparser/src/nsElementTable.cpp | 14 +- parser/htmlparser/src/nsHTMLTags.cpp | 2 + 33 files changed, 1536 insertions(+), 43 deletions(-) create mode 100644 content/html/content/src/HTMLTrackElement.cpp create mode 100644 content/html/content/src/HTMLTrackElement.h create mode 100644 content/media/TextTrack.cpp create mode 100644 content/media/TextTrack.h create mode 100644 content/media/TextTrackCue.cpp create mode 100644 content/media/TextTrackCue.h create mode 100644 content/media/TextTrackCueList.cpp create mode 100644 content/media/TextTrackCueList.h create mode 100644 content/media/TextTrackList.cpp create mode 100644 content/media/TextTrackList.h create mode 100644 dom/webidl/HTMLTrackElement.webidl create mode 100644 dom/webidl/TextTrack.webidl create mode 100644 dom/webidl/TextTrackCue.webidl create mode 100644 dom/webidl/TextTrackCueList.webidl create mode 100644 dom/webidl/TextTrackList.webidl diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 1af304445f2a..071960bcb743 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -1875,6 +1875,11 @@ GK_ATOM(onratechange, "onratechange") GK_ATOM(ondurationchange, "ondurationchange") GK_ATOM(onvolumechange, "onvolumechange") GK_ATOM(onMozAudioAvailable, "onMozAudioAvailable") +GK_ATOM(onaddtrack, "onaddtrack") +GK_ATOM(oncuechange, "oncuechange") +GK_ATOM(onenter, "onenter") +GK_ATOM(onexit, "onexit") +GK_ATOM(onremovetrack, "onremovetrack") GK_ATOM(loadstart, "loadstart") GK_ATOM(suspend, "suspend") GK_ATOM(emptied, "emptied") diff --git a/content/html/content/public/HTMLMediaElement.h b/content/html/content/public/HTMLMediaElement.h index cfd093243f88..3d91c0afcddc 100644 --- a/content/html/content/public/HTMLMediaElement.h +++ b/content/html/content/public/HTMLMediaElement.h @@ -28,6 +28,8 @@ #include "MediaMetadataManager.h" #include "AudioChannelAgent.h" #include "mozilla/Attributes.h" +#include "mozilla/dom/TextTrack.h" +#include "mozilla/dom/TextTrackList.h" #include "mozilla/ErrorResult.h" // Define to output information on decoding and painting framerate @@ -509,6 +511,16 @@ public: SetHTMLAttr(nsGkAtoms::mozaudiochannel, aValue, aRv); } + TextTrackList* TextTracks() const; + + already_AddRefed AddTextTrack(TextTrackKind aKind, + const nsAString& aLabel, + const nsAString& aLanguage); + + void AddTextTrack(TextTrack* aTextTrack) { + mTextTracks->AddTextTrack(aTextTrack); + } + protected: class MediaLoadListener; class StreamListener; @@ -630,11 +642,6 @@ protected: */ void AbortExistingLoads(); - /** - * Create a URI for the given aURISpec string. - */ - nsresult NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI); - /** * Called when all potential resources are exhausted. Changes network * state to NETWORK_NO_SOURCE, and sends error event with code @@ -1103,6 +1110,9 @@ protected: // An agent used to join audio channel service. nsCOMPtr mAudioChannelAgent; + + // List of our attached text track objects. + nsRefPtr mTextTracks; }; } // namespace dom diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp index 10b68a57af1c..54a144c1f660 100644 --- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -412,6 +412,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream); } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTracks); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement) @@ -430,6 +431,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputStreams[i].mStream); } NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlayed); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTracks); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLMediaElement) @@ -1947,6 +1949,8 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed aNodeInfo) RegisterFreezableElement(); NotifyOwnerDocumentActivityChanged(); + + mTextTracks = new TextTrackList(OwnerDoc()->GetParentObject()); } HTMLMediaElement::~HTMLMediaElement() @@ -2680,38 +2684,6 @@ void HTMLMediaElement::EndSrcMediaStreamPlayback() mSrcStream = nullptr; } -nsresult HTMLMediaElement::NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI) -{ - NS_ENSURE_ARG_POINTER(aURI); - - *aURI = nullptr; - - nsCOMPtr doc = OwnerDoc(); - - nsCOMPtr baseURI = GetBaseURI(); - nsCOMPtr uri; - nsresult rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri), - aURISpec, - doc, - baseURI); - NS_ENSURE_SUCCESS(rv, rv); - - bool equal; - if (aURISpec.IsEmpty() && - doc->GetDocumentURI() && - NS_SUCCEEDED(doc->GetDocumentURI()->Equals(uri, &equal)) && - equal) { - // It's not possible for a media resource to be embedded in the current - // document we extracted aURISpec from, so there's no point returning - // the current document URI just to let the caller attempt and fail to - // decode it. - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - uri.forget(aURI); - return NS_OK; -} - void HTMLMediaElement::ProcessMediaFragmentURI() { nsMediaFragmentURIParser parser(mLoadingSrc); @@ -3568,6 +3540,14 @@ void HTMLMediaElement::FireTimeUpdate(bool aPeriodic) mFragmentStart = -1.0; mDecoder->SetFragmentEndTime(mFragmentEnd); } + + // Update visible text tracks. + // Here mTextTracks can be null if the cycle collector has unlinked + // us before our parent. In that case UnbindFromTree will call us + // when our parent is unlinked. + if (mTextTracks) { + mTextTracks->Update(time); + } } void HTMLMediaElement::GetCurrentSpec(nsCString& aString) @@ -3771,5 +3751,20 @@ NS_IMETHODIMP HTMLMediaElement::CanPlayChanged(bool canPlay) return NS_OK; } +/* readonly attribute TextTrackList textTracks; */ +TextTrackList* +HTMLMediaElement::TextTracks() const +{ + return mTextTracks; +} + +already_AddRefed +HTMLMediaElement::AddTextTrack(TextTrackKind aKind, + const nsAString& aLabel, + const nsAString& aLanguage) +{ + return mTextTracks->AddTextTrack(aKind, aLabel, aLanguage); +} + } // namespace dom } // namespace mozilla diff --git a/content/html/content/src/HTMLTrackElement.cpp b/content/html/content/src/HTMLTrackElement.cpp new file mode 100644 index 000000000000..aa5da3381527 --- /dev/null +++ b/content/html/content/src/HTMLTrackElement.cpp @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "mozilla/dom/Element.h" +#include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/dom/HTMLTrackElement.h" +#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 "nsIAsyncVerifyRedirectCallback.h" +#include "nsICachingChannel.h" +#include "nsIChannelEventSink.h" +#include "nsIChannelPolicy.h" +#include "nsIContentPolicy.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIDocument.h" +#include "nsIDOMEventTarget.h" +#include "nsIDOMHTMLMediaElement.h" +#include "nsIFrame.h" +#include "nsIHttpChannel.h" +#include "nsIInterfaceRequestor.h" +#include "nsILoadGroup.h" +#include "nsIObserver.h" +#include "nsIStreamListener.h" +#include "nsISupportsImpl.h" +#include "nsMappedAttributes.h" +#include "nsNetUtil.h" +#include "nsRuleData.h" +#include "nsStyleConsts.h" +#include "nsThreadUtils.h" +#include "nsVideoFrame.h" +#include "webvtt/parser.h" + +#ifdef PR_LOGGING +static PRLogModuleInfo* gTrackElementLog; +#define LOG(type, msg) PR_LOG(gTrackElementLog, type, msg) +#else +#define LOG(type, msg) +#endif + +// Replace the usual NS_IMPL_NS_NEW_HTML_ELEMENT(Track) so +// we can return an UnknownElement instead when pref'd off. +nsGenericHTMLElement* +NS_NewHTMLTrackElement(already_AddRefed aNodeInfo, + mozilla::dom::FromParser aFromParser) +{ + if (!mozilla::dom::HTMLTrackElement::IsWebVTTEnabled()) { + return mozilla::dom::NewHTMLElementHelper::Create(aNodeInfo); + } + + return mozilla::dom::NewHTMLElementHelper::Create(aNodeInfo); +} + +namespace mozilla { +namespace dom { + +/** HTMLTrackElement */ +HTMLTrackElement::HTMLTrackElement(already_AddRefed aNodeInfo) + : nsGenericHTMLElement(aNodeInfo) + , mReadyState(NONE) +{ +#ifdef PR_LOGGING + if (!gTrackElementLog) { + gTrackElementLog = PR_NewLogModule("nsTrackElement"); + } +#endif + + SetIsDOMBinding(); +} + +HTMLTrackElement::~HTMLTrackElement() +{ +} + +NS_IMPL_ELEMENT_CLONE(HTMLTrackElement) + +NS_IMPL_ADDREF_INHERITED(HTMLTrackElement, Element) +NS_IMPL_RELEASE_INHERITED(HTMLTrackElement, Element) + +NS_IMPL_CYCLE_COLLECTION_INHERITED_3(HTMLTrackElement, nsGenericHTMLElement, + mTrack, mChannel, mMediaParent) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTrackElement) + NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement) +NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement) + +JSObject* +HTMLTrackElement::WrapNode(JSContext* aCx, JS::Handle aScope) +{ + return HTMLTrackElementBinding::Wrap(aCx, aScope, this); +} + +bool +HTMLTrackElement::IsWebVTTEnabled() +{ + return HTMLTrackElementBinding::PrefEnabled(); +} + +TextTrack* +HTMLTrackElement::Track() +{ + if (!mTrack) { + // We're expected to always have an internal TextTrack so create + // an empty object to return if we don't already have one. + mTrack = new TextTrack(OwnerDoc()->GetParentObject()); + } + + return mTrack; +} + +void +HTMLTrackElement::DisplayCueText(webvtt_node* head) +{ + // TODO: Bug 833382 - Propagate to the LoadListener. +} + +void +HTMLTrackElement::CreateTextTrack() +{ + DOMString label, srcLang; + GetSrclang(srcLang); + GetLabel(label); + mTrack = new TextTrack(OwnerDoc()->GetParentObject(), Kind(), label, srcLang); + + if (mMediaParent) { + mMediaParent->AddTextTrack(mTrack); + } +} + +TextTrackKind +HTMLTrackElement::Kind() const +{ + const nsAttrValue* value = GetParsedAttr(nsGkAtoms::kind); + if (!value) { + return TextTrackKind::Subtitles; + } + return static_cast(value->GetEnumValue()); +} + +static EnumEntry +StringFromKind(TextTrackKind aKind) +{ + return TextTrackKindValues::strings[static_cast(aKind)]; +} + +void +HTMLTrackElement::SetKind(TextTrackKind aKind, ErrorResult& aError) +{ + const EnumEntry& string = StringFromKind(aKind); + nsAutoString kind; + + kind.AssignASCII(string.value, string.length); + SetHTMLAttr(nsGkAtoms::kind, kind, aError); +} + +bool +HTMLTrackElement::ParseAttribute(int32_t aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult) +{ + // Map html attribute string values to TextTrackKind enums. + static const nsAttrValue::EnumTable kKindTable[] = { + { "subtitles", static_cast(TextTrackKind::Subtitles) }, + { "captions", static_cast(TextTrackKind::Captions) }, + { "descriptions", static_cast(TextTrackKind::Descriptions) }, + { "chapters", static_cast(TextTrackKind::Chapters) }, + { "metadata", static_cast(TextTrackKind::Metadata) }, + { 0 } + }; + + if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::kind) { + // Case-insensitive lookup, with the first element as the default. + return aResult.ParseEnumValue(aValue, kKindTable, false, kKindTable); + } + + // Otherwise call the generic implementation. + return nsGenericHTMLElement::ParseAttribute(aNamespaceID, + aAttribute, + aValue, + aResult); +} + +nsresult +HTMLTrackElement::BindToTree(nsIDocument* aDocument, + nsIContent* aParent, + nsIContent* aBindingParent, + bool aCompileEventHandlers) +{ + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, + aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + if (!aDocument) { + return NS_OK; + } + + LOG(PR_LOG_DEBUG, ("Track Element bound to tree.")); + if (!aParent || !aParent->IsNodeOfType(nsINode::eMEDIA)) { + return NS_OK; + } + + // Store our parent so we can look up its frame for display. + if (!mMediaParent) { + mMediaParent = static_cast(aParent); + + HTMLMediaElement* media = static_cast(aParent); + // TODO: separate notification for 'alternate' tracks? + media->NotifyAddedSource(); + LOG(PR_LOG_DEBUG, ("Track element sent notification to parent.")); + + // TODO: this section needs to become async in bug 833382. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=833385#c55. + + // Find our 'src' url + nsAutoString src; + + // TODO: we might want to instead call LoadResource() in a + // AfterSetAttr, like we do in media element. + if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) { + nsCOMPtr uri; + nsresult rvTwo = NewURIFromString(src, getter_AddRefs(uri)); + if (NS_SUCCEEDED(rvTwo)) { + LOG(PR_LOG_ALWAYS, ("%p Trying to load from src=%s", this, + NS_ConvertUTF16toUTF8(src).get())); + // TODO: bug 833382 - dispatch a load request. + } + } + } + + return NS_OK; +} + +void +HTMLTrackElement::UnbindFromTree(bool aDeep, bool aNullParent) +{ + if (mMediaParent && aNullParent) { + mMediaParent = nullptr; + } + + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); +} + +} // namespace dom +} // namespace mozilla diff --git a/content/html/content/src/HTMLTrackElement.h b/content/html/content/src/HTMLTrackElement.h new file mode 100644 index 000000000000..6015541df46f --- /dev/null +++ b/content/html/content/src/HTMLTrackElement.h @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef mozilla_dom_HTMLTrackElement_h +#define mozilla_dom_HTMLTrackElement_h + +#define WEBVTT_NO_CONFIG_H 1 +#define WEBVTT_STATIC 1 + +#include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/dom/TextTrack.h" +#include "nsCycleCollectionParticipant.h" +#include "nsGenericHTMLElement.h" +#include "nsGkAtoms.h" +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMEventTarget.h" +#include "nsIHttpChannel.h" +#include "webvtt/node.h" + +namespace mozilla { +namespace dom { + +class HTMLTrackElement MOZ_FINAL : public nsGenericHTMLElement + , public nsIDOMHTMLElement +{ +public: + HTMLTrackElement(already_AddRefed aNodeInfo); + virtual ~HTMLTrackElement(); + + // nsISupports + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTrackElement, + nsGenericHTMLElement) + + // nsIDOMNode + NS_FORWARD_NSIDOMNODE_TO_NSINODE + + // nsIDOMElement + NS_FORWARD_NSIDOMELEMENT_TO_GENERIC + + // nsIDOMHTMLElement + NS_FORWARD_NSIDOMHTMLELEMENT_TO_GENERIC + + // HTMLTrackElement WebIDL + TextTrackKind Kind() const; + void SetKind(TextTrackKind aKind, ErrorResult& aError); + + void GetSrc(DOMString& aSrc) const + { + GetHTMLURIAttr(nsGkAtoms::src, aSrc); + } + void SetSrc(const nsAString& aSrc, ErrorResult& aError) + { + SetHTMLAttr(nsGkAtoms::src, aSrc, aError); + } + + void GetSrclang(DOMString& aSrclang) const + { + GetHTMLAttr(nsGkAtoms::srclang, aSrclang); + } + void SetSrclang(const nsAString& aSrclang, ErrorResult& aError) + { + SetHTMLAttr(nsGkAtoms::srclang, aSrclang, aError); + } + + void GetLabel(DOMString& aLabel) const + { + GetHTMLAttr(nsGkAtoms::label, aLabel); + } + void SetLabel(const nsAString& aLabel, ErrorResult& aError) + { + SetHTMLAttr(nsGkAtoms::label, aLabel, aError); + } + + bool Default() const + { + return GetBoolAttr(nsGkAtoms::_default); + } + void SetDefault(bool aDefault, ErrorResult& aError) + { + SetHTMLBoolAttr(nsGkAtoms::_default, aDefault, aError); + } + + // Constants for numeric readyState property values. + enum { + NONE = 0U, + LOADING = 1U, + LOADED = 2U, + ERROR = 3U + }; + uint16_t ReadyState() const + { + return mReadyState; + } + + TextTrack* Track(); + + virtual nsresult Clone(nsINodeInfo* aNodeInfo, nsINode** aResult) const MOZ_OVERRIDE; + virtual nsIDOMNode* AsDOMNode() MOZ_OVERRIDE { return this; } + + // For Track, ItemValue reflects the src attribute + virtual void GetItemValueText(nsAString& aText) + { + DOMString value; + GetSrc(value); + aText = value; + } + virtual void SetItemValueText(const nsAString& aText) + { + ErrorResult rv; + SetSrc(aText, rv); + } + + // Override ParseAttribute() to convert kind strings to enum values. + virtual bool ParseAttribute(int32_t aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult); + + // Override BindToTree() so that we can trigger a load when we become + // the child of a media element. + virtual nsresult BindToTree(nsIDocument* aDocument, + nsIContent* aParent, + nsIContent* aBindingParent, + bool aCompileEventHandlers) MOZ_OVERRIDE; + virtual void UnbindFromTree(bool aDeep, bool aNullParent) MOZ_OVERRIDE; + + void DisplayCueText(webvtt_node* head); + + // Check enabling preference. + static bool IsWebVTTEnabled(); + +protected: + virtual JSObject* WrapNode(JSContext* aCx, + JS::Handle aScope) MOZ_OVERRIDE; + + nsRefPtr mTrack; + nsCOMPtr mChannel; + nsRefPtr mMediaParent; + uint16_t mReadyState; + + void CreateTextTrack(); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_HTMLTrackElement_h diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in index d6d677c8b40b..c0c0a5bc07ea 100644 --- a/content/html/content/src/Makefile.in +++ b/content/html/content/src/Makefile.in @@ -81,6 +81,7 @@ CPPSRCS = \ HTMLTextAreaElement.cpp \ HTMLTimeElement.cpp \ HTMLTitleElement.cpp \ + HTMLTrackElement.cpp \ HTMLVideoElement.cpp \ HTMLUnknownElement.cpp \ MediaError.cpp \ @@ -118,4 +119,6 @@ INCLUDES += \ -I$(topsrcdir)/xpcom/ds \ $(NULL) -DEFINES += -D_IMPL_NS_LAYOUT +DEFINES += \ + -D_IMPL_NS_LAYOUT \ + $(NULL) diff --git a/content/html/content/src/moz.build b/content/html/content/src/moz.build index 0ff096506498..d57b06316384 100644 --- a/content/html/content/src/moz.build +++ b/content/html/content/src/moz.build @@ -67,6 +67,7 @@ EXPORTS.mozilla.dom += [ 'HTMLTextAreaElement.h', 'HTMLTimeElement.h', 'HTMLTitleElement.h', + 'HTMLTrackElement.h', 'HTMLUnknownElement.h', 'MediaError.h', 'TimeRanges.h', diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index aad76cd9aa52..1f05b85aabe0 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -3325,3 +3325,37 @@ nsGenericHTMLElement::IsEventAttributeName(nsIAtom *aName) { return nsContentUtils::IsEventAttributeName(aName, EventNameType_HTML); } + +/** + * Construct a URI from a string, as an element.src attribute + * would be set to. Helper for the media elements. + */ +nsresult +nsGenericHTMLElement::NewURIFromString(const nsAutoString& aURISpec, + nsIURI** aURI) +{ + NS_ENSURE_ARG_POINTER(aURI); + + *aURI = nullptr; + + nsCOMPtr doc = OwnerDoc(); + + nsCOMPtr baseURI = GetBaseURI(); + nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI, aURISpec, + doc, baseURI); + NS_ENSURE_SUCCESS(rv, rv); + + bool equal; + if (aURISpec.IsEmpty() && + doc->GetDocumentURI() && + NS_SUCCEEDED(doc->GetDocumentURI()->Equals(*aURI, &equal)) && + equal) { + // Assume an element can't point to a fragment of its embedding + // document. Fail here instead of returning the recursive URI + // and waiting for the subsequent load to fail. + NS_RELEASE(*aURI); + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + return NS_OK; +} diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 1b34e22d4a6f..bbdfadb1c4e8 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -795,6 +795,13 @@ protected: virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const; + /** + * Create a URI for the given aURISpec string. + * Returns INVALID_STATE_ERR and nulls *aURI if aURISpec is empty + * and the document's URI matches the element's base URI. + */ + nsresult NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI); + void GetHTMLAttr(nsIAtom* aName, nsAString& aResult) const { GetAttr(kNameSpaceID_None, aName, aResult); @@ -1981,6 +1988,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Tfoot) NS_DECLARE_NS_NEW_HTML_ELEMENT(Thead) NS_DECLARE_NS_NEW_HTML_ELEMENT(Time) NS_DECLARE_NS_NEW_HTML_ELEMENT(Title) +NS_DECLARE_NS_NEW_HTML_ELEMENT(Track) NS_DECLARE_NS_NEW_HTML_ELEMENT(Unknown) NS_DECLARE_NS_NEW_HTML_ELEMENT(Video) diff --git a/content/media/Makefile.in b/content/media/Makefile.in index d25c74d25656..6bdf8db9e05b 100644 --- a/content/media/Makefile.in +++ b/content/media/Makefile.in @@ -35,6 +35,10 @@ CPPSRCS = \ MediaStreamGraph.cpp \ MediaStreamTrack.cpp \ StreamBuffer.cpp \ + TextTrack.cpp \ + TextTrackList.cpp \ + TextTrackCue.cpp \ + TextTrackCueList.cpp \ VideoFrameContainer.cpp \ VideoSegment.cpp \ VideoStreamTrack.cpp \ diff --git a/content/media/TextTrack.cpp b/content/media/TextTrack.cpp new file mode 100644 index 000000000000..d4e726266582 --- /dev/null +++ b/content/media/TextTrack.cpp @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 et tw=78: */ +/* 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/. */ + +#include "mozilla/dom/TextTrack.h" +#include "mozilla/dom/TextTrackBinding.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(TextTrack, + mParent, + mCueList, + mActiveCueList) + +NS_IMPL_ADDREF_INHERITED(TextTrack, nsDOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(TextTrack, nsDOMEventTargetHelper) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TextTrack) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) + +TextTrack::TextTrack(nsISupports* aParent, + TextTrackKind aKind, + const nsAString& aLabel, + const nsAString& aLanguage) + : mParent(aParent) + , mKind(aKind) + , mLabel(aLabel) + , mLanguage(aLanguage) + , mMode(TextTrackMode::Hidden) + , mCueList(new TextTrackCueList(aParent)) + , mActiveCueList(new TextTrackCueList(aParent)) +{ + SetIsDOMBinding(); +} + +TextTrack::TextTrack(nsISupports* aParent) + : mParent(aParent) + , mKind(TextTrackKind::Subtitles) + , mMode(TextTrackMode::Disabled) + , mCueList(new TextTrackCueList(aParent)) + , mActiveCueList(new TextTrackCueList(aParent)) +{ + SetIsDOMBinding(); +} + +void +TextTrack::Update(double time) +{ + mCueList->Update(time); +} + +JSObject* +TextTrack::WrapObject(JSContext* aCx, JS::Handle aScope) +{ + return TextTrackBinding::Wrap(aCx, aScope, this); +} + +void +TextTrack::SetMode(TextTrackMode aValue) +{ + mMode = aValue; +} + +void +TextTrack::AddCue(TextTrackCue& aCue) +{ + //XXX: If cue exists, remove. Bug 867823. + mCueList->AddCue(aCue); +} + +void +TextTrack::RemoveCue(TextTrackCue& aCue) +{ + //XXX: If cue does not exists throw NotFoundError. Bug 867823. + mCueList->RemoveCue(aCue); +} + +void +TextTrack::CueChanged(TextTrackCue& aCue) +{ + //XXX: Implement Cue changed. Bug 867823. +} + +} // namespace dom +} // namespace mozilla diff --git a/content/media/TextTrack.h b/content/media/TextTrack.h new file mode 100644 index 000000000000..1e393db9d248 --- /dev/null +++ b/content/media/TextTrack.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 et tw=78: */ +/* 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/. */ + +#ifndef mozilla_dom_TextTrack_h +#define mozilla_dom_TextTrack_h + +#include "mozilla/dom/TextTrackBinding.h" +#include "mozilla/dom/TextTrackCue.h" +#include "mozilla/dom/TextTrackCueList.h" +#include "nsCOMPtr.h" +#include "nsCycleCollectionParticipant.h" +#include "nsDOMEventTargetHelper.h" +#include "nsString.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +class TextTrackCue; +class TextTrackCueList; + +class TextTrack MOZ_FINAL : public nsDOMEventTargetHelper +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(TextTrack, + nsDOMEventTargetHelper) + + TextTrack(nsISupports* aParent); + TextTrack(nsISupports* aParent, + TextTrackKind aKind, + const nsAString& aLabel, + const nsAString& aLanguage); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aScope) MOZ_OVERRIDE; + + nsISupports* GetParentObject() const + { + return mParent; + } + + TextTrackKind Kind() const + { + return mKind; + } + void GetLabel(nsAString& aLabel) const + { + aLabel = mLabel; + } + void GetLanguage(nsAString& aLanguage) const + { + aLanguage = mLanguage; + } + void GetInBandMetadataTrackDispatchType(nsAString& aType) const + { + aType = mType; + } + + TextTrackMode Mode() const + { + return mMode; + } + void SetMode(TextTrackMode aValue); + + TextTrackCueList* GetCues() const + { + if (mMode == TextTrackMode::Disabled) { + return nullptr; + } + return mCueList; + } + + TextTrackCueList* GetActiveCues() const + { + if (mMode == TextTrackMode::Disabled) { + return nullptr; + } + return mActiveCueList; + } + + void Update(double time); + + void AddCue(TextTrackCue& aCue); + void RemoveCue(TextTrackCue& aCue); + void CueChanged(TextTrackCue& aCue); + + IMPL_EVENT_HANDLER(cuechange) + +private: + nsCOMPtr mParent; + + TextTrackKind mKind; + nsString mLabel; + nsString mLanguage; + nsString mType; + TextTrackMode mMode; + + nsRefPtr mCueList; + nsRefPtr mActiveCueList; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_TextTrack_h diff --git a/content/media/TextTrackCue.cpp b/content/media/TextTrackCue.cpp new file mode 100644 index 000000000000..f85e7dc7338c --- /dev/null +++ b/content/media/TextTrackCue.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "mozilla/dom/HTMLTrackElement.h" +#include "mozilla/dom/TextTrackCue.h" +#include "mozilla/dom/TextTrackCueBinding.h" +#include "webvtt/cue.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(TextTrackCue, + mGlobal, + mTrack, + mTrackElement) + +NS_IMPL_ADDREF_INHERITED(TextTrackCue, nsDOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(TextTrackCue, nsDOMEventTargetHelper) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TextTrackCue) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) + +// Set cue setting defaults based on step 19 & seq. +// in http://dev.w3.org/html5/webvtt/#parsing +void +TextTrackCue::SetDefaultCueSettings() +{ + mPosition = 50; + mSize = 100; + mPauseOnExit = false; + mSnapToLines = true; + mLine = WEBVTT_AUTO; + mAlign = TextTrackCueAlign::Middle; +} + +TextTrackCue::TextTrackCue(nsISupports* aGlobal, + double aStartTime, + double aEndTime, + const nsAString& aText) + : mGlobal(aGlobal) + , mText(aText) + , mStartTime(aStartTime) + , mEndTime(aEndTime) + , mHead(nullptr) +{ + SetDefaultCueSettings(); + MOZ_ASSERT(aGlobal); + SetIsDOMBinding(); +} + +TextTrackCue::TextTrackCue(nsISupports* aGlobal, + double aStartTime, + double aEndTime, + const nsAString& aText, + HTMLTrackElement* aTrackElement, + webvtt_node* head) + : mGlobal(aGlobal) + , mText(aText) + , mStartTime(aStartTime) + , mEndTime(aEndTime) + , mTrackElement(aTrackElement) + , mHead(head) +{ + // Use the webvtt library's reference counting. + webvtt_ref_node(mHead); + SetDefaultCueSettings(); + MOZ_ASSERT(aGlobal); + SetIsDOMBinding(); +} + +TextTrackCue::~TextTrackCue() +{ + if (mHead) { + // Release our reference and null mHead. + webvtt_release_node(&mHead); + } +} + +void +TextTrackCue::DisplayCue() +{ + if (mTrackElement) { + mTrackElement->DisplayCueText(mHead); + } +} + +JSObject* +TextTrackCue::WrapObject(JSContext* aCx, JS::Handle aScope) +{ + return TextTrackCueBinding::Wrap(aCx, aScope, this); +} + +void +TextTrackCue::CueChanged() +{ + if (mTrack) { + mTrack->CueChanged(*this); + } +} +} // namespace dom +} // namespace mozilla diff --git a/content/media/TextTrackCue.h b/content/media/TextTrackCue.h new file mode 100644 index 000000000000..d65214511a7f --- /dev/null +++ b/content/media/TextTrackCue.h @@ -0,0 +1,277 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 et tw=78: */ +/* 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/. */ + +#ifndef mozilla_dom_TextTrackCue_h +#define mozilla_dom_TextTrackCue_h + +#define WEBVTT_NO_CONFIG_H 1 +#define WEBVTT_STATIC 1 + +#include "mozilla/dom/DocumentFragment.h" +#include "mozilla/dom/TextTrack.h" +#include "mozilla/dom/TextTrackCueBinding.h" +#include "nsCycleCollectionParticipant.h" +#include "nsDOMEventTargetHelper.h" +#include "webvtt/node.h" + +namespace mozilla { +namespace dom { + +class HTMLTrackElement; +class TextTrack; + +class TextTrackCue MOZ_FINAL : public nsDOMEventTargetHelper +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(TextTrackCue, + nsDOMEventTargetHelper) + + // TextTrackCue WebIDL + // See bug 868509 about splitting out the WebVTT-specific interfaces. + static already_AddRefed + Constructor(GlobalObject& aGlobal, + double aStartTime, + double aEndTime, + const nsAString& aText, + ErrorResult& aRv) + { + nsRefPtr ttcue = new TextTrackCue(aGlobal.Get(), aStartTime, + aEndTime, aText); + return ttcue.forget(); + } + TextTrackCue(nsISupports* aGlobal, double aStartTime, double aEndTime, + const nsAString& aText); + + TextTrackCue(nsISupports* aGlobal, double aStartTime, double aEndTime, + const nsAString& aText, HTMLTrackElement* aTrackElement, + webvtt_node* head); + + ~TextTrackCue(); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aScope) MOZ_OVERRIDE; + + nsISupports* GetParentObject() + { + return mGlobal; + } + + TextTrack* GetTrack() const + { + return mTrack; + } + + void GetId(nsAString& aId) const + { + aId = mId; + } + + void SetId(const nsAString& aId) + { + if (mId == aId) { + return; + } + + mId = aId; + CueChanged(); + } + + double StartTime() const + { + return mStartTime; + } + + void SetStartTime(double aStartTime) + { + //XXXhumph: validate? bug 868519. + if (mStartTime == aStartTime) + return; + + mStartTime = aStartTime; + CueChanged(); + } + + double EndTime() const + { + return mEndTime; + } + + void SetEndTime(double aEndTime) + { + //XXXhumph: validate? bug 868519. + if (mEndTime == aEndTime) + return; + + mEndTime = aEndTime; + CueChanged(); + } + + bool PauseOnExit() + { + return mPauseOnExit; + } + + void SetPauseOnExit(bool aPauseOnExit) + { + if (mPauseOnExit == aPauseOnExit) + return; + + mPauseOnExit = aPauseOnExit; + CueChanged(); + } + + void GetVertical(nsAString& aVertical) + { + aVertical = mVertical; + } + + void SetVertical(const nsAString& aVertical) + { + if (mVertical == aVertical) + return; + + mVertical = aVertical; + CueChanged(); + } + + bool SnapToLines() + { + return mSnapToLines; + } + + void SetSnapToLines(bool aSnapToLines) + { + if (mSnapToLines == aSnapToLines) + return; + + mSnapToLines = aSnapToLines; + CueChanged(); + } + + double Line() const + { + return mLine; + } + + void SetLine(double aLine) + { + //XXX: validate? bug 868519. + mLine = aLine; + } + + int32_t Position() const + { + return mPosition; + } + + void SetPosition(int32_t aPosition) + { + // XXXhumph: validate? bug 868519. + if (mPosition == aPosition) + return; + + mPosition = aPosition; + CueChanged(); + } + + int32_t Size() const + { + return mSize; + } + + void SetSize(int32_t aSize) + { + if (mSize == aSize) { + return; + } + + if (aSize < 0 || aSize > 100) { + //XXX:throw IndexSizeError; bug 868519. + } + + mSize = aSize; + CueChanged(); + } + + TextTrackCueAlign Align() const + { + return mAlign; + } + + void SetAlign(TextTrackCueAlign& aAlign) + { + if (mAlign == aAlign) + return; + + mAlign = aAlign; + CueChanged(); + } + + void GetText(nsAString& aText) const + { + aText = mText; + } + + void SetText(const nsAString& aText) + { + // XXXhumph: validate? bug 868519. + if (mText == aText) + return; + + mText = aText; + CueChanged(); + } + + already_AddRefed GetCueAsHTML() const + { + // XXXhumph: todo. Bug 868509. + return nullptr; + } + + IMPL_EVENT_HANDLER(enter) + IMPL_EVENT_HANDLER(exit) + + // Helper functions for implementation. + bool + operator==(const TextTrackCue& rhs) const + { + return mId.Equals(rhs.mId); + } + + const nsAString& Id() const + { + return mId; + } + + void DisplayCue(); + +private: + void CueChanged(); + void SetDefaultCueSettings(); + + nsCOMPtr mGlobal; + nsString mText; + double mStartTime; + double mEndTime; + + nsRefPtr mTrack; + nsRefPtr mTrackElement; + webvtt_node *mHead; + nsString mId; + int32_t mPosition; + int32_t mSize; + bool mPauseOnExit; + bool mSnapToLines; + nsString mVertical; + int mLine; + TextTrackCueAlign mAlign; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_TextTrackCue_h diff --git a/content/media/TextTrackCueList.cpp b/content/media/TextTrackCueList.cpp new file mode 100644 index 000000000000..687b48f8f1cb --- /dev/null +++ b/content/media/TextTrackCueList.cpp @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "mozilla/dom/TextTrackCueList.h" +#include "mozilla/dom/TextTrackCueListBinding.h" +#include "mozilla/dom/TextTrackCue.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TextTrackCueList, mParent, mList) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackCueList) +NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackCueList) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackCueList) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +TextTrackCueList::TextTrackCueList(nsISupports* aParent) : mParent(aParent) +{ + SetIsDOMBinding(); +} + +void +TextTrackCueList::Update(double time) +{ + const uint32_t length = mList.Length(); + for (uint32_t i = 0; i < length; i++) { + if (time > mList[i]->StartTime() && time < mList[i]->EndTime()) { + mList[i]->DisplayCue(); + } + } +} + +JSObject* +TextTrackCueList::WrapObject(JSContext* aCx, JS::Handle aScope) +{ + return TextTrackCueListBinding::Wrap(aCx, aScope, this); +} + +TextTrackCue* +TextTrackCueList::IndexedGetter(uint32_t aIndex, bool& aFound) +{ + aFound = aIndex < mList.Length(); + return aFound ? mList[aIndex] : nullptr; +} + +TextTrackCue* +TextTrackCueList::GetCueById(const nsAString& aId) +{ + if (aId.IsEmpty()) { + return nullptr; + } + + for (uint32_t i = 0; i < mList.Length(); i++) { + if (aId.Equals(mList[i]->Id())) { + return mList[i]; + } + } + return nullptr; +} + +void +TextTrackCueList::AddCue(TextTrackCue& cue) +{ + mList.AppendElement(&cue); +} + +void +TextTrackCueList::RemoveCue(TextTrackCue& cue) +{ + mList.RemoveElement(&cue); +} + +} // namespace dom +} // namespace mozilla diff --git a/content/media/TextTrackCueList.h b/content/media/TextTrackCueList.h new file mode 100644 index 000000000000..6594f97f0587 --- /dev/null +++ b/content/media/TextTrackCueList.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 et tw=78: */ +/* 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/. */ + +#ifndef mozilla_dom_TextTrackCueList_h +#define mozilla_dom_TextTrackCueList_h + +#include "mozilla/dom/TextTrackCue.h" +#include "nsCOMPtr.h" +#include "nsCycleCollectionParticipant.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +class TextTrackCue; + +class TextTrackCueList MOZ_FINAL : public nsISupports + , public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextTrackCueList) + + // TextTrackCueList WebIDL + TextTrackCueList(nsISupports* aParent); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aScope) MOZ_OVERRIDE; + + nsISupports* GetParentObject() const + { + return mParent; + } + + uint32_t Length() const + { + return mList.Length(); + } + + void Update(double time); + + TextTrackCue* IndexedGetter(uint32_t aIndex, bool& aFound); + TextTrackCue* GetCueById(const nsAString& aId); + + void AddCue(TextTrackCue& cue); + void RemoveCue(TextTrackCue& cue); + +private: + nsCOMPtr mParent; + + nsTArray< nsRefPtr > mList; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_TextTrackCueList_h diff --git a/content/media/TextTrackList.cpp b/content/media/TextTrackList.cpp new file mode 100644 index 000000000000..a67ec21e7c1a --- /dev/null +++ b/content/media/TextTrackList.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "mozilla/dom/TextTrackList.h" +#include "mozilla/dom/TextTrackListBinding.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TextTrackList, mGlobal, mTextTracks) + +NS_IMPL_ADDREF_INHERITED(TextTrackList, nsDOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(TextTrackList, nsDOMEventTargetHelper) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TextTrackList) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) + +TextTrackList::TextTrackList(nsISupports* aGlobal) : mGlobal(aGlobal) +{ + SetIsDOMBinding(); +} + +JSObject* +TextTrackList::WrapObject(JSContext* aCx, JS::Handle aScope) +{ + return TextTrackListBinding::Wrap(aCx, aScope, this); +} + +TextTrack* +TextTrackList::IndexedGetter(uint32_t aIndex, bool& aFound) +{ + aFound = aIndex < mTextTracks.Length(); + return aFound ? mTextTracks[aIndex] : nullptr; +} + +already_AddRefed +TextTrackList::AddTextTrack(TextTrackKind aKind, + const nsAString& aLabel, + const nsAString& aLanguage) +{ + nsRefPtr track = new TextTrack(mGlobal, aKind, aLabel, aLanguage); + mTextTracks.AppendElement(track); + // TODO: dispatch addtrack event + return track.forget(); +} + +void +TextTrackList::RemoveTextTrack(const TextTrack& aTrack) +{ + mTextTracks.RemoveElement(&aTrack); +} + +} // namespace dom +} // namespace mozilla diff --git a/content/media/TextTrackList.h b/content/media/TextTrackList.h new file mode 100644 index 000000000000..af845aba0c31 --- /dev/null +++ b/content/media/TextTrackList.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 et tw=78: */ +/* 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/. */ + +#ifndef mozilla_dom_TextTrackList_h +#define mozilla_dom_TextTrackList_h + +#include "mozilla/dom/TextTrack.h" +#include "nsCycleCollectionParticipant.h" +#include "nsDOMEventTargetHelper.h" + +namespace mozilla { +namespace dom { + +class TextTrack; + +class TextTrackList MOZ_FINAL : public nsDOMEventTargetHelper +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(TextTrackList, + nsDOMEventTargetHelper) + + TextTrackList(nsISupports* aGlobal); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aScope) MOZ_OVERRIDE; + + nsISupports* GetParentObject() const + { + return mGlobal; + } + + uint32_t Length() const + { + return mTextTracks.Length(); + } + + void Update(double time) { + uint32_t length = Length(), i; + for( i = 0; i < length; i++ ) { + mTextTracks[i]->Update(time); + } + } + TextTrack* IndexedGetter(uint32_t aIndex, bool& aFound); + + already_AddRefed AddTextTrack(TextTrackKind aKind, + const nsAString& aLabel, + const nsAString& aLanguage); + void AddTextTrack(TextTrack* aTextTrack) { + mTextTracks.AppendElement(aTextTrack); + } + + void RemoveTextTrack(const TextTrack& aTrack); + + IMPL_EVENT_HANDLER(addtrack) + IMPL_EVENT_HANDLER(removetrack) + +private: + nsCOMPtr mGlobal; + nsTArray< nsRefPtr > mTextTracks; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_TextTrackList_h diff --git a/content/media/moz.build b/content/media/moz.build index 7d1c43b26c0a..514da77fac60 100644 --- a/content/media/moz.build +++ b/content/media/moz.build @@ -77,6 +77,9 @@ EXPORTS += [ EXPORTS.mozilla.dom += [ 'AudioStreamTrack.h', 'MediaStreamTrack.h', + 'TextTrack.h', + 'TextTrackCue.h', + 'TextTrackCueList.h', + 'TextTrackList.h', 'VideoStreamTrack.h', ] - diff --git a/dom/webidl/HTMLMediaElement.webidl b/dom/webidl/HTMLMediaElement.webidl index 302fc36baff5..bc47a72bfacb 100644 --- a/dom/webidl/HTMLMediaElement.webidl +++ b/dom/webidl/HTMLMediaElement.webidl @@ -87,8 +87,12 @@ interface HTMLMediaElement : HTMLElement { // tracks //readonly attribute AudioTrackList audioTracks; //readonly attribute VideoTrackList videoTracks; - //readonly attribute TextTrackList textTracks; - //TextTrack addTextTrack(DOMString kind, optional DOMString label, optional DOMString language); + [Pref="media.webvtt.enabled"] + readonly attribute TextTrackList textTracks; + [Pref="media.webvtt.enabled"] + TextTrack addTextTrack(TextTrackKind kind, + optional DOMString label = "", + optional DOMString language = ""); }; // Mozilla extensions: diff --git a/dom/webidl/HTMLTrackElement.webidl b/dom/webidl/HTMLTrackElement.webidl new file mode 100644 index 000000000000..d72f70c04803 --- /dev/null +++ b/dom/webidl/HTMLTrackElement.webidl @@ -0,0 +1,30 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#the-track-element + */ + +[Pref="media.webvtt.enabled"] +interface HTMLTrackElement : HTMLElement { + [SetterThrows, Pure] + attribute TextTrackKind kind; + [SetterThrows, Pure] + attribute DOMString src; + [SetterThrows, Pure] + attribute DOMString srclang; + [SetterThrows, Pure] + attribute DOMString label; + [SetterThrows, Pure] + attribute boolean default; + + const unsigned short NONE = 0; + const unsigned short LOADING = 1; + const unsigned short LOADED = 2; + const unsigned short ERROR = 3; + readonly attribute unsigned short readyState; + + readonly attribute TextTrack track; +}; diff --git a/dom/webidl/TextTrack.webidl b/dom/webidl/TextTrack.webidl new file mode 100644 index 000000000000..f2a94966376d --- /dev/null +++ b/dom/webidl/TextTrack.webidl @@ -0,0 +1,41 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#texttrack + */ + +enum TextTrackKind { + "subtitles", + "captions", + "descriptions", + "chapters", + "metadata" +}; + +enum TextTrackMode { + "disabled", + "hidden", + "showing" +}; + +[Pref="media.webvtt.enabled"] +interface TextTrack : EventTarget { + readonly attribute TextTrackKind kind; + readonly attribute DOMString label; + readonly attribute DOMString language; + readonly attribute DOMString inBandMetadataTrackDispatchType; + + attribute TextTrackMode mode; + + readonly attribute TextTrackCueList? cues; + readonly attribute TextTrackCueList? activeCues; + + void addCue(TextTrackCue cue); + void removeCue(TextTrackCue cue); + + [SetterThrows] + attribute EventHandler oncuechange; +}; diff --git a/dom/webidl/TextTrackCue.webidl b/dom/webidl/TextTrackCue.webidl new file mode 100644 index 000000000000..9dcce1231b9d --- /dev/null +++ b/dom/webidl/TextTrackCue.webidl @@ -0,0 +1,46 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#texttrackcue + */ + +enum AutoKeyword { "auto" }; + +/* Non-spec: Request to add this enum to spec + * can be found here: https://www.w3.org/Bugs/Public/show_bug.cgi?id=20996 */ +enum TextTrackCueAlign { + "start", + "middle", + "end", + "left", + "right" +}; + +[Constructor(double startTime, double endTime, DOMString text), + Pref="media.webvtt.enabled"] +interface TextTrackCue : EventTarget { + readonly attribute TextTrack? track; + + attribute DOMString id; + attribute double startTime; + attribute double endTime; + attribute boolean pauseOnExit; + attribute DOMString vertical; + attribute boolean snapToLines; + // XXXhumph: https://www.w3.org/Bugs/Public/show_bug.cgi?id=20651 + // attribute (long or AutoKeyword) line; + attribute long position; + attribute long size; + attribute TextTrackCueAlign align; + attribute DOMString text; + DocumentFragment getCueAsHTML(); + + [SetterThrows] + attribute EventHandler onenter; + + [SetterThrows] + attribute EventHandler onexit; +}; diff --git a/dom/webidl/TextTrackCueList.webidl b/dom/webidl/TextTrackCueList.webidl new file mode 100644 index 000000000000..ee24160b6ec4 --- /dev/null +++ b/dom/webidl/TextTrackCueList.webidl @@ -0,0 +1,15 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#texttrackcuelist + */ + +[Pref="media.webvtt.enabled"] +interface TextTrackCueList { + readonly attribute unsigned long length; + getter TextTrackCue (unsigned long index); + TextTrackCue? getCueById(DOMString id); +}; diff --git a/dom/webidl/TextTrackList.webidl b/dom/webidl/TextTrackList.webidl new file mode 100644 index 000000000000..49ec493a1421 --- /dev/null +++ b/dom/webidl/TextTrackList.webidl @@ -0,0 +1,19 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#texttracklist + */ + +[Pref="media.webvtt.enabled"] +interface TextTrackList : EventTarget { + readonly attribute unsigned long length; + getter TextTrack (unsigned long index); + + [SetterThrows] + attribute EventHandler onaddtrack; + [SetterThrows] + attribute EventHandler onremovetrack; +}; diff --git a/dom/webidl/WebIDL.mk b/dom/webidl/WebIDL.mk index 212d203db619..6550ab4b7355 100644 --- a/dom/webidl/WebIDL.mk +++ b/dom/webidl/WebIDL.mk @@ -150,6 +150,7 @@ webidl_files = \ HTMLTableSectionElement.webidl \ HTMLTemplateElement.webidl \ HTMLTextAreaElement.webidl \ + HTMLTrackElement.webidl \ HTMLTimeElement.webidl \ HTMLTitleElement.webidl \ HTMLUListElement.webidl \ @@ -315,6 +316,10 @@ webidl_files = \ Text.webidl \ TextDecoder.webidl \ TextEncoder.webidl \ + TextTrack.webidl \ + TextTrackCue.webidl \ + TextTrackCueList.webidl \ + TextTrackList.webidl \ TimeRanges.webidl \ Touch.webidl \ TouchEvent.webidl \ diff --git a/editor/libeditor/base/nsEditPropertyAtomList.h b/editor/libeditor/base/nsEditPropertyAtomList.h index 6cc270463136..ccbeff696296 100644 --- a/editor/libeditor/base/nsEditPropertyAtomList.h +++ b/editor/libeditor/base/nsEditPropertyAtomList.h @@ -152,6 +152,7 @@ EDITOR_ATOM(thead, "thead") EDITOR_ATOM(th, "th") EDITOR_ATOM(time, "time") EDITOR_ATOM(tr, "tr") +EDITOR_ATOM(track, "track") EDITOR_ATOM(tt, "tt") EDITOR_ATOM(ul, "ul") EDITOR_ATOM(u, "u") diff --git a/editor/libeditor/html/nsHTMLEditUtils.cpp b/editor/libeditor/html/nsHTMLEditUtils.cpp index 179ace18a579..070c30d46946 100644 --- a/editor/libeditor/html/nsHTMLEditUtils.cpp +++ b/editor/libeditor/html/nsHTMLEditUtils.cpp @@ -748,6 +748,7 @@ static const nsElementInfo kElements[eHTMLTag_userdefined] = { ELEM(time, true, false, GROUP_PHRASE, GROUP_INLINE_ELEMENT), ELEM(title, true, false, GROUP_HEAD_CONTENT, GROUP_LEAF), ELEM(tr, true, false, GROUP_TBODY_CONTENT, GROUP_TR_CONTENT), + ELEM(track, false, false, GROUP_NONE, GROUP_NONE), ELEM(tt, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), ELEM(u, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), // XXX Can contain self and ol because editor does sublists illegally. diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index afad4d5e1995..cb40ec813be2 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -575,3 +575,9 @@ hb_unicode_funcs_set_eastasian_width_func hb_unicode_funcs_set_general_category_func hb_unicode_funcs_set_mirroring_func hb_unicode_funcs_set_script_func +webvtt_string_text +webvtt_create_parser +webvtt_delete_parser +webvtt_parse_chunk +webvtt_ref_node +webvtt_release_node diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 9fef7b747f04..03de3b9687c1 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -202,6 +202,8 @@ pref("media.peerconnection.noise", 1); pref("media.navigator.enabled", true); #endif #endif +// TextTrack support +pref("media.webvtt.enabled", false); #ifdef MOZ_WEBSPEECH pref("media.webspeech.recognition.enable", false); diff --git a/parser/htmlparser/public/nsHTMLTagList.h b/parser/htmlparser/public/nsHTMLTagList.h index f432fb458312..1927f5f61d1a 100644 --- a/parser/htmlparser/public/nsHTMLTagList.h +++ b/parser/htmlparser/public/nsHTMLTagList.h @@ -153,6 +153,7 @@ HTML_TAG(template, Template) HTML_TAG(time, Time) HTML_TAG(title, Title) HTML_TAG(tr, TableRow) +HTML_TAG(track, Track) HTML_HTMLELEMENT_TAG(tt) HTML_HTMLELEMENT_TAG(u) HTML_TAG(ul, SharedList) diff --git a/parser/htmlparser/src/nsElementTable.cpp b/parser/htmlparser/src/nsElementTable.cpp index eaf6ff37e1ba..b96dfb297057 100644 --- a/parser/htmlparser/src/nsElementTable.cpp +++ b/parser/htmlparser/src/nsElementTable.cpp @@ -44,6 +44,7 @@ DECL_TAG_LIST(gParamParents,{eHTMLTag_applet COMMA eHTMLTag_object}) DECL_TAG_LIST(gTRParents,{eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_thead COMMA eHTMLTag_table}) DECL_TAG_LIST(gTREndParents,{eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_thead COMMA eHTMLTag_table COMMA eHTMLTag_applet}) DECL_TAG_LIST(gSourceParents,{eHTMLTag_video COMMA eHTMLTag_audio}) +DECL_TAG_LIST(gTrackParents,{eHTMLTag_video COMMA eHTMLTag_audio}) //********************************************************************************************* // Next, define the set of taglists for tags with special kids... @@ -88,8 +89,8 @@ DECL_TAG_LIST(gTableElemKids,{eHTMLTag_form COMMA eHTMLTag_noscript COMMA eHTMLT DECL_TAG_LIST(gTRKids,{eHTMLTag_td COMMA eHTMLTag_th COMMA eHTMLTag_form COMMA eHTMLTag_script})// Removed INPUT - Ref. Bug 20087, 25382 | Removed MAP to fix 58942 DECL_TAG_LIST(gTBodyKids,{eHTMLTag_tr COMMA eHTMLTag_form}) // Removed INPUT - Ref. Bug 20087, 25382 DECL_TAG_LIST(gULKids,{eHTMLTag_li COMMA eHTMLTag_p}) -DECL_TAG_LIST(gVideoKids,{eHTMLTag_source}) -DECL_TAG_LIST(gAudioKids,{eHTMLTag_source}) +DECL_TAG_LIST(gVideoKids,{eHTMLTag_source COMMA eHTMLTag_track}) +DECL_TAG_LIST(gAudioKids,{eHTMLTag_source COMMA eHTMLTag_track}) //********************************************************************************************* // The following tag lists are used to define common set of root notes for the HTML elements... @@ -1229,6 +1230,15 @@ const nsHTMLElement gHTMLElements[] = { /*special props, prop-range*/ (kBadContentWatch|kNoStyleLeaksIn|kNoStyleLeaksOut), kNoPropRange, /*special parents,kids*/ &gTRParents,&gTRKids, }, + { + /*tag*/ eHTMLTag_track, + /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, + /*rootnodes,endrootnodes*/ &gTrackParents,&gTrackParents, + /*autoclose starttags and endtags*/ &gPAutoClose, 0, 0,0, + /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, + /*special props, prop-range*/ kNonContainer,kNoPropRange, + /*special parents,kids*/ &gTrackParents,0, + }, { /*tag*/ eHTMLTag_tt, /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, diff --git a/parser/htmlparser/src/nsHTMLTags.cpp b/parser/htmlparser/src/nsHTMLTags.cpp index 9d25e7a0ab04..ddfb6fd6421b 100644 --- a/parser/htmlparser/src/nsHTMLTags.cpp +++ b/parser/htmlparser/src/nsHTMLTags.cpp @@ -259,6 +259,8 @@ static const PRUnichar sHTMLTagUnicodeName_title[] = {'t', 'i', 't', 'l', 'e', '\0'}; static const PRUnichar sHTMLTagUnicodeName_tr[] = {'t', 'r', '\0'}; +static const PRUnichar sHTMLTagUnicodeName_track[] = + {'t', 'r', 'a', 'c', 'k', '\0'}; static const PRUnichar sHTMLTagUnicodeName_tt[] = {'t', 't', '\0'}; static const PRUnichar sHTMLTagUnicodeName_u[] =