Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/ImageTrackList.h"
#include "MediaResult.h"
#include "mozilla/dom/ImageDecoder.h"
#include "mozilla/dom/ImageTrack.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/image/ImageUtils.h"
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageTrackList, mParent, mDecoder,
mReadyPromise, mTracks)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageTrackList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageTrackList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageTrackList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
ImageTrackList::ImageTrackList(nsIGlobalObject* aParent, ImageDecoder* aDecoder)
: mParent(aParent), mDecoder(aDecoder) {}
ImageTrackList::~ImageTrackList() = default;
JSObject* ImageTrackList::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
AssertIsOnOwningThread();
return ImageTrackList_Binding::Wrap(aCx, this, aGivenProto);
}
void ImageTrackList::Initialize(ErrorResult& aRv) {
mReadyPromise = Promise::Create(mParent, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
void ImageTrackList::Destroy() {
if (!mIsReady && mReadyPromise && mReadyPromise->PromiseObj()) {
mReadyPromise->MaybeRejectWithAbortError("ImageTrackList destroyed");
mIsReady = true;
}
for (auto& track : mTracks) {
track->Destroy();
}
mTracks.Clear();
mDecoder = nullptr;
mSelectedIndex = -1;
}
void ImageTrackList::MaybeRejectReady(const MediaResult& aResult) {
if (mIsReady || !mReadyPromise || !mReadyPromise->PromiseObj()) {
return;
}
aResult.RejectTo(mReadyPromise);
mIsReady = true;
}
void ImageTrackList::OnMetadataSuccess(
const image::DecodeMetadataResult& aMetadata) {
// 10.2.5. Establish Tracks
//
// Note that our implementation only supports one track, so many of these
// steps are simplified.
// 4. Let newTrackList be a new list.
MOZ_ASSERT(mTracks.IsEmpty());
// 5. For each image track found in [[encoded data]]:
// 5.1. Let newTrack be a new ImageTrack, initialized as follows:
// 5.1.1. Assign this to [[ImageDecoder]].
// 5.1.2. Assign tracks to [[ImageTrackList]].
// 5.1.3. If image track is found to be animated, assign true to newTrack's
// [[animated]] internal slot. Otherwise, assign false.
// 5.1.4. If image track is found to describe a frame count, assign that
// count to newTrack's [[frame count]] internal slot. Otherwise, assign
// 0.
// 5.1.5. If image track is found to describe a repetition count, assign that
// count to [[repetition count]] internal slot. Otherwise, assign 0.
// 5.1.6. Assign false to newTrack’s [[selected]] internal slot.
// 5.2. Append newTrack to newTrackList.
// 6. Let selectedTrackIndex be the result of running the Get Default Selected
// Track Index algorithm with newTrackList.
// 7. Let selectedTrack be the track at position selectedTrackIndex within
// newTrackList.
// 8. Assign true to selectedTrack’s [[selected]] internal slot.
// 9. Assign selectedTrackIndex to [[internal selected track index]].
const float repetitions = aMetadata.mRepetitions < 0
? std::numeric_limits<float>::infinity()
: static_cast<float>(aMetadata.mRepetitions);
auto track = MakeRefPtr<ImageTrack>(
this, /* aIndex */ 0, /* aSelected */ true, aMetadata.mAnimated,
aMetadata.mFrameCount, aMetadata.mFrameCountComplete, repetitions);
// 11. Queue a task to perform the following steps:
//
// Note that we were already dispatched by the image decoder.
// 11.1. Assign newTrackList to the tracks [[track list]] internal slot.
mTracks.AppendElement(std::move(track));
// 11.2. Assign selectedTrackIndex to tracks [[selected index]].
mSelectedIndex = 0;
// 11.3. Resolve [[ready promise]].
MOZ_ASSERT(!mIsReady);
mReadyPromise->MaybeResolveWithUndefined();
mIsReady = true;
}
void ImageTrackList::OnFrameCountSuccess(
const image::DecodeFrameCountResult& aResult) {
if (mTracks.IsEmpty()) {
return;
}
// 10.2.5. Update Tracks
//
// Note that we were already dispatched from the decoding threads.
// 3. Let trackList be a copy of tracks' [[track list]].
// 4. For each track in trackList:
// 4.1. Let trackIndex be the position of track in trackList.
// 4.2. Let latestFrameCount be the frame count as indicated by
// [[encoded data]] for the track corresponding to track.
// 4.3. Assert that latestFrameCount is greater than or equal to
// track.frameCount.
// 4.4. If latestFrameCount is greater than track.frameCount:
// 4.4.1. Let change be a track update struct whose track index is trackIndex
// and frame count is latestFrameCount.
// 4.4.2. Append change to tracksChanges.
// 5. If tracksChanges is empty, abort these steps.
// 6. Queue a task to perform the following steps:
// 6.1. For each update in trackChanges:
// 6.1.1. Let updateTrack be the ImageTrack at position update.trackIndex
// within tracks' [[track list]].
// 6.1.2. Assign update.frameCount to updateTrack’s [[frame count]].
mTracks.LastElement()->OnFrameCountSuccess(aResult);
}
void ImageTrackList::SetSelectedIndex(int32_t aIndex, bool aSelected) {
MOZ_ASSERT(aIndex >= 0);
MOZ_ASSERT(uint32_t(aIndex) < mTracks.Length());
// 10.7.2. Attributes - selected, of type boolean
// 1. If [[ImageDecoder]]'s [[closed]] slot is true, abort these steps.
if (!mDecoder) {
return;
}
// 2. Let newValue be the given value.
// 3. If newValue equals [[selected]], abort these steps.
// 4. Assign newValue to [[selected]].
// 5. Let parentTrackList be [[ImageTrackList]]
// 6. Let oldSelectedIndex be the value of parentTrackList [[selected index]].
// 7. If oldSelectedIndex is not -1:
// 7.1. Let oldSelectedTrack be the ImageTrack in parentTrackList
// [[track list]] at the position of oldSelectedIndex.
// 7.2. Assign false to oldSelectedTrack [[selected]]
// 8. If newValue is true, let selectedIndex be the index of this ImageTrack
// within parentTrackList's [[track list]]. Otherwise, let selectedIndex be
// -1.
// 9. Assign selectedIndex to parentTrackList [[selected index]].
if (aSelected) {
if (mSelectedIndex == -1) {
MOZ_ASSERT(!mTracks[aIndex]->Selected());
mTracks[aIndex]->MarkSelected();
mSelectedIndex = aIndex;
} else if (mSelectedIndex != aIndex) {
MOZ_ASSERT(mTracks[mSelectedIndex]->Selected());
MOZ_ASSERT(!mTracks[aIndex]->Selected());
mTracks[mSelectedIndex]->ClearSelected();
mTracks[aIndex]->MarkSelected();
mSelectedIndex = aIndex;
} else {
MOZ_ASSERT(mTracks[mSelectedIndex]->Selected());
return;
}
} else if (mSelectedIndex == aIndex) {
mTracks[mSelectedIndex]->ClearSelected();
mSelectedIndex = -1;
} else {
MOZ_ASSERT(!mTracks[aIndex]->Selected());
return;
}
// 10. Run the Reset ImageDecoder algorithm on [[ImageDecoder]].
mDecoder->Reset();
// 11. Queue a control message to [[ImageDecoder]]'s control message queue to
// update the internal selected track index with selectedIndex.
mDecoder->QueueSelectTrackMessage(mSelectedIndex);
// 12. Process the control message queue belonging to [[ImageDecoder]].
mDecoder->ProcessControlMessageQueue();
}
} // namespace mozilla::dom