TextTrackCue.cpp (8047B)
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/. */ 5 6 #include "mozilla/dom/TextTrackCue.h" 7 8 #include "mozilla/ClearOnShutdown.h" 9 #include "mozilla/dom/Document.h" 10 #include "mozilla/dom/HTMLTrackElement.h" 11 #include "mozilla/dom/TextTrackList.h" 12 #include "mozilla/dom/TextTrackRegion.h" 13 #include "mozilla/intl/Bidi.h" 14 #include "nsComponentManagerUtils.h" 15 #include "nsGlobalWindowInner.h" 16 17 extern mozilla::LazyLogModule gTextTrackLog; 18 19 #define LOG(msg, ...) \ 20 MOZ_LOG(gTextTrackLog, LogLevel::Debug, \ 21 ("TextTrackCue=%p, " msg, this, ##__VA_ARGS__)) 22 23 namespace mozilla::dom { 24 25 NS_IMPL_CYCLE_COLLECTION_INHERITED(TextTrackCue, DOMEventTargetHelper, 26 mDocument, mTrack, mTrackElement, 27 mDisplayState, mRegion) 28 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) 33 34 StaticRefPtr<nsIWebVTTParserWrapper> TextTrackCue::sParserWrapper; 35 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; 49 } 50 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); 68 } 69 } 70 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); 89 } 90 } 91 92 TextTrackCue::~TextTrackCue() = default; 93 94 /** Save a reference to our creating document so we don't have to 95 * keep getting it from our window. 96 */ 97 nsresult TextTrackCue::StashDocument() { 98 nsPIDOMWindowInner* window = GetOwnerWindow(); 99 if (!window) { 100 return NS_ERROR_NO_INTERFACE; 101 } 102 mDocument = window->GetDoc(); 103 if (!mDocument) { 104 return NS_ERROR_NOT_AVAILABLE; 105 } 106 return NS_OK; 107 } 108 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; 114 } 115 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(); 122 } 123 sParserWrapper = parserWrapper; 124 ClearOnShutdown(&sParserWrapper); 125 } 126 127 nsPIDOMWindowInner* window = mDocument->GetInnerWindow(); 128 if (!window) { 129 return mDocument->CreateDocumentFragment(); 130 } 131 132 RefPtr<DocumentFragment> frag; 133 sParserWrapper->ConvertCueToDOMTree(window, static_cast<EventTarget*>(this), 134 getter_AddRefs(frag)); 135 if (!frag) { 136 return mDocument->CreateDocumentFragment(); 137 } 138 return frag.forget(); 139 } 140 141 void TextTrackCue::SetTrackElement(HTMLTrackElement* aTrackElement) { 142 mTrackElement = aTrackElement; 143 } 144 145 JSObject* TextTrackCue::WrapObject(JSContext* aCx, 146 JS::Handle<JSObject*> aGivenProto) { 147 return VTTCue_Binding::Wrap(aCx, this, aGivenProto); 148 } 149 150 TextTrackRegion* TextTrackCue::GetRegion() { return mRegion; } 151 152 void TextTrackCue::SetRegion(TextTrackRegion* aRegion) { 153 if (mRegion == aRegion) { 154 return; 155 } 156 mRegion = aRegion; 157 mReset = true; 158 } 159 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; 171 } 172 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++; 180 } 181 182 if (mTrack == track) { 183 break; 184 } 185 } 186 187 return (-1.0) * showingTracksNum; 188 } 189 190 double TextTrackCue::ComputedPosition() { 191 // See spec https://w3c.github.io/webvtt/#cue-computed-position 192 if (!mPositionIsAutoKeyword) { 193 return mPosition; 194 } 195 if (ComputedPositionAlign() == PositionAlignSetting::Line_left) { 196 return 0.0; 197 } 198 if (ComputedPositionAlign() == PositionAlignSetting::Line_right) { 199 return 100.0; 200 } 201 return 50.0; 202 } 203 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; 218 } 219 return PositionAlignSetting::Center; 220 } 221 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; 227 } 228 229 void TextTrackCue::NotifyDisplayStatesChanged() { 230 if (!mReset) { 231 return; 232 } 233 234 if (!mTrack || !mTrack->GetTextTrackList() || 235 !mTrack->GetTextTrackList()->GetMediaElement()) { 236 return; 237 } 238 239 mTrack->GetTextTrackList() 240 ->GetMediaElement() 241 ->NotifyCueDisplayStatesChanged(); 242 } 243 244 void TextTrackCue::SetActive(bool aActive) { 245 if (mActive == aActive) { 246 return; 247 } 248 249 LOG("TextTrackCue, SetActive=%d", aActive); 250 mActive = aActive; 251 mDisplayState = mActive ? mDisplayState : nullptr; 252 if (mTrack) { 253 mTrack->NotifyCueActiveStateChanged(this); 254 } 255 } 256 257 #undef LOG 258 259 } // namespace mozilla::dom