summaryrefslogtreecommitdiffstats
path: root/dom/media/webvtt/TextTrackCue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webvtt/TextTrackCue.cpp')
-rw-r--r--dom/media/webvtt/TextTrackCue.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/dom/media/webvtt/TextTrackCue.cpp b/dom/media/webvtt/TextTrackCue.cpp
new file mode 100644
index 0000000000..434337a337
--- /dev/null
+++ b/dom/media/webvtt/TextTrackCue.cpp
@@ -0,0 +1,260 @@
+/* -*- 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/TextTrackCue.h"
+
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/HTMLTrackElement.h"
+#include "mozilla/dom/TextTrackList.h"
+#include "mozilla/dom/TextTrackRegion.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/intl/Bidi.h"
+
+extern mozilla::LazyLogModule gTextTrackLog;
+
+#define LOG(msg, ...) \
+ MOZ_LOG(gTextTrackLog, LogLevel::Debug, \
+ ("TextTrackCue=%p, " msg, this, ##__VA_ARGS__))
+
+namespace mozilla::dom {
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(TextTrackCue, DOMEventTargetHelper,
+ mDocument, mTrack, mTrackElement,
+ mDisplayState, mRegion)
+
+NS_IMPL_ADDREF_INHERITED(TextTrackCue, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(TextTrackCue, DOMEventTargetHelper)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackCue)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+StaticRefPtr<nsIWebVTTParserWrapper> TextTrackCue::sParserWrapper;
+
+// Set default value for cue, spec https://w3c.github.io/webvtt/#model-cues
+void TextTrackCue::SetDefaultCueSettings() {
+ mPositionIsAutoKeyword = true;
+ // Spec https://www.w3.org/TR/webvtt1/#webvtt-cue-position-automatic-alignment
+ mPositionAlign = PositionAlignSetting::Auto;
+ mSize = 100.0;
+ mPauseOnExit = false;
+ mSnapToLines = true;
+ mLineIsAutoKeyword = true;
+ mAlign = AlignSetting::Center;
+ mLineAlign = LineAlignSetting::Start;
+ mVertical = DirectionSetting::_empty;
+ mActive = false;
+}
+
+TextTrackCue::TextTrackCue(nsPIDOMWindowInner* aOwnerWindow, double aStartTime,
+ double aEndTime, const nsAString& aText,
+ ErrorResult& aRv)
+ : DOMEventTargetHelper(aOwnerWindow),
+ mText(aText),
+ mStartTime(aStartTime),
+ mEndTime(aEndTime),
+ mPosition(0.0),
+ mLine(0.0),
+ mReset(false, "TextTrackCue::mReset"),
+ mHaveStartedWatcher(false),
+ mWatchManager(
+ this, GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other)) {
+ LOG("create TextTrackCue");
+ SetDefaultCueSettings();
+ MOZ_ASSERT(aOwnerWindow);
+ if (NS_FAILED(StashDocument())) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+}
+
+TextTrackCue::TextTrackCue(nsPIDOMWindowInner* aOwnerWindow, double aStartTime,
+ double aEndTime, const nsAString& aText,
+ HTMLTrackElement* aTrackElement, ErrorResult& aRv)
+ : DOMEventTargetHelper(aOwnerWindow),
+ mText(aText),
+ mStartTime(aStartTime),
+ mEndTime(aEndTime),
+ mTrackElement(aTrackElement),
+ mPosition(0.0),
+ mLine(0.0),
+ mReset(false, "TextTrackCue::mReset"),
+ mHaveStartedWatcher(false),
+ mWatchManager(
+ this, GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other)) {
+ LOG("create TextTrackCue");
+ SetDefaultCueSettings();
+ MOZ_ASSERT(aOwnerWindow);
+ if (NS_FAILED(StashDocument())) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+}
+
+TextTrackCue::~TextTrackCue() = default;
+
+/** Save a reference to our creating document so we don't have to
+ * keep getting it from our window.
+ */
+nsresult TextTrackCue::StashDocument() {
+ nsPIDOMWindowInner* window = GetOwner();
+ if (!window) {
+ return NS_ERROR_NO_INTERFACE;
+ }
+ mDocument = window->GetDoc();
+ if (!mDocument) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ return NS_OK;
+}
+
+already_AddRefed<DocumentFragment> TextTrackCue::GetCueAsHTML() {
+ // mDocument may be null during cycle collector shutdown.
+ // See bug 941701.
+ if (!mDocument) {
+ return nullptr;
+ }
+
+ if (!sParserWrapper) {
+ nsresult rv;
+ nsCOMPtr<nsIWebVTTParserWrapper> parserWrapper =
+ do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ return mDocument->CreateDocumentFragment();
+ }
+ sParserWrapper = parserWrapper;
+ ClearOnShutdown(&sParserWrapper);
+ }
+
+ nsPIDOMWindowInner* window = mDocument->GetInnerWindow();
+ if (!window) {
+ return mDocument->CreateDocumentFragment();
+ }
+
+ RefPtr<DocumentFragment> frag;
+ sParserWrapper->ConvertCueToDOMTree(window, static_cast<EventTarget*>(this),
+ getter_AddRefs(frag));
+ if (!frag) {
+ return mDocument->CreateDocumentFragment();
+ }
+ return frag.forget();
+}
+
+void TextTrackCue::SetTrackElement(HTMLTrackElement* aTrackElement) {
+ mTrackElement = aTrackElement;
+}
+
+JSObject* TextTrackCue::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return VTTCue_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+TextTrackRegion* TextTrackCue::GetRegion() { return mRegion; }
+
+void TextTrackCue::SetRegion(TextTrackRegion* aRegion) {
+ if (mRegion == aRegion) {
+ return;
+ }
+ mRegion = aRegion;
+ mReset = true;
+}
+
+double TextTrackCue::ComputedLine() {
+ // See spec https://w3c.github.io/webvtt/#cue-computed-line
+ if (!mLineIsAutoKeyword && !mSnapToLines && (mLine < 0.0 || mLine > 100.0)) {
+ return 100.0;
+ } else if (!mLineIsAutoKeyword) {
+ return mLine;
+ } else if (mLineIsAutoKeyword && !mSnapToLines) {
+ return 100.0;
+ } else if (!mTrack || !mTrack->GetTextTrackList() ||
+ !mTrack->GetTextTrackList()->GetMediaElement()) {
+ return -1.0;
+ }
+
+ RefPtr<TextTrackList> trackList = mTrack->GetTextTrackList();
+ bool dummy;
+ uint32_t showingTracksNum = 0;
+ for (uint32_t idx = 0; idx < trackList->Length(); idx++) {
+ RefPtr<TextTrack> track = trackList->IndexedGetter(idx, dummy);
+ if (track->Mode() == TextTrackMode::Showing) {
+ showingTracksNum++;
+ }
+
+ if (mTrack == track) {
+ break;
+ }
+ }
+
+ return (-1.0) * showingTracksNum;
+}
+
+double TextTrackCue::ComputedPosition() {
+ // See spec https://w3c.github.io/webvtt/#cue-computed-position
+ if (!mPositionIsAutoKeyword) {
+ return mPosition;
+ }
+ if (ComputedPositionAlign() == PositionAlignSetting::Line_left) {
+ return 0.0;
+ }
+ if (ComputedPositionAlign() == PositionAlignSetting::Line_right) {
+ return 100.0;
+ }
+ return 50.0;
+}
+
+PositionAlignSetting TextTrackCue::ComputedPositionAlign() {
+ // See spec https://w3c.github.io/webvtt/#cue-computed-position-alignment
+ if (mPositionAlign != PositionAlignSetting::Auto) {
+ return mPositionAlign;
+ } else if (mAlign == AlignSetting::Left) {
+ return PositionAlignSetting::Line_left;
+ } else if (mAlign == AlignSetting::Right) {
+ return PositionAlignSetting::Line_right;
+ } else if (mAlign == AlignSetting::Start) {
+ return IsTextBaseDirectionLTR() ? PositionAlignSetting::Line_left
+ : PositionAlignSetting::Line_right;
+ } else if (mAlign == AlignSetting::End) {
+ return IsTextBaseDirectionLTR() ? PositionAlignSetting::Line_right
+ : PositionAlignSetting::Line_left;
+ }
+ return PositionAlignSetting::Center;
+}
+
+bool TextTrackCue::IsTextBaseDirectionLTR() const {
+ // The returned result by `ubidi_getBaseDirection` might be `neutral` if the
+ // text only contains netural charaters. In this case, we would treat its
+ // base direction as LTR.
+ return intl::Bidi::GetBaseDirection(mText) != intl::Bidi::BaseDirection::RTL;
+}
+
+void TextTrackCue::NotifyDisplayStatesChanged() {
+ if (!mReset) {
+ return;
+ }
+
+ if (!mTrack || !mTrack->GetTextTrackList() ||
+ !mTrack->GetTextTrackList()->GetMediaElement()) {
+ return;
+ }
+
+ mTrack->GetTextTrackList()
+ ->GetMediaElement()
+ ->NotifyCueDisplayStatesChanged();
+}
+
+void TextTrackCue::SetActive(bool aActive) {
+ if (mActive == aActive) {
+ return;
+ }
+
+ LOG("TextTrackCue, SetActive=%d", aActive);
+ mActive = aActive;
+ mDisplayState = mActive ? mDisplayState : nullptr;
+ if (mTrack) {
+ mTrack->NotifyCueActiveStateChanged(this);
+ }
+}
+
+#undef LOG
+
+} // namespace mozilla::dom