Backed out changeset f594e6f00208 (bug 1940883) for causing crashes in bug 1941164.
[gecko.git] / dom / media / webvtt / TextTrackCue.cpp
blob9eb1829fc859d1761c7a9998bd7b583df9bc778c
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/dom/TextTrackCue.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/HTMLTrackElement.h"
10 #include "mozilla/dom/TextTrackList.h"
11 #include "mozilla/dom/TextTrackRegion.h"
12 #include "nsComponentManagerUtils.h"
13 #include "mozilla/ClearOnShutdown.h"
14 #include "mozilla/intl/Bidi.h"
15 #include "nsGlobalWindowInner.h"
17 extern mozilla::LazyLogModule gTextTrackLog;
19 #define LOG(msg, ...) \
20 MOZ_LOG(gTextTrackLog, LogLevel::Debug, \
21 ("TextTrackCue=%p, " msg, this, ##__VA_ARGS__))
23 namespace mozilla::dom {
25 NS_IMPL_CYCLE_COLLECTION_INHERITED(TextTrackCue, DOMEventTargetHelper,
26 mDocument, mTrack, mTrackElement,
27 mDisplayState, mRegion)
29 NS_IMPL_ADDREF_INHERITED(TextTrackCue, DOMEventTargetHelper)
30 NS_IMPL_RELEASE_INHERITED(TextTrackCue, DOMEventTargetHelper)
31 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackCue)
32 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
34 StaticRefPtr<nsIWebVTTParserWrapper> TextTrackCue::sParserWrapper;
36 // Set default value for cue, spec https://w3c.github.io/webvtt/#model-cues
37 void TextTrackCue::SetDefaultCueSettings() {
38 mPositionIsAutoKeyword = true;
39 // Spec https://www.w3.org/TR/webvtt1/#webvtt-cue-position-automatic-alignment
40 mPositionAlign = PositionAlignSetting::Auto;
41 mSize = 100.0;
42 mPauseOnExit = false;
43 mSnapToLines = true;
44 mLineIsAutoKeyword = true;
45 mAlign = AlignSetting::Center;
46 mLineAlign = LineAlignSetting::Start;
47 mVertical = DirectionSetting::_empty;
48 mActive = false;
51 TextTrackCue::TextTrackCue(nsPIDOMWindowInner* aOwnerWindow, double aStartTime,
52 double aEndTime, const nsAString& aText,
53 ErrorResult& aRv)
54 : DOMEventTargetHelper(aOwnerWindow),
55 mText(aText),
56 mStartTime(aStartTime),
57 mEndTime(aEndTime),
58 mPosition(0.0),
59 mLine(0.0),
60 mReset(false, "TextTrackCue::mReset"),
61 mHaveStartedWatcher(false),
62 mWatchManager(this, AbstractThread::MainThread()) {
63 LOG("create TextTrackCue");
64 SetDefaultCueSettings();
65 MOZ_ASSERT(aOwnerWindow);
66 if (NS_FAILED(StashDocument())) {
67 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
71 TextTrackCue::TextTrackCue(nsPIDOMWindowInner* aOwnerWindow, double aStartTime,
72 double aEndTime, const nsAString& aText,
73 HTMLTrackElement* aTrackElement, ErrorResult& aRv)
74 : DOMEventTargetHelper(aOwnerWindow),
75 mText(aText),
76 mStartTime(aStartTime),
77 mEndTime(aEndTime),
78 mTrackElement(aTrackElement),
79 mPosition(0.0),
80 mLine(0.0),
81 mReset(false, "TextTrackCue::mReset"),
82 mHaveStartedWatcher(false),
83 mWatchManager(this, AbstractThread::MainThread()) {
84 LOG("create TextTrackCue");
85 SetDefaultCueSettings();
86 MOZ_ASSERT(aOwnerWindow);
87 if (NS_FAILED(StashDocument())) {
88 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
92 TextTrackCue::~TextTrackCue() = default;
94 /** Save a reference to our creating document so we don't have to
95 * keep getting it from our window.
97 nsresult TextTrackCue::StashDocument() {
98 nsPIDOMWindowInner* window = GetOwnerWindow();
99 if (!window) {
100 return NS_ERROR_NO_INTERFACE;
102 mDocument = window->GetDoc();
103 if (!mDocument) {
104 return NS_ERROR_NOT_AVAILABLE;
106 return NS_OK;
109 already_AddRefed<DocumentFragment> TextTrackCue::GetCueAsHTML() {
110 // mDocument may be null during cycle collector shutdown.
111 // See bug 941701.
112 if (!mDocument) {
113 return nullptr;
116 if (!sParserWrapper) {
117 nsresult rv;
118 nsCOMPtr<nsIWebVTTParserWrapper> parserWrapper =
119 do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID, &rv);
120 if (NS_FAILED(rv)) {
121 return mDocument->CreateDocumentFragment();
123 sParserWrapper = parserWrapper;
124 ClearOnShutdown(&sParserWrapper);
127 nsPIDOMWindowInner* window = mDocument->GetInnerWindow();
128 if (!window) {
129 return mDocument->CreateDocumentFragment();
132 RefPtr<DocumentFragment> frag;
133 sParserWrapper->ConvertCueToDOMTree(window, static_cast<EventTarget*>(this),
134 getter_AddRefs(frag));
135 if (!frag) {
136 return mDocument->CreateDocumentFragment();
138 return frag.forget();
141 void TextTrackCue::SetTrackElement(HTMLTrackElement* aTrackElement) {
142 mTrackElement = aTrackElement;
145 JSObject* TextTrackCue::WrapObject(JSContext* aCx,
146 JS::Handle<JSObject*> aGivenProto) {
147 return VTTCue_Binding::Wrap(aCx, this, aGivenProto);
150 TextTrackRegion* TextTrackCue::GetRegion() { return mRegion; }
152 void TextTrackCue::SetRegion(TextTrackRegion* aRegion) {
153 if (mRegion == aRegion) {
154 return;
156 mRegion = aRegion;
157 mReset = true;
160 double TextTrackCue::ComputedLine() {
161 // See spec https://w3c.github.io/webvtt/#cue-computed-line
162 if (!mLineIsAutoKeyword && !mSnapToLines && (mLine < 0.0 || mLine > 100.0)) {
163 return 100.0;
164 } else if (!mLineIsAutoKeyword) {
165 return mLine;
166 } else if (mLineIsAutoKeyword && !mSnapToLines) {
167 return 100.0;
168 } else if (!mTrack || !mTrack->GetTextTrackList() ||
169 !mTrack->GetTextTrackList()->GetMediaElement()) {
170 return -1.0;
173 RefPtr<TextTrackList> trackList = mTrack->GetTextTrackList();
174 bool dummy;
175 uint32_t showingTracksNum = 0;
176 for (uint32_t idx = 0; idx < trackList->Length(); idx++) {
177 RefPtr<TextTrack> track = trackList->IndexedGetter(idx, dummy);
178 if (track->Mode() == TextTrackMode::Showing) {
179 showingTracksNum++;
182 if (mTrack == track) {
183 break;
187 return (-1.0) * showingTracksNum;
190 double TextTrackCue::ComputedPosition() {
191 // See spec https://w3c.github.io/webvtt/#cue-computed-position
192 if (!mPositionIsAutoKeyword) {
193 return mPosition;
195 if (ComputedPositionAlign() == PositionAlignSetting::Line_left) {
196 return 0.0;
198 if (ComputedPositionAlign() == PositionAlignSetting::Line_right) {
199 return 100.0;
201 return 50.0;
204 PositionAlignSetting TextTrackCue::ComputedPositionAlign() {
205 // See spec https://w3c.github.io/webvtt/#cue-computed-position-alignment
206 if (mPositionAlign != PositionAlignSetting::Auto) {
207 return mPositionAlign;
208 } else if (mAlign == AlignSetting::Left) {
209 return PositionAlignSetting::Line_left;
210 } else if (mAlign == AlignSetting::Right) {
211 return PositionAlignSetting::Line_right;
212 } else if (mAlign == AlignSetting::Start) {
213 return IsTextBaseDirectionLTR() ? PositionAlignSetting::Line_left
214 : PositionAlignSetting::Line_right;
215 } else if (mAlign == AlignSetting::End) {
216 return IsTextBaseDirectionLTR() ? PositionAlignSetting::Line_right
217 : PositionAlignSetting::Line_left;
219 return PositionAlignSetting::Center;
222 bool TextTrackCue::IsTextBaseDirectionLTR() const {
223 // The result returned by `GetBaseDirection` might be `neutral` if the text
224 // only contains neutral charaters. In this case, we would treat its base
225 // direction as LTR.
226 return intl::Bidi::GetBaseDirection(mText) != intl::Bidi::BaseDirection::RTL;
229 void TextTrackCue::NotifyDisplayStatesChanged() {
230 if (!mReset) {
231 return;
234 if (!mTrack || !mTrack->GetTextTrackList() ||
235 !mTrack->GetTextTrackList()->GetMediaElement()) {
236 return;
239 mTrack->GetTextTrackList()
240 ->GetMediaElement()
241 ->NotifyCueDisplayStatesChanged();
244 void TextTrackCue::SetActive(bool aActive) {
245 if (mActive == aActive) {
246 return;
249 LOG("TextTrackCue, SetActive=%d", aActive);
250 mActive = aActive;
251 mDisplayState = mActive ? mDisplayState : nullptr;
252 if (mTrack) {
253 mTrack->NotifyCueActiveStateChanged(this);
257 #undef LOG
259 } // namespace mozilla::dom