/* -*- 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/TextTrackList.h" #include "mozilla/dom/TextTrackRegion.h" #include "nsComponentManagerUtils.h" #include "mozilla/ClearOnShutdown.h" namespace mozilla { namespace 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 TextTrackCue::sParserWrapper; // Set cue setting defaults based on step 19 & seq. // in http://dev.w3.org/html5/webvtt/#parsing void TextTrackCue::SetDefaultCueSettings() { mPositionIsAutoKeyword = true; mPositionAlign = PositionAlignSetting::Center; 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)) { 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)) { SetDefaultCueSettings(); MOZ_ASSERT(aOwnerWindow); if (NS_FAILED(StashDocument())) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); } } TextTrackCue::~TextTrackCue() {} /** 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 TextTrackCue::GetCueAsHTML() { // mDocument may be null during cycle collector shutdown. // See bug 941701. if (!mDocument) { return nullptr; } if (!sParserWrapper) { nsresult rv; nsCOMPtr 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 frag; sParserWrapper->ConvertCueToDOMTree(window, 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 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 trackList = mTrack->GetTextTrackList(); bool dummy; uint32_t showingTracksNum = 0; for (uint32_t idx = 0; idx < trackList->Length(); idx++) { RefPtr 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; } else if (mAlign == AlignSetting::Left) { return 0.0; } else if (mAlign == AlignSetting::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; } return PositionAlignSetting::Center; } void TextTrackCue::NotifyDisplayStatesChanged() { if (!mReset) { return; } if (!mTrack || !mTrack->GetTextTrackList() || !mTrack->GetTextTrackList()->GetMediaElement()) { return; } mTrack->GetTextTrackList() ->GetMediaElement() ->NotifyCueDisplayStatesChanged(); } } // namespace dom } // namespace mozilla