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
;
44 mLineIsAutoKeyword
= true;
45 mAlign
= AlignSetting::Center
;
46 mLineAlign
= LineAlignSetting::Start
;
47 mVertical
= DirectionSetting::_empty
;
51 TextTrackCue::TextTrackCue(nsPIDOMWindowInner
* aOwnerWindow
, double aStartTime
,
52 double aEndTime
, const nsAString
& aText
,
54 : DOMEventTargetHelper(aOwnerWindow
),
56 mStartTime(aStartTime
),
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
),
76 mStartTime(aStartTime
),
78 mTrackElement(aTrackElement
),
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();
100 return NS_ERROR_NO_INTERFACE
;
102 mDocument
= window
->GetDoc();
104 return NS_ERROR_NOT_AVAILABLE
;
109 already_AddRefed
<DocumentFragment
> TextTrackCue::GetCueAsHTML() {
110 // mDocument may be null during cycle collector shutdown.
116 if (!sParserWrapper
) {
118 nsCOMPtr
<nsIWebVTTParserWrapper
> parserWrapper
=
119 do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID
, &rv
);
121 return mDocument
->CreateDocumentFragment();
123 sParserWrapper
= parserWrapper
;
124 ClearOnShutdown(&sParserWrapper
);
127 nsPIDOMWindowInner
* window
= mDocument
->GetInnerWindow();
129 return mDocument
->CreateDocumentFragment();
132 RefPtr
<DocumentFragment
> frag
;
133 sParserWrapper
->ConvertCueToDOMTree(window
, static_cast<EventTarget
*>(this),
134 getter_AddRefs(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
) {
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)) {
164 } else if (!mLineIsAutoKeyword
) {
166 } else if (mLineIsAutoKeyword
&& !mSnapToLines
) {
168 } else if (!mTrack
|| !mTrack
->GetTextTrackList() ||
169 !mTrack
->GetTextTrackList()->GetMediaElement()) {
173 RefPtr
<TextTrackList
> trackList
= mTrack
->GetTextTrackList();
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
) {
182 if (mTrack
== track
) {
187 return (-1.0) * showingTracksNum
;
190 double TextTrackCue::ComputedPosition() {
191 // See spec https://w3c.github.io/webvtt/#cue-computed-position
192 if (!mPositionIsAutoKeyword
) {
195 if (ComputedPositionAlign() == PositionAlignSetting::Line_left
) {
198 if (ComputedPositionAlign() == PositionAlignSetting::Line_right
) {
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
226 return intl::Bidi::GetBaseDirection(mText
) != intl::Bidi::BaseDirection::RTL
;
229 void TextTrackCue::NotifyDisplayStatesChanged() {
234 if (!mTrack
|| !mTrack
->GetTextTrackList() ||
235 !mTrack
->GetTextTrackList()->GetMediaElement()) {
239 mTrack
->GetTextTrackList()
241 ->NotifyCueDisplayStatesChanged();
244 void TextTrackCue::SetActive(bool aActive
) {
245 if (mActive
== aActive
) {
249 LOG("TextTrackCue, SetActive=%d", aActive
);
251 mDisplayState
= mActive
? mDisplayState
: nullptr;
253 mTrack
->NotifyCueActiveStateChanged(this);
259 } // namespace mozilla::dom