summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/track
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/html/track
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/html/track')
-rw-r--r--Source/WebCore/html/track/AudioTrack.cpp157
-rw-r--r--Source/WebCore/html/track/AudioTrack.h65
-rw-r--r--Source/WebCore/html/track/AudioTrack.idl5
-rw-r--r--Source/WebCore/html/track/AudioTrackList.cpp35
-rw-r--r--Source/WebCore/html/track/AudioTrackList.h20
-rw-r--r--Source/WebCore/html/track/AudioTrackList.idl22
-rw-r--r--Source/WebCore/html/track/BufferedLineReader.cpp104
-rw-r--r--Source/WebCore/html/track/BufferedLineReader.h76
-rw-r--r--Source/WebCore/html/track/DataCue.cpp193
-rw-r--r--Source/WebCore/html/track/DataCue.h109
-rw-r--r--Source/WebCore/html/track/DataCue.idl38
-rw-r--r--Source/WebCore/html/track/InbandDataTextTrack.cpp122
-rw-r--r--Source/WebCore/html/track/InbandDataTextTrack.h59
-rw-r--r--Source/WebCore/html/track/InbandGenericTextTrack.cpp239
-rw-r--r--Source/WebCore/html/track/InbandGenericTextTrack.h59
-rw-r--r--Source/WebCore/html/track/InbandTextTrack.cpp173
-rw-r--r--Source/WebCore/html/track/InbandTextTrack.h71
-rw-r--r--Source/WebCore/html/track/InbandWebVTTTextTrack.cpp64
-rw-r--r--Source/WebCore/html/track/InbandWebVTTTextTrack.h38
-rw-r--r--Source/WebCore/html/track/LoadableTextTrack.cpp73
-rw-r--r--Source/WebCore/html/track/LoadableTextTrack.h60
-rw-r--r--Source/WebCore/html/track/TextTrack.cpp436
-rw-r--r--Source/WebCore/html/track/TextTrack.h175
-rw-r--r--Source/WebCore/html/track/TextTrack.idl42
-rw-r--r--Source/WebCore/html/track/TextTrackCue.cpp1094
-rw-r--r--Source/WebCore/html/track/TextTrackCue.h248
-rw-r--r--Source/WebCore/html/track/TextTrackCue.idl47
-rw-r--r--Source/WebCore/html/track/TextTrackCueGeneric.cpp163
-rw-r--r--Source/WebCore/html/track/TextTrackCueGeneric.h69
-rw-r--r--Source/WebCore/html/track/TextTrackCueList.cpp145
-rw-r--r--Source/WebCore/html/track/TextTrackCueList.h56
-rw-r--r--Source/WebCore/html/track/TextTrackCueList.idl4
-rw-r--r--Source/WebCore/html/track/TextTrackList.cpp176
-rw-r--r--Source/WebCore/html/track/TextTrackList.h34
-rw-r--r--Source/WebCore/html/track/TextTrackList.idl21
-rw-r--r--Source/WebCore/html/track/TrackBase.cpp109
-rw-r--r--Source/WebCore/html/track/TrackBase.h49
-rw-r--r--Source/WebCore/html/track/TrackEvent.cpp32
-rw-r--r--Source/WebCore/html/track/TrackEvent.h48
-rw-r--r--Source/WebCore/html/track/TrackEvent.idl11
-rw-r--r--Source/WebCore/html/track/TrackListBase.cpp63
-rw-r--r--Source/WebCore/html/track/TrackListBase.h35
-rw-r--r--Source/WebCore/html/track/VTTCue.cpp1180
-rw-r--r--Source/WebCore/html/track/VTTCue.h231
-rw-r--r--Source/WebCore/html/track/VTTCue.idl43
-rw-r--r--Source/WebCore/html/track/VTTRegion.cpp428
-rw-r--r--Source/WebCore/html/track/VTTRegion.h (renamed from Source/WebCore/html/track/TextTrackRegion.h)97
-rw-r--r--Source/WebCore/html/track/VTTRegion.idl (renamed from Source/WebCore/html/track/TextTrackRegion.idl)29
-rw-r--r--Source/WebCore/html/track/VTTRegionList.cpp71
-rw-r--r--Source/WebCore/html/track/VTTRegionList.h (renamed from Source/WebCore/html/track/TextTrackRegionList.h)58
-rw-r--r--Source/WebCore/html/track/VTTRegionList.idl (renamed from Source/WebCore/html/track/TextTrackRegionList.idl)18
-rw-r--r--Source/WebCore/html/track/VTTScanner.cpp180
-rw-r--r--Source/WebCore/html/track/VTTScanner.h230
-rw-r--r--Source/WebCore/html/track/VideoTrack.cpp157
-rw-r--r--Source/WebCore/html/track/VideoTrack.h65
-rw-r--r--Source/WebCore/html/track/VideoTrack.idl5
-rw-r--r--Source/WebCore/html/track/VideoTrackList.cpp41
-rw-r--r--Source/WebCore/html/track/VideoTrackList.h25
-rw-r--r--Source/WebCore/html/track/VideoTrackList.idl23
-rw-r--r--Source/WebCore/html/track/WebVTTElement.cpp59
-rw-r--r--Source/WebCore/html/track/WebVTTElement.h29
-rw-r--r--Source/WebCore/html/track/WebVTTParser.cpp598
-rw-r--r--Source/WebCore/html/track/WebVTTParser.h128
-rw-r--r--Source/WebCore/html/track/WebVTTToken.h172
-rw-r--r--Source/WebCore/html/track/WebVTTTokenizer.cpp322
-rw-r--r--Source/WebCore/html/track/WebVTTTokenizer.h83
66 files changed, 5506 insertions, 3605 deletions
diff --git a/Source/WebCore/html/track/AudioTrack.cpp b/Source/WebCore/html/track/AudioTrack.cpp
index aecdb0af6..eeb05537f 100644
--- a/Source/WebCore/html/track/AudioTrack.cpp
+++ b/Source/WebCore/html/track/AudioTrack.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -30,158 +30,161 @@
*/
#include "config.h"
+#include "AudioTrack.h"
#if ENABLE(VIDEO_TRACK)
-#include "AudioTrack.h"
-
-#include "AudioTrackList.h"
-#include "Event.h"
#include "HTMLMediaElement.h"
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
const AtomicString& AudioTrack::alternativeKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, alternative, ("alternative", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<AtomicString> alternative("alternative", AtomicString::ConstructFromLiteral);
return alternative;
}
const AtomicString& AudioTrack::descriptionKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, description, ("description", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<AtomicString> description("description", AtomicString::ConstructFromLiteral);
return description;
}
const AtomicString& AudioTrack::mainKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, main, ("main", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<AtomicString> main("main", AtomicString::ConstructFromLiteral);
return main;
}
const AtomicString& AudioTrack::mainDescKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, mainDesc, ("main-desc", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<AtomicString> mainDesc("main-desc", AtomicString::ConstructFromLiteral);
return mainDesc;
}
const AtomicString& AudioTrack::translationKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, translation, ("translation", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<AtomicString> translation("translation", AtomicString::ConstructFromLiteral);
return translation;
}
const AtomicString& AudioTrack::commentaryKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, commentary, ("commentary", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<AtomicString> commentary("commentary", AtomicString::ConstructFromLiteral);
return commentary;
}
-AudioTrack::AudioTrack(AudioTrackClient* client, PassRefPtr<AudioTrackPrivate> trackPrivate)
- : TrackBase(TrackBase::AudioTrack, trackPrivate->id(), trackPrivate->label(), trackPrivate->language())
- , m_enabled(trackPrivate->enabled())
- , m_client(client)
+AudioTrack::AudioTrack(AudioTrackClient& client, AudioTrackPrivate& trackPrivate)
+ : MediaTrackBase(MediaTrackBase::AudioTrack, trackPrivate.id(), trackPrivate.label(), trackPrivate.language())
+ , m_enabled(trackPrivate.enabled())
+ , m_client(&client)
, m_private(trackPrivate)
{
m_private->setClient(this);
-
- switch (m_private->kind()) {
- case AudioTrackPrivate::Alternative:
- setKind(AudioTrack::alternativeKeyword());
- break;
- case AudioTrackPrivate::Description:
- setKind(AudioTrack::descriptionKeyword());
- break;
- case AudioTrackPrivate::Main:
- setKind(AudioTrack::mainKeyword());
- break;
- case AudioTrackPrivate::MainDesc:
- setKind(AudioTrack::mainDescKeyword());
- break;
- case AudioTrackPrivate::Translation:
- setKind(AudioTrack::translationKeyword());
- break;
- case AudioTrackPrivate::Commentary:
- setKind(AudioTrack::commentaryKeyword());
- break;
- case AudioTrackPrivate::None:
- setKind(emptyString());
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
+ updateKindFromPrivate();
}
AudioTrack::~AudioTrack()
{
- m_private->setClient(0);
+ m_private->setClient(nullptr);
}
-bool AudioTrack::isValidKind(const AtomicString& value) const
+void AudioTrack::setPrivate(AudioTrackPrivate& trackPrivate)
{
- if (value == alternativeKeyword())
- return true;
- if (value == descriptionKeyword())
- return true;
- if (value == mainKeyword())
- return true;
- if (value == mainDescKeyword())
- return true;
- if (value == translationKeyword())
- return true;
- if (value == commentaryKeyword())
- return true;
+ if (m_private.ptr() == &trackPrivate)
+ return;
+
+ m_private->setClient(nullptr);
+ m_private = trackPrivate;
+ m_private->setEnabled(m_enabled);
+ m_private->setClient(this);
- return false;
+ updateKindFromPrivate();
+}
+
+bool AudioTrack::isValidKind(const AtomicString& value) const
+{
+ return value == alternativeKeyword()
+ || value == commentaryKeyword()
+ || value == descriptionKeyword()
+ || value == mainKeyword()
+ || value == mainDescKeyword()
+ || value == translationKeyword();
}
-void AudioTrack::setEnabled(const bool enabled)
+void AudioTrack::setEnabled(bool enabled)
{
if (m_enabled == enabled)
return;
- m_enabled = enabled;
m_private->setEnabled(enabled);
-
- if (m_client)
- m_client->audioTrackEnabledChanged(this);
}
-size_t AudioTrack::inbandTrackIndex()
+size_t AudioTrack::inbandTrackIndex() const
{
- ASSERT(m_private);
return m_private->trackIndex();
}
-void AudioTrack::enabledChanged(AudioTrackPrivate* trackPrivate, bool enabled)
+void AudioTrack::enabledChanged(bool enabled)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
- setEnabled(enabled);
+ if (m_enabled == enabled)
+ return;
+
+ m_enabled = enabled;
+
+ if (m_client)
+ m_client->audioTrackEnabledChanged(*this);
}
-void AudioTrack::idChanged(TrackPrivateBase* trackPrivate, const String& id)
+void AudioTrack::idChanged(const AtomicString& id)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setId(id);
}
-void AudioTrack::labelChanged(TrackPrivateBase* trackPrivate, const String& label)
+void AudioTrack::labelChanged(const AtomicString& label)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setLabel(label);
}
-void AudioTrack::languageChanged(TrackPrivateBase* trackPrivate, const String& language)
+void AudioTrack::languageChanged(const AtomicString& language)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setLanguage(language);
}
-void AudioTrack::willRemove(TrackPrivateBase* trackPrivate)
+void AudioTrack::willRemove()
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
- mediaElement()->removeAudioTrack(this);
+ mediaElement()->removeAudioTrack(*this);
+}
+
+void AudioTrack::updateKindFromPrivate()
+{
+ switch (m_private->kind()) {
+ case AudioTrackPrivate::Alternative:
+ setKind(AudioTrack::alternativeKeyword());
+ break;
+ case AudioTrackPrivate::Description:
+ setKind(AudioTrack::descriptionKeyword());
+ break;
+ case AudioTrackPrivate::Main:
+ setKind(AudioTrack::mainKeyword());
+ break;
+ case AudioTrackPrivate::MainDesc:
+ setKind(AudioTrack::mainDescKeyword());
+ break;
+ case AudioTrackPrivate::Translation:
+ setKind(AudioTrack::translationKeyword());
+ break;
+ case AudioTrackPrivate::Commentary:
+ setKind(AudioTrack::commentaryKeyword());
+ break;
+ case AudioTrackPrivate::None:
+ setKind(emptyString());
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/AudioTrack.h b/Source/WebCore/html/track/AudioTrack.h
index 29c5bd4c0..07c7794fa 100644
--- a/Source/WebCore/html/track/AudioTrack.h
+++ b/Source/WebCore/html/track/AudioTrack.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,17 +24,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AudioTrack_h
-#define AudioTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "AudioTrackPrivate.h"
-#include "ExceptionCode.h"
#include "TrackBase.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -43,14 +38,14 @@ class AudioTrack;
class AudioTrackClient {
public:
virtual ~AudioTrackClient() { }
- virtual void audioTrackEnabledChanged(AudioTrack*) = 0;
+ virtual void audioTrackEnabledChanged(AudioTrack&) = 0;
};
-class AudioTrack : public TrackBase, public AudioTrackPrivateClient {
+class AudioTrack final : public MediaTrackBase, private AudioTrackPrivateClient {
public:
- static PassRefPtr<AudioTrack> create(AudioTrackClient* client, PassRefPtr<AudioTrackPrivate> trackPrivate)
+ static Ref<AudioTrack> create(AudioTrackClient& client, AudioTrackPrivate& trackPrivate)
{
- return adoptRef(new AudioTrack(client, trackPrivate));
+ return adoptRef(*new AudioTrack(client, trackPrivate));
}
virtual ~AudioTrack();
@@ -60,41 +55,43 @@ public:
static const AtomicString& mainDescKeyword();
static const AtomicString& translationKeyword();
static const AtomicString& commentaryKeyword();
- virtual const AtomicString& defaultKindKeyword() const override { return emptyAtom; }
- virtual bool enabled() const override { return m_enabled; }
- virtual void setEnabled(const bool);
+ bool enabled() const final { return m_enabled; }
+ void setEnabled(const bool);
- virtual void clearClient() override { m_client = 0; }
+ void clearClient() final { m_client = nullptr; }
AudioTrackClient* client() const { return m_client; }
- size_t inbandTrackIndex();
+ size_t inbandTrackIndex() const;
-protected:
- AudioTrack(AudioTrackClient*, PassRefPtr<AudioTrackPrivate>);
+ void setPrivate(AudioTrackPrivate&);
private:
- virtual bool isValidKind(const AtomicString&) const override;
+ AudioTrack(AudioTrackClient&, AudioTrackPrivate&);
- virtual void enabledChanged(AudioTrackPrivate*, bool) override;
- virtual void idChanged(TrackPrivateBase*, const String&) override;
- virtual void labelChanged(TrackPrivateBase*, const String&) override;
- virtual void languageChanged(TrackPrivateBase*, const String&) override;
- virtual void willRemove(TrackPrivateBase*) override;
+ bool isValidKind(const AtomicString&) const final;
+
+ // AudioTrackPrivateClient
+ void enabledChanged(bool) final;
+
+ // TrackPrivateBaseClient
+ void idChanged(const AtomicString&) final;
+ void labelChanged(const AtomicString&) final;
+ void languageChanged(const AtomicString&) final;
+ void willRemove() final;
+
+ void updateKindFromPrivate();
bool m_enabled;
AudioTrackClient* m_client;
- RefPtr<AudioTrackPrivate> m_private;
+ Ref<AudioTrackPrivate> m_private;
};
-inline AudioTrack* toAudioTrack(TrackBase* track)
-{
- ASSERT_WITH_SECURITY_IMPLICATION(track->type() == TrackBase::AudioTrack);
- return static_cast<AudioTrack*>(track);
-}
-
} // namespace WebCore
-#endif
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::AudioTrack)
+ static bool isType(const WebCore::TrackBase& track) { return track.type() == WebCore::TrackBase::AudioTrack; }
+SPECIALIZE_TYPE_TRAITS_END()
+
#endif
diff --git a/Source/WebCore/html/track/AudioTrack.idl b/Source/WebCore/html/track/AudioTrack.idl
index fefd44ea5..addf4bf83 100644
--- a/Source/WebCore/html/track/AudioTrack.idl
+++ b/Source/WebCore/html/track/AudioTrack.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,7 +24,6 @@
*/
[
- NoInterfaceObject,
Conditional=VIDEO_TRACK,
GenerateIsReachable=ImplElementRoot,
JSCustomMarkFunction
diff --git a/Source/WebCore/html/track/AudioTrackList.cpp b/Source/WebCore/html/track/AudioTrackList.cpp
index eb8c9a73f..71155690a 100644
--- a/Source/WebCore/html/track/AudioTrackList.cpp
+++ b/Source/WebCore/html/track/AudioTrackList.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -30,7 +30,6 @@
#include "AudioTrackList.h"
#include "AudioTrack.h"
-#include "EventNames.h"
using namespace WebCore;
@@ -43,36 +42,40 @@ AudioTrackList::~AudioTrackList()
{
}
-void AudioTrackList::append(PassRefPtr<AudioTrack> prpTrack)
+void AudioTrackList::append(Ref<AudioTrack>&& track)
{
- RefPtr<AudioTrack> track = prpTrack;
-
// Insert tracks in the media file order.
size_t index = track->inbandTrackIndex();
- m_inbandTracks.insert(index, track);
+ size_t insertionIndex;
+ for (insertionIndex = 0; insertionIndex < m_inbandTracks.size(); ++insertionIndex) {
+ auto& otherTrack = downcast<AudioTrack>(*m_inbandTracks[insertionIndex]);
+ if (otherTrack.inbandTrackIndex() > index)
+ break;
+ }
+ m_inbandTracks.insert(insertionIndex, track.ptr());
+
ASSERT(!track->mediaElement() || track->mediaElement() == mediaElement());
track->setMediaElement(mediaElement());
- scheduleAddTrackEvent(track.release());
+ scheduleAddTrackEvent(WTFMove(track));
}
AudioTrack* AudioTrackList::item(unsigned index) const
{
if (index < m_inbandTracks.size())
- return toAudioTrack(m_inbandTracks[index].get());
-
- return 0;
+ return downcast<AudioTrack>(m_inbandTracks[index].get());
+ return nullptr;
}
AudioTrack* AudioTrackList::getTrackById(const AtomicString& id) const
{
- for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
- AudioTrack* track = toAudioTrack(m_inbandTracks[i].get());
- if (track->id() == id)
- return track;
+ for (auto& inbandTrack : m_inbandTracks) {
+ auto& track = downcast<AudioTrack>(*inbandTrack);
+ if (track.id() == id)
+ return &track;
}
- return 0;
+ return nullptr;
}
EventTargetInterface AudioTrackList::eventTargetInterface() const
diff --git a/Source/WebCore/html/track/AudioTrackList.h b/Source/WebCore/html/track/AudioTrackList.h
index 9104b6bfd..0c637ddc3 100644
--- a/Source/WebCore/html/track/AudioTrackList.h
+++ b/Source/WebCore/html/track/AudioTrackList.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AudioTrackList_h
-#define AudioTrackList_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
@@ -34,11 +33,11 @@ namespace WebCore {
class AudioTrack;
-class AudioTrackList : public TrackListBase {
+class AudioTrackList final : public TrackListBase {
public:
- static PassRefPtr<AudioTrackList> create(HTMLMediaElement* owner, ScriptExecutionContext* context)
+ static Ref<AudioTrackList> create(HTMLMediaElement* owner, ScriptExecutionContext* context)
{
- return adoptRef(new AudioTrackList(owner, context));
+ return adoptRef(*new AudioTrackList(owner, context));
}
virtual ~AudioTrackList();
@@ -46,10 +45,10 @@ public:
AudioTrack* item(unsigned index) const;
AudioTrack* lastItem() const { return item(length() - 1); }
- void append(PassRefPtr<AudioTrack>);
+ void append(Ref<AudioTrack>&&);
// EventTarget
- virtual EventTargetInterface eventTargetInterface() const override;
+ EventTargetInterface eventTargetInterface() const override;
private:
AudioTrackList(HTMLMediaElement*, ScriptExecutionContext*);
@@ -57,5 +56,4 @@ private:
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/AudioTrackList.idl b/Source/WebCore/html/track/AudioTrackList.idl
index 439384725..cde73f40a 100644
--- a/Source/WebCore/html/track/AudioTrackList.idl
+++ b/Source/WebCore/html/track/AudioTrackList.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,26 +24,16 @@
*/
[
- NoInterfaceObject,
Conditional=VIDEO_TRACK,
GenerateIsReachable=ImplElementRoot,
- EventTarget,
JSCustomMarkFunction,
-] interface AudioTrackList {
+] interface AudioTrackList : EventTarget {
readonly attribute unsigned long length;
getter AudioTrack item(unsigned long index);
AudioTrack getTrackById(DOMString id);
- attribute EventListener onchange;
- attribute EventListener onaddtrack;
- attribute EventListener onremovetrack;
-
- void addEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- void removeEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- [RaisesException] boolean dispatchEvent(Event evt);
+ attribute EventHandler onchange;
+ attribute EventHandler onaddtrack;
+ attribute EventHandler onremovetrack;
};
diff --git a/Source/WebCore/html/track/BufferedLineReader.cpp b/Source/WebCore/html/track/BufferedLineReader.cpp
new file mode 100644
index 000000000..8f2362512
--- /dev/null
+++ b/Source/WebCore/html/track/BufferedLineReader.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013, Opera Software ASA. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BufferedLineReader.h"
+
+#include <wtf/unicode/CharacterNames.h>
+
+namespace WebCore {
+
+std::optional<String> BufferedLineReader::nextLine()
+{
+ if (m_maybeSkipLF) {
+ // We ran out of data after a CR (U+000D), which means that we may be
+ // in the middle of a CRLF pair. If the next character is a LF (U+000A)
+ // then skip it, and then (unconditionally) return the buffered line.
+ if (!m_buffer.isEmpty()) {
+ if (m_buffer.currentCharacter() == newlineCharacter)
+ m_buffer.advancePastNewline();
+ m_maybeSkipLF = false;
+ }
+ // If there was no (new) data available, then keep m_maybeSkipLF set,
+ // and fall through all the way down to the EOS check at the end of the function.
+ }
+
+ bool shouldReturnLine = false;
+ bool checkForLF = false;
+ while (!m_buffer.isEmpty()) {
+ UChar character = m_buffer.currentCharacter();
+ m_buffer.advance();
+
+ if (character == newlineCharacter || character == carriageReturn) {
+ // We found a line ending. Return the accumulated line.
+ shouldReturnLine = true;
+ checkForLF = (character == carriageReturn);
+ break;
+ }
+
+ // NULs are transformed into U+FFFD (REPLACEMENT CHAR.) in step 1 of
+ // the WebVTT parser algorithm.
+ if (character == '\0')
+ character = replacementCharacter;
+
+ m_lineBuffer.append(character);
+ }
+
+ if (checkForLF) {
+ // May be in the middle of a CRLF pair.
+ if (!m_buffer.isEmpty()) {
+ if (m_buffer.currentCharacter() == newlineCharacter)
+ m_buffer.advancePastNewline();
+ } else {
+ // Check for the newline on the next call (unless we reached EOS, in
+ // which case we'll return the contents of the line buffer, and
+ // reset state for the next line.)
+ m_maybeSkipLF = true;
+ }
+ }
+
+ if (isAtEndOfStream()) {
+ // We've reached the end of the stream proper. Emit a line if the
+ // current line buffer is non-empty. (Note that if shouldReturnLine is
+ // set already, we want to return a line nonetheless.)
+ shouldReturnLine |= !m_lineBuffer.isEmpty();
+ }
+
+ if (shouldReturnLine) {
+ auto line = m_lineBuffer.toString();
+ m_lineBuffer.clear();
+ return WTFMove(line);
+ }
+
+ ASSERT(m_buffer.isEmpty());
+ return std::nullopt;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/track/BufferedLineReader.h b/Source/WebCore/html/track/BufferedLineReader.h
new file mode 100644
index 000000000..9334ae73e
--- /dev/null
+++ b/Source/WebCore/html/track/BufferedLineReader.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013, Opera Software ASA. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "SegmentedString.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+// Line collection helper for the WebVTT Parser.
+//
+// Converts a stream of data (== a sequence of Strings) into a set of
+// lines. CR, LR or CRLF are considered line breaks. Normalizes NULs (U+0000)
+// to 'REPLACEMENT CHARACTER' (U+FFFD) and does not return the line breaks as
+// part of the result.
+class BufferedLineReader {
+ WTF_MAKE_NONCOPYABLE(BufferedLineReader);
+public:
+ BufferedLineReader() = default;
+ void reset();
+
+ void append(String&& data)
+ {
+ ASSERT(!m_endOfStream);
+ m_buffer.append(WTFMove(data));
+ }
+
+ void appendEndOfStream() { m_endOfStream = true; }
+ bool isAtEndOfStream() const { return m_endOfStream && m_buffer.isEmpty(); }
+
+ std::optional<String> nextLine();
+
+private:
+ SegmentedString m_buffer;
+ StringBuilder m_lineBuffer;
+ bool m_endOfStream { false };
+ bool m_maybeSkipLF { false };
+};
+
+inline void BufferedLineReader::reset()
+{
+ m_buffer.clear();
+ m_lineBuffer.clear();
+ m_endOfStream = false;
+ m_maybeSkipLF = false;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/track/DataCue.cpp b/Source/WebCore/html/track/DataCue.cpp
new file mode 100644
index 000000000..3bc272ad0
--- /dev/null
+++ b/Source/WebCore/html/track/DataCue.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2014 Cable Television Labs Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO_TRACK)
+#include "DataCue.h"
+
+#include "Logging.h"
+#include "TextTrack.h"
+#include "TextTrackCueList.h"
+#include <runtime/JSCInlines.h>
+#include <runtime/Protect.h>
+
+using namespace JSC;
+
+namespace WebCore {
+
+DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, ArrayBuffer& data, const String& type)
+ : TextTrackCue(context, start, end)
+ , m_type(type)
+{
+ setData(data);
+}
+
+DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const void* data, unsigned length)
+ : TextTrackCue(context, start, end)
+ , m_data(ArrayBuffer::create(data, length))
+{
+}
+
+DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, RefPtr<SerializedPlatformRepresentation>&& platformValue, const String& type)
+ : TextTrackCue(context, start, end)
+ , m_type(type)
+ , m_platformValue(WTFMove(platformValue))
+{
+}
+
+DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, JSC::JSValue value, const String& type)
+ : TextTrackCue(context, start, end)
+ , m_type(type)
+ , m_value(value)
+{
+ if (m_value)
+ JSC::gcProtect(m_value);
+}
+
+DataCue::~DataCue()
+{
+ if (m_value)
+ JSC::gcUnprotect(m_value);
+}
+
+RefPtr<ArrayBuffer> DataCue::data() const
+{
+ if (m_platformValue)
+ return m_platformValue->data();
+
+ if (!m_data)
+ return nullptr;
+
+ return ArrayBuffer::create(*m_data);
+}
+
+void DataCue::setData(ArrayBuffer& data)
+{
+ m_platformValue = nullptr;
+ if (m_value)
+ JSC::gcUnprotect(m_value);
+ m_value = JSC::JSValue();
+
+ m_data = ArrayBuffer::create(data);
+}
+
+DataCue* toDataCue(TextTrackCue* cue)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(cue->cueType() == TextTrackCue::Data);
+ return static_cast<DataCue*>(cue);
+}
+
+const DataCue* toDataCue(const TextTrackCue* cue)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(cue->cueType() == TextTrackCue::Data);
+ return static_cast<const DataCue*>(cue);
+}
+
+bool DataCue::cueContentsMatch(const TextTrackCue& cue) const
+{
+ if (cue.cueType() != TextTrackCue::Data)
+ return false;
+
+ const DataCue* dataCue = toDataCue(&cue);
+ RefPtr<ArrayBuffer> otherData = dataCue->data();
+ if ((otherData && !m_data) || (!otherData && m_data))
+ return false;
+ if (m_data && m_data->byteLength() != otherData->byteLength())
+ return false;
+ if (m_data && m_data->data() && memcmp(m_data->data(), otherData->data(), m_data->byteLength()))
+ return false;
+
+ const SerializedPlatformRepresentation* otherPlatformValue = dataCue->platformValue();
+ if ((otherPlatformValue && !m_platformValue) || (!otherPlatformValue && m_platformValue))
+ return false;
+ if (m_platformValue && !m_platformValue->isEqual(*otherPlatformValue))
+ return false;
+
+ JSC::JSValue thisValue = valueOrNull();
+ JSC::JSValue otherValue = dataCue->valueOrNull();
+ if ((otherValue && !thisValue) || (!otherValue && thisValue))
+ return false;
+ if (!JSC::JSValue::strictEqual(nullptr, thisValue, otherValue))
+ return false;
+
+ return true;
+}
+
+bool DataCue::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
+{
+ if (!TextTrackCue::isEqual(cue, match))
+ return false;
+
+ if (cue.cueType() != TextTrackCue::Data)
+ return false;
+
+ return cueContentsMatch(cue);
+}
+
+bool DataCue::doesExtendCue(const TextTrackCue& cue) const
+{
+ if (!cueContentsMatch(cue))
+ return false;
+
+ return TextTrackCue::doesExtendCue(cue);
+}
+
+JSC::JSValue DataCue::value(JSC::ExecState& state) const
+{
+ if (m_platformValue)
+ return m_platformValue->deserialize(&state);
+
+ if (m_value)
+ return m_value;
+
+ return JSC::jsNull();
+}
+
+void DataCue::setValue(JSC::ExecState&, JSC::JSValue value)
+{
+ // FIXME: this should use a SerializedScriptValue.
+ if (m_value)
+ JSC::gcUnprotect(m_value);
+ m_value = value;
+ if (m_value)
+ JSC::gcProtect(m_value);
+
+ m_platformValue = nullptr;
+ m_data = nullptr;
+}
+
+JSValue DataCue::valueOrNull() const
+{
+ if (m_value)
+ return m_value;
+
+ return jsNull();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/DataCue.h b/Source/WebCore/html/track/DataCue.h
new file mode 100644
index 000000000..ea32bccb6
--- /dev/null
+++ b/Source/WebCore/html/track/DataCue.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 Cable Television Labs Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "SerializedPlatformRepresentation.h"
+#include "TextTrackCue.h"
+#include <runtime/ArrayBuffer.h>
+#include <runtime/JSCJSValue.h>
+#include <wtf/MediaTime.h>
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+
+class DataCue final : public TextTrackCue {
+public:
+ static Ref<DataCue> create(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, ArrayBuffer& data)
+ {
+ return adoptRef(*new DataCue(context, start, end, data, emptyString()));
+ }
+
+ static Ref<DataCue> create(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const void* data, unsigned length)
+ {
+ return adoptRef(*new DataCue(context, start, end, data, length));
+ }
+
+ static Ref<DataCue> create(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, ArrayBuffer& data, const String& type)
+ {
+ return adoptRef(*new DataCue(context, start, end, data, type));
+ }
+
+ static Ref<DataCue> create(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, RefPtr<SerializedPlatformRepresentation>&& platformValue, const String& type)
+ {
+ return adoptRef(*new DataCue(context, start, end, WTFMove(platformValue), type));
+ }
+
+ static Ref<DataCue> create(ScriptExecutionContext& context, double start, double end, ArrayBuffer& data)
+ {
+ return adoptRef(*new DataCue(context, MediaTime::createWithDouble(start), MediaTime::createWithDouble(end), data, emptyString()));
+ }
+ static Ref<DataCue> create(ScriptExecutionContext& context, double start, double end, JSC::JSValue value, const String& type)
+ {
+ return adoptRef(*new DataCue(context, MediaTime::createWithDouble(start), MediaTime::createWithDouble(end), value, type));
+ }
+
+ virtual ~DataCue();
+ CueType cueType() const override { return Data; }
+
+ RefPtr<JSC::ArrayBuffer> data() const;
+ void setData(JSC::ArrayBuffer&);
+
+ const SerializedPlatformRepresentation* platformValue() const { return m_platformValue.get(); }
+
+ JSC::JSValue value(JSC::ExecState&) const;
+ void setValue(JSC::ExecState&, JSC::JSValue);
+
+ String type() const { return m_type; }
+ void setType(const String& type) { m_type = type; }
+
+ bool isEqual(const TextTrackCue&, CueMatchRules) const override;
+ bool cueContentsMatch(const TextTrackCue&) const override;
+ bool doesExtendCue(const TextTrackCue&) const override;
+
+private:
+ DataCue(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end, ArrayBuffer&, const String&);
+ DataCue(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end, const void*, unsigned);
+ DataCue(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end, RefPtr<SerializedPlatformRepresentation>&&, const String&);
+ DataCue(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end, JSC::JSValue, const String&);
+
+ JSC::JSValue valueOrNull() const;
+
+ RefPtr<ArrayBuffer> m_data;
+ String m_type;
+ RefPtr<SerializedPlatformRepresentation> m_platformValue;
+ JSC::JSValue m_value;
+};
+
+DataCue* toDataCue(TextTrackCue*);
+const DataCue* toDataCue(const TextTrackCue*);
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/DataCue.idl b/Source/WebCore/html/track/DataCue.idl
new file mode 100644
index 000000000..3ebc041c1
--- /dev/null
+++ b/Source/WebCore/html/track/DataCue.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 Cable Television Labs Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+ Conditional=VIDEO_TRACK,
+ Constructor(unrestricted double startTime, unrestricted double endTime, ArrayBuffer data),
+ Constructor(unrestricted double startTime, unrestricted double endTime, any value, optional DOMString type),
+ ConstructorCallWith=ScriptExecutionContext
+] interface DataCue : TextTrackCue {
+ attribute ArrayBuffer data;
+
+ // Proposed extensions.
+ [CallWith=ScriptState] attribute any value;
+ readonly attribute DOMString type;
+};
diff --git a/Source/WebCore/html/track/InbandDataTextTrack.cpp b/Source/WebCore/html/track/InbandDataTextTrack.cpp
new file mode 100644
index 000000000..d2d4a01dc
--- /dev/null
+++ b/Source/WebCore/html/track/InbandDataTextTrack.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2014 Cable Television Labs Inc. All rights reserved.
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InbandDataTextTrack.h"
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "DataCue.h"
+#include "HTMLMediaElement.h"
+#include "InbandTextTrackPrivate.h"
+#include "Logging.h"
+
+namespace WebCore {
+
+inline InbandDataTextTrack::InbandDataTextTrack(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
+ : InbandTextTrack(context, client, trackPrivate)
+{
+}
+
+Ref<InbandDataTextTrack> InbandDataTextTrack::create(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
+{
+ return adoptRef(*new InbandDataTextTrack(context, client, trackPrivate));
+}
+
+InbandDataTextTrack::~InbandDataTextTrack()
+{
+}
+
+void InbandDataTextTrack::addDataCue(const MediaTime& start, const MediaTime& end, const void* data, unsigned length)
+{
+ addCue(DataCue::create(*scriptExecutionContext(), start, end, data, length));
+}
+
+#if ENABLE(DATACUE_VALUE)
+
+void InbandDataTextTrack::addDataCue(const MediaTime& start, const MediaTime& end, Ref<SerializedPlatformRepresentation>&& platformValue, const String& type)
+{
+ if (m_incompleteCueMap.contains(platformValue.ptr()))
+ return;
+
+ auto cue = DataCue::create(*scriptExecutionContext(), start, end, platformValue.copyRef(), type);
+ if (hasCue(cue.ptr(), TextTrackCue::IgnoreDuration)) {
+ LOG(Media, "InbandDataTextTrack::addDataCue ignoring already added cue: start=%s, end=%s\n", toString(cue->startTime()).utf8().data(), toString(cue->endTime()).utf8().data());
+ return;
+ }
+
+ if (end.isPositiveInfinite() && mediaElement()) {
+ cue->setEndTime(mediaElement()->durationMediaTime());
+ m_incompleteCueMap.add(WTFMove(platformValue), cue.copyRef());
+ }
+
+ addCue(WTFMove(cue));
+}
+
+void InbandDataTextTrack::updateDataCue(const MediaTime& start, const MediaTime& inEnd, SerializedPlatformRepresentation& platformValue)
+{
+ RefPtr<DataCue> cue = m_incompleteCueMap.get(&platformValue);
+ if (!cue)
+ return;
+
+ cue->willChange();
+
+ MediaTime end = inEnd;
+ if (end.isPositiveInfinite() && mediaElement())
+ end = mediaElement()->durationMediaTime();
+ else
+ m_incompleteCueMap.remove(&platformValue);
+
+ LOG(Media, "InbandDataTextTrack::updateDataCue: was start=%s, end=%s, will be start=%s, end=%s\n", toString(cue->startTime()).utf8().data(), toString(cue->endTime()).utf8().data(), toString(start).utf8().data(), toString(end).utf8().data());
+
+ cue->setStartTime(start);
+ cue->setEndTime(end);
+
+ cue->didChange();
+}
+
+void InbandDataTextTrack::removeDataCue(const MediaTime&, const MediaTime&, SerializedPlatformRepresentation& platformValue)
+{
+ if (auto cue = m_incompleteCueMap.take(&platformValue)) {
+ LOG(Media, "InbandDataTextTrack::removeDataCue removing cue: start=%s, end=%s\n", toString(cue->startTime()).utf8().data(), toString(cue->endTime()).utf8().data());
+ InbandTextTrack::removeCue(*cue);
+ }
+}
+
+ExceptionOr<void> InbandDataTextTrack::removeCue(TextTrackCue& cue)
+{
+ ASSERT(cue.cueType() == TextTrackCue::Data);
+
+ m_incompleteCueMap.remove(const_cast<SerializedPlatformRepresentation*>(toDataCue(&cue)->platformValue()));
+
+ return InbandTextTrack::removeCue(cue);
+}
+
+#endif
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/InbandDataTextTrack.h b/Source/WebCore/html/track/InbandDataTextTrack.h
new file mode 100644
index 000000000..67aeb6d05
--- /dev/null
+++ b/Source/WebCore/html/track/InbandDataTextTrack.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 Cable Television Labs Inc. All rights reserved.
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "InbandTextTrack.h"
+
+namespace WebCore {
+
+class DataCue;
+
+class InbandDataTextTrack final : public InbandTextTrack {
+public:
+ static Ref<InbandDataTextTrack> create(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
+ virtual ~InbandDataTextTrack();
+
+private:
+ InbandDataTextTrack(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
+
+ void addDataCue(const MediaTime& start, const MediaTime& end, const void*, unsigned) final;
+
+#if ENABLE(DATACUE_VALUE)
+ void addDataCue(const MediaTime& start, const MediaTime& end, Ref<SerializedPlatformRepresentation>&&, const String&) final;
+ void updateDataCue(const MediaTime& start, const MediaTime& end, SerializedPlatformRepresentation&) final;
+ void removeDataCue(const MediaTime& start, const MediaTime& end, SerializedPlatformRepresentation&) final;
+ ExceptionOr<void> removeCue(TextTrackCue&) final;
+
+ HashMap<RefPtr<SerializedPlatformRepresentation>, RefPtr<DataCue>> m_incompleteCueMap;
+#endif
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/InbandGenericTextTrack.cpp b/Source/WebCore/html/track/InbandGenericTextTrack.cpp
index d807dc2d3..8065c8843 100644
--- a/Source/WebCore/html/track/InbandGenericTextTrack.cpp
+++ b/Source/WebCore/html/track/InbandGenericTextTrack.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,170 +24,199 @@
*/
#include "config.h"
+#include "InbandGenericTextTrack.h"
#if ENABLE(VIDEO_TRACK)
-#include "InbandGenericTextTrack.h"
-
-#include "ExceptionCodePlaceholder.h"
+#include "DataCue.h"
#include "HTMLMediaElement.h"
#include "InbandTextTrackPrivate.h"
#include "Logging.h"
+#include "VTTRegionList.h"
#include <math.h>
#include <wtf/text/CString.h>
namespace WebCore {
-GenericTextTrackCueMap::GenericTextTrackCueMap()
+void GenericTextTrackCueMap::add(GenericCueData& cueData, TextTrackCueGeneric& cue)
{
+ m_dataToCueMap.add(&cueData, &cue);
+ m_cueToDataMap.add(&cue, &cueData);
}
-GenericTextTrackCueMap::~GenericTextTrackCueMap()
+TextTrackCueGeneric* GenericTextTrackCueMap::find(GenericCueData& cueData)
{
+ return m_dataToCueMap.get(&cueData);
}
-void GenericTextTrackCueMap::add(GenericCueData* cueData, TextTrackCueGeneric* cue)
+GenericCueData* GenericTextTrackCueMap::find(TextTrackCue& cue)
{
- m_dataToCueMap.add(cueData, cue);
- m_cueToDataMap.add(cue, cueData);
-}
-
-PassRefPtr<TextTrackCueGeneric> GenericTextTrackCueMap::find(GenericCueData* cueData)
-{
- CueDataToCueMap::iterator iter = m_dataToCueMap.find(cueData);
- if (iter == m_dataToCueMap.end())
- return 0;
-
- return iter->value;
+ return m_cueToDataMap.get(&cue);
}
-PassRefPtr<GenericCueData> GenericTextTrackCueMap::find(TextTrackCue* cue)
+void GenericTextTrackCueMap::remove(GenericCueData& cueData)
{
- CueToDataMap::iterator iter = m_cueToDataMap.find(cue);
- if (iter == m_cueToDataMap.end())
- return 0;
-
- return iter->value;
-}
-
-void GenericTextTrackCueMap::remove(GenericCueData* cueData)
-{
- RefPtr<TextTrackCueGeneric> cue = find(cueData);
-
- if (cue)
+ if (auto cue = m_dataToCueMap.take(&cueData))
m_cueToDataMap.remove(cue);
- m_dataToCueMap.remove(cueData);
}
-void GenericTextTrackCueMap::remove(TextTrackCue* cue)
+void GenericTextTrackCueMap::remove(TextTrackCue& cue)
{
- RefPtr<GenericCueData> genericData = find(cue);
- if (genericData) {
- m_dataToCueMap.remove(genericData);
- m_cueToDataMap.remove(cue);
- }
+ if (auto data = m_cueToDataMap.take(&cue))
+ m_dataToCueMap.remove(data);
}
-PassRefPtr<InbandGenericTextTrack> InbandGenericTextTrack::create(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> playerPrivate)
+inline InbandGenericTextTrack::InbandGenericTextTrack(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
+ : InbandTextTrack(context, client, trackPrivate)
{
- return adoptRef(new InbandGenericTextTrack(context, client, playerPrivate));
}
-InbandGenericTextTrack::InbandGenericTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> trackPrivate)
- : InbandTextTrack(context, client, trackPrivate)
+Ref<InbandGenericTextTrack> InbandGenericTextTrack::create(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
{
+ return adoptRef(*new InbandGenericTextTrack(context, client, trackPrivate));
}
InbandGenericTextTrack::~InbandGenericTextTrack()
{
}
-void InbandGenericTextTrack::updateCueFromCueData(TextTrackCueGeneric* cue, GenericCueData* cueData)
+void InbandGenericTextTrack::updateCueFromCueData(TextTrackCueGeneric& cue, GenericCueData& cueData)
{
- cue->willChange();
-
- cue->setStartTime(cueData->startTime(), IGNORE_EXCEPTION);
- double endTime = cueData->endTime();
- if (std::isinf(endTime) && mediaElement())
- endTime = mediaElement()->duration();
- cue->setEndTime(endTime, IGNORE_EXCEPTION);
- cue->setText(cueData->content());
- cue->setId(cueData->id());
- cue->setBaseFontSizeRelativeToVideoHeight(cueData->baseFontSize());
- cue->setFontSizeMultiplier(cueData->relativeFontSize());
- cue->setFontName(cueData->fontName());
-
- if (cueData->position() > 0)
- cue->setPosition(lround(cueData->position()), IGNORE_EXCEPTION);
- if (cueData->line() > 0)
- cue->setLine(lround(cueData->line()), IGNORE_EXCEPTION);
- if (cueData->size() > 0)
- cue->setSize(lround(cueData->size()), IGNORE_EXCEPTION);
- if (cueData->backgroundColor().isValid())
- cue->setBackgroundColor(cueData->backgroundColor().rgb());
- if (cueData->foregroundColor().isValid())
- cue->setForegroundColor(cueData->foregroundColor().rgb());
- if (cueData->highlightColor().isValid())
- cue->setHighlightColor(cueData->highlightColor().rgb());
-
- if (cueData->align() == GenericCueData::Start)
- cue->setAlign(ASCIILiteral("start"), IGNORE_EXCEPTION);
- else if (cueData->align() == GenericCueData::Middle)
- cue->setAlign(ASCIILiteral("middle"), IGNORE_EXCEPTION);
- else if (cueData->align() == GenericCueData::End)
- cue->setAlign(ASCIILiteral("end"), IGNORE_EXCEPTION);
- cue->setSnapToLines(false);
-
- cue->didChange();
+ cue.willChange();
+
+ cue.setStartTime(cueData.startTime());
+ MediaTime endTime = cueData.endTime();
+ if (endTime.isPositiveInfinite() && mediaElement())
+ endTime = mediaElement()->durationMediaTime();
+ cue.setEndTime(endTime);
+ cue.setText(cueData.content());
+ cue.setId(cueData.id());
+ cue.setBaseFontSizeRelativeToVideoHeight(cueData.baseFontSize());
+ cue.setFontSizeMultiplier(cueData.relativeFontSize());
+ cue.setFontName(cueData.fontName());
+
+ if (cueData.position() > 0)
+ cue.setPosition(std::round(cueData.position()));
+ if (cueData.line() > 0)
+ cue.setLine(std::round(cueData.line()));
+ if (cueData.size() > 0)
+ cue.setSize(std::round(cueData.size()));
+ if (cueData.backgroundColor().isValid())
+ cue.setBackgroundColor(cueData.backgroundColor().rgb());
+ if (cueData.foregroundColor().isValid())
+ cue.setForegroundColor(cueData.foregroundColor().rgb());
+ if (cueData.highlightColor().isValid())
+ cue.setHighlightColor(cueData.highlightColor().rgb());
+
+ if (cueData.align() == GenericCueData::Start)
+ cue.setAlign(ASCIILiteral("start"));
+ else if (cueData.align() == GenericCueData::Middle)
+ cue.setAlign(ASCIILiteral("middle"));
+ else if (cueData.align() == GenericCueData::End)
+ cue.setAlign(ASCIILiteral("end"));
+ cue.setSnapToLines(false);
+
+ cue.didChange();
}
-void InbandGenericTextTrack::addGenericCue(InbandTextTrackPrivate* trackPrivate, PassRefPtr<GenericCueData> prpCueData)
+void InbandGenericTextTrack::addGenericCue(GenericCueData& cueData)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
-
- RefPtr<GenericCueData> cueData = prpCueData;
- if (m_cueMap.find(cueData.get()))
+ if (m_cueMap.find(cueData))
return;
- RefPtr<TextTrackCueGeneric> cue = TextTrackCueGeneric::create(*scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
- updateCueFromCueData(cue.get(), cueData.get());
- if (hasCue(cue.get(), TextTrackCue::IgnoreDuration)) {
- LOG(Media, "InbandGenericTextTrack::addGenericCue ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
+ auto cue = TextTrackCueGeneric::create(*scriptExecutionContext(), cueData.startTime(), cueData.endTime(), cueData.content());
+ updateCueFromCueData(cue.get(), cueData);
+ if (hasCue(cue.ptr(), TextTrackCue::IgnoreDuration)) {
+ LOG(Media, "InbandGenericTextTrack::addGenericCue ignoring already added cue: start=%s, end=%s, content=\"%s\"\n", toString(cueData.startTime()).utf8().data(), toString(cueData.endTime()).utf8().data(), cueData.content().utf8().data());
return;
}
- if (cueData->status() != GenericCueData::Complete)
- m_cueMap.add(cueData.get(), cue.get());
+ LOG(Media, "InbandGenericTextTrack::addGenericCue added cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData.startTime().toDouble(), cueData.endTime().toDouble(), cueData.content().utf8().data());
- addCue(cue);
+ if (cueData.status() != GenericCueData::Complete)
+ m_cueMap.add(cueData, cue);
+
+ addCue(WTFMove(cue));
}
-void InbandGenericTextTrack::updateGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
+void InbandGenericTextTrack::updateGenericCue(GenericCueData& cueData)
{
- RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
+ auto* cue = m_cueMap.find(cueData);
if (!cue)
return;
- updateCueFromCueData(cue.get(), cueData);
+ updateCueFromCueData(*cue, cueData);
- if (cueData->status() == GenericCueData::Complete)
+ if (cueData.status() == GenericCueData::Complete)
m_cueMap.remove(cueData);
}
-void InbandGenericTextTrack::removeGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
+void InbandGenericTextTrack::removeGenericCue(GenericCueData& cueData)
{
- RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
+ auto* cue = m_cueMap.find(cueData);
if (cue) {
- LOG(Media, "InbandGenericTextTrack::removeGenericCue removing cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
- removeCue(cue.get(), IGNORE_EXCEPTION);
- } else
- m_cueMap.remove(cueData);
+ LOG(Media, "InbandGenericTextTrack::removeGenericCue removing cue: start=%s, end=%s, content=\"%s\"\n", toString(cueData.startTime()).utf8().data(), toString(cueData.endTime()).utf8().data(), cueData.content().utf8().data());
+ removeCue(*cue);
+ } else {
+ LOG(Media, "InbandGenericTextTrack::removeGenericCue UNABLE to find cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData.startTime().toDouble(), cueData.endTime().toDouble(), cueData.content().utf8().data());
+ }
+}
+
+ExceptionOr<void> InbandGenericTextTrack::removeCue(TextTrackCue& cue)
+{
+ auto result = TextTrack::removeCue(cue);
+ if (!result.hasException())
+ m_cueMap.remove(cue);
+ return result;
+}
+
+WebVTTParser& InbandGenericTextTrack::parser()
+{
+ if (!m_webVTTParser)
+ m_webVTTParser = std::make_unique<WebVTTParser>(static_cast<WebVTTParserClient*>(this), scriptExecutionContext());
+ return *m_webVTTParser;
+}
+
+void InbandGenericTextTrack::parseWebVTTCueData(const ISOWebVTTCue& cueData)
+{
+ parser().parseCueData(cueData);
+}
+
+void InbandGenericTextTrack::parseWebVTTFileHeader(String&& header)
+{
+ parser().parseFileHeader(WTFMove(header));
+}
+
+void InbandGenericTextTrack::newCuesParsed()
+{
+ Vector<RefPtr<WebVTTCueData>> cues;
+ parser().getNewCues(cues);
+
+ for (auto& cueData : cues) {
+ auto vttCue = VTTCue::create(*scriptExecutionContext(), *cueData);
+
+ if (hasCue(vttCue.ptr(), TextTrackCue::IgnoreDuration)) {
+ LOG(Media, "InbandGenericTextTrack::newCuesParsed ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", vttCue->startTime(), vttCue->endTime(), vttCue->text().utf8().data());
+ return;
+ }
+ addCue(WTFMove(vttCue));
+ }
+}
+
+void InbandGenericTextTrack::newRegionsParsed()
+{
+ Vector<RefPtr<VTTRegion>> newRegions;
+ parser().getNewRegions(newRegions);
+
+ for (auto& region : newRegions) {
+ region->setTrack(this);
+ regions()->add(region.releaseNonNull());
+ }
}
-void InbandGenericTextTrack::removeCue(TextTrackCue* cue, ExceptionCode& ec)
+void InbandGenericTextTrack::fileFailedToParse()
{
- m_cueMap.remove(cue);
- TextTrack::removeCue(cue, ec);
+ LOG(Media, "Error parsing WebVTT stream.");
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/InbandGenericTextTrack.h b/Source/WebCore/html/track/InbandGenericTextTrack.h
index 2456a9adc..e5feb254b 100644
--- a/Source/WebCore/html/track/InbandGenericTextTrack.h
+++ b/Source/WebCore/html/track/InbandGenericTextTrack.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,64 +23,61 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef InbandGenericTextTrack_h
-#define InbandGenericTextTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "InbandTextTrack.h"
#include "TextTrackCueGeneric.h"
-#include <wtf/RefPtr.h>
+#include "WebVTTParser.h"
namespace WebCore {
-class Document;
-class InbandTextTrackPrivate;
-class TextTrackCue;
-
class GenericTextTrackCueMap {
public:
- GenericTextTrackCueMap();
- virtual ~GenericTextTrackCueMap();
-
- void add(GenericCueData*, TextTrackCueGeneric*);
+ void add(GenericCueData&, TextTrackCueGeneric&);
- void remove(TextTrackCue*);
- void remove(GenericCueData*);
+ void remove(TextTrackCue&);
+ void remove(GenericCueData&);
- PassRefPtr<GenericCueData> find(TextTrackCue*);
- PassRefPtr<TextTrackCueGeneric> find(GenericCueData*);
+ GenericCueData* find(TextTrackCue&);
+ TextTrackCueGeneric* find(GenericCueData&);
private:
- typedef HashMap<RefPtr<TextTrackCue>, RefPtr<GenericCueData>> CueToDataMap;
- typedef HashMap<RefPtr<GenericCueData>, RefPtr<TextTrackCueGeneric>> CueDataToCueMap;
+ using CueToDataMap = HashMap<RefPtr<TextTrackCue>, RefPtr<GenericCueData>>;
+ using CueDataToCueMap = HashMap<RefPtr<GenericCueData>, RefPtr<TextTrackCueGeneric>>;
CueToDataMap m_cueToDataMap;
CueDataToCueMap m_dataToCueMap;
};
-class InbandGenericTextTrack : public InbandTextTrack {
+class InbandGenericTextTrack final : public InbandTextTrack, private WebVTTParserClient {
public:
- static PassRefPtr<InbandGenericTextTrack> create(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+ static Ref<InbandGenericTextTrack> create(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
virtual ~InbandGenericTextTrack();
private:
- InbandGenericTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+ InbandGenericTextTrack(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
- virtual void addGenericCue(InbandTextTrackPrivate*, PassRefPtr<GenericCueData>) override;
- virtual void updateGenericCue(InbandTextTrackPrivate*, GenericCueData*) override;
- virtual void removeGenericCue(InbandTextTrackPrivate*, GenericCueData*) override;
- virtual void removeCue(TextTrackCue*, ExceptionCode&) override;
+ void addGenericCue(GenericCueData&) final;
+ void updateGenericCue(GenericCueData&) final;
+ void removeGenericCue(GenericCueData&) final;
+ ExceptionOr<void> removeCue(TextTrackCue&) final;
- virtual void parseWebVTTCueData(InbandTextTrackPrivate*, const char*, unsigned) override { ASSERT_NOT_REACHED(); }
+ void updateCueFromCueData(TextTrackCueGeneric&, GenericCueData&);
- PassRefPtr<TextTrackCueGeneric> createCue(PassRefPtr<GenericCueData>);
- void updateCueFromCueData(TextTrackCueGeneric*, GenericCueData*);
+ WebVTTParser& parser();
+ void parseWebVTTCueData(const ISOWebVTTCue&) final;
+ void parseWebVTTFileHeader(String&&) final;
+
+ void newCuesParsed() final;
+ void newRegionsParsed() final;
+ void fileFailedToParse() final;
GenericTextTrackCueMap m_cueMap;
+ std::unique_ptr<WebVTTParser> m_webVTTParser;
};
} // namespace WebCore
#endif
-#endif
diff --git a/Source/WebCore/html/track/InbandTextTrack.cpp b/Source/WebCore/html/track/InbandTextTrack.cpp
index f8772cbc2..bd65e548a 100644
--- a/Source/WebCore/html/track/InbandTextTrack.cpp
+++ b/Source/WebCore/html/track/InbandTextTrack.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,160 +24,171 @@
*/
#include "config.h"
+#include "InbandTextTrack.h"
#if ENABLE(VIDEO_TRACK)
-#include "InbandTextTrack.h"
-
-#include "Document.h"
-#include "Event.h"
-#include "ExceptionCodePlaceholder.h"
#include "HTMLMediaElement.h"
+#include "InbandDataTextTrack.h"
#include "InbandGenericTextTrack.h"
#include "InbandTextTrackPrivate.h"
#include "InbandWebVTTTextTrack.h"
-#include "Logging.h"
-#include "TextTrackCueList.h"
-#include <math.h>
-#include <wtf/text/CString.h>
namespace WebCore {
-PassRefPtr<InbandTextTrack> InbandTextTrack::create(ScriptExecutionContext* context,
- TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> trackPrivate)
+Ref<InbandTextTrack> InbandTextTrack::create(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
{
- switch (trackPrivate->cueFormat()) {
+ switch (trackPrivate.cueFormat()) {
+ case InbandTextTrackPrivate::Data:
+ return InbandDataTextTrack::create(context, client, trackPrivate);
case InbandTextTrackPrivate::Generic:
return InbandGenericTextTrack::create(context, client, trackPrivate);
case InbandTextTrackPrivate::WebVTT:
return InbandWebVTTTextTrack::create(context, client, trackPrivate);
- default:
- ASSERT_NOT_REACHED();
- return 0;
}
+ ASSERT_NOT_REACHED();
+ return InbandDataTextTrack::create(context, client, trackPrivate);
}
-InbandTextTrack::InbandTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> trackPrivate)
- : TextTrack(context, client, emptyString(), trackPrivate->id(), trackPrivate->label(), trackPrivate->language(), InBand)
+InbandTextTrack::InbandTextTrack(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
+ : TextTrack(&context, &client, emptyAtom, trackPrivate.id(), trackPrivate.label(), trackPrivate.language(), InBand)
, m_private(trackPrivate)
{
m_private->setClient(this);
-
- switch (m_private->kind()) {
- case InbandTextTrackPrivate::Subtitles:
- setKind(TextTrack::subtitlesKeyword());
- break;
- case InbandTextTrackPrivate::Captions:
- setKind(TextTrack::captionsKeyword());
- break;
- case InbandTextTrackPrivate::Descriptions:
- setKind(TextTrack::descriptionsKeyword());
- break;
- case InbandTextTrackPrivate::Chapters:
- setKind(TextTrack::chaptersKeyword());
- break;
- case InbandTextTrackPrivate::Metadata:
- setKind(TextTrack::metadataKeyword());
- break;
- case InbandTextTrackPrivate::Forced:
- setKind(TextTrack::forcedKeyword());
- break;
- case InbandTextTrackPrivate::None:
- default:
- ASSERT_NOT_REACHED();
- break;
- }
+ updateKindFromPrivate();
}
InbandTextTrack::~InbandTextTrack()
{
- m_private->setClient(0);
+ m_private->setClient(nullptr);
+}
+
+void InbandTextTrack::setPrivate(InbandTextTrackPrivate& trackPrivate)
+{
+ if (m_private.ptr() == &trackPrivate)
+ return;
+
+ m_private->setClient(nullptr);
+ m_private = trackPrivate;
+ m_private->setClient(this);
+
+ setModeInternal(mode());
+ updateKindFromPrivate();
}
-void InbandTextTrack::setMode(const AtomicString& mode)
+void InbandTextTrack::setMode(Mode mode)
{
TextTrack::setMode(mode);
+ setModeInternal(mode);
+}
- if (mode == TextTrack::disabledKeyword())
- m_private->setMode(InbandTextTrackPrivate::Disabled);
- else if (mode == TextTrack::hiddenKeyword())
- m_private->setMode(InbandTextTrackPrivate::Hidden);
- else if (mode == TextTrack::showingKeyword())
- m_private->setMode(InbandTextTrackPrivate::Showing);
- else
- ASSERT_NOT_REACHED();
+static inline InbandTextTrackPrivate::Mode toPrivate(TextTrack::Mode mode)
+{
+ switch (mode) {
+ case TextTrack::Mode::Disabled:
+ return InbandTextTrackPrivate::Disabled;
+ case TextTrack::Mode::Hidden:
+ return InbandTextTrackPrivate::Hidden;
+ case TextTrack::Mode::Showing:
+ return InbandTextTrackPrivate::Showing;
+ }
+ ASSERT_NOT_REACHED();
+ return InbandTextTrackPrivate::Disabled;
}
-bool InbandTextTrack::isClosedCaptions() const
+void InbandTextTrack::setModeInternal(Mode mode)
{
- if (!m_private)
- return false;
+ m_private->setMode(toPrivate(mode));
+}
+bool InbandTextTrack::isClosedCaptions() const
+{
return m_private->isClosedCaptions();
}
bool InbandTextTrack::isSDH() const
{
- if (!m_private)
- return false;
-
return m_private->isSDH();
}
bool InbandTextTrack::containsOnlyForcedSubtitles() const
{
- if (!m_private)
- return false;
-
return m_private->containsOnlyForcedSubtitles();
}
bool InbandTextTrack::isMainProgramContent() const
{
- if (!m_private)
- return false;
-
return m_private->isMainProgramContent();
}
bool InbandTextTrack::isEasyToRead() const
{
- if (!m_private)
- return false;
-
return m_private->isEasyToRead();
}
size_t InbandTextTrack::inbandTrackIndex()
{
- ASSERT(m_private);
return m_private->trackIndex();
}
-void InbandTextTrack::idChanged(TrackPrivateBase* trackPrivate, const String& id)
+AtomicString InbandTextTrack::inBandMetadataTrackDispatchType() const
+{
+ return m_private->inBandMetadataTrackDispatchType();
+}
+
+void InbandTextTrack::idChanged(const AtomicString& id)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setId(id);
}
-void InbandTextTrack::labelChanged(TrackPrivateBase* trackPrivate, const String& label)
+void InbandTextTrack::labelChanged(const AtomicString& label)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setLabel(label);
}
-void InbandTextTrack::languageChanged(TrackPrivateBase* trackPrivate, const String& language)
+void InbandTextTrack::languageChanged(const AtomicString& language)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setLanguage(language);
}
-void InbandTextTrack::willRemove(TrackPrivateBase* trackPrivate)
+void InbandTextTrack::willRemove()
+{
+ auto* element = mediaElement();
+ if (!element)
+ return;
+ element->removeTextTrack(*this);
+}
+
+void InbandTextTrack::updateKindFromPrivate()
{
- if (!mediaElement())
+ switch (m_private->kind()) {
+ case InbandTextTrackPrivate::Subtitles:
+ setKind(Kind::Subtitles);
return;
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
- mediaElement()->removeTextTrack(this);
+ case InbandTextTrackPrivate::Captions:
+ setKind(Kind::Captions);
+ return;
+ case InbandTextTrackPrivate::Descriptions:
+ setKind(Kind::Descriptions);
+ return;
+ case InbandTextTrackPrivate::Chapters:
+ setKind(Kind::Chapters);
+ return;
+ case InbandTextTrackPrivate::Metadata:
+ setKind(Kind::Metadata);
+ return;
+ case InbandTextTrackPrivate::Forced:
+ setKind(Kind::Forced);
+ return;
+ case InbandTextTrackPrivate::None:
+ break;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+MediaTime InbandTextTrack::startTimeVariance() const
+{
+ return m_private->startTimeVariance();
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/InbandTextTrack.h b/Source/WebCore/html/track/InbandTextTrack.h
index 1e1313bf5..6cf2687bb 100644
--- a/Source/WebCore/html/track/InbandTextTrack.h
+++ b/Source/WebCore/html/track/InbandTextTrack.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,49 +23,70 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef InbandTextTrack_h
-#define InbandTextTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "InbandTextTrackPrivateClient.h"
#include "TextTrack.h"
-#include "TextTrackCueGeneric.h"
-#include <wtf/RefPtr.h>
namespace WebCore {
-class InbandTextTrack : public TextTrack, public InbandTextTrackPrivateClient {
+class InbandTextTrack : public TextTrack, private InbandTextTrackPrivateClient {
public:
- static PassRefPtr<InbandTextTrack> create(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+ static Ref<InbandTextTrack> create(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
virtual ~InbandTextTrack();
- virtual bool isClosedCaptions() const override;
- virtual bool isSDH() const override;
- virtual bool containsOnlyForcedSubtitles() const override;
- virtual bool isMainProgramContent() const override;
- virtual bool isEasyToRead() const override;
- virtual void setMode(const AtomicString&) override;
+ bool isClosedCaptions() const override;
+ bool isSDH() const override;
+ bool containsOnlyForcedSubtitles() const override;
+ bool isMainProgramContent() const override;
+ bool isEasyToRead() const override;
+ void setMode(Mode) override;
size_t inbandTrackIndex();
+ AtomicString inBandMetadataTrackDispatchType() const override;
+
+ void setPrivate(InbandTextTrackPrivate&);
+
protected:
- InbandTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+ InbandTextTrack(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
+
+ void setModeInternal(Mode);
+ void updateKindFromPrivate();
- RefPtr<InbandTextTrackPrivate> m_private;
+ Ref<InbandTextTrackPrivate> m_private;
private:
+ bool isInband() const final { return true; }
+ void idChanged(const AtomicString&) override;
+ void labelChanged(const AtomicString&) override;
+ void languageChanged(const AtomicString&) override;
+ void willRemove() override;
- virtual void idChanged(TrackPrivateBase*, const String&) override;
- virtual void labelChanged(TrackPrivateBase*, const String&) override;
- virtual void languageChanged(TrackPrivateBase*, const String&) override;
- virtual void willRemove(TrackPrivateBase*) override;
+ void addDataCue(const MediaTime&, const MediaTime&, const void*, unsigned) override { ASSERT_NOT_REACHED(); }
-#if USE(PLATFORM_TEXT_TRACK_MENU)
- virtual InbandTextTrackPrivate* privateTrack() override { return m_private.get(); }
+#if ENABLE(DATACUE_VALUE)
+ void addDataCue(const MediaTime&, const MediaTime&, Ref<SerializedPlatformRepresentation>&&, const String&) override { ASSERT_NOT_REACHED(); }
+ void updateDataCue(const MediaTime&, const MediaTime&, SerializedPlatformRepresentation&) override { ASSERT_NOT_REACHED(); }
+ void removeDataCue(const MediaTime&, const MediaTime&, SerializedPlatformRepresentation&) override { ASSERT_NOT_REACHED(); }
#endif
+
+ void addGenericCue(GenericCueData&) override { ASSERT_NOT_REACHED(); }
+ void updateGenericCue(GenericCueData&) override { ASSERT_NOT_REACHED(); }
+ void removeGenericCue(GenericCueData&) override { ASSERT_NOT_REACHED(); }
+
+ void parseWebVTTFileHeader(String&&) override { ASSERT_NOT_REACHED(); }
+ void parseWebVTTCueData(const char*, unsigned) override { ASSERT_NOT_REACHED(); }
+ void parseWebVTTCueData(const ISOWebVTTCue&) override { ASSERT_NOT_REACHED(); }
+
+ MediaTime startTimeVariance() const override;
};
} // namespace WebCore
-#endif
-#endif
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::InbandTextTrack)
+ static bool isType(const WebCore::TextTrack& track) { return track.isInband(); }
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/InbandWebVTTTextTrack.cpp b/Source/WebCore/html/track/InbandWebVTTTextTrack.cpp
index 7e03d41a6..d0fae4e9b 100644
--- a/Source/WebCore/html/track/InbandWebVTTTextTrack.cpp
+++ b/Source/WebCore/html/track/InbandWebVTTTextTrack.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,60 +24,76 @@
*/
#include "config.h"
+#include "InbandWebVTTTextTrack.h"
#if ENABLE(VIDEO_TRACK)
-#include "InbandWebVTTTextTrack.h"
-
#include "InbandTextTrackPrivate.h"
#include "Logging.h"
+#include "VTTCue.h"
+#include "VTTRegionList.h"
#include <wtf/text/CString.h>
namespace WebCore {
-PassRefPtr<InbandTextTrack> InbandWebVTTTextTrack::create(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> playerPrivate)
+inline InbandWebVTTTextTrack::InbandWebVTTTextTrack(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
+ : InbandTextTrack(context, client, trackPrivate)
{
- return adoptRef(new InbandWebVTTTextTrack(context, client, playerPrivate));
}
-InbandWebVTTTextTrack::InbandWebVTTTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> trackPrivate)
- : InbandTextTrack(context, client, trackPrivate)
+Ref<InbandTextTrack> InbandWebVTTTextTrack::create(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
{
+ return adoptRef(*new InbandWebVTTTextTrack(context, client, trackPrivate));
}
InbandWebVTTTextTrack::~InbandWebVTTTextTrack()
{
}
-void InbandWebVTTTextTrack::parseWebVTTCueData(InbandTextTrackPrivate* trackPrivate, const char* data, unsigned length)
+WebVTTParser& InbandWebVTTTextTrack::parser()
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
if (!m_webVTTParser)
- m_webVTTParser = WebVTTParser::create(this, scriptExecutionContext());
- m_webVTTParser->parseBytes(data, length);
+ m_webVTTParser = std::make_unique<WebVTTParser>(static_cast<WebVTTParserClient*>(this), scriptExecutionContext());
+ return *m_webVTTParser;
+}
+
+void InbandWebVTTTextTrack::parseWebVTTCueData(const char* data, unsigned length)
+{
+ parser().parseBytes(data, length);
+}
+
+void InbandWebVTTTextTrack::parseWebVTTCueData(const ISOWebVTTCue& cueData)
+{
+ parser().parseCueData(cueData);
}
void InbandWebVTTTextTrack::newCuesParsed()
{
Vector<RefPtr<WebVTTCueData>> cues;
- m_webVTTParser->getNewCues(cues);
- for (size_t i = 0; i < cues.size(); ++i) {
- RefPtr<WebVTTCueData> cueData = cues[i];
- RefPtr<TextTrackCue> cue = TextTrackCue::create(*scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
- cue->setId(cueData->id());
- cue->setCueSettings(cueData->settings());
-
- if (hasCue(cue.get(), TextTrackCue::IgnoreDuration)) {
- LOG(Media, "InbandWebVTTTextTrack::newCuesParsed ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
+ parser().getNewCues(cues);
+ for (auto& cueData : cues) {
+ auto vttCue = VTTCue::create(*scriptExecutionContext(), *cueData);
+ if (hasCue(vttCue.ptr(), TextTrackCue::IgnoreDuration)) {
+ LOG(Media, "InbandWebVTTTextTrack::newCuesParsed ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", vttCue->startTime(), vttCue->endTime(), vttCue->text().utf8().data());
return;
}
- addCue(cue.release());
+ addCue(WTFMove(vttCue));
+ }
+}
+
+void InbandWebVTTTextTrack::newRegionsParsed()
+{
+ Vector<RefPtr<VTTRegion>> newRegions;
+ parser().getNewRegions(newRegions);
+ for (auto& region : newRegions) {
+ region->setTrack(this);
+ regions()->add(region.releaseNonNull());
}
}
void InbandWebVTTTextTrack::fileFailedToParse()
{
- LOG(Media, "Unable to parse WebVTT stream.");
+ LOG(Media, "Error parsing WebVTT stream.");
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/InbandWebVTTTextTrack.h b/Source/WebCore/html/track/InbandWebVTTTextTrack.h
index c0c2ef830..21d913469 100644
--- a/Source/WebCore/html/track/InbandWebVTTTextTrack.h
+++ b/Source/WebCore/html/track/InbandWebVTTTextTrack.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,41 +23,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef InbandWebVTTTextTrack_h
-#define InbandWebVTTTextTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "InbandTextTrack.h"
#include "WebVTTParser.h"
-#include <wtf/RefPtr.h>
+#include <memory>
namespace WebCore {
-class InbandWebVTTTextTrack : public InbandTextTrack, private WebVTTParserClient {
+class InbandWebVTTTextTrack final : public InbandTextTrack, private WebVTTParserClient {
public:
- static PassRefPtr<InbandTextTrack> create(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+ static Ref<InbandTextTrack> create(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
virtual ~InbandWebVTTTextTrack();
private:
- InbandWebVTTTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+ InbandWebVTTTextTrack(ScriptExecutionContext&, TextTrackClient&, InbandTextTrackPrivate&);
- virtual void parseWebVTTCueData(InbandTextTrackPrivate*, const char* data, unsigned length) override;
+ WebVTTParser& parser();
+ void parseWebVTTCueData(const char* data, unsigned length) final;
+ void parseWebVTTCueData(const ISOWebVTTCue&) final;
- virtual void newCuesParsed() override;
-#if ENABLE(WEBVTT_REGIONS)
- virtual void newRegionsParsed() override;
-#endif
- virtual void fileFailedToParse() override;
+ void newCuesParsed() final;
+ void newRegionsParsed() final;
+ void fileFailedToParse() final;
- virtual void addGenericCue(InbandTextTrackPrivate*, PassRefPtr<GenericCueData>) override { ASSERT_NOT_REACHED(); }
- virtual void updateGenericCue(InbandTextTrackPrivate*, GenericCueData*) override { ASSERT_NOT_REACHED(); }
- virtual void removeGenericCue(InbandTextTrackPrivate*, GenericCueData*) override { ASSERT_NOT_REACHED(); }
-
- OwnPtr<WebVTTParser> m_webVTTParser;
+ std::unique_ptr<WebVTTParser> m_webVTTParser;
};
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/LoadableTextTrack.cpp b/Source/WebCore/html/track/LoadableTextTrack.cpp
index e61cffc6a..5528de17b 100644
--- a/Source/WebCore/html/track/LoadableTextTrack.cpp
+++ b/Source/WebCore/html/track/LoadableTextTrack.cpp
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,36 +25,24 @@
*/
#include "config.h"
+#include "LoadableTextTrack.h"
#if ENABLE(VIDEO_TRACK)
-#include "LoadableTextTrack.h"
-
-#include "Event.h"
#include "HTMLTrackElement.h"
-#include "ScriptExecutionContext.h"
#include "TextTrackCueList.h"
+#include "VTTRegionList.h"
namespace WebCore {
-LoadableTextTrack::LoadableTextTrack(HTMLTrackElement* track, const String& kind, const String& label, const String& language)
- : TextTrack(&track->document(), track, kind, emptyString(), label, language, TrackElement)
- , m_trackElement(track)
- , m_loadTimer(this, &LoadableTextTrack::loadTimerFired)
+LoadableTextTrack::LoadableTextTrack(HTMLTrackElement& track, const String& kind, const String& label, const String& language)
+ : TextTrack(&track.document(), &track, kind, emptyString(), label, language, TrackElement)
+ , m_trackElement(&track)
+ , m_loadTimer(*this, &LoadableTextTrack::loadTimerFired)
, m_isDefault(false)
{
}
-LoadableTextTrack::~LoadableTextTrack()
-{
-}
-
-void LoadableTextTrack::clearClient()
-{
- m_trackElement = 0;
- TextTrack::clearClient();
-}
-
void LoadableTextTrack::scheduleLoad(const URL& url)
{
if (url == m_url)
@@ -74,14 +63,8 @@ Element* LoadableTextTrack::element()
{
return m_trackElement;
}
-
-void LoadableTextTrack::setTrackElement(HTMLTrackElement* element)
-{
- ASSERT(!m_trackElement || m_trackElement == element);
- m_trackElement = element;
-}
-void LoadableTextTrack::loadTimerFired(Timer<LoadableTextTrack>&)
+void LoadableTextTrack::loadTimerFired()
{
if (m_loader)
m_loader->cancelLoad();
@@ -94,14 +77,14 @@ void LoadableTextTrack::loadTimerFired(Timer<LoadableTextTrack>&)
// 4. Download: If URL is not the empty string, perform a potentially CORS-enabled fetch of URL, with the
// mode being the state of the media element's crossorigin content attribute, the origin being the
// origin of the media element's Document, and the default origin behaviour set to fail.
- m_loader = TextTrackLoader::create(*this, static_cast<ScriptExecutionContext*>(&m_trackElement->document()));
- if (!m_loader->load(m_url, m_trackElement->mediaElementCrossOriginAttribute()))
+ m_loader = std::make_unique<TextTrackLoader>(static_cast<TextTrackLoaderClient&>(*this), static_cast<ScriptExecutionContext*>(&m_trackElement->document()));
+ if (!m_loader->load(m_url, m_trackElement->mediaElementCrossOriginAttribute(), m_trackElement->isInUserAgentShadowTree()))
m_trackElement->didCompleteLoad(HTMLTrackElement::Failure);
}
void LoadableTextTrack::newCuesAvailable(TextTrackLoader* loader)
{
- ASSERT_UNUSED(loader, m_loader == loader);
+ ASSERT_UNUSED(loader, m_loader.get() == loader);
Vector<RefPtr<TextTrackCue>> newCues;
m_loader->getNewCues(newCues);
@@ -109,18 +92,18 @@ void LoadableTextTrack::newCuesAvailable(TextTrackLoader* loader)
if (!m_cues)
m_cues = TextTrackCueList::create();
- for (size_t i = 0; i < newCues.size(); ++i) {
- newCues[i]->setTrack(this);
- m_cues->add(newCues[i]);
+ for (auto& newCue : newCues) {
+ newCue->setTrack(this);
+ m_cues->add(newCue.releaseNonNull());
}
if (client())
- client()->textTrackAddCues(this, m_cues.get());
+ client()->textTrackAddCues(*this, *m_cues);
}
void LoadableTextTrack::cueLoadingCompleted(TextTrackLoader* loader, bool loadingFailed)
{
- ASSERT_UNUSED(loader, m_loader == loader);
+ ASSERT_UNUSED(loader, m_loader.get() == loader);
if (!m_trackElement)
return;
@@ -128,26 +111,24 @@ void LoadableTextTrack::cueLoadingCompleted(TextTrackLoader* loader, bool loadin
m_trackElement->didCompleteLoad(loadingFailed ? HTMLTrackElement::Failure : HTMLTrackElement::Success);
}
-#if ENABLE(WEBVTT_REGIONS)
void LoadableTextTrack::newRegionsAvailable(TextTrackLoader* loader)
{
- ASSERT_UNUSED(loader, m_loader == loader);
+ ASSERT_UNUSED(loader, m_loader.get() == loader);
- Vector<RefPtr<TextTrackRegion>> newRegions;
+ Vector<RefPtr<VTTRegion>> newRegions;
m_loader->getNewRegions(newRegions);
- for (size_t i = 0; i < newRegions.size(); ++i) {
- newRegions[i]->setTrack(this);
- regionList()->add(newRegions[i]);
+ for (auto& newRegion : newRegions) {
+ newRegion->setTrack(this);
+ regions()->add(newRegion.releaseNonNull());
}
}
-#endif
AtomicString LoadableTextTrack::id() const
{
- if (m_trackElement)
- return m_trackElement->getAttribute("id");
- return emptyString();
+ if (!m_trackElement)
+ return emptyAtom;
+ return m_trackElement->attributeWithoutSynchronization(idAttr);
}
size_t LoadableTextTrack::trackElementIndex()
diff --git a/Source/WebCore/html/track/LoadableTextTrack.h b/Source/WebCore/html/track/LoadableTextTrack.h
index 970c3322d..ba9c76fb2 100644
--- a/Source/WebCore/html/track/LoadableTextTrack.h
+++ b/Source/WebCore/html/track/LoadableTextTrack.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,61 +24,56 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef LoadableTextTrack_h
-#define LoadableTextTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "TextTrack.h"
#include "TextTrackLoader.h"
-#include <wtf/Vector.h>
namespace WebCore {
class HTMLTrackElement;
-class LoadableTextTrack;
-class LoadableTextTrack : public TextTrack, private TextTrackLoaderClient {
+class LoadableTextTrack final : public TextTrack, private TextTrackLoaderClient {
public:
- static PassRefPtr<LoadableTextTrack> create(HTMLTrackElement* track, const String& kind, const String& label, const String& language)
+ static Ref<LoadableTextTrack> create(HTMLTrackElement& track, const String& kind, const String& label, const String& language)
{
- return adoptRef(new LoadableTextTrack(track, kind, label, language));
+ return adoptRef(*new LoadableTextTrack(track, kind, label, language));
}
- virtual ~LoadableTextTrack();
void scheduleLoad(const URL&);
- virtual void clearClient() override;
-
- virtual AtomicString id() const override;
-
size_t trackElementIndex();
- HTMLTrackElement* trackElement() { return m_trackElement; }
- void setTrackElement(HTMLTrackElement*);
- virtual Element* element() override;
+ HTMLTrackElement* trackElement() const { return m_trackElement; }
+ void clearElement() { m_trackElement = nullptr; }
- virtual bool isDefault() const override { return m_isDefault; }
- virtual void setIsDefault(bool isDefault) override { m_isDefault = isDefault; }
+ void setIsDefault(bool isDefault) final { m_isDefault = isDefault; }
private:
- // TextTrackLoaderClient
- virtual void newCuesAvailable(TextTrackLoader*) override;
- virtual void cueLoadingCompleted(TextTrackLoader*, bool loadingFailed) override;
-#if ENABLE(WEBVTT_REGIONS)
- virtual void newRegionsAvailable(TextTrackLoader*);
-#endif
+ LoadableTextTrack(HTMLTrackElement&, const String& kind, const String& label, const String& language);
+
+ void newCuesAvailable(TextTrackLoader*) final;
+ void cueLoadingCompleted(TextTrackLoader*, bool loadingFailed) final;
+ void newRegionsAvailable(TextTrackLoader*) final;
- LoadableTextTrack(HTMLTrackElement*, const String& kind, const String& label, const String& language);
+ AtomicString id() const final;
+ bool isDefault() const final { return m_isDefault; }
+ Element* element() final;
- void loadTimerFired(Timer<LoadableTextTrack>&);
+ void loadTimerFired();
HTMLTrackElement* m_trackElement;
- Timer<LoadableTextTrack> m_loadTimer;
- OwnPtr<TextTrackLoader> m_loader;
+ Timer m_loadTimer;
+ std::unique_ptr<TextTrackLoader> m_loader;
URL m_url;
- bool m_isDefault;
+ bool m_isDefault { false };
};
+
} // namespace WebCore
-#endif
-#endif
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::LoadableTextTrack)
+ static bool isType(const WebCore::TextTrack& track) { return track.trackType() == WebCore::TextTrack::TrackElement; }
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/TextTrack.cpp b/Source/WebCore/html/track/TextTrack.cpp
index 52b57b32c..0445edcdb 100644
--- a/Source/WebCore/html/track/TextTrack.cpp
+++ b/Source/WebCore/html/track/TextTrack.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -30,130 +30,104 @@
*/
#include "config.h"
+#include "TextTrack.h"
#if ENABLE(VIDEO_TRACK)
-#include "TextTrack.h"
-
#include "Event.h"
+#include "ExceptionCode.h"
#include "HTMLMediaElement.h"
#include "SourceBuffer.h"
#include "TextTrackCueList.h"
#include "TextTrackList.h"
-#include "TextTrackRegionList.h"
+#include "VTTRegion.h"
+#include "VTTRegionList.h"
namespace WebCore {
-static const int invalidTrackIndex = -1;
-
const AtomicString& TextTrack::subtitlesKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, subtitles, ("subtitles", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> subtitles("subtitles", AtomicString::ConstructFromLiteral);
return subtitles;
}
-const AtomicString& TextTrack::captionsKeyword()
+static const AtomicString& captionsKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, captions, ("captions", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> captions("captions", AtomicString::ConstructFromLiteral);
return captions;
}
-const AtomicString& TextTrack::descriptionsKeyword()
+static const AtomicString& descriptionsKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, descriptions, ("descriptions", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> descriptions("descriptions", AtomicString::ConstructFromLiteral);
return descriptions;
}
-const AtomicString& TextTrack::chaptersKeyword()
+static const AtomicString& chaptersKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, chapters, ("chapters", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> chapters("chapters", AtomicString::ConstructFromLiteral);
return chapters;
}
-const AtomicString& TextTrack::metadataKeyword()
+static const AtomicString& metadataKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, metadata, ("metadata", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> metadata("metadata", AtomicString::ConstructFromLiteral);
return metadata;
}
-const AtomicString& TextTrack::forcedKeyword()
+static const AtomicString& forcedKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, forced, ("forced", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> forced("forced", AtomicString::ConstructFromLiteral);
return forced;
}
-const AtomicString& TextTrack::disabledKeyword()
-{
- DEFINE_STATIC_LOCAL(const AtomicString, open, ("disabled", AtomicString::ConstructFromLiteral));
- return open;
-}
-
-const AtomicString& TextTrack::hiddenKeyword()
-{
- DEFINE_STATIC_LOCAL(const AtomicString, closed, ("hidden", AtomicString::ConstructFromLiteral));
- return closed;
-}
-
-const AtomicString& TextTrack::showingKeyword()
-{
- DEFINE_STATIC_LOCAL(const AtomicString, ended, ("showing", AtomicString::ConstructFromLiteral));
- return ended;
-}
-
TextTrack* TextTrack::captionMenuOffItem()
{
- static TextTrack* off = TextTrack::create(0, 0, "off menu item", "", "", "").leakRef();
- return off;
+ static TextTrack& off = TextTrack::create(nullptr, nullptr, "off menu item", emptyAtom, emptyAtom, emptyAtom).leakRef();
+ return &off;
}
TextTrack* TextTrack::captionMenuAutomaticItem()
{
- static TextTrack* automatic = TextTrack::create(0, 0, "automatic menu item", "", "", "").leakRef();
- return automatic;
+ static TextTrack& automatic = TextTrack::create(nullptr, nullptr, "automatic menu item", emptyAtom, emptyAtom, emptyAtom).leakRef();
+ return &automatic;
}
TextTrack::TextTrack(ScriptExecutionContext* context, TextTrackClient* client, const AtomicString& kind, const AtomicString& id, const AtomicString& label, const AtomicString& language, TextTrackType type)
: TrackBase(TrackBase::TextTrack, id, label, language)
- , m_cues(0)
, m_scriptExecutionContext(context)
-#if ENABLE(WEBVTT_REGIONS)
- , m_regions(0)
-#endif
- , m_mode(disabledKeyword().string())
, m_client(client)
, m_trackType(type)
- , m_readinessState(NotLoaded)
- , m_trackIndex(invalidTrackIndex)
- , m_renderedTrackIndex(invalidTrackIndex)
- , m_hasBeenConfigured(false)
{
- setKindInternal(kind);
+ if (kind == captionsKeyword())
+ m_kind = Kind::Captions;
+ else if (kind == chaptersKeyword())
+ m_kind = Kind::Chapters;
+ else if (kind == descriptionsKeyword())
+ m_kind = Kind::Descriptions;
+ else if (kind == forcedKeyword())
+ m_kind = Kind::Forced;
+ else if (kind == metadataKeyword())
+ m_kind = Kind::Metadata;
}
TextTrack::~TextTrack()
{
if (m_cues) {
if (m_client)
- m_client->textTrackRemoveCues(this, m_cues.get());
-
+ m_client->textTrackRemoveCues(*this, *m_cues);
for (size_t i = 0; i < m_cues->length(); ++i)
- m_cues->item(i)->setTrack(0);
-#if ENABLE(WEBVTT_REGIONS)
+ m_cues->item(i)->setTrack(nullptr);
+ }
+ if (m_regions) {
for (size_t i = 0; i < m_regions->length(); ++i)
- m_regions->item(i)->setTrack(0);
-#endif
+ m_regions->item(i)->setTrack(nullptr);
}
- clearClient();
-}
-
-bool TextTrack::isValidKind(const AtomicString& value) const
-{
- return TextTrack::isValidKindKeyword(value);
}
bool TextTrack::enabled() const
{
- return m_mode != disabledKeyword();
+ return m_mode != Mode::Disabled;
}
bool TextTrack::isValidKindKeyword(const AtomicString& value)
@@ -174,60 +148,102 @@ bool TextTrack::isValidKindKeyword(const AtomicString& value)
return false;
}
-void TextTrack::setKind(const AtomicString& newKind)
+const AtomicString& TextTrack::kindKeyword() const
+{
+ switch (m_kind) {
+ case Kind::Captions:
+ return captionsKeyword();
+ case Kind::Chapters:
+ return chaptersKeyword();
+ case Kind::Descriptions:
+ return descriptionsKeyword();
+ case Kind::Forced:
+ return forcedKeyword();
+ case Kind::Metadata:
+ return metadataKeyword();
+ case Kind::Subtitles:
+ return subtitlesKeyword();
+ }
+ ASSERT_NOT_REACHED();
+ return subtitlesKeyword();
+}
+
+void TextTrack::setKind(Kind newKind)
{
- String oldKind = kind();
+ auto oldKind = m_kind;
-#if ENABLE(MEDIA_SOURCE)
// 10.1 kind, on setting:
// 1. If the value being assigned to this attribute does not match one of the text track kinds,
// then abort these steps.
- if (!isValidKindKeyword(newKind))
- return;
// 2. Update this attribute to the new value.
- setKindInternal(newKind);
+ m_kind = newKind;
+#if ENABLE(MEDIA_SOURCE)
// 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
// event named change at sourceBuffer.textTracks.
if (m_sourceBuffer)
- m_sourceBuffer->textTracks()->scheduleChangeEvent();
+ m_sourceBuffer->textTracks().scheduleChangeEvent();
// 4. Queue a task to fire a simple event named change at the TextTrackList object referenced by
// the textTracks attribute on the HTMLMediaElement.
if (mediaElement())
- mediaElement()->textTracks()->scheduleChangeEvent();
-#else
- TrackBase::setKind(newKind);
+ mediaElement()->textTracks().scheduleChangeEvent();
#endif
- if (m_client && oldKind != kind())
- m_client->textTrackKindChanged(this);
+ if (m_client && oldKind != m_kind)
+ m_client->textTrackKindChanged(*this);
}
-void TextTrack::setMode(const AtomicString& mode)
+void TextTrack::setKindKeywordIgnoringASCIICase(StringView keyword)
{
- // On setting, if the new value isn't equal to what the attribute would currently
- // return, the new value must be processed as follows ...
- if (mode != disabledKeyword() && mode != hiddenKeyword() && mode != showingKeyword())
+ if (keyword.isNull()) {
+ // The missing value default is the subtitles state.
+ setKind(Kind::Subtitles);
return;
+ }
+ if (equalLettersIgnoringASCIICase(keyword, "captions"))
+ setKind(Kind::Captions);
+ else if (equalLettersIgnoringASCIICase(keyword, "chapters"))
+ setKind(Kind::Chapters);
+ else if (equalLettersIgnoringASCIICase(keyword, "descriptions"))
+ setKind(Kind::Descriptions);
+ else if (equalLettersIgnoringASCIICase(keyword, "forced"))
+ setKind(Kind::Forced);
+ else if (equalLettersIgnoringASCIICase(keyword, "metadata"))
+ setKind(Kind::Metadata);
+ else if (equalLettersIgnoringASCIICase(keyword, "subtitles"))
+ setKind(Kind::Subtitles);
+ else {
+ // The invalid value default is the metadata state.
+ setKind(Kind::Metadata);
+ }
+}
+void TextTrack::setMode(Mode mode)
+{
+ // On setting, if the new value isn't equal to what the attribute would currently
+ // return, the new value must be processed as follows ...
if (m_mode == mode)
return;
// If mode changes to disabled, remove this track's cues from the client
// because they will no longer be accessible from the cues() function.
- if (mode == disabledKeyword() && m_client && m_cues)
- m_client->textTrackRemoveCues(this, m_cues.get());
-
- if (mode != showingKeyword() && m_cues)
- for (size_t i = 0; i < m_cues->length(); ++i)
- m_cues->item(i)->removeDisplayTree();
+ if (mode == Mode::Disabled && m_client && m_cues)
+ m_client->textTrackRemoveCues(*this, *m_cues);
+
+ if (mode != Mode::Showing && m_cues) {
+ for (size_t i = 0; i < m_cues->length(); ++i) {
+ TextTrackCue* cue = m_cues->item(i);
+ if (cue->isRenderable())
+ toVTTCue(cue)->removeDisplayTree();
+ }
+ }
m_mode = mode;
if (m_client)
- m_client->textTrackModeChanged(this);
+ m_client->textTrackModeChanged(*this);
}
TextTrackCueList* TextTrack::cues()
@@ -237,9 +253,9 @@ TextTrackCueList* TextTrack::cues()
// Otherwise, it must return null. When an object is returned, the
// same object must be returned each time.
// http://www.whatwg.org/specs/web-apps/current-work/#dom-texttrack-cues
- if (m_mode != disabledKeyword())
- return ensureTextTrackCueList();
- return 0;
+ if (m_mode == Mode::Disabled)
+ return nullptr;
+ return &ensureTextTrackCueList();
}
void TextTrack::removeAllCues()
@@ -248,12 +264,12 @@ void TextTrack::removeAllCues()
return;
if (m_client)
- m_client->textTrackRemoveCues(this, m_cues.get());
+ m_client->textTrackRemoveCues(*this, *m_cues);
for (size_t i = 0; i < m_cues->length(); ++i)
- m_cues->item(i)->setTrack(0);
+ m_cues->item(i)->setTrack(nullptr);
- m_cues = 0;
+ m_cues = nullptr;
}
TextTrackCueList* TextTrack::activeCues() const
@@ -264,145 +280,136 @@ TextTrackCueList* TextTrack::activeCues() const
// order. Otherwise, it must return null. When an object is returned, the
// same object must be returned each time.
// http://www.whatwg.org/specs/web-apps/current-work/#dom-texttrack-activecues
- if (m_cues && m_mode != disabledKeyword())
- return m_cues->activeCues();
- return 0;
+ if (!m_cues || m_mode == Mode::Disabled)
+ return nullptr;
+ return &m_cues->activeCues();
}
-void TextTrack::addCue(PassRefPtr<TextTrackCue> prpCue)
+ExceptionOr<void> TextTrack::addCue(Ref<TextTrackCue>&& cue)
{
- if (!prpCue)
- return;
-
- RefPtr<TextTrackCue> cue = prpCue;
+ // 4.7.10.12.6 Text tracks exposing in-band metadata
+ // The UA will use DataCue to expose only text track cue objects that belong to a text track that has a text
+ // track kind of metadata.
+ // If a DataCue is added to a TextTrack via the addCue() method but the text track does not have its text
+ // track kind set to metadata, throw a InvalidNodeTypeError exception and don't add the cue to the TextTrackList
+ // of the TextTrack.
+ if (cue->cueType() == TextTrackCue::Data && m_kind != Kind::Metadata)
+ return Exception { INVALID_NODE_TYPE_ERR };
// TODO(93143): Add spec-compliant behavior for negative time values.
- if (std::isnan(cue->startTime()) || std::isnan(cue->endTime()) || cue->startTime() < 0 || cue->endTime() < 0)
- return;
+ if (!cue->startMediaTime().isValid() || !cue->endMediaTime().isValid() || cue->startMediaTime() < MediaTime::zeroTime() || cue->endMediaTime() < MediaTime::zeroTime())
+ return { };
// 4.8.10.12.5 Text track API
// The addCue(cue) method of TextTrack objects, when invoked, must run the following steps:
+ auto* cueTrack = cue->track();
+ if (cueTrack == this)
+ return { };
+
// 1. If the given cue is in a text track list of cues, then remove cue from that text track
// list of cues.
- TextTrack* cueTrack = cue->track();
- if (cueTrack && cueTrack != this)
- cueTrack->removeCue(cue.get(), ASSERT_NO_EXCEPTION);
+ if (cueTrack)
+ cueTrack->removeCue(cue.get());
// 2. Add cue to the method's TextTrack object's text track's text track list of cues.
cue->setTrack(this);
- ensureTextTrackCueList()->add(cue);
+ ensureTextTrackCueList().add(cue.copyRef());
if (m_client)
- m_client->textTrackAddCue(this, cue.get());
+ m_client->textTrackAddCue(*this, cue);
+
+ return { };
}
-void TextTrack::removeCue(TextTrackCue* cue, ExceptionCode& ec)
+ExceptionOr<void> TextTrack::removeCue(TextTrackCue& cue)
{
- if (!cue)
- return;
-
// 4.8.10.12.5 Text track API
// The removeCue(cue) method of TextTrack objects, when invoked, must run the following steps:
// 1. If the given cue is not currently listed in the method's TextTrack
// object's text track's text track list of cues, then throw a NotFoundError exception.
- if (cue->track() != this) {
- ec = NOT_FOUND_ERR;
- return;
- }
+ if (cue.track() != this)
+ return Exception { NOT_FOUND_ERR };
+ if (!m_cues)
+ return Exception { INVALID_STATE_ERR };
// 2. Remove cue from the method's TextTrack object's text track's text track list of cues.
- if (!m_cues || !m_cues->remove(cue)) {
- ec = INVALID_STATE_ERR;
- return;
- }
-
- cue->setTrack(0);
+ m_cues->remove(cue);
+ cue.setIsActive(false);
+ cue.setTrack(nullptr);
if (m_client)
- m_client->textTrackRemoveCue(this, cue);
-}
+ m_client->textTrackRemoveCue(*this, cue);
-#if ENABLE(VIDEO_TRACK) && ENABLE(WEBVTT_REGIONS)
-TextTrackRegionList* TextTrack::regionList()
-{
- return ensureTextTrackRegionList();
+ return { };
}
-TextTrackRegionList* TextTrack::ensureTextTrackRegionList()
+VTTRegionList& TextTrack::ensureVTTRegionList()
{
if (!m_regions)
- m_regions = TextTrackRegionList::create();
+ m_regions = VTTRegionList::create();
- return m_regions.get();
+ return *m_regions;
}
-TextTrackRegionList* TextTrack::regions()
+VTTRegionList* TextTrack::regions()
{
// If the text track mode of the text track that the TextTrack object
// represents is not the text track disabled mode, then the regions
- // attribute must return a live TextTrackRegionList object that represents
+ // attribute must return a live VTTRegionList object that represents
// the text track list of regions of the text track. Otherwise, it must
// return null. When an object is returned, the same object must be returned
// each time.
- if (m_mode != disabledKeyword())
- return ensureTextTrackRegionList();
-
- return 0;
+ if (m_mode == Mode::Disabled)
+ return nullptr;
+ return &ensureVTTRegionList();
}
-void TextTrack::addRegion(PassRefPtr<TextTrackRegion> prpRegion)
+void TextTrack::addRegion(RefPtr<VTTRegion>&& region)
{
- if (!prpRegion)
+ if (!region)
return;
- RefPtr<TextTrackRegion> region = prpRegion;
- TextTrackRegionList* regionList = ensureTextTrackRegionList();
+ auto& regionList = ensureVTTRegionList();
// 1. If the given region is in a text track list of regions, then remove
// region from that text track list of regions.
- TextTrack* regionTrack = region->track();
+ auto* regionTrack = region->track();
if (regionTrack && regionTrack != this)
- regionTrack->removeRegion(region.get(), ASSERT_NO_EXCEPTION);
+ regionTrack->removeRegion(region.get());
// 2. If the method's TextTrack object's text track list of regions contains
// a region with the same identifier as region replace the values of that
// region's width, height, anchor point, viewport anchor point and scroll
// attributes with those of region.
- TextTrackRegion* existingRegion = regionList->getRegionById(region->id());
+ auto* existingRegion = regionList.getRegionById(region->id());
if (existingRegion) {
- existingRegion->updateParametersFromRegion(region.get());
+ existingRegion->updateParametersFromRegion(*region);
return;
}
- // Otherwise: add region to the method's TextTrack object's text track
- // list of regions.
+ // Otherwise: add region to the method's TextTrack object's text track list of regions.
region->setTrack(this);
- regionList->add(region);
+ regionList.add(region.releaseNonNull());
}
-void TextTrack::removeRegion(TextTrackRegion* region, ExceptionCode &ec)
+ExceptionOr<void> TextTrack::removeRegion(VTTRegion* region)
{
if (!region)
- return;
+ return { };
// 1. If the given region is not currently listed in the method's TextTrack
// object's text track list of regions, then throw a NotFoundError exception.
- if (region->track() != this) {
- ec = NOT_FOUND_ERR;
- return;
- }
-
- if (!m_regions || !m_regions->remove(region)) {
- ec = INVALID_STATE_ERR;
- return;
- }
+ if (region->track() != this)
+ return Exception { NOT_FOUND_ERR };
- region->setTrack(0);
+ ASSERT(m_regions);
+ m_regions->remove(*region);
+ region->setTrack(nullptr);
+ return { };
}
-#endif
void TextTrack::cueWillChange(TextTrackCue* cue)
{
@@ -411,7 +418,7 @@ void TextTrack::cueWillChange(TextTrackCue* cue)
// The cue may need to be repositioned in the media element's interval tree, may need to
// be re-rendered, etc, so remove it before the modification...
- m_client->textTrackRemoveCue(this, cue);
+ m_client->textTrackRemoveCue(*this, *cue);
}
void TextTrack::cueDidChange(TextTrackCue* cue)
@@ -420,60 +427,50 @@ void TextTrack::cueDidChange(TextTrackCue* cue)
return;
// Make sure the TextTrackCueList order is up-to-date.
- ensureTextTrackCueList()->updateCueIndex(cue);
+ ensureTextTrackCueList().updateCueIndex(*cue);
// ... and add it back again.
- m_client->textTrackAddCue(this, cue);
+ m_client->textTrackAddCue(*this, *cue);
}
int TextTrack::trackIndex()
{
ASSERT(m_mediaElement);
-
- if (m_trackIndex == invalidTrackIndex)
- m_trackIndex = m_mediaElement->textTracks()->getTrackIndex(this);
-
- return m_trackIndex;
+ if (!m_trackIndex)
+ m_trackIndex = m_mediaElement->textTracks().getTrackIndex(*this);
+ return m_trackIndex.value();
}
void TextTrack::invalidateTrackIndex()
{
- m_trackIndex = invalidTrackIndex;
- m_renderedTrackIndex = invalidTrackIndex;
+ m_trackIndex = std::nullopt;
+ m_renderedTrackIndex = std::nullopt;
}
bool TextTrack::isRendered()
{
- if (kind() != captionsKeyword() && kind() != subtitlesKeyword() && kind() != forcedKeyword())
- return false;
-
- if (m_mode != showingKeyword())
- return false;
-
- return true;
+ return (m_kind == Kind::Captions || m_kind == Kind::Subtitles || m_kind == Kind::Forced)
+ && m_mode == Mode::Showing;
}
-TextTrackCueList* TextTrack::ensureTextTrackCueList()
+TextTrackCueList& TextTrack::ensureTextTrackCueList()
{
if (!m_cues)
m_cues = TextTrackCueList::create();
-
- return m_cues.get();
+ return *m_cues;
}
int TextTrack::trackIndexRelativeToRenderedTracks()
{
ASSERT(m_mediaElement);
-
- if (m_renderedTrackIndex == invalidTrackIndex)
- m_renderedTrackIndex = m_mediaElement->textTracks()->getTrackIndexRelativeToRenderedTracks(this);
-
- return m_renderedTrackIndex;
+ if (!m_renderedTrackIndex)
+ m_renderedTrackIndex = m_mediaElement->textTracks().getTrackIndexRelativeToRenderedTracks(*this);
+ return m_renderedTrackIndex.value();
}
bool TextTrack::hasCue(TextTrackCue* cue, TextTrackCue::CueMatchRules match)
{
- if (cue->startTime() < 0 || cue->endTime() < 0)
+ if (cue->startMediaTime() < MediaTime::zeroTime() || cue->endMediaTime() < MediaTime::zeroTime())
return false;
if (!m_cues || !m_cues->length())
@@ -495,7 +492,7 @@ bool TextTrack::hasCue(TextTrackCue* cue, TextTrackCue::CueMatchRules match)
// If there is more than one cue with the same start time, back up to first one so we
// consider all of them.
- while (searchStart >= 2 && cue->startTime() == m_cues->item(searchStart - 2)->startTime())
+ while (searchStart >= 2 && cue->hasEquivalentStartTime(*m_cues->item(searchStart - 2)))
--searchStart;
bool firstCompare = true;
@@ -507,19 +504,20 @@ bool TextTrack::hasCue(TextTrackCue* cue, TextTrackCue::CueMatchRules match)
return false;
existingCue = m_cues->item(searchStart - 1);
- if (!existingCue || cue->startTime() > existingCue->startTime())
+ if (!existingCue)
return false;
- if (!existingCue->isEqual(*cue, match))
- continue;
-
- return true;
+ if (cue->startMediaTime() > (existingCue->startMediaTime() + startTimeVariance()))
+ return false;
+
+ if (existingCue->isEqual(*cue, match))
+ return true;
}
}
size_t index = (searchStart + searchEnd) / 2;
existingCue = m_cues->item(index);
- if (cue->startTime() < existingCue->startTime() || (match != TextTrackCue::IgnoreDuration && cue->startTime() == existingCue->startTime() && cue->endTime() > existingCue->endTime()))
+ if ((cue->startMediaTime() + startTimeVariance()) < existingCue->startMediaTime() || (match != TextTrackCue::IgnoreDuration && cue->hasEquivalentStartTime(*existingCue) && cue->endMediaTime() > existingCue->endMediaTime()))
searchEnd = index;
else
searchStart = index + 1;
@@ -529,58 +527,29 @@ bool TextTrack::hasCue(TextTrackCue* cue, TextTrackCue::CueMatchRules match)
return false;
}
-#if USE(PLATFORM_TEXT_TRACK_MENU)
-PassRefPtr<PlatformTextTrack> TextTrack::platformTextTrack()
-{
- static int uniqueId = 0;
-
- if (m_platformTextTrack)
- return m_platformTextTrack;
-
- PlatformTextTrack::TrackKind platformKind = PlatformTextTrack::Caption;
- if (kind() == subtitlesKeyword())
- platformKind = PlatformTextTrack::Subtitle;
- else if (kind() == captionsKeyword())
- platformKind = PlatformTextTrack::Caption;
- else if (kind() == descriptionsKeyword())
- platformKind = PlatformTextTrack::Description;
- else if (kind() == chaptersKeyword())
- platformKind = PlatformTextTrack::Chapter;
- else if (kind() == metadataKeyword())
- platformKind = PlatformTextTrack::MetaData;
- else if (kind() == forcedKeyword())
- platformKind = PlatformTextTrack::Forced;
-
- PlatformTextTrack::TrackType type = PlatformTextTrack::OutOfBand;
- if (m_trackType == TrackElement)
- type = PlatformTextTrack::OutOfBand;
- else if (m_trackType == AddTrack)
- type = PlatformTextTrack::Script;
- else if (m_trackType == InBand)
- type = PlatformTextTrack::InBand;
-
- m_platformTextTrack = PlatformTextTrack::create(this, label(), language(), platformKind, type, ++uniqueId);
-
- return m_platformTextTrack;
-}
-#endif
-
bool TextTrack::isMainProgramContent() const
{
// "Main program" content is intrinsic to the presentation of the media file, regardless of locale. Content such as
// directors commentary is not "main program" because it is not essential for the presentation. HTML5 doesn't have
// a way to express this in a machine-reable form, it is typically done with the track label, so we assume that caption
// tracks are main content and all other track types are not.
- return kind() == captionsKeyword();
+ return m_kind == Kind::Captions;
+}
+
+bool TextTrack::containsOnlyForcedSubtitles() const
+{
+ return m_kind == Kind::Forced;
}
#if ENABLE(MEDIA_SOURCE)
+
void TextTrack::setLanguage(const AtomicString& language)
{
// 11.1 language, on setting:
// 1. If the value being assigned to this attribute is not an empty string or a BCP 47 language
// tag[BCP47], then abort these steps.
- // FIXME(123926): Validate the BCP47-ness of langague.
+ // BCP 47 validation is done in TrackBase::setLanguage() which is
+ // shared between all tracks that support setting language.
// 2. Update this attribute to the new value.
TrackBase::setLanguage(language);
@@ -588,13 +557,14 @@ void TextTrack::setLanguage(const AtomicString& language)
// 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
// event named change at sourceBuffer.textTracks.
if (m_sourceBuffer)
- m_sourceBuffer->textTracks()->scheduleChangeEvent();
+ m_sourceBuffer->textTracks().scheduleChangeEvent();
// 4. Queue a task to fire a simple event named change at the TextTrackList object referenced by
// the textTracks attribute on the HTMLMediaElement.
if (mediaElement())
- mediaElement()->textTracks()->scheduleChangeEvent();
+ mediaElement()->textTracks().scheduleChangeEvent();
}
+
#endif
} // namespace WebCore
diff --git a/Source/WebCore/html/track/TextTrack.h b/Source/WebCore/html/track/TextTrack.h
index 43e788f33..8bb47b276 100644
--- a/Source/WebCore/html/track/TextTrack.h
+++ b/Source/WebCore/html/track/TextTrack.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,78 +24,68 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrack_h
-#define TextTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
-#include "ExceptionCode.h"
#include "TextTrackCue.h"
#include "TrackBase.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/text/WTFString.h>
-
-#if USE(PLATFORM_TEXT_TRACK_MENU)
-#include "PlatformTextTrack.h"
-#endif
namespace WebCore {
class ScriptExecutionContext;
class TextTrack;
class TextTrackCueList;
-#if ENABLE(WEBVTT_REGIONS)
-class TextTrackRegion;
-class TextTrackRegionList;
-#endif
+class VTTRegion;
+class VTTRegionList;
class TextTrackClient {
public:
virtual ~TextTrackClient() { }
- virtual void textTrackKindChanged(TextTrack*) = 0;
- virtual void textTrackModeChanged(TextTrack*) = 0;
- virtual void textTrackAddCues(TextTrack*, const TextTrackCueList*) = 0;
- virtual void textTrackRemoveCues(TextTrack*, const TextTrackCueList*) = 0;
- virtual void textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue>) = 0;
- virtual void textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue>) = 0;
+ virtual void textTrackKindChanged(TextTrack&) = 0;
+ virtual void textTrackModeChanged(TextTrack&) = 0;
+ virtual void textTrackAddCues(TextTrack&, const TextTrackCueList&) = 0;
+ virtual void textTrackRemoveCues(TextTrack&, const TextTrackCueList&) = 0;
+ virtual void textTrackAddCue(TextTrack&, TextTrackCue&) = 0;
+ virtual void textTrackRemoveCue(TextTrack&, TextTrackCue&) = 0;
};
-class TextTrack : public TrackBase, public EventTargetWithInlineData
-#if USE(PLATFORM_TEXT_TRACK_MENU)
- , public PlatformTextTrackClient
-#endif
- {
+class TextTrack : public TrackBase, public EventTargetWithInlineData {
public:
- static PassRefPtr<TextTrack> create(ScriptExecutionContext* context, TextTrackClient* client, const AtomicString& kind, const AtomicString& id, const AtomicString& label, const AtomicString& language)
+ static Ref<TextTrack> create(ScriptExecutionContext* context, TextTrackClient* client, const AtomicString& kind, const AtomicString& id, const AtomicString& label, const AtomicString& language)
{
- return adoptRef(new TextTrack(context, client, kind, id, label, language, AddTrack));
+ return adoptRef(*new TextTrack(context, client, kind, id, label, language, AddTrack));
}
virtual ~TextTrack();
- virtual EventTargetInterface eventTargetInterface() const override final { return TextTrackEventTargetInterfaceType; }
- virtual ScriptExecutionContext* scriptExecutionContext() const override final { return m_scriptExecutionContext; }
+ EventTargetInterface eventTargetInterface() const final { return TextTrackEventTargetInterfaceType; }
+ ScriptExecutionContext* scriptExecutionContext() const final { return m_scriptExecutionContext; }
static TextTrack* captionMenuOffItem();
static TextTrack* captionMenuAutomaticItem();
static const AtomicString& subtitlesKeyword();
- static const AtomicString& captionsKeyword();
- static const AtomicString& descriptionsKeyword();
- static const AtomicString& chaptersKeyword();
- static const AtomicString& metadataKeyword();
- static const AtomicString& forcedKeyword();
- virtual const AtomicString& defaultKindKeyword() const override { return subtitlesKeyword(); }
static bool isValidKindKeyword(const AtomicString&);
static const AtomicString& disabledKeyword();
static const AtomicString& hiddenKeyword();
static const AtomicString& showingKeyword();
- virtual void setKind(const AtomicString&) override;
+ enum class Kind { Subtitles, Captions, Descriptions, Chapters, Metadata, Forced };
+ Kind kind() const;
+ void setKind(Kind);
- AtomicString mode() const { return m_mode; }
- virtual void setMode(const AtomicString&);
+ Kind kindForBindings() const;
+ void setKindForBindings(Kind);
+
+ const AtomicString& kindKeyword() const;
+ void setKindKeywordIgnoringASCIICase(StringView);
+
+ virtual AtomicString inBandMetadataTrackDispatchType() const { return emptyString(); }
+
+ enum class Mode { Disabled, Hidden, Showing };
+ Mode mode() const;
+ virtual void setMode(Mode);
enum ReadinessState { NotLoaded = 0, Loading = 1, Loaded = 2, FailedToLoad = 3 };
ReadinessState readinessState() const { return m_readinessState; }
@@ -104,31 +94,27 @@ public:
TextTrackCueList* cues();
TextTrackCueList* activeCues() const;
- virtual void clearClient() override { m_client = 0; }
+ void clearClient() override { m_client = nullptr; }
TextTrackClient* client() { return m_client; }
- void addCue(PassRefPtr<TextTrackCue>);
- virtual void removeCue(TextTrackCue*, ExceptionCode&);
+ ExceptionOr<void> addCue(Ref<TextTrackCue>&&);
+ virtual ExceptionOr<void> removeCue(TextTrackCue&);
bool hasCue(TextTrackCue*, TextTrackCue::CueMatchRules = TextTrackCue::MatchAllFields);
-#if ENABLE(VIDEO_TRACK) && ENABLE(WEBVTT_REGIONS)
- TextTrackRegionList* regions();
- void addRegion(PassRefPtr<TextTrackRegion>);
- void removeRegion(TextTrackRegion*, ExceptionCode&);
-#endif
+ VTTRegionList* regions();
+ void addRegion(RefPtr<VTTRegion>&&);
+ ExceptionOr<void> removeRegion(VTTRegion*);
void cueWillChange(TextTrackCue*);
void cueDidChange(TextTrackCue*);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(cuechange);
-
enum TextTrackType { TrackElement, AddTrack, InBand };
TextTrackType trackType() const { return m_trackType; }
virtual bool isClosedCaptions() const { return false; }
virtual bool isSDH() const { return false; }
- virtual bool containsOnlyForcedSubtitles() const { return false; }
+ virtual bool containsOnlyForcedSubtitles() const;
virtual bool isMainProgramContent() const;
virtual bool isEasyToRead() const { return false; }
@@ -146,63 +132,82 @@ public:
void removeAllCues();
-#if USE(PLATFORM_TEXT_TRACK_MENU)
- PassRefPtr<PlatformTextTrack> platformTextTrack();
-#endif
-
#if ENABLE(MEDIA_SOURCE)
- virtual void setLanguage(const AtomicString&) override;
+ void setLanguage(const AtomicString&) override;
#endif
+ virtual bool isInband() const { return false; }
+
+ virtual MediaTime startTimeVariance() const { return MediaTime::zeroTime(); }
+
using RefCounted<TrackBase>::ref;
using RefCounted<TrackBase>::deref;
protected:
TextTrack(ScriptExecutionContext*, TextTrackClient*, const AtomicString& kind, const AtomicString& id, const AtomicString& label, const AtomicString& language, TextTrackType);
-#if ENABLE(VIDEO_TRACK) && ENABLE(WEBVTT_REGIONS)
- TextTrackRegionList* regionList();
-#endif
RefPtr<TextTrackCueList> m_cues;
private:
- virtual bool isValidKind(const AtomicString&) const override;
+ bool enabled() const override;
- virtual bool enabled() const override;
+ void refEventTarget() final { ref(); }
+ void derefEventTarget() final { deref(); }
- virtual void refEventTarget() override final { ref(); }
- virtual void derefEventTarget() override final { deref(); }
-
-#if ENABLE(VIDEO_TRACK) && ENABLE(WEBVTT_REGIONS)
- TextTrackRegionList* ensureTextTrackRegionList();
- RefPtr<TextTrackRegionList> m_regions;
-#endif
-
-#if USE(PLATFORM_TEXT_TRACK_MENU)
- virtual TextTrack* publicTrack() override { return this; }
-
- RefPtr<PlatformTextTrack> m_platformTextTrack;
-#endif
+ VTTRegionList& ensureVTTRegionList();
+ RefPtr<VTTRegionList> m_regions;
- TextTrackCueList* ensureTextTrackCueList();
+ TextTrackCueList& ensureTextTrackCueList();
ScriptExecutionContext* m_scriptExecutionContext;
- AtomicString m_mode;
+ Mode m_mode { Mode::Disabled };
+ Kind m_kind { Kind::Subtitles };
TextTrackClient* m_client;
TextTrackType m_trackType;
- ReadinessState m_readinessState;
- int m_trackIndex;
- int m_renderedTrackIndex;
- bool m_hasBeenConfigured;
+ ReadinessState m_readinessState { NotLoaded };
+ std::optional<int> m_trackIndex;
+ std::optional<int> m_renderedTrackIndex;
+ bool m_hasBeenConfigured { false };
};
-inline TextTrack* toTextTrack(TrackBase* track)
+inline auto TextTrack::mode() const -> Mode
{
- ASSERT_WITH_SECURITY_IMPLICATION(track->type() == TrackBase::TextTrack);
- return static_cast<TextTrack*>(track);
+ return m_mode;
}
-} // namespace WebCore
+inline auto TextTrack::kind() const -> Kind
+{
+ return m_kind;
+}
+
+inline auto TextTrack::kindForBindings() const -> Kind
+{
+ return kind();
+}
+
+#if !ENABLE(MEDIA_SOURCE)
+
+inline void TextTrack::setKindForBindings(Kind)
+{
+ // FIXME: We are using kindForBindings only to implement this empty function, preserving the
+ // behavior of doing nothing when trying to set the kind, originally implemented in a custom setter.
+ // Once we no longer need this special case, we should remove kindForBindings and setKindForBindings.
+}
+
+#else
+
+inline void TextTrack::setKindForBindings(Kind kind)
+{
+ setKind(kind);
+}
#endif
+
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::TextTrack)
+ static bool isType(const WebCore::TrackBase& track) { return track.type() == WebCore::TrackBase::TextTrack; }
+SPECIALIZE_TYPE_TRAITS_END()
+
#endif
diff --git a/Source/WebCore/html/track/TextTrack.idl b/Source/WebCore/html/track/TextTrack.idl
index 90f6d1b93..c09f0d105 100644
--- a/Source/WebCore/html/track/TextTrack.idl
+++ b/Source/WebCore/html/track/TextTrack.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,39 +23,33 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+enum TextTrackMode { "disabled", "hidden", "showing" };
+enum TextTrackKind { "subtitles", "captions", "descriptions", "chapters", "metadata", "forced" };
+
[
Conditional=VIDEO_TRACK,
- EventTarget,
GenerateIsReachable=ImplElementRoot,
JSCustomMarkFunction,
SkipVTableValidation,
-] interface TextTrack {
+] interface TextTrack : EventTarget {
readonly attribute DOMString id;
- [CustomSetter] attribute DOMString kind;
+ [ImplementedAs=kindForBindings] attribute TextTrackKind kind;
readonly attribute DOMString label;
[CustomSetter] attribute DOMString language;
+ readonly attribute DOMString inBandMetadataTrackDispatchType;
- attribute DOMString mode;
+ attribute TextTrackMode mode;
- readonly attribute TextTrackCueList cues;
- readonly attribute TextTrackCueList activeCues;
- attribute EventListener oncuechange;
+ readonly attribute TextTrackCueList? cues;
+ readonly attribute TextTrackCueList? activeCues;
- void addCue(TextTrackCue cue);
- [RaisesException] void removeCue(TextTrackCue cue);
+ [MayThrowException] void addCue(TextTrackCue cue);
+ [MayThrowException] void removeCue(TextTrackCue cue);
-#if defined(ENABLE_WEBVTT_REGIONS) && ENABLE_WEBVTT_REGIONS
- readonly attribute TextTrackRegionList regions;
- void addRegion(TextTrackRegion region);
- [RaisesException] void removeRegion(TextTrackRegion region);
-#endif
+ attribute EventHandler oncuechange;
- // EventTarget interface
- void addEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- void removeEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- [RaisesException] boolean dispatchEvent(Event evt);
+ readonly attribute VTTRegionList regions;
+ // FIXME: region parameter should not be nullable in addRegion and removeRegion.
+ void addRegion(VTTRegion? region);
+ [MayThrowException] void removeRegion(VTTRegion? region);
};
diff --git a/Source/WebCore/html/track/TextTrackCue.cpp b/Source/WebCore/html/track/TextTrackCue.cpp
index 67ff91a98..339172d10 100644
--- a/Source/WebCore/html/track/TextTrackCue.cpp
+++ b/Source/WebCore/html/track/TextTrackCue.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -30,208 +30,38 @@
*/
#include "config.h"
+#include "TextTrackCue.h"
#if ENABLE(VIDEO_TRACK)
-#include "TextTrackCue.h"
-
#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
-#include "DocumentFragment.h"
#include "Event.h"
-#include "HTMLDivElement.h"
-#include "HTMLSpanElement.h"
#include "Logging.h"
#include "NodeTraversal.h"
-#include "RenderTextTrackCue.h"
#include "Text.h"
#include "TextTrack.h"
#include "TextTrackCueList.h"
-#include "WebVTTElement.h"
-#include "WebVTTParser.h"
+#include "VTTCue.h"
+#include "VTTRegionList.h"
#include <wtf/MathExtras.h>
-#include <wtf/text/StringBuilder.h>
namespace WebCore {
-static const int invalidCueIndex = -1;
-static const int undefinedPosition = -1;
-
-static const String& startKeyword()
-{
- DEFINE_STATIC_LOCAL(const String, start, (ASCIILiteral("start")));
- return start;
-}
-
-static const String& middleKeyword()
-{
- DEFINE_STATIC_LOCAL(const String, middle, (ASCIILiteral("middle")));
- return middle;
-}
-
-static const String& endKeyword()
-{
- DEFINE_STATIC_LOCAL(const String, end, (ASCIILiteral("end")));
- return end;
-}
-
-static const String& horizontalKeyword()
-{
- return emptyString();
-}
-
-static const String& verticalGrowingLeftKeyword()
-{
- DEFINE_STATIC_LOCAL(const String, verticalrl, (ASCIILiteral("rl")));
- return verticalrl;
-}
-
-static const String& verticalGrowingRightKeyword()
-{
- DEFINE_STATIC_LOCAL(const String, verticallr, (ASCIILiteral("lr")));
- return verticallr;
-}
-
-// ----------------------------
-
-TextTrackCueBox::TextTrackCueBox(Document& document, TextTrackCue* cue)
- : HTMLElement(divTag, document)
- , m_cue(cue)
-{
- setPseudo(textTrackCueBoxShadowPseudoId());
-}
-
-TextTrackCue* TextTrackCueBox::getCue() const
-{
- return m_cue;
-}
-
-void TextTrackCueBox::applyCSSProperties(const IntSize&)
-{
- // FIXME: Apply all the initial CSS positioning properties. http://wkb.ug/79916
-
- // 3.5.1 On the (root) List of WebVTT Node Objects:
-
- // the 'position' property must be set to 'absolute'
- setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute);
-
- // the 'unicode-bidi' property must be set to 'plaintext'
- setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext);
-
- // the 'direction' property must be set to direction
- setInlineStyleProperty(CSSPropertyDirection, m_cue->getCSSWritingDirection());
-
- // the 'writing-mode' property must be set to writing-mode
- setInlineStyleProperty(CSSPropertyWebkitWritingMode, m_cue->getCSSWritingMode(), false);
-
- std::pair<float, float> position = m_cue->getCSSPosition();
-
- // the 'top' property must be set to top,
- setInlineStyleProperty(CSSPropertyTop, static_cast<double>(position.second), CSSPrimitiveValue::CSS_PERCENTAGE);
-
- // the 'left' property must be set to left
- setInlineStyleProperty(CSSPropertyLeft, static_cast<double>(position.first), CSSPrimitiveValue::CSS_PERCENTAGE);
-
- // the 'width' property must be set to width, and the 'height' property must be set to height
- if (m_cue->vertical() == horizontalKeyword()) {
- setInlineStyleProperty(CSSPropertyWidth, static_cast<double>(m_cue->getCSSSize()), CSSPrimitiveValue::CSS_PERCENTAGE);
- setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto);
- } else {
- setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto);
- setInlineStyleProperty(CSSPropertyHeight, static_cast<double>(m_cue->getCSSSize()), CSSPrimitiveValue::CSS_PERCENTAGE);
- }
-
- // The 'text-align' property on the (root) List of WebVTT Node Objects must
- // be set to the value in the second cell of the row of the table below
- // whose first cell is the value of the corresponding cue's text track cue
- // alignment:
- if (m_cue->align() == startKeyword())
- setInlineStyleProperty(CSSPropertyTextAlign, CSSValueStart);
- else if (m_cue->align() == endKeyword())
- setInlineStyleProperty(CSSPropertyTextAlign, CSSValueEnd);
- else
- setInlineStyleProperty(CSSPropertyTextAlign, CSSValueCenter);
-
- if (!m_cue->snapToLines()) {
- // 10.13.1 Set up x and y:
- // Note: x and y are set through the CSS left and top above.
-
- // 10.13.2 Position the boxes in boxes such that the point x% along the
- // width of the bounding box of the boxes in boxes is x% of the way
- // across the width of the video's rendering area, and the point y%
- // along the height of the bounding box of the boxes in boxes is y%
- // of the way across the height of the video's rendering area, while
- // maintaining the relative positions of the boxes in boxes to each
- // other.
- setInlineStyleProperty(CSSPropertyWebkitTransform,
- String::format("translate(-%.2f%%, -%.2f%%)", position.first, position.second));
-
- setInlineStyleProperty(CSSPropertyWhiteSpace, CSSValuePre);
- }
-}
-
-const AtomicString& TextTrackCueBox::textTrackCueBoxShadowPseudoId()
+const AtomicString& TextTrackCue::cueShadowPseudoId()
{
- DEFINE_STATIC_LOCAL(const AtomicString, trackDisplayBoxShadowPseudoId, ("-webkit-media-text-track-display", AtomicString::ConstructFromLiteral));
- return trackDisplayBoxShadowPseudoId;
+ static NeverDestroyed<const AtomicString> cue("cue", AtomicString::ConstructFromLiteral);
+ return cue;
}
-RenderPtr<RenderElement> TextTrackCueBox::createElementRenderer(PassRef<RenderStyle> style)
-{
- return createRenderer<RenderTextTrackCue>(*this, std::move(style));
-}
-
-// ----------------------------
-
-TextTrackCue::TextTrackCue(ScriptExecutionContext& context, double start, double end, const String& content)
+TextTrackCue::TextTrackCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end)
: m_startTime(start)
, m_endTime(end)
- , m_content(content)
- , m_linePosition(undefinedPosition)
- , m_computedLinePosition(undefinedPosition)
- , m_textPosition(50)
- , m_cueSize(100)
- , m_cueIndex(invalidCueIndex)
- , m_processingCueChanges(0)
- , m_writingDirection(Horizontal)
- , m_cueAlignment(Middle)
- , m_webVTTNodeTree(0)
- , m_track(0)
, m_scriptExecutionContext(context)
, m_isActive(false)
, m_pauseOnExit(false)
- , m_snapToLines(true)
- , m_cueBackgroundBox(HTMLSpanElement::create(spanTag, toDocument(context)))
- , m_displayTreeShouldChange(true)
- , m_displayDirection(CSSValueLtr)
{
ASSERT(m_scriptExecutionContext.isDocument());
-
- // 4. If the text track cue writing direction is horizontal, then let
- // writing-mode be 'horizontal-tb'. Otherwise, if the text track cue writing
- // direction is vertical growing left, then let writing-mode be
- // 'vertical-rl'. Otherwise, the text track cue writing direction is
- // vertical growing right; let writing-mode be 'vertical-lr'.
- m_displayWritingModeMap[Horizontal] = CSSValueHorizontalTb;
- m_displayWritingModeMap[VerticalGrowingLeft] = CSSValueVerticalRl;
- m_displayWritingModeMap[VerticalGrowingRight] = CSSValueVerticalLr;
-}
-
-TextTrackCue::~TextTrackCue()
-{
- removeDisplayTree();
-}
-
-PassRefPtr<TextTrackCueBox> TextTrackCue::createDisplayTree()
-{
- return TextTrackCueBox::create(ownerDocument(), this);
-}
-
-TextTrackCueBox* TextTrackCue::displayTreeInternal()
-{
- if (!m_displayTree)
- m_displayTree = createDisplayTree();
- return m_displayTree.get();
}
void TextTrackCue::willChange()
@@ -251,8 +81,6 @@ void TextTrackCue::didChange()
if (m_track)
m_track->cueDidChange(this);
-
- m_displayTreeShouldChange = true;
}
TextTrack* TextTrackCue::track() const
@@ -275,928 +103,116 @@ void TextTrackCue::setId(const String& id)
didChange();
}
-void TextTrackCue::setStartTime(double value, ExceptionCode& ec)
+void TextTrackCue::setStartTime(double value)
{
- // NaN, Infinity and -Infinity values should trigger a TypeError.
- if (std::isinf(value) || std::isnan(value)) {
- ec = TypeError;
- return;
- }
-
// TODO(93143): Add spec-compliant behavior for negative time values.
- if (m_startTime == value || value < 0)
- return;
-
- willChange();
- m_startTime = value;
- didChange();
-}
-
-void TextTrackCue::setEndTime(double value, ExceptionCode& ec)
-{
- // NaN, Infinity and -Infinity values should trigger a TypeError.
- if (std::isinf(value) || std::isnan(value)) {
- ec = TypeError;
- return;
- }
-
- // TODO(93143): Add spec-compliant behavior for negative time values.
- if (m_endTime == value || value < 0)
- return;
-
- willChange();
- m_endTime = value;
- didChange();
-}
-
-void TextTrackCue::setPauseOnExit(bool value)
-{
- if (m_pauseOnExit == value)
- return;
-
- m_pauseOnExit = value;
-}
-
-const String& TextTrackCue::vertical() const
-{
- switch (m_writingDirection) {
- case Horizontal:
- return horizontalKeyword();
- case VerticalGrowingLeft:
- return verticalGrowingLeftKeyword();
- case VerticalGrowingRight:
- return verticalGrowingRightKeyword();
- default:
- ASSERT_NOT_REACHED();
- return emptyString();
- }
-}
-
-void TextTrackCue::setVertical(const String& value, ExceptionCode& ec)
-{
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-vertical
- // On setting, the text track cue writing direction must be set to the value given
- // in the first cell of the row in the table above whose second cell is a
- // case-sensitive match for the new value, if any. If none of the values match, then
- // the user agent must instead throw a SyntaxError exception.
-
- WritingDirection direction = m_writingDirection;
- if (value == horizontalKeyword())
- direction = Horizontal;
- else if (value == verticalGrowingLeftKeyword())
- direction = VerticalGrowingLeft;
- else if (value == verticalGrowingRightKeyword())
- direction = VerticalGrowingRight;
- else
- ec = SYNTAX_ERR;
-
- if (direction == m_writingDirection)
+ if (m_startTime.toDouble() == value || value < 0)
return;
- willChange();
- m_writingDirection = direction;
- didChange();
+ setStartTime(MediaTime::createWithDouble(value));
}
-void TextTrackCue::setSnapToLines(bool value)
+void TextTrackCue::setStartTime(const MediaTime& value)
{
- if (m_snapToLines == value)
- return;
-
willChange();
- m_snapToLines = value;
- didChange();
-}
-
-void TextTrackCue::setLine(int position, ExceptionCode& ec)
-{
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-line
- // On setting, if the text track cue snap-to-lines flag is not set, and the new
- // value is negative or greater than 100, then throw an IndexSizeError exception.
- if (!m_snapToLines && (position < 0 || position > 100)) {
- ec = INDEX_SIZE_ERR;
- return;
- }
-
- // Otherwise, set the text track cue line position to the new value.
- if (m_linePosition == position)
- return;
-
- willChange();
- m_linePosition = position;
- m_computedLinePosition = calculateComputedLinePosition();
+ m_startTime = value;
didChange();
}
-
-void TextTrackCue::setPosition(int position, ExceptionCode& ec)
-{
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-position
- // On setting, if the new value is negative or greater than 100, then throw an IndexSizeError exception.
- // Otherwise, set the text track cue text position to the new value.
- if (position < 0 || position > 100) {
- ec = INDEX_SIZE_ERR;
- return;
- }
-
- // Otherwise, set the text track cue line position to the new value.
- if (m_textPosition == position)
- return;
- willChange();
- m_textPosition = position;
- didChange();
-}
-
-void TextTrackCue::setSize(int size, ExceptionCode& ec)
+void TextTrackCue::setEndTime(double value)
{
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-size
- // On setting, if the new value is negative or greater than 100, then throw an IndexSizeError
- // exception. Otherwise, set the text track cue size to the new value.
- if (size < 0 || size > 100) {
- ec = INDEX_SIZE_ERR;
- return;
- }
-
- // Otherwise, set the text track cue line position to the new value.
- if (m_cueSize == size)
+ // TODO(93143): Add spec-compliant behavior for negative time values.
+ if (m_endTime.toDouble() == value || value < 0)
return;
-
- willChange();
- m_cueSize = size;
- didChange();
-}
-const String& TextTrackCue::align() const
-{
- switch (m_cueAlignment) {
- case Start:
- return startKeyword();
- case Middle:
- return middleKeyword();
- case End:
- return endKeyword();
- default:
- ASSERT_NOT_REACHED();
- return emptyString();
- }
+ setEndTime(MediaTime::createWithDouble(value));
}
-void TextTrackCue::setAlign(const String& value, ExceptionCode& ec)
+void TextTrackCue::setEndTime(const MediaTime& value)
{
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-align
- // On setting, the text track cue alignment must be set to the value given in the
- // first cell of the row in the table above whose second cell is a case-sensitive
- // match for the new value, if any. If none of the values match, then the user
- // agent must instead throw a SyntaxError exception.
-
- CueAlignment alignment = m_cueAlignment;
- if (value == startKeyword())
- alignment = Start;
- else if (value == middleKeyword())
- alignment = Middle;
- else if (value == endKeyword())
- alignment = End;
- else
- ec = SYNTAX_ERR;
-
- if (alignment == m_cueAlignment)
- return;
-
willChange();
- m_cueAlignment = alignment;
+ m_endTime = value;
didChange();
}
-void TextTrackCue::setText(const String& text)
+void TextTrackCue::setPauseOnExit(bool value)
{
- if (m_content == text)
+ if (m_pauseOnExit == value)
return;
- willChange();
- // Clear the document fragment but don't bother to create it again just yet as we can do that
- // when it is requested.
- m_webVTTNodeTree = 0;
- m_content = text;
- didChange();
-}
-
-int TextTrackCue::cueIndex()
-{
- if (m_cueIndex == invalidCueIndex) {
- ASSERT(track());
- ASSERT(track()->cues());
- if (TextTrackCueList* cueList = track()->cues())
- m_cueIndex = cueList->getCueIndex(this);
- }
-
- return m_cueIndex;
-}
-
-void TextTrackCue::invalidateCueIndex()
-{
- m_cueIndex = invalidCueIndex;
-}
-
-void TextTrackCue::createWebVTTNodeTree()
-{
- if (!m_webVTTNodeTree)
- m_webVTTNodeTree = WebVTTParser::create(0, &m_scriptExecutionContext)->createDocumentFragmentFromCueText(m_content);
-}
-
-void TextTrackCue::copyWebVTTNodeToDOMTree(ContainerNode* webVTTNode, ContainerNode* parent)
-{
- for (Node* node = webVTTNode->firstChild(); node; node = node->nextSibling()) {
- RefPtr<Node> clonedNode;
- if (node->isWebVTTElement())
- clonedNode = toWebVTTElement(node)->createEquivalentHTMLElement(ownerDocument());
- else
- clonedNode = node->cloneNode(false);
- parent->appendChild(clonedNode, ASSERT_NO_EXCEPTION);
- if (node->isContainerNode())
- copyWebVTTNodeToDOMTree(toContainerNode(node), toContainerNode(clonedNode.get()));
- }
-}
-
-PassRefPtr<DocumentFragment> TextTrackCue::getCueAsHTML()
-{
- createWebVTTNodeTree();
- if (!m_webVTTNodeTree)
- return 0;
-
- RefPtr<DocumentFragment> clonedFragment = DocumentFragment::create(ownerDocument());
- copyWebVTTNodeToDOMTree(m_webVTTNodeTree.get(), clonedFragment.get());
- return clonedFragment.release();
-}
-
-PassRefPtr<DocumentFragment> TextTrackCue::createCueRenderingTree()
-{
- RefPtr<DocumentFragment> clonedFragment;
- createWebVTTNodeTree();
- if (!m_webVTTNodeTree)
- return 0;
-
- clonedFragment = DocumentFragment::create(ownerDocument());
- m_webVTTNodeTree->cloneChildNodes(clonedFragment.get());
- return clonedFragment.release();
+ m_pauseOnExit = value;
}
-bool TextTrackCue::dispatchEvent(PassRefPtr<Event> event)
+bool TextTrackCue::dispatchEvent(Event& event)
{
// When a TextTrack's mode is disabled: no cues are active, no events fired.
- if (!track() || track()->mode() == TextTrack::disabledKeyword())
+ if (!track() || track()->mode() == TextTrack::Mode::Disabled)
return false;
return EventTarget::dispatchEvent(event);
}
-#if ENABLE(WEBVTT_REGIONS)
-void TextTrackCue::setRegionId(const String& regionId)
-{
- if (m_regionId == regionId)
- return;
-
- willChange();
- m_regionId = regionId;
- didChange();
-}
-#endif
-
bool TextTrackCue::isActive()
{
- return m_isActive && track() && track()->mode() != TextTrack::disabledKeyword();
+ return m_isActive && track() && track()->mode() != TextTrack::Mode::Disabled;
}
void TextTrackCue::setIsActive(bool active)
{
m_isActive = active;
-
- if (!active) {
- if (!hasDisplayTree())
- return;
-
- // Remove the display tree as soon as the cue becomes inactive.
- displayTreeInternal()->remove(ASSERT_NO_EXCEPTION);
- }
-}
-
-int TextTrackCue::calculateComputedLinePosition()
-{
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-computed-line-position
-
- // If the text track cue line position is numeric, then that is the text
- // track cue computed line position.
- if (m_linePosition != undefinedPosition)
- return m_linePosition;
-
- // If the text track cue snap-to-lines flag of the text track cue is not
- // set, the text track cue computed line position is the value 100;
- if (!m_snapToLines)
- return 100;
-
- // Otherwise, it is the value returned by the following algorithm:
-
- // If cue is not associated with a text track, return -1 and abort these
- // steps.
- if (!track())
- return -1;
-
- // Let n be the number of text tracks whose text track mode is showing or
- // showing by default and that are in the media element's list of text
- // tracks before track.
- int n = track()->trackIndexRelativeToRenderedTracks();
-
- // Increment n by one.
- n++;
-
- // Negate n.
- n = -n;
-
- return n;
-}
-
-static bool isCueParagraphSeparator(UChar character)
-{
- // Within a cue, paragraph boundaries are only denoted by Type B characters,
- // such as U+000A LINE FEED (LF), U+0085 NEXT LINE (NEL), and U+2029 PARAGRAPH SEPARATOR.
- return u_charType(character) == U_PARAGRAPH_SEPARATOR;
-}
-
-void TextTrackCue::determineTextDirection()
-{
- DEFINE_STATIC_LOCAL(const String, rtTag, (ASCIILiteral("rt")));
- createWebVTTNodeTree();
- if (!m_webVTTNodeTree)
- return;
-
- // Apply the Unicode Bidirectional Algorithm's Paragraph Level steps to the
- // concatenation of the values of each WebVTT Text Object in nodes, in a
- // pre-order, depth-first traversal, excluding WebVTT Ruby Text Objects and
- // their descendants.
- StringBuilder paragraphBuilder;
- for (Node* node = m_webVTTNodeTree->firstChild(); node; node = NodeTraversal::next(node, m_webVTTNodeTree.get())) {
- // FIXME: The code does not match the comment above. This does not actually exclude Ruby Text Object descendant.
- if (!node->isTextNode() || node->localName() == rtTag)
- continue;
-
- paragraphBuilder.append(node->nodeValue());
- }
-
- String paragraph = paragraphBuilder.toString();
- if (!paragraph.length())
- return;
-
- for (size_t i = 0; i < paragraph.length(); ++i) {
- UChar current = paragraph[i];
- if (!current || isCueParagraphSeparator(current))
- return;
-
- if (UChar current = paragraph[i]) {
- UCharDirection charDirection = u_charDirection(current);
- if (charDirection == U_LEFT_TO_RIGHT) {
- m_displayDirection = CSSValueLtr;
- return;
- }
- if (charDirection == U_RIGHT_TO_LEFT || charDirection == U_RIGHT_TO_LEFT_ARABIC) {
- m_displayDirection = CSSValueRtl;
- return;
- }
- }
- }
-}
-
-void TextTrackCue::calculateDisplayParameters()
-{
- // Steps 10.2, 10.3
- determineTextDirection();
-
- // 10.4 If the text track cue writing direction is horizontal, then let
- // block-flow be 'tb'. Otherwise, if the text track cue writing direction is
- // vertical growing left, then let block-flow be 'lr'. Otherwise, the text
- // track cue writing direction is vertical growing right; let block-flow be
- // 'rl'.
- m_displayWritingMode = m_displayWritingModeMap[m_writingDirection];
-
- // 10.5 Determine the value of maximum size for cue as per the appropriate
- // rules from the following list:
- int maximumSize = m_textPosition;
- if ((m_writingDirection == Horizontal && m_cueAlignment == Start && m_displayDirection == CSSValueLtr)
- || (m_writingDirection == Horizontal && m_cueAlignment == End && m_displayDirection == CSSValueRtl)
- || (m_writingDirection == VerticalGrowingLeft && m_cueAlignment == Start)
- || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == Start)) {
- maximumSize = 100 - m_textPosition;
- } else if ((m_writingDirection == Horizontal && m_cueAlignment == End && m_displayDirection == CSSValueLtr)
- || (m_writingDirection == Horizontal && m_cueAlignment == Start && m_displayDirection == CSSValueRtl)
- || (m_writingDirection == VerticalGrowingLeft && m_cueAlignment == End)
- || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == End)) {
- maximumSize = m_textPosition;
- } else if (m_cueAlignment == Middle) {
- maximumSize = m_textPosition <= 50 ? m_textPosition : (100 - m_textPosition);
- maximumSize = maximumSize * 2;
- }
-
- // 10.6 If the text track cue size is less than maximum size, then let size
- // be text track cue size. Otherwise, let size be maximum size.
- m_displaySize = std::min(m_cueSize, maximumSize);
-
- // 10.8 Determine the value of x-position or y-position for cue as per the
- // appropriate rules from the following list:
- if (m_writingDirection == Horizontal) {
- if (m_cueAlignment == Start) {
- if (m_displayDirection == CSSValueLtr)
- m_displayPosition.first = m_textPosition;
- else
- m_displayPosition.first = 100 - m_textPosition - m_displaySize;
- } else if (m_cueAlignment == End) {
- if (m_displayDirection == CSSValueRtl)
- m_displayPosition.first = 100 - m_textPosition;
- else
- m_displayPosition.first = m_textPosition - m_displaySize;
- }
- }
-
- if ((m_writingDirection == VerticalGrowingLeft && m_cueAlignment == Start)
- || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == Start)) {
- m_displayPosition.second = m_textPosition;
- } else if ((m_writingDirection == VerticalGrowingLeft && m_cueAlignment == End)
- || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == End)) {
- m_displayPosition.second = 100 - m_textPosition;
- }
-
- if (m_writingDirection == Horizontal && m_cueAlignment == Middle) {
- if (m_displayDirection == CSSValueLtr)
- m_displayPosition.first = m_textPosition - m_displaySize / 2;
- else
- m_displayPosition.first = 100 - m_textPosition - m_displaySize / 2;
- }
-
- if ((m_writingDirection == VerticalGrowingLeft && m_cueAlignment == Middle)
- || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == Middle))
- m_displayPosition.second = m_textPosition - m_displaySize / 2;
-
- // 10.9 Determine the value of whichever of x-position or y-position is not
- // yet calculated for cue as per the appropriate rules from the following
- // list:
- if (m_snapToLines && m_displayPosition.second == undefinedPosition && m_writingDirection == Horizontal)
- m_displayPosition.second = 0;
-
- if (!m_snapToLines && m_displayPosition.second == undefinedPosition && m_writingDirection == Horizontal)
- m_displayPosition.second = m_computedLinePosition;
-
- if (m_snapToLines && m_displayPosition.first == undefinedPosition
- && (m_writingDirection == VerticalGrowingLeft || m_writingDirection == VerticalGrowingRight))
- m_displayPosition.first = 0;
-
- if (!m_snapToLines && (m_writingDirection == VerticalGrowingLeft || m_writingDirection == VerticalGrowingRight))
- m_displayPosition.first = m_computedLinePosition;
-
- // A text track cue has a text track cue computed line position whose value
- // is defined in terms of the other aspects of the cue.
- m_computedLinePosition = calculateComputedLinePosition();
-}
-
-void TextTrackCue::markFutureAndPastNodes(ContainerNode* root, double previousTimestamp, double movieTime)
-{
- DEFINE_STATIC_LOCAL(const String, timestampTag, (ASCIILiteral("timestamp")));
-
- bool isPastNode = true;
- double currentTimestamp = previousTimestamp;
- if (currentTimestamp > movieTime)
- isPastNode = false;
-
- for (Node* child = root->firstChild(); child; child = NodeTraversal::next(child, root)) {
- if (child->nodeName() == timestampTag) {
- unsigned position = 0;
- String timestamp = child->nodeValue();
- double currentTimestamp = WebVTTParser::create(0, &m_scriptExecutionContext)->collectTimeStamp(timestamp, &position);
- ASSERT(currentTimestamp != -1);
-
- if (currentTimestamp > movieTime)
- isPastNode = false;
- }
-
- if (child->isWebVTTElement()) {
- toWebVTTElement(child)->setIsPastNode(isPastNode);
- // Make an elemenet id match a cue id for style matching purposes.
- if (!m_id.isEmpty())
- toElement(child)->setIdAttribute(m_id);
- }
- }
-}
-
-void TextTrackCue::updateDisplayTree(double movieTime)
-{
- // The display tree may contain WebVTT timestamp objects representing
- // timestamps (processing instructions), along with displayable nodes.
-
- if (!track()->isRendered())
- return;
-
- // Clear the contents of the set.
- m_cueBackgroundBox->removeChildren();
-
- // Update the two sets containing past and future WebVTT objects.
- RefPtr<DocumentFragment> referenceTree = createCueRenderingTree();
- if (!referenceTree)
- return;
-
- markFutureAndPastNodes(referenceTree.get(), startTime(), movieTime);
- m_cueBackgroundBox->appendChild(referenceTree);
-}
-
-TextTrackCueBox* TextTrackCue::getDisplayTree(const IntSize& videoSize)
-{
- RefPtr<TextTrackCueBox> displayTree = displayTreeInternal();
- if (!m_displayTreeShouldChange || !track()->isRendered())
- return displayTree.get();
-
- // 10.1 - 10.10
- calculateDisplayParameters();
-
- // 10.11. Apply the terms of the CSS specifications to nodes within the
- // following constraints, thus obtaining a set of CSS boxes positioned
- // relative to an initial containing block:
- displayTree->removeChildren();
-
- // The document tree is the tree of WebVTT Node Objects rooted at nodes.
-
- // The children of the nodes must be wrapped in an anonymous box whose
- // 'display' property has the value 'inline'. This is the WebVTT cue
- // background box.
-
- // Note: This is contained by default in m_cueBackgroundBox.
- m_cueBackgroundBox->setPseudo(cueShadowPseudoId());
- displayTree->appendChild(m_cueBackgroundBox, ASSERT_NO_EXCEPTION);
-
- // FIXME(BUG 79916): Runs of children of WebVTT Ruby Objects that are not
- // WebVTT Ruby Text Objects must be wrapped in anonymous boxes whose
- // 'display' property has the value 'ruby-base'.
-
- // FIXME(BUG 79916): Text runs must be wrapped according to the CSS
- // line-wrapping rules, except that additionally, regardless of the value of
- // the 'white-space' property, lines must be wrapped at the edge of their
- // containing blocks, even if doing so requires splitting a word where there
- // is no line breaking opportunity. (Thus, normally text wraps as needed,
- // but if there is a particularly long word, it does not overflow as it
- // normally would in CSS, it is instead forcibly wrapped at the box's edge.)
- displayTree->applyCSSProperties(videoSize);
-
- m_displayTreeShouldChange = false;
-
- // 10.15. Let cue's text track cue display state have the CSS boxes in
- // boxes.
- return displayTree.get();
-}
-
-void TextTrackCue::removeDisplayTree()
-{
- if (!hasDisplayTree())
- return;
- displayTreeInternal()->remove(ASSERT_NO_EXCEPTION);
}
-std::pair<double, double> TextTrackCue::getPositionCoordinates() const
-{
- // This method is used for setting x and y when snap to lines is not set.
- std::pair<double, double> coordinates;
-
- if (m_writingDirection == Horizontal && m_displayDirection == CSSValueLtr) {
- coordinates.first = m_textPosition;
- coordinates.second = m_computedLinePosition;
-
- return coordinates;
- }
-
- if (m_writingDirection == Horizontal && m_displayDirection == CSSValueRtl) {
- coordinates.first = 100 - m_textPosition;
- coordinates.second = m_computedLinePosition;
-
- return coordinates;
- }
-
- if (m_writingDirection == VerticalGrowingLeft) {
- coordinates.first = 100 - m_computedLinePosition;
- coordinates.second = m_textPosition;
-
- return coordinates;
- }
-
- if (m_writingDirection == VerticalGrowingRight) {
- coordinates.first = m_computedLinePosition;
- coordinates.second = m_textPosition;
-
- return coordinates;
- }
-
- ASSERT_NOT_REACHED();
-
- return coordinates;
-}
-
-TextTrackCue::CueSetting TextTrackCue::settingName(const String& name)
-{
- DEFINE_STATIC_LOCAL(const String, verticalKeyword, (ASCIILiteral("vertical")));
- DEFINE_STATIC_LOCAL(const String, lineKeyword, (ASCIILiteral("line")));
- DEFINE_STATIC_LOCAL(const String, positionKeyword, (ASCIILiteral("position")));
- DEFINE_STATIC_LOCAL(const String, sizeKeyword, (ASCIILiteral("size")));
- DEFINE_STATIC_LOCAL(const String, alignKeyword, (ASCIILiteral("align")));
-#if ENABLE(WEBVTT_REGIONS)
- DEFINE_STATIC_LOCAL(const String, regionIdKeyword, (ASCIILiteral("region")));
-#endif
-
- if (name == verticalKeyword)
- return Vertical;
- else if (name == lineKeyword)
- return Line;
- else if (name == positionKeyword)
- return Position;
- else if (name == sizeKeyword)
- return Size;
- else if (name == alignKeyword)
- return Align;
-#if ENABLE(WEBVTT_REGIONS)
- else if (name == regionIdKeyword)
- return RegionId;
-#endif
-
- return None;
-}
-
-void TextTrackCue::setCueSettings(const String& input)
-{
- m_settings = input;
- unsigned position = 0;
-
- while (position < input.length()) {
-
- // The WebVTT cue settings part of a WebVTT cue consists of zero or more of the following components, in any order,
- // separated from each other by one or more U+0020 SPACE characters or U+0009 CHARACTER TABULATION (tab) characters.
- while (position < input.length() && WebVTTParser::isValidSettingDelimiter(input[position]))
- position++;
- if (position >= input.length())
- break;
-
- // When the user agent is to parse the WebVTT settings given by a string input for a text track cue cue,
- // the user agent must run the following steps:
- // 1. Let settings be the result of splitting input on spaces.
- // 2. For each token setting in the list settings, run the following substeps:
- // 1. If setting does not contain a U+003A COLON character (:), or if the first U+003A COLON character (:)
- // in setting is either the first or last character of setting, then jump to the step labeled next setting.
- unsigned endOfSetting = position;
- String setting = WebVTTParser::collectWord(input, &endOfSetting);
- CueSetting name;
- size_t colonOffset = setting.find(':', 1);
- if (colonOffset == notFound || colonOffset == 0 || colonOffset == setting.length() - 1)
- goto NextSetting;
-
- // 2. Let name be the leading substring of setting up to and excluding the first U+003A COLON character (:) in that string.
- name = settingName(setting.substring(0, colonOffset));
-
- // 3. Let value be the trailing substring of setting starting from the character immediately after the first U+003A COLON character (:) in that string.
- position += colonOffset + 1;
- if (position >= input.length())
- break;
-
- // 4. Run the appropriate substeps that apply for the value of name, as follows:
- switch (name) {
- case Vertical:
- {
- // If name is a case-sensitive match for "vertical"
- // 1. If value is a case-sensitive match for the string "rl", then let cue's text track cue writing direction
- // be vertical growing left.
- String writingDirection = WebVTTParser::collectWord(input, &position);
- if (writingDirection == verticalGrowingLeftKeyword())
- m_writingDirection = VerticalGrowingLeft;
-
- // 2. Otherwise, if value is a case-sensitive match for the string "lr", then let cue's text track cue writing
- // direction be vertical growing right.
- else if (writingDirection == verticalGrowingRightKeyword())
- m_writingDirection = VerticalGrowingRight;
- }
- break;
- case Line:
- {
- // 1-2 - Collect chars that are either '-', '%', or a digit.
- // 1. If value contains any characters other than U+002D HYPHEN-MINUS characters (-), U+0025 PERCENT SIGN
- // characters (%), and characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump
- // to the step labeled next setting.
- StringBuilder linePositionBuilder;
- while (position < input.length() && (input[position] == '-' || input[position] == '%' || isASCIIDigit(input[position])))
- linePositionBuilder.append(input[position++]);
- if (position < input.length() && !WebVTTParser::isValidSettingDelimiter(input[position]))
- break;
-
- // 2. If value does not contain at least one character in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT
- // NINE (9), then jump to the step labeled next setting.
- // 3. If any character in value other than the first character is a U+002D HYPHEN-MINUS character (-), then
- // jump to the step labeled next setting.
- // 4. If any character in value other than the last character is a U+0025 PERCENT SIGN character (%), then
- // jump to the step labeled next setting.
- String linePosition = linePositionBuilder.toString();
- if (linePosition.find('-', 1) != notFound || linePosition.reverseFind("%", linePosition.length() - 2) != notFound)
- break;
-
- // 5. If the first character in value is a U+002D HYPHEN-MINUS character (-) and the last character in value is a
- // U+0025 PERCENT SIGN character (%), then jump to the step labeled next setting.
- if (linePosition[0] == '-' && linePosition[linePosition.length() - 1] == '%')
- break;
-
- // 6. Ignoring the trailing percent sign, if any, interpret value as a (potentially signed) integer, and
- // let number be that number.
- // NOTE: toInt ignores trailing non-digit characters, such as '%'.
- bool validNumber;
- int number = linePosition.toInt(&validNumber);
- if (!validNumber)
- break;
-
- // 7. If the last character in value is a U+0025 PERCENT SIGN character (%), but number is not in the range
- // 0 ≤ number ≤ 100, then jump to the step labeled next setting.
- // 8. Let cue's text track cue line position be number.
- // 9. If the last character in value is a U+0025 PERCENT SIGN character (%), then let cue's text track cue
- // snap-to-lines flag be false. Otherwise, let it be true.
- if (linePosition[linePosition.length() - 1] == '%') {
- if (number < 0 || number > 100)
- break;
-
- // 10 - If '%' then set snap-to-lines flag to false.
- m_snapToLines = false;
- }
-
- m_linePosition = number;
- }
- break;
- case Position:
- {
- // 1. If value contains any characters other than U+0025 PERCENT SIGN characters (%) and characters in the range
- // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump to the step labeled next setting.
- // 2. If value does not contain at least one character in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9),
- // then jump to the step labeled next setting.
- String textPosition = WebVTTParser::collectDigits(input, &position);
- if (textPosition.isEmpty())
- break;
- if (position >= input.length())
- break;
-
- // 3. If any character in value other than the last character is a U+0025 PERCENT SIGN character (%), then jump
- // to the step labeled next setting.
- // 4. If the last character in value is not a U+0025 PERCENT SIGN character (%), then jump to the step labeled
- // next setting.
- if (input[position++] != '%')
- break;
- if (position < input.length() && !WebVTTParser::isValidSettingDelimiter(input[position]))
- break;
-
- // 5. Ignoring the trailing percent sign, interpret value as an integer, and let number be that number.
- // 6. If number is not in the range 0 ≤ number ≤ 100, then jump to the step labeled next setting.
- // NOTE: toInt ignores trailing non-digit characters, such as '%'.
- bool validNumber;
- int number = textPosition.toInt(&validNumber);
- if (!validNumber)
- break;
- if (number < 0 || number > 100)
- break;
-
- // 7. Let cue's text track cue text position be number.
- m_textPosition = number;
- }
- break;
- case Size:
- {
- // 1. If value contains any characters other than U+0025 PERCENT SIGN characters (%) and characters in the
- // range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump to the step labeled next setting.
- // 2. If value does not contain at least one character in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT
- // NINE (9), then jump to the step labeled next setting.
- String cueSize = WebVTTParser::collectDigits(input, &position);
- if (cueSize.isEmpty())
- break;
- if (position >= input.length())
- break;
-
- // 3. If any character in value other than the last character is a U+0025 PERCENT SIGN character (%),
- // then jump to the step labeled next setting.
- // 4. If the last character in value is not a U+0025 PERCENT SIGN character (%), then jump to the step
- // labeled next setting.
- if (input[position++] != '%')
- break;
- if (position < input.length() && !WebVTTParser::isValidSettingDelimiter(input[position]))
- break;
-
- // 5. Ignoring the trailing percent sign, interpret value as an integer, and let number be that number.
- // 6. If number is not in the range 0 ≤ number ≤ 100, then jump to the step labeled next setting.
- bool validNumber;
- int number = cueSize.toInt(&validNumber);
- if (!validNumber)
- break;
- if (number < 0 || number > 100)
- break;
-
- // 7. Let cue's text track cue size be number.
- m_cueSize = number;
- }
- break;
- case Align:
- {
- String cueAlignment = WebVTTParser::collectWord(input, &position);
-
- // 1. If value is a case-sensitive match for the string "start", then let cue's text track cue alignment be start alignment.
- if (cueAlignment == startKeyword())
- m_cueAlignment = Start;
-
- // 2. If value is a case-sensitive match for the string "middle", then let cue's text track cue alignment be middle alignment.
- else if (cueAlignment == middleKeyword())
- m_cueAlignment = Middle;
-
- // 3. If value is a case-sensitive match for the string "end", then let cue's text track cue alignment be end alignment.
- else if (cueAlignment == endKeyword())
- m_cueAlignment = End;
- }
- break;
-#if ENABLE(WEBVTT_REGIONS)
- case RegionId:
- m_regionId = WebVTTParser::collectWord(input, &position);
- break;
-#endif
- case None:
- break;
- }
-
-NextSetting:
- position = endOfSetting;
- }
-#if ENABLE(WEBVTT_REGIONS)
- // If cue's line position is not auto or cue's size is not 100 or cue's
- // writing direction is not horizontal, but cue's region identifier is not
- // the empty string, let cue's region identifier be the empty string.
- if (m_regionId.isEmpty())
- return;
-
- if (m_linePosition != undefinedPosition || m_cueSize != 100 || m_writingDirection != Horizontal)
- m_regionId = emptyString();
-#endif
-}
-
-CSSValueID TextTrackCue::getCSSWritingDirection() const
-{
- return m_displayDirection;
-}
-
-CSSValueID TextTrackCue::getCSSWritingMode() const
+bool TextTrackCue::isOrderedBefore(const TextTrackCue* other) const
{
- return m_displayWritingMode;
+ return startMediaTime() < other->startMediaTime() || (startMediaTime() == other->startMediaTime() && endMediaTime() > other->endMediaTime());
}
-int TextTrackCue::getCSSSize() const
+bool TextTrackCue::cueContentsMatch(const TextTrackCue& cue) const
{
- return m_displaySize;
-}
+ if (cueType() != cue.cueType())
+ return false;
-std::pair<double, double> TextTrackCue::getCSSPosition() const
-{
- if (!m_snapToLines)
- return getPositionCoordinates();
+ if (id() != cue.id())
+ return false;
- return m_displayPosition;
+ return true;
}
-bool TextTrackCue::isEqual(const TextTrackCue& cue, CueMatchRules match) const
+bool TextTrackCue::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
{
if (cueType() != cue.cueType())
return false;
-
- if (match != IgnoreDuration && m_endTime != cue.endTime())
- return false;
- if (m_startTime != cue.startTime())
- return false;
- if (m_content != cue.text())
- return false;
- if (m_settings != cue.cueSettings())
- return false;
- if (m_id != cue.id())
- return false;
- if (m_textPosition != cue.position())
- return false;
- if (m_linePosition != cue.line())
+
+ if (match != IgnoreDuration && endMediaTime() != cue.endMediaTime())
return false;
- if (m_cueSize != cue.size())
+ if (!hasEquivalentStartTime(cue))
return false;
- if (align() != cue.align())
+ if (!cueContentsMatch(cue))
return false;
-
+
return true;
}
-bool TextTrackCue::isOrderedBefore(const TextTrackCue* other) const
+bool TextTrackCue::hasEquivalentStartTime(const TextTrackCue& cue) const
{
- return startTime() < other->startTime() || (startTime() == other->startTime() && endTime() > other->endTime());
+ MediaTime startTimeVariance = MediaTime::zeroTime();
+ if (track())
+ startTimeVariance = track()->startTimeVariance();
+ else if (cue.track())
+ startTimeVariance = cue.track()->startTimeVariance();
+
+ return abs(abs(startMediaTime()) - abs(cue.startMediaTime())) <= startTimeVariance;
}
-void TextTrackCue::setFontSize(int fontSize, const IntSize&, bool important)
+bool TextTrackCue::doesExtendCue(const TextTrackCue& cue) const
{
- if (!hasDisplayTree() || !fontSize)
- return;
-
- LOG(Media, "TextTrackCue::setFontSize - setting cue font size to %i", fontSize);
+ if (!cueContentsMatch(cue))
+ return false;
- displayTreeInternal()->setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX, important);
+ if (endMediaTime() != cue.startMediaTime())
+ return false;
+
+ return true;
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/TextTrackCue.h b/Source/WebCore/html/track/TextTrackCue.h
index 5d3cf4e9c..4907546a2 100644
--- a/Source/WebCore/html/track/TextTrackCue.h
+++ b/Source/WebCore/html/track/TextTrackCue.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -29,62 +29,20 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrackCue_h
-#define TextTrackCue_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
-#include "EventTarget.h"
-#include "HTMLElement.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/RefCounted.h>
+#include "Document.h"
+#include <wtf/MediaTime.h>
namespace WebCore {
-class DocumentFragment;
-class HTMLSpanElement;
-class ScriptExecutionContext;
class TextTrack;
-class TextTrackCue;
-
-// ----------------------------
-
-class TextTrackCueBox : public HTMLElement {
-public:
- static PassRefPtr<TextTrackCueBox> create(Document& document, TextTrackCue* cue)
- {
- return adoptRef(new TextTrackCueBox(document, cue));
- }
-
- TextTrackCue* getCue() const;
- virtual void applyCSSProperties(const IntSize& videoSize);
-
- static const AtomicString& textTrackCueBoxShadowPseudoId();
-
-protected:
- TextTrackCueBox(Document&, TextTrackCue*);
-
- virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) override;
-
- TextTrackCue* m_cue;
-};
-
-// ----------------------------
class TextTrackCue : public RefCounted<TextTrackCue>, public EventTargetWithInlineData {
public:
- static PassRefPtr<TextTrackCue> create(ScriptExecutionContext& context, double start, double end, const String& content)
- {
- return adoptRef(new TextTrackCue(context, start, end, content));
- }
-
- static const AtomicString& cueShadowPseudoId()
- {
- DEFINE_STATIC_LOCAL(const AtomicString, cue, ("cue", AtomicString::ConstructFromLiteral));
- return cue;
- }
-
- virtual ~TextTrackCue();
+ static const AtomicString& cueShadowPseudoId();
TextTrack* track() const;
void setTrack(TextTrack*);
@@ -92,193 +50,73 @@ public:
const String& id() const { return m_id; }
void setId(const String&);
- double startTime() const { return m_startTime; }
- void setStartTime(double, ExceptionCode&);
+ double startTime() const { return startMediaTime().toDouble(); }
+ void setStartTime(double);
- double endTime() const { return m_endTime; }
- void setEndTime(double, ExceptionCode&);
+ double endTime() const { return endMediaTime().toDouble(); }
+ void setEndTime(double);
bool pauseOnExit() const { return m_pauseOnExit; }
void setPauseOnExit(bool);
- const String& vertical() const;
- void setVertical(const String&, ExceptionCode&);
+ MediaTime startMediaTime() const { return m_startTime; }
+ void setStartTime(const MediaTime&);
- bool snapToLines() const { return m_snapToLines; }
- void setSnapToLines(bool);
-
- int line() const { return m_linePosition; }
- virtual void setLine(int, ExceptionCode&);
-
- int position() const { return m_textPosition; }
- virtual void setPosition(int, ExceptionCode&);
-
- int size() const { return m_cueSize; }
- virtual void setSize(int, ExceptionCode&);
-
- const String& align() const;
- void setAlign(const String&, ExceptionCode&);
-
- const String& text() const { return m_content; }
- void setText(const String&);
-
- const String& cueSettings() const { return m_settings; }
- void setCueSettings(const String&);
-
- int cueIndex();
- void invalidateCueIndex();
-
- PassRefPtr<DocumentFragment> getCueAsHTML();
- PassRefPtr<DocumentFragment> createCueRenderingTree();
-
- using EventTarget::dispatchEvent;
- virtual bool dispatchEvent(PassRefPtr<Event>) override;
-
-#if ENABLE(WEBVTT_REGIONS)
- const String& regionId() const { return m_regionId; }
- void setRegionId(const String&);
-#endif
+ MediaTime endMediaTime() const { return m_endTime; }
+ void setEndTime(const MediaTime&);
bool isActive();
- void setIsActive(bool);
+ virtual void setIsActive(bool);
- bool hasDisplayTree() const { return m_displayTree; }
- TextTrackCueBox* getDisplayTree(const IntSize& videoSize);
- HTMLSpanElement* element() const { return m_cueBackgroundBox.get(); }
-
- void updateDisplayTree(double);
- void removeDisplayTree();
- void markFutureAndPastNodes(ContainerNode*, double, double);
-
- int calculateComputedLinePosition();
- std::pair<double, double> getPositionCoordinates() const;
-
- virtual EventTargetInterface eventTargetInterface() const override final { return TextTrackCueEventTargetInterfaceType; }
- virtual ScriptExecutionContext* scriptExecutionContext() const override final { return &m_scriptExecutionContext; }
-
- std::pair<double, double> getCSSPosition() const;
-
- int getCSSSize() const;
- CSSValueID getCSSWritingDirection() const;
- CSSValueID getCSSWritingMode() const;
-
- enum WritingDirection {
- Horizontal,
- VerticalGrowingLeft,
- VerticalGrowingRight,
- NumberOfWritingDirections
- };
- WritingDirection getWritingDirection() const { return m_writingDirection; }
+ virtual bool isOrderedBefore(const TextTrackCue*) const;
+ virtual bool isPositionedAbove(const TextTrackCue* cue) const { return isOrderedBefore(cue); }
- enum CueAlignment {
- Start,
- Middle,
- End
- };
- CueAlignment getAlignment() const { return m_cueAlignment; }
+ bool hasEquivalentStartTime(const TextTrackCue&) const;
- virtual void setFontSize(int, const IntSize&, bool important);
+ enum CueType { Data, Generic, WebVTT };
+ virtual CueType cueType() const = 0;
+ virtual bool isRenderable() const { return false; }
- enum CueMatchRules {
- MatchAllFields,
- IgnoreDuration,
- };
+ enum CueMatchRules { MatchAllFields, IgnoreDuration };
virtual bool isEqual(const TextTrackCue&, CueMatchRules) const;
-
- virtual bool isOrderedBefore(const TextTrackCue*) const;
-
- enum CueType {
- Generic,
- WebVTT
- };
- virtual CueType cueType() const { return WebVTT; }
+ virtual bool doesExtendCue(const TextTrackCue&) const;
void willChange();
- void didChange();
-
- DEFINE_ATTRIBUTE_EVENT_LISTENER(enter);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(exit);
+ virtual void didChange();
- using RefCounted<TextTrackCue>::ref;
- using RefCounted<TextTrackCue>::deref;
+ using RefCounted::ref;
+ using RefCounted::deref;
protected:
- TextTrackCue(ScriptExecutionContext&, double start, double end, const String& content);
-
- Document& ownerDocument() { return toDocument(m_scriptExecutionContext); }
+ TextTrackCue(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end);
- virtual PassRefPtr<TextTrackCueBox> createDisplayTree();
- TextTrackCueBox* displayTreeInternal();
+ Document& ownerDocument() { return downcast<Document>(m_scriptExecutionContext); }
private:
- void createWebVTTNodeTree();
- void copyWebVTTNodeToDOMTree(ContainerNode* WebVTTNode, ContainerNode* root);
-
- void parseSettings(const String&);
-
- void determineTextDirection();
- void calculateDisplayParameters();
-
- virtual void refEventTarget() override final { ref(); }
- virtual void derefEventTarget() override final { deref(); }
-
- enum CueSetting {
- None,
- Vertical,
- Line,
- Position,
- Size,
- Align,
-#if ENABLE(WEBVTT_REGIONS)
- RegionId
-#endif
- };
- CueSetting settingName(const String&);
+ void refEventTarget() final { ref(); }
+ void derefEventTarget() final { deref(); }
- String m_id;
- double m_startTime;
- double m_endTime;
- String m_content;
- String m_settings;
- int m_linePosition;
- int m_computedLinePosition;
- int m_textPosition;
- int m_cueSize;
- int m_cueIndex;
- int m_processingCueChanges;
-
- WritingDirection m_writingDirection;
-
- CueAlignment m_cueAlignment;
-
- RefPtr<DocumentFragment> m_webVTTNodeTree;
- TextTrack* m_track;
-
- ScriptExecutionContext& m_scriptExecutionContext;
-
- bool m_isActive;
- bool m_pauseOnExit;
- bool m_snapToLines;
+ using EventTarget::dispatchEvent;
+ bool dispatchEvent(Event&) final;
- RefPtr<HTMLSpanElement> m_cueBackgroundBox;
+ EventTargetInterface eventTargetInterface() const final { return TextTrackCueEventTargetInterfaceType; }
+ ScriptExecutionContext* scriptExecutionContext() const final { return &m_scriptExecutionContext; }
- bool m_displayTreeShouldChange;
- RefPtr<TextTrackCueBox> m_displayTree;
+ virtual bool cueContentsMatch(const TextTrackCue&) const;
- CSSValueID m_displayDirection;
+ String m_id;
+ MediaTime m_startTime;
+ MediaTime m_endTime;
+ int m_processingCueChanges { 0 };
- CSSValueID m_displayWritingModeMap[NumberOfWritingDirections];
- CSSValueID m_displayWritingMode;
+ TextTrack* m_track { nullptr };
- int m_displaySize;
+ ScriptExecutionContext& m_scriptExecutionContext;
- std::pair<float, float> m_displayPosition;
-#if ENABLE(WEBVTT_REGIONS)
- String m_regionId;
-#endif
+ bool m_isActive : 1;
+ bool m_pauseOnExit : 1;
};
} // namespace WebCore
#endif
-#endif
diff --git a/Source/WebCore/html/track/TextTrackCue.idl b/Source/WebCore/html/track/TextTrackCue.idl
index e860b9765..44fe168aa 100644
--- a/Source/WebCore/html/track/TextTrackCue.idl
+++ b/Source/WebCore/html/track/TextTrackCue.idl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -25,45 +25,18 @@
[
Conditional=VIDEO_TRACK,
- JSGenerateToNativeObject,
- Constructor(double startTime, double endTime, DOMString text),
- ConstructorCallWith=ScriptExecutionContext,
- EventTarget,
- JSCustomMarkFunction,
CustomIsReachable,
+ CustomToJSObject,
+ JSCustomMarkFunction,
SkipVTableValidation,
-] interface TextTrackCue {
+] interface TextTrackCue : EventTarget {
readonly attribute TextTrack track;
attribute DOMString id;
- [SetterRaisesException] attribute double startTime;
- [SetterRaisesException] attribute double endTime;
+ attribute double startTime;
+ attribute double endTime;
attribute boolean pauseOnExit;
- [SetterRaisesException] attribute DOMString vertical;
- attribute boolean snapToLines;
- [SetterRaisesException] attribute long line;
- [SetterRaisesException] attribute long position;
- [SetterRaisesException] attribute long size;
- [SetterRaisesException] attribute DOMString align;
-
- attribute DOMString text;
- DocumentFragment getCueAsHTML();
-
- attribute EventListener onenter;
- attribute EventListener onexit;
-
- // EventTarget interface
- void addEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- void removeEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- [RaisesException] boolean dispatchEvent(Event evt);
-
-#if defined(ENABLE_WEBVTT_REGIONS) && ENABLE_WEBVTT_REGIONS
- attribute DOMString regionId;
-#endif
+ attribute EventHandler onenter;
+ attribute EventHandler onexit;
};
-
diff --git a/Source/WebCore/html/track/TextTrackCueGeneric.cpp b/Source/WebCore/html/track/TextTrackCueGeneric.cpp
index a3344dcbc..f63583924 100644
--- a/Source/WebCore/html/track/TextTrackCueGeneric.cpp
+++ b/Source/WebCore/html/track/TextTrackCueGeneric.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -30,32 +30,37 @@
#include "TextTrackCueGeneric.h"
#include "CSSPropertyNames.h"
+#include "CSSStyleDeclaration.h"
#include "CSSValueKeywords.h"
-#include "HTMLNames.h"
#include "HTMLSpanElement.h"
#include "InbandTextTrackPrivateClient.h"
#include "Logging.h"
#include "RenderObject.h"
#include "ScriptExecutionContext.h"
+#include "StyleProperties.h"
#include "TextTrackCue.h"
+#include <wtf/MathExtras.h>
namespace WebCore {
-class TextTrackCueGenericBoxElement final : public TextTrackCueBox {
+// This default value must be the same as the one specified in mediaControlsApple.css for -webkit-media-controls-closed-captions-container
+const static int DEFAULTCAPTIONFONTSIZE = 10;
+
+class TextTrackCueGenericBoxElement final : public VTTCueBox {
public:
- static PassRefPtr<TextTrackCueGenericBoxElement> create(Document& document, TextTrackCueGeneric* cue)
+ static Ref<TextTrackCueGenericBoxElement> create(Document& document, TextTrackCueGeneric& cue)
{
- return adoptRef(new TextTrackCueGenericBoxElement(document, cue));
+ return adoptRef(*new TextTrackCueGenericBoxElement(document, cue));
}
- virtual void applyCSSProperties(const IntSize&) override;
+ void applyCSSProperties(const IntSize&) override;
private:
- TextTrackCueGenericBoxElement(Document&, TextTrackCue*);
+ TextTrackCueGenericBoxElement(Document&, VTTCue&);
};
-TextTrackCueGenericBoxElement::TextTrackCueGenericBoxElement(Document& document, TextTrackCue* cue)
- : TextTrackCueBox(document, cue)
+TextTrackCueGenericBoxElement::TextTrackCueGenericBoxElement(Document& document, VTTCue& cue)
+ : VTTCueBox(document, cue)
{
}
@@ -65,8 +70,9 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext);
TextTrackCueGeneric* cue = static_cast<TextTrackCueGeneric*>(getCue());
- RefPtr<HTMLSpanElement> cueElement = cue->element();
+ Ref<HTMLSpanElement> cueElement = cue->element();
+ CSSValueID alignment = cue->getCSSAlignment();
float size = static_cast<float>(cue->getCSSSize());
if (cue->useDefaultPosition()) {
setInlineStyleProperty(CSSPropertyBottom, 0, CSSPrimitiveValue::CSS_PX);
@@ -75,10 +81,40 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
setInlineStyleProperty(CSSPropertyLeft, static_cast<float>(cue->position()), CSSPrimitiveValue::CSS_PERCENTAGE);
setInlineStyleProperty(CSSPropertyTop, static_cast<float>(cue->line()), CSSPrimitiveValue::CSS_PERCENTAGE);
- if (cue->getWritingDirection() == TextTrackCue::Horizontal)
- setInlineStyleProperty(CSSPropertyWidth, size, CSSPrimitiveValue::CSS_PERCENTAGE);
- else
- setInlineStyleProperty(CSSPropertyHeight, size, CSSPrimitiveValue::CSS_PERCENTAGE);
+ double authorFontSize = videoSize.height() * cue->baseFontSizeRelativeToVideoHeight() / 100.0;
+ if (!authorFontSize)
+ authorFontSize = DEFAULTCAPTIONFONTSIZE;
+
+ if (cue->fontSizeMultiplier())
+ authorFontSize *= cue->fontSizeMultiplier() / 100;
+
+ double multiplier = m_fontSizeFromCaptionUserPrefs / authorFontSize;
+ double newCueSize = std::min(size * multiplier, 100.0);
+ if (cue->getWritingDirection() == VTTCue::Horizontal) {
+ setInlineStyleProperty(CSSPropertyWidth, newCueSize, CSSPrimitiveValue::CSS_PERCENTAGE);
+ if ((alignment == CSSValueMiddle || alignment == CSSValueCenter) && multiplier != 1.0)
+ setInlineStyleProperty(CSSPropertyLeft, static_cast<double>(cue->position() - (newCueSize - m_cue.getCSSSize()) / 2), CSSPrimitiveValue::CSS_PERCENTAGE);
+ } else {
+ setInlineStyleProperty(CSSPropertyHeight, newCueSize, CSSPrimitiveValue::CSS_PERCENTAGE);
+ if ((alignment == CSSValueMiddle || alignment == CSSValueCenter) && multiplier != 1.0)
+ setInlineStyleProperty(CSSPropertyTop, static_cast<double>(cue->line() - (newCueSize - m_cue.getCSSSize()) / 2), CSSPrimitiveValue::CSS_PERCENTAGE);
+ }
+ }
+
+ double textPosition = m_cue.position();
+ double maxSize = 100.0;
+
+ if (alignment == CSSValueEnd || alignment == CSSValueRight)
+ maxSize = textPosition;
+ else if (alignment == CSSValueStart || alignment == CSSValueLeft)
+ maxSize = 100.0 - textPosition;
+
+ if (cue->getWritingDirection() == VTTCue::Horizontal) {
+ setInlineStyleProperty(CSSPropertyMinWidth, "-webkit-min-content");
+ setInlineStyleProperty(CSSPropertyMaxWidth, maxSize, CSSPrimitiveValue::CSS_PERCENTAGE);
+ } else {
+ setInlineStyleProperty(CSSPropertyMinHeight, "-webkit-min-content");
+ setInlineStyleProperty(CSSPropertyMaxHeight, maxSize, CSSPrimitiveValue::CSS_PERCENTAGE);
}
if (cue->foregroundColor().isValid())
@@ -86,7 +122,7 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
if (cue->highlightColor().isValid())
cueElement->setInlineStyleProperty(CSSPropertyBackgroundColor, cue->highlightColor().serialized());
- if (cue->getWritingDirection() == TextTrackCue::Horizontal)
+ if (cue->getWritingDirection() == VTTCue::Horizontal)
setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto);
else
setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto);
@@ -94,43 +130,49 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
if (cue->baseFontSizeRelativeToVideoHeight())
cue->setFontSize(cue->baseFontSizeRelativeToVideoHeight(), videoSize, false);
- if (cue->getAlignment() == TextTrackCue::Middle)
+ if (cue->getAlignment() == VTTCue::Middle)
setInlineStyleProperty(CSSPropertyTextAlign, CSSValueCenter);
- else if (cue->getAlignment() == TextTrackCue::End)
+ else if (cue->getAlignment() == VTTCue::End)
setInlineStyleProperty(CSSPropertyTextAlign, CSSValueEnd);
else
setInlineStyleProperty(CSSPropertyTextAlign, CSSValueStart);
if (cue->backgroundColor().isValid())
setInlineStyleProperty(CSSPropertyBackgroundColor, cue->backgroundColor().serialized());
- setInlineStyleProperty(CSSPropertyWebkitWritingMode, cue->getCSSWritingMode(), false);
+ setInlineStyleProperty(CSSPropertyWritingMode, cue->getCSSWritingMode(), false);
setInlineStyleProperty(CSSPropertyWhiteSpace, CSSValuePreWrap);
- setInlineStyleProperty(CSSPropertyWordBreak, CSSValueNormal);
+
+ // Make sure shadow or stroke is not clipped.
+ setInlineStyleProperty(CSSPropertyOverflow, CSSValueVisible);
+ cueElement->setInlineStyleProperty(CSSPropertyOverflow, CSSValueVisible);
}
-TextTrackCueGeneric::TextTrackCueGeneric(ScriptExecutionContext& context, double start, double end, const String& content)
- : TextTrackCue(context, start, end, content)
+TextTrackCueGeneric::TextTrackCueGeneric(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const String& content)
+ : VTTCue(context, start, end, content)
, m_baseFontSizeRelativeToVideoHeight(0)
, m_fontSizeMultiplier(0)
- , m_defaultPosition(true)
{
}
-PassRefPtr<TextTrackCueBox> TextTrackCueGeneric::createDisplayTree()
+Ref<VTTCueBox> TextTrackCueGeneric::createDisplayTree()
{
- return TextTrackCueGenericBoxElement::create(ownerDocument(), this);
+ return TextTrackCueGenericBoxElement::create(ownerDocument(), *this);
}
-void TextTrackCueGeneric::setLine(int line, ExceptionCode& ec)
+ExceptionOr<void> TextTrackCueGeneric::setLine(double line)
{
- m_defaultPosition = false;
- TextTrackCue::setLine(line, ec);
+ auto result = VTTCue::setLine(line);
+ if (!result.hasException())
+ m_useDefaultPosition = false;
+ return result;
}
-void TextTrackCueGeneric::setPosition(int position, ExceptionCode& ec)
+ExceptionOr<void> TextTrackCueGeneric::setPosition(double position)
{
- m_defaultPosition = false;
- TextTrackCue::setPosition(position, ec);
+ auto result = VTTCue::setPosition(position);
+ if (!result.hasException())
+ m_useDefaultPosition = false;
+ return result;
}
void TextTrackCueGeneric::setFontSize(int fontSize, const IntSize& videoSize, bool important)
@@ -139,23 +181,25 @@ void TextTrackCueGeneric::setFontSize(int fontSize, const IntSize& videoSize, bo
return;
if (important || !baseFontSizeRelativeToVideoHeight()) {
- TextTrackCue::setFontSize(fontSize, videoSize, important);
+ VTTCue::setFontSize(fontSize, videoSize, important);
return;
}
double size = videoSize.height() * baseFontSizeRelativeToVideoHeight() / 100;
if (fontSizeMultiplier())
size *= fontSizeMultiplier() / 100;
- displayTreeInternal()->setInlineStyleProperty(CSSPropertyFontSize, lround(size), CSSPrimitiveValue::CSS_PX);
+ displayTreeInternal().setInlineStyleProperty(CSSPropertyFontSize, lround(size), CSSPrimitiveValue::CSS_PX);
LOG(Media, "TextTrackCueGeneric::setFontSize - setting cue font size to %li", lround(size));
}
-
-bool TextTrackCueGeneric::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
+
+bool TextTrackCueGeneric::cueContentsMatch(const TextTrackCue& cue) const
{
- if (cue.cueType() != TextTrackCue::Generic)
+ // Do call the parent class cueContentsMatch here, because we want to confirm
+ // the content of the two cues are identical (even though the types are not the same).
+ if (!VTTCue::cueContentsMatch(cue))
return false;
-
+
const TextTrackCueGeneric* other = static_cast<const TextTrackCueGeneric*>(&cue);
if (m_baseFontSizeRelativeToVideoHeight != other->baseFontSizeRelativeToVideoHeight())
@@ -169,23 +213,60 @@ bool TextTrackCueGeneric::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatc
if (m_backgroundColor != other->backgroundColor())
return false;
- return TextTrackCue::isEqual(cue, match);
+ return true;
+}
+
+bool TextTrackCueGeneric::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
+{
+ // Do not call the parent class isEqual here, because we are not cueType() == VTTCue,
+ // and will fail that equality test.
+ if (!TextTrackCue::isEqual(cue, match))
+ return false;
+
+ if (cue.cueType() != TextTrackCue::Generic)
+ return false;
+
+ return cueContentsMatch(cue);
+}
+
+
+bool TextTrackCueGeneric::doesExtendCue(const TextTrackCue& cue) const
+{
+ if (!cueContentsMatch(cue))
+ return false;
+
+ return VTTCue::doesExtendCue(cue);
}
bool TextTrackCueGeneric::isOrderedBefore(const TextTrackCue* that) const
{
- if (TextTrackCue::isOrderedBefore(that))
+ if (VTTCue::isOrderedBefore(that))
return true;
if (that->cueType() == Generic && startTime() == that->startTime() && endTime() == that->endTime()) {
// Further order generic cues by their calculated line value.
std::pair<double, double> thisPosition = getPositionCoordinates();
- std::pair<double, double> thatPosition = that->getPositionCoordinates();
+ std::pair<double, double> thatPosition = toVTTCue(that)->getPositionCoordinates();
return thisPosition.second > thatPosition.second || (thisPosition.second == thatPosition.second && thisPosition.first < thatPosition.first);
}
return false;
}
+
+bool TextTrackCueGeneric::isPositionedAbove(const TextTrackCue* that) const
+{
+ if (that->cueType() == Generic && startTime() == that->startTime() && endTime() == that->endTime()) {
+ // Further order generic cues by their calculated line value.
+ std::pair<double, double> thisPosition = getPositionCoordinates();
+ std::pair<double, double> thatPosition = toVTTCue(that)->getPositionCoordinates();
+ return thisPosition.second > thatPosition.second || (thisPosition.second == thatPosition.second && thisPosition.first < thatPosition.first);
+ }
+
+ if (that->cueType() == Generic)
+ return startTime() > that->startTime();
+
+ return VTTCue::isOrderedBefore(that);
+}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/TextTrackCueGeneric.h b/Source/WebCore/html/track/TextTrackCueGeneric.h
index 37d908013..6c281eb2c 100644
--- a/Source/WebCore/html/track/TextTrackCueGeneric.h
+++ b/Source/WebCore/html/track/TextTrackCueGeneric.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,74 +23,73 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrackCueGeneric_h
-#define TextTrackCueGeneric_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "Color.h"
-#include "TextTrackCue.h"
+#include "VTTCue.h"
namespace WebCore {
class GenericCueData;
// A "generic" cue is a non-WebVTT cue, so it is not positioned/sized with the WebVTT logic.
-class TextTrackCueGeneric final : public TextTrackCue {
+class TextTrackCueGeneric final : public VTTCue {
public:
- static PassRefPtr<TextTrackCueGeneric> create(ScriptExecutionContext& context, double start, double end, const String& content)
+ static Ref<TextTrackCueGeneric> create(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const String& content)
{
- return adoptRef(new TextTrackCueGeneric(context, start, end, content));
+ return adoptRef(*new TextTrackCueGeneric(context, start, end, content));
}
-
- virtual ~TextTrackCueGeneric() { }
- virtual PassRefPtr<TextTrackCueBox> createDisplayTree() override;
+ ExceptionOr<void> setLine(double) final;
+ ExceptionOr<void> setPosition(double) final;
- virtual void setLine(int, ExceptionCode&) override;
- virtual void setPosition(int, ExceptionCode&) override;
+ bool useDefaultPosition() const { return m_useDefaultPosition; }
- bool useDefaultPosition() const { return m_defaultPosition; }
-
double baseFontSizeRelativeToVideoHeight() const { return m_baseFontSizeRelativeToVideoHeight; }
void setBaseFontSizeRelativeToVideoHeight(double size) { m_baseFontSizeRelativeToVideoHeight = size; }
double fontSizeMultiplier() const { return m_fontSizeMultiplier; }
void setFontSizeMultiplier(double size) { m_fontSizeMultiplier = size; }
- String fontName() const { return m_fontName; }
- void setFontName(String name) { m_fontName = name; }
+ const String& fontName() const { return m_fontName; }
+ void setFontName(const String& name) { m_fontName = name; }
- Color foregroundColor() const { return m_foregroundColor; }
- void setForegroundColor(RGBA32 color) { m_foregroundColor.setRGB(color); }
+ const Color& foregroundColor() const { return m_foregroundColor; }
+ void setForegroundColor(const Color& color) { m_foregroundColor = color; }
- Color backgroundColor() const { return m_backgroundColor; }
- void setBackgroundColor(RGBA32 color) { m_backgroundColor.setRGB(color); }
+ const Color& backgroundColor() const { return m_backgroundColor; }
+ void setBackgroundColor(const Color& color) { m_backgroundColor = color; }
- Color highlightColor() const { return m_highlightColor; }
- void setHighlightColor(RGBA32 color) { m_highlightColor.setRGB(color); }
+ const Color& highlightColor() const { return m_highlightColor; }
+ void setHighlightColor(const Color& color) { m_highlightColor = color; }
+
+ void setFontSize(int, const IntSize&, bool important) final;
+
+private:
+ TextTrackCueGeneric(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end, const String&);
- virtual void setFontSize(int, const IntSize&, bool important) override;
+ bool isOrderedBefore(const TextTrackCue*) const final;
+ bool isPositionedAbove(const TextTrackCue*) const final;
- virtual bool isEqual(const TextTrackCue&, CueMatchRules) const override;
+ Ref<VTTCueBox> createDisplayTree() final;
- virtual TextTrackCue::CueType cueType() const override { return TextTrackCue::Generic; }
+ bool isEqual(const TextTrackCue&, CueMatchRules) const final;
+ bool cueContentsMatch(const TextTrackCue&) const final;
+ bool doesExtendCue(const TextTrackCue&) const final;
-private:
- virtual bool isOrderedBefore(const TextTrackCue*) const override;
+ CueType cueType() const final { return Generic; }
- TextTrackCueGeneric(ScriptExecutionContext&, double start, double end, const String&);
-
Color m_foregroundColor;
Color m_backgroundColor;
Color m_highlightColor;
- double m_baseFontSizeRelativeToVideoHeight;
- double m_fontSizeMultiplier;
+ double m_baseFontSizeRelativeToVideoHeight { 0 };
+ double m_fontSizeMultiplier { 0 };
String m_fontName;
- bool m_defaultPosition;
+ bool m_useDefaultPosition { true };
};
} // namespace WebCore
#endif
-#endif
diff --git a/Source/WebCore/html/track/TextTrackCueList.cpp b/Source/WebCore/html/track/TextTrackCueList.cpp
index f5451f5f0..03827c8a7 100644
--- a/Source/WebCore/html/track/TextTrackCueList.cpp
+++ b/Source/WebCore/html/track/TextTrackCueList.cpp
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -29,118 +30,100 @@
#include "TextTrackCueList.h"
-namespace WebCore {
+// Checking sorting is too slow for general use; turn it on explicitly when working on this class.
+#undef CHECK_SORTING
-TextTrackCueList::TextTrackCueList()
-{
-}
+#ifdef CHECK_SORTING
+#define ASSERT_SORTED(begin, end) ASSERT(std::is_sorted(begin, end, compareCues))
+#else
+#define ASSERT_SORTED(begin, end) ((void)0)
+#endif
+
+namespace WebCore {
-unsigned long TextTrackCueList::length() const
+static inline bool compareCues(const RefPtr<TextTrackCue>& a, const RefPtr<TextTrackCue>& b)
{
- return m_list.size();
+ return a->isOrderedBefore(b.get());
}
-unsigned long TextTrackCueList::getCueIndex(TextTrackCue* cue) const
+unsigned TextTrackCueList::cueIndex(TextTrackCue& cue) const
{
- return m_list.find(cue);
+ ASSERT(m_vector.contains(&cue));
+ return m_vector.find(&cue);
}
TextTrackCue* TextTrackCueList::item(unsigned index) const
{
- if (index < m_list.size())
- return m_list[index].get();
- return 0;
+ if (index >= m_vector.size())
+ return nullptr;
+ return m_vector[index].get();
}
TextTrackCue* TextTrackCueList::getCueById(const String& id) const
{
- for (size_t i = 0; i < m_list.size(); ++i) {
- if (m_list[i]->id() == id)
- return m_list[i].get();
+ for (auto& cue : m_vector) {
+ if (cue->id() == id)
+ return cue.get();
}
- return 0;
+ return nullptr;
}
-TextTrackCueList* TextTrackCueList::activeCues()
+TextTrackCueList& TextTrackCueList::activeCues()
{
if (!m_activeCues)
m_activeCues = create();
- m_activeCues->clear();
- for (size_t i = 0; i < m_list.size(); ++i) {
- RefPtr<TextTrackCue> cue = m_list[i];
+ Vector<RefPtr<TextTrackCue>> activeCuesVector;
+ for (auto& cue : m_vector) {
if (cue->isActive())
- m_activeCues->add(cue);
- }
- return m_activeCues.get();
-}
-
-bool TextTrackCueList::add(PassRefPtr<TextTrackCue> cue)
-{
- ASSERT(cue->startTime() >= 0);
- ASSERT(cue->endTime() >= 0);
-
- return add(cue, 0, m_list.size());
-}
-
-bool TextTrackCueList::add(PassRefPtr<TextTrackCue> prpCue, size_t start, size_t end)
-{
- ASSERT_WITH_SECURITY_IMPLICATION(start <= m_list.size());
- ASSERT_WITH_SECURITY_IMPLICATION(end <= m_list.size());
-
- // Maintain text track cue order:
- // http://www.whatwg.org/specs/web-apps/current-work/#text-track-cue-order
- RefPtr<TextTrackCue> cue = prpCue;
- if (start == end) {
- if (!m_list.isEmpty() && (start > 0) && (m_list[start - 1].get() == cue.get()))
- return false;
-
- m_list.insert(start, cue);
- invalidateCueIndexes(start);
- return true;
+ activeCuesVector.append(cue);
}
+ ASSERT_SORTED(activeCuesVector.begin(), activeCuesVector.end());
+ m_activeCues->m_vector = WTFMove(activeCuesVector);
- size_t index = (start + end) / 2;
- if (cue->isOrderedBefore(m_list[index].get()))
- return add(cue.release(), start, index);
-
- return add(cue.release(), index + 1, end);
+ // FIXME: This list of active cues is not updated as cues are added, removed, become active, and become inactive.
+ // Instead it is only updated each time this function is called again. That is not consistent with other dynamic DOM lists.
+ return *m_activeCues;
}
-bool TextTrackCueList::remove(TextTrackCue* cue)
+void TextTrackCueList::add(Ref<TextTrackCue>&& cue)
{
- size_t index = m_list.find(cue);
- if (index == notFound)
- return false;
-
- cue->setIsActive(false);
- m_list.remove(index);
- return true;
+ ASSERT(!m_vector.contains(cue.ptr()));
+ ASSERT(cue->startMediaTime() >= MediaTime::zeroTime());
+ ASSERT(cue->endMediaTime() >= MediaTime::zeroTime());
+
+ RefPtr<TextTrackCue> cueRefPtr { WTFMove(cue) };
+ unsigned insertionPosition = std::upper_bound(m_vector.begin(), m_vector.end(), cueRefPtr, compareCues) - m_vector.begin();
+ ASSERT_SORTED(m_vector.begin(), m_vector.end());
+ m_vector.insert(insertionPosition, WTFMove(cueRefPtr));
+ ASSERT_SORTED(m_vector.begin(), m_vector.end());
}
-bool TextTrackCueList::contains(TextTrackCue* cue) const
+void TextTrackCueList::remove(TextTrackCue& cue)
{
- return m_list.contains(cue);
+ ASSERT_SORTED(m_vector.begin(), m_vector.end());
+ m_vector.remove(cueIndex(cue));
+ ASSERT_SORTED(m_vector.begin(), m_vector.end());
}
-bool TextTrackCueList::updateCueIndex(TextTrackCue* cue)
+void TextTrackCueList::updateCueIndex(TextTrackCue& cue)
{
- if (!contains(cue))
- return false;
-
- remove(cue);
- return add(cue);
-}
-
-void TextTrackCueList::clear()
-{
- m_list.clear();
-}
+ auto cuePosition = m_vector.begin() + cueIndex(cue);
+ auto afterCuePosition = cuePosition + 1;
+
+ ASSERT_SORTED(m_vector.begin(), cuePosition);
+ ASSERT_SORTED(afterCuePosition, m_vector.end());
+
+ auto reinsertionPosition = std::upper_bound(m_vector.begin(), cuePosition, *cuePosition, compareCues);
+ if (reinsertionPosition != cuePosition)
+ std::rotate(reinsertionPosition, cuePosition, afterCuePosition);
+ else {
+ reinsertionPosition = std::upper_bound(afterCuePosition, m_vector.end(), *cuePosition, compareCues);
+ if (reinsertionPosition != afterCuePosition)
+ std::rotate(cuePosition, afterCuePosition, reinsertionPosition);
+ }
-void TextTrackCueList::invalidateCueIndexes(size_t start)
-{
- for (size_t i = start; i < m_list.size(); ++i)
- m_list[i]->invalidateCueIndex();
+ ASSERT_SORTED(m_vector.begin(), m_vector.end());
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/TextTrackCueList.h b/Source/WebCore/html/track/TextTrackCueList.h
index 8478fa31f..fe04c446d 100644
--- a/Source/WebCore/html/track/TextTrackCueList.h
+++ b/Source/WebCore/html/track/TextTrackCueList.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,52 +24,47 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrackCueList_h
-#define TextTrackCueList_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "TextTrackCue.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
namespace WebCore {
class TextTrackCueList : public RefCounted<TextTrackCueList> {
public:
- static PassRefPtr<TextTrackCueList> create()
- {
- return adoptRef(new TextTrackCueList);
- }
-
- ~TextTrackCueList() { }
-
- unsigned long length() const;
- unsigned long getCueIndex(TextTrackCue*) const;
+ static Ref<TextTrackCueList> create();
+ unsigned length() const;
TextTrackCue* item(unsigned index) const;
TextTrackCue* getCueById(const String&) const;
- TextTrackCueList* activeCues();
- bool add(PassRefPtr<TextTrackCue>);
- bool remove(TextTrackCue*);
- bool contains(TextTrackCue*) const;
-
- bool updateCueIndex(TextTrackCue*);
+ unsigned cueIndex(TextTrackCue&) const;
+
+ void add(Ref<TextTrackCue>&&);
+ void remove(TextTrackCue&);
+ void updateCueIndex(TextTrackCue&);
+
+ TextTrackCueList& activeCues();
private:
- TextTrackCueList();
- bool add(PassRefPtr<TextTrackCue>, size_t, size_t);
- void clear();
- void invalidateCueIndexes(size_t);
+ TextTrackCueList() = default;
- Vector<RefPtr<TextTrackCue>> m_list;
+ Vector<RefPtr<TextTrackCue>> m_vector;
RefPtr<TextTrackCueList> m_activeCues;
-
};
+inline Ref<TextTrackCueList> TextTrackCueList::create()
+{
+ return adoptRef(*new TextTrackCueList);
+}
+
+inline unsigned TextTrackCueList::length() const
+{
+ return m_vector.size();
+}
+
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/TextTrackCueList.idl b/Source/WebCore/html/track/TextTrackCueList.idl
index 3a083b91b..6aaafdb08 100644
--- a/Source/WebCore/html/track/TextTrackCueList.idl
+++ b/Source/WebCore/html/track/TextTrackCueList.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
diff --git a/Source/WebCore/html/track/TextTrackList.cpp b/Source/WebCore/html/track/TextTrackList.cpp
index 18d3f1bab..32f6bca0a 100644
--- a/Source/WebCore/html/track/TextTrackList.cpp
+++ b/Source/WebCore/html/track/TextTrackList.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -29,7 +29,6 @@
#include "TextTrackList.h"
-#include "EventNames.h"
#include "HTMLMediaElement.h"
#include "InbandTextTrack.h"
#include "InbandTextTrackPrivate.h"
@@ -44,6 +43,20 @@ TextTrackList::TextTrackList(HTMLMediaElement* element, ScriptExecutionContext*
TextTrackList::~TextTrackList()
{
+ clearElement();
+}
+
+void TextTrackList::clearElement()
+{
+ TrackListBase::clearElement();
+ for (auto& track : m_elementTracks) {
+ track->setMediaElement(nullptr);
+ track->clearClient();
+ }
+ for (auto& track : m_addTrackTracks) {
+ track->setMediaElement(nullptr);
+ track->clearClient();
+ }
}
unsigned TextTrackList::length() const
@@ -51,56 +64,51 @@ unsigned TextTrackList::length() const
return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
}
-int TextTrackList::getTrackIndex(TextTrack *textTrack)
+int TextTrackList::getTrackIndex(TextTrack& textTrack)
{
- if (textTrack->trackType() == TextTrack::TrackElement)
- return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
+ if (is<LoadableTextTrack>(textTrack))
+ return downcast<LoadableTextTrack>(textTrack).trackElementIndex();
- if (textTrack->trackType() == TextTrack::AddTrack)
- return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
+ if (textTrack.trackType() == TextTrack::AddTrack)
+ return m_elementTracks.size() + m_addTrackTracks.find(&textTrack);
- if (textTrack->trackType() == TextTrack::InBand)
- return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
+ if (textTrack.trackType() == TextTrack::InBand)
+ return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(&textTrack);
ASSERT_NOT_REACHED();
return -1;
}
-int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
+int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack& textTrack)
{
// Calculate the "Let n be the number of text tracks whose text track mode is showing and that are in the media element's list of text tracks before track."
int trackIndex = 0;
- for (size_t i = 0; i < m_elementTracks.size(); ++i) {
- if (!toTextTrack(m_elementTracks[i].get())->isRendered())
+ for (auto& elementTrack : m_elementTracks) {
+ if (!downcast<TextTrack>(*elementTrack).isRendered())
continue;
-
- if (m_elementTracks[i] == textTrack)
+ if (elementTrack == &textTrack)
return trackIndex;
++trackIndex;
}
- for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
- if (!toTextTrack(m_addTrackTracks[i].get())->isRendered())
+ for (auto& addTrack : m_addTrackTracks) {
+ if (!downcast<TextTrack>(*addTrack).isRendered())
continue;
-
- if (m_addTrackTracks[i] == textTrack)
+ if (addTrack == &textTrack)
return trackIndex;
++trackIndex;
}
- for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
- if (!toTextTrack(m_inbandTracks[i].get())->isRendered())
+ for (auto& inbandTrack : m_inbandTracks) {
+ if (!downcast<TextTrack>(*inbandTrack).isRendered())
continue;
-
- if (m_inbandTracks[i] == textTrack)
+ if (inbandTrack == &textTrack)
return trackIndex;
++trackIndex;
}
-
ASSERT_NOT_REACHED();
-
return -1;
}
@@ -114,17 +122,17 @@ TextTrack* TextTrackList::item(unsigned index) const
// resource), in the order defined by the media resource's format specification.
if (index < m_elementTracks.size())
- return toTextTrack(m_elementTracks[index].get());
+ return downcast<TextTrack>(m_elementTracks[index].get());
index -= m_elementTracks.size();
if (index < m_addTrackTracks.size())
- return toTextTrack(m_addTrackTracks[index].get());
+ return downcast<TextTrack>(m_addTrackTracks[index].get());
index -= m_addTrackTracks.size();
if (index < m_inbandTracks.size())
- return toTextTrack(m_inbandTracks[index].get());
+ return downcast<TextTrack>(m_inbandTracks[index].get());
- return 0;
+ return nullptr;
}
TextTrack* TextTrackList::getTrackById(const AtomicString& id)
@@ -134,108 +142,122 @@ TextTrack* TextTrackList::getTrackById(const AtomicString& id)
// TextTrackList object whose id IDL attribute would return a value equal
// to the value of the id argument.
for (unsigned i = 0; i < length(); ++i) {
- TextTrack* track = item(i);
- if (track->id() == id)
- return track;
+ auto& track = *item(i);
+ if (track.id() == id)
+ return &track;
}
// When no tracks match the given argument, the method must return null.
return nullptr;
}
-void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
+void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack& track)
{
- Vector<RefPtr<TrackBase>>* tracks = 0;
+ Vector<RefPtr<TrackBase>>* tracks = nullptr;
- if (track->trackType() == TextTrack::TrackElement) {
+ switch (track.trackType()) {
+ case TextTrack::TrackElement:
tracks = &m_elementTracks;
- for (size_t i = 0; i < m_addTrackTracks.size(); ++i)
- toTextTrack(m_addTrackTracks[i].get())->invalidateTrackIndex();
- for (size_t i = 0; i < m_inbandTracks.size(); ++i)
- toTextTrack(m_inbandTracks[i].get())->invalidateTrackIndex();
- } else if (track->trackType() == TextTrack::AddTrack) {
+ for (auto& addTrack : m_addTrackTracks)
+ downcast<TextTrack>(addTrack.get())->invalidateTrackIndex();
+ for (auto& inbandTrack : m_inbandTracks)
+ downcast<TextTrack>(inbandTrack.get())->invalidateTrackIndex();
+ break;
+ case TextTrack::AddTrack:
tracks = &m_addTrackTracks;
- for (size_t i = 0; i < m_inbandTracks.size(); ++i)
- toTextTrack(m_inbandTracks[i].get())->invalidateTrackIndex();
- } else if (track->trackType() == TextTrack::InBand)
+ for (auto& inbandTrack : m_inbandTracks)
+ downcast<TextTrack>(inbandTrack.get())->invalidateTrackIndex();
+ break;
+ case TextTrack::InBand:
tracks = &m_inbandTracks;
- else
+ break;
+ default:
ASSERT_NOT_REACHED();
+ }
- size_t index = tracks->find(track);
+ size_t index = tracks->find(&track);
if (index == notFound)
return;
for (size_t i = index; i < tracks->size(); ++i)
- toTextTrack(tracks->at(index).get())->invalidateTrackIndex();
+ downcast<TextTrack>(*tracks->at(index)).invalidateTrackIndex();
}
-void TextTrackList::append(PassRefPtr<TextTrack> prpTrack)
+void TextTrackList::append(Ref<TextTrack>&& track)
{
- RefPtr<TextTrack> track = prpTrack;
-
if (track->trackType() == TextTrack::AddTrack)
- m_addTrackTracks.append(track);
- else if (track->trackType() == TextTrack::TrackElement) {
+ m_addTrackTracks.append(track.ptr());
+ else if (is<LoadableTextTrack>(track.get())) {
// Insert tracks added for <track> element in tree order.
- size_t index = static_cast<LoadableTextTrack*>(track.get())->trackElementIndex();
- m_elementTracks.insert(index, track);
+ size_t index = downcast<LoadableTextTrack>(track.get()).trackElementIndex();
+ m_elementTracks.insert(index, track.ptr());
} else if (track->trackType() == TextTrack::InBand) {
// Insert tracks added for in-band in the media file order.
- size_t index = static_cast<InbandTextTrack*>(track.get())->inbandTrackIndex();
- m_inbandTracks.insert(index, track);
+ size_t index = downcast<InbandTextTrack>(track.get()).inbandTrackIndex();
+ m_inbandTracks.insert(index, track.ptr());
} else
ASSERT_NOT_REACHED();
- invalidateTrackIndexesAfterTrack(track.get());
+ invalidateTrackIndexesAfterTrack(track);
ASSERT(!track->mediaElement() || track->mediaElement() == mediaElement());
track->setMediaElement(mediaElement());
- scheduleAddTrackEvent(track.release());
+ scheduleAddTrackEvent(WTFMove(track));
}
-void TextTrackList::remove(TrackBase* track)
+void TextTrackList::remove(TrackBase& track, bool scheduleEvent)
{
- TextTrack* textTrack = toTextTrack(track);
- Vector<RefPtr<TrackBase>>* tracks = 0;
- if (textTrack->trackType() == TextTrack::TrackElement)
+ auto& textTrack = downcast<TextTrack>(track);
+ Vector<RefPtr<TrackBase>>* tracks = nullptr;
+ switch (textTrack.trackType()) {
+ case TextTrack::TrackElement:
tracks = &m_elementTracks;
- else if (textTrack->trackType() == TextTrack::AddTrack)
+ break;
+ case TextTrack::AddTrack:
tracks = &m_addTrackTracks;
- else if (textTrack->trackType() == TextTrack::InBand)
+ break;
+ case TextTrack::InBand:
tracks = &m_inbandTracks;
- else
+ break;
+ default:
ASSERT_NOT_REACHED();
+ }
- size_t index = tracks->find(track);
+ size_t index = tracks->find(&track);
if (index == notFound)
return;
invalidateTrackIndexesAfterTrack(textTrack);
- ASSERT(!track->mediaElement() || track->mediaElement() == element());
- track->setMediaElement(0);
+ ASSERT(!track.mediaElement() || !element() || track.mediaElement() == element());
+ track.setMediaElement(nullptr);
- RefPtr<TrackBase> trackRef = (*tracks)[index];
+ Ref<TrackBase> trackRef = *(*tracks)[index];
tracks->remove(index);
- scheduleRemoveTrackEvent(trackRef.release());
+
+ if (scheduleEvent)
+ scheduleRemoveTrackEvent(WTFMove(trackRef));
}
-bool TextTrackList::contains(TrackBase* track) const
+bool TextTrackList::contains(TrackBase& track) const
{
- const Vector<RefPtr<TrackBase>>* tracks = 0;
- TextTrack::TextTrackType type = toTextTrack(track)->trackType();
- if (type == TextTrack::TrackElement)
+ const Vector<RefPtr<TrackBase>>* tracks = nullptr;
+ switch (downcast<TextTrack>(track).trackType()) {
+ case TextTrack::TrackElement:
tracks = &m_elementTracks;
- else if (type == TextTrack::AddTrack)
+ break;
+ case TextTrack::AddTrack:
tracks = &m_addTrackTracks;
- else if (type == TextTrack::InBand)
+ break;
+ case TextTrack::InBand:
tracks = &m_inbandTracks;
- else
+ break;
+ default:
ASSERT_NOT_REACHED();
+ }
- return tracks->find(track) != notFound;
+ return tracks->find(&track) != notFound;
}
EventTargetInterface TextTrackList::eventTargetInterface() const
diff --git a/Source/WebCore/html/track/TextTrackList.h b/Source/WebCore/html/track/TextTrackList.h
index 57c8b8288..c42f1e194 100644
--- a/Source/WebCore/html/track/TextTrackList.h
+++ b/Source/WebCore/html/track/TextTrackList.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrackList_h
-#define TextTrackList_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
@@ -34,33 +33,35 @@ namespace WebCore {
class TextTrack;
-class TextTrackList : public TrackListBase {
+class TextTrackList final : public TrackListBase {
public:
- static PassRefPtr<TextTrackList> create(HTMLMediaElement* element, ScriptExecutionContext* context)
+ static Ref<TextTrackList> create(HTMLMediaElement* element, ScriptExecutionContext* context)
{
- return adoptRef(new TextTrackList(element, context));
+ return adoptRef(*new TextTrackList(element, context));
}
virtual ~TextTrackList();
- virtual unsigned length() const override;
- int getTrackIndex(TextTrack*);
- int getTrackIndexRelativeToRenderedTracks(TextTrack*);
- virtual bool contains(TrackBase*) const override;
+ void clearElement() override;
+
+ unsigned length() const override;
+ int getTrackIndex(TextTrack&);
+ int getTrackIndexRelativeToRenderedTracks(TextTrack&);
+ bool contains(TrackBase&) const override;
TextTrack* item(unsigned index) const;
TextTrack* getTrackById(const AtomicString&);
TextTrack* lastItem() const { return item(length() - 1); }
- void append(PassRefPtr<TextTrack>);
- virtual void remove(TrackBase*) override;
+ void append(Ref<TextTrack>&&);
+ void remove(TrackBase&, bool scheduleEvent = true) override;
// EventTarget
- virtual EventTargetInterface eventTargetInterface() const override;
+ EventTargetInterface eventTargetInterface() const override;
private:
TextTrackList(HTMLMediaElement*, ScriptExecutionContext*);
- void invalidateTrackIndexesAfterTrack(TextTrack*);
+ void invalidateTrackIndexesAfterTrack(TextTrack&);
Vector<RefPtr<TrackBase>> m_addTrackTracks;
Vector<RefPtr<TrackBase>> m_elementTracks;
@@ -68,5 +69,4 @@ private:
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/TextTrackList.idl b/Source/WebCore/html/track/TextTrackList.idl
index 10e514fe5..fedd73b55 100644
--- a/Source/WebCore/html/track/TextTrackList.idl
+++ b/Source/WebCore/html/track/TextTrackList.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -26,23 +26,14 @@
[
Conditional=VIDEO_TRACK,
GenerateIsReachable=ImplElementRoot,
- EventTarget,
JSCustomMarkFunction,
-] interface TextTrackList {
+] interface TextTrackList : EventTarget {
readonly attribute unsigned long length;
getter TextTrack item(unsigned long index);
TextTrack getTrackById(DOMString id);
- attribute EventListener onaddtrack;
- attribute EventListener onchange;
- attribute EventListener onremovetrack;
-
- void addEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- void removeEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- [RaisesException] boolean dispatchEvent(Event evt);
+ attribute EventHandler onaddtrack;
+ attribute EventHandler onchange;
+ attribute EventHandler onremovetrack;
};
diff --git a/Source/WebCore/html/track/TrackBase.cpp b/Source/WebCore/html/track/TrackBase.cpp
index e93e9e908..bc95111e1 100644
--- a/Source/WebCore/html/track/TrackBase.cpp
+++ b/Source/WebCore/html/track/TrackBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -26,20 +26,23 @@
#include "config.h"
#include "TrackBase.h"
-#include "HTMLMediaElement.h"
+#include "Language.h"
+#include <wtf/text/StringBuilder.h>
#if ENABLE(VIDEO_TRACK)
+#include "HTMLMediaElement.h"
+
namespace WebCore {
+static int s_uniqueId = 0;
+
TrackBase::TrackBase(Type type, const AtomicString& id, const AtomicString& label, const AtomicString& language)
- : m_mediaElement(0)
-#if ENABLE(MEDIA_SOURCE)
- , m_sourceBuffer(0)
-#endif
+ : m_uniqueId(++s_uniqueId)
, m_id(id)
, m_label(label)
, m_language(language)
+ , m_validBCP47Language(language)
{
ASSERT(type != BaseTrack);
m_type = type;
@@ -54,19 +57,99 @@ Element* TrackBase::element()
return m_mediaElement;
}
-void TrackBase::setKind(const AtomicString& kind)
+// See: https://tools.ietf.org/html/bcp47#section-2.1
+static bool isValidBCP47LanguageTag(const String& languageTag)
{
- setKindInternal(kind);
+ auto const length = languageTag.length();
+
+ // Max length picked as double the longest example tag in spec which is 49 characters:
+ // https://tools.ietf.org/html/bcp47#section-4.4.2
+ if (length < 2 || length > 100)
+ return false;
+
+ UChar firstChar = languageTag[0];
+
+ if (!isASCIIAlpha(firstChar))
+ return false;
+
+ UChar secondChar = languageTag[1];
+
+ if (length == 2)
+ return isASCIIAlpha(secondChar);
+
+ bool grandFatheredIrregularOrPrivateUse = (firstChar == 'i' || firstChar == 'x') && secondChar == '-';
+ unsigned nextCharIndexToCheck;
+
+ if (!grandFatheredIrregularOrPrivateUse) {
+ if (!isASCIIAlpha(secondChar))
+ return false;
+
+ if (length == 3)
+ return isASCIIAlpha(languageTag[2]);
+
+ if (isASCIIAlpha(languageTag[2])) {
+ if (languageTag[3] == '-')
+ nextCharIndexToCheck = 4;
+ else
+ return false;
+ } else if (languageTag[2] == '-')
+ nextCharIndexToCheck = 3;
+ else
+ return false;
+ } else
+ nextCharIndexToCheck = 2;
+
+ for (; nextCharIndexToCheck < length; ++nextCharIndexToCheck) {
+ UChar c = languageTag[nextCharIndexToCheck];
+ if (isASCIIAlphanumeric(c) || c == '-')
+ continue;
+ return false;
+ }
+ return true;
+}
+
+void TrackBase::setLanguage(const AtomicString& language)
+{
+ if (!language.isEmpty() && !isValidBCP47LanguageTag(language)) {
+ String message;
+ if (language.contains((UChar)'\0'))
+ message = WTF::ASCIILiteral("The language contains a null character and is not a valid BCP 47 language tag.");
+ else {
+ StringBuilder stringBuilder;
+ stringBuilder.appendLiteral("The language '");
+ stringBuilder.append(language);
+ stringBuilder.appendLiteral("' is not a valid BCP 47 language tag.");
+ message = stringBuilder.toString();
+ }
+ if (auto element = this->element())
+ element->document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Warning, message);
+ } else
+ m_validBCP47Language = language;
+
+ m_language = language;
}
-void TrackBase::setKindInternal(const AtomicString& kind)
+AtomicString TrackBase::validBCP47Language() const
{
- String oldKind = m_kind;
+ return m_validBCP47Language;
+}
+MediaTrackBase::MediaTrackBase(Type type, const AtomicString& id, const AtomicString& label, const AtomicString& language)
+ : TrackBase(type, id, label, language)
+{
+}
+
+void MediaTrackBase::setKind(const AtomicString& kind)
+{
+ setKindInternal(kind);
+}
+
+void MediaTrackBase::setKindInternal(const AtomicString& kind)
+{
if (isValidKind(kind))
m_kind = kind;
else
- m_kind = defaultKindKeyword();
+ m_kind = emptyAtom;
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/TrackBase.h b/Source/WebCore/html/track/TrackBase.h
index 509f7a61f..16d162a13 100644
--- a/Source/WebCore/html/track/TrackBase.h
+++ b/Source/WebCore/html/track/TrackBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,13 +23,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TrackBase_h
-#define TrackBase_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
-#include "EventTarget.h"
-#include <wtf/RefCounted.h>
+#include <wtf/text/AtomicString.h>
namespace WebCore {
@@ -51,17 +49,17 @@ public:
virtual AtomicString id() const { return m_id; }
virtual void setId(const AtomicString& id) { m_id = id; }
- AtomicString kind() const { return m_kind; }
- virtual void setKind(const AtomicString&);
-
AtomicString label() const { return m_label; }
void setLabel(const AtomicString& label) { m_label = label; }
+ AtomicString validBCP47Language() const;
AtomicString language() const { return m_language; }
- virtual void setLanguage(const AtomicString& language) { m_language = language; }
+ virtual void setLanguage(const AtomicString&);
virtual void clearClient() = 0;
+ virtual int uniqueId() const { return m_uniqueId; }
+
#if ENABLE(MEDIA_SOURCE)
SourceBuffer* sourceBuffer() const { return m_sourceBuffer; }
void setSourceBuffer(SourceBuffer* buffer) { m_sourceBuffer = buffer; }
@@ -72,26 +70,37 @@ public:
protected:
TrackBase(Type, const AtomicString& id, const AtomicString& label, const AtomicString& language);
- virtual bool isValidKind(const AtomicString&) const = 0;
- virtual const AtomicString& defaultKindKeyword() const = 0;
-
- void setKindInternal(const AtomicString&);
-
- HTMLMediaElement* m_mediaElement;
+ HTMLMediaElement* m_mediaElement { nullptr };
#if ENABLE(MEDIA_SOURCE)
- SourceBuffer* m_sourceBuffer;
+ SourceBuffer* m_sourceBuffer { nullptr };
#endif
private:
Type m_type;
+ int m_uniqueId;
AtomicString m_id;
- AtomicString m_kind;
AtomicString m_label;
AtomicString m_language;
+ AtomicString m_validBCP47Language;
+};
+
+class MediaTrackBase : public TrackBase {
+public:
+ const AtomicString& kind() const { return m_kind; }
+ virtual void setKind(const AtomicString&);
+
+protected:
+ MediaTrackBase(Type, const AtomicString& id, const AtomicString& label, const AtomicString& language);
+
+ void setKindInternal(const AtomicString&);
+
+private:
+ virtual bool isValidKind(const AtomicString&) const = 0;
+
+ AtomicString m_kind;
};
} // namespace WebCore
#endif
-#endif // TrackBase_h
diff --git a/Source/WebCore/html/track/TrackEvent.cpp b/Source/WebCore/html/track/TrackEvent.cpp
index 16eb4d8be..7da7d5117 100644
--- a/Source/WebCore/html/track/TrackEvent.cpp
+++ b/Source/WebCore/html/track/TrackEvent.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -29,22 +29,34 @@
#include "TrackEvent.h"
-#include "EventNames.h"
-
namespace WebCore {
-TrackEventInit::TrackEventInit()
+static inline std::optional<TrackEvent::TrackEventTrack> convertToTrackEventTrack(Ref<TrackBase>&& track)
{
+ switch (track->type()) {
+ case TrackBase::BaseTrack:
+ return std::nullopt;
+ case TrackBase::TextTrack:
+ return TrackEvent::TrackEventTrack { RefPtr<TextTrack>(&downcast<TextTrack>(track.get())) };
+ case TrackBase::AudioTrack:
+ return TrackEvent::TrackEventTrack { RefPtr<AudioTrack>(&downcast<AudioTrack>(track.get())) };
+ case TrackBase::VideoTrack:
+ return TrackEvent::TrackEventTrack { RefPtr<VideoTrack>(&downcast<VideoTrack>(track.get())) };
+ }
+
+ ASSERT_NOT_REACHED();
+ return std::nullopt;
}
-
-TrackEvent::TrackEvent()
+TrackEvent::TrackEvent(const AtomicString& type, bool canBubble, bool cancelable, Ref<TrackBase>&& track)
+ : Event(type, canBubble, cancelable)
+ , m_track(convertToTrackEventTrack(WTFMove(track)))
{
}
-TrackEvent::TrackEvent(const AtomicString& type, const TrackEventInit& initializer)
- : Event(type, initializer)
- , m_track(initializer.track)
+TrackEvent::TrackEvent(const AtomicString& type, Init&& initializer, IsTrusted isTrusted)
+ : Event(type, initializer, isTrusted)
+ , m_track(WTFMove(initializer.track))
{
}
diff --git a/Source/WebCore/html/track/TrackEvent.h b/Source/WebCore/html/track/TrackEvent.h
index 3c7e43a45..8432633d2 100644
--- a/Source/WebCore/html/track/TrackEvent.h
+++ b/Source/WebCore/html/track/TrackEvent.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,48 +23,48 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TrackEvent_h
-#define TrackEvent_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
+#include "AudioTrack.h"
#include "Event.h"
-#include "TrackBase.h"
+#include "TextTrack.h"
+#include "VideoTrack.h"
namespace WebCore {
-struct TrackEventInit : public EventInit {
- TrackEventInit();
-
- RefPtr<TrackBase> track;
-};
-
-class TrackEvent : public Event {
+class TrackEvent final : public Event {
public:
virtual ~TrackEvent();
- static PassRefPtr<TrackEvent> create()
+ static Ref<TrackEvent> create(const AtomicString& type, bool canBubble, bool cancelable, Ref<TrackBase>&& track)
{
- return adoptRef(new TrackEvent);
+ return adoptRef(*new TrackEvent(type, canBubble, cancelable, WTFMove(track)));
}
- static PassRefPtr<TrackEvent> create(const AtomicString& type, const TrackEventInit& initializer)
+ using TrackEventTrack = Variant<RefPtr<VideoTrack>, RefPtr<AudioTrack>, RefPtr<TextTrack>>;
+
+ struct Init : public EventInit {
+ std::optional<TrackEventTrack> track;
+ };
+
+ static Ref<TrackEvent> create(const AtomicString& type, Init&& initializer, IsTrusted isTrusted = IsTrusted::No)
{
- return adoptRef(new TrackEvent(type, initializer));
+ return adoptRef(*new TrackEvent(type, WTFMove(initializer), isTrusted));
}
- virtual EventInterface eventInterface() const override;
-
- TrackBase* track() const { return m_track.get(); }
+ std::optional<TrackEventTrack> track() const { return m_track; }
private:
- TrackEvent();
- TrackEvent(const AtomicString& type, const TrackEventInit& initializer);
+ TrackEvent(const AtomicString& type, bool canBubble, bool cancelable, Ref<TrackBase>&&);
+ TrackEvent(const AtomicString& type, Init&& initializer, IsTrusted);
+
+ EventInterface eventInterface() const override;
- RefPtr<TrackBase> m_track;
+ std::optional<TrackEventTrack> m_track;
};
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/TrackEvent.idl b/Source/WebCore/html/track/TrackEvent.idl
index 576761e1a..8a9330462 100644
--- a/Source/WebCore/html/track/TrackEvent.idl
+++ b/Source/WebCore/html/track/TrackEvent.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -25,8 +25,11 @@
[
Conditional=VIDEO_TRACK,
- ConstructorTemplate=Event
+ Constructor(DOMString type, optional TrackEventInit eventInitDict)
] interface TrackEvent : Event {
- [InitializedByEventConstructor, CustomGetter] readonly attribute object track;
+ readonly attribute (VideoTrack or AudioTrack or TextTrack)? track;
};
+dictionary TrackEventInit : EventInit {
+ (VideoTrack or AudioTrack or TextTrack)? track = null;
+};
diff --git a/Source/WebCore/html/track/TrackListBase.cpp b/Source/WebCore/html/track/TrackListBase.cpp
index 7fb47b68d..ef892cbb5 100644
--- a/Source/WebCore/html/track/TrackListBase.cpp
+++ b/Source/WebCore/html/track/TrackListBase.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -46,6 +46,16 @@ TrackListBase::TrackListBase(HTMLMediaElement* element, ScriptExecutionContext*
TrackListBase::~TrackListBase()
{
+ clearElement();
+}
+
+void TrackListBase::clearElement()
+{
+ m_element = nullptr;
+ for (auto& track : m_inbandTracks) {
+ track->setMediaElement(nullptr);
+ track->clearClient();
+ }
}
Element* TrackListBase::element() const
@@ -58,37 +68,36 @@ unsigned TrackListBase::length() const
return m_inbandTracks.size();
}
-void TrackListBase::remove(TrackBase* track)
+void TrackListBase::remove(TrackBase& track, bool scheduleEvent)
{
- size_t index = m_inbandTracks.find(track);
- ASSERT(index != notFound);
+ size_t index = m_inbandTracks.find(&track);
+ if (index == notFound)
+ return;
- ASSERT(track->mediaElement() == m_element);
- track->setMediaElement(0);
+ if (track.mediaElement()) {
+ ASSERT(track.mediaElement() == m_element);
+ track.setMediaElement(nullptr);
+ }
- RefPtr<TrackBase> trackRef = m_inbandTracks[index];
+ Ref<TrackBase> trackRef = *m_inbandTracks[index];
m_inbandTracks.remove(index);
- scheduleRemoveTrackEvent(trackRef.release());
+ if (scheduleEvent)
+ scheduleRemoveTrackEvent(WTFMove(trackRef));
}
-bool TrackListBase::contains(TrackBase* track) const
+bool TrackListBase::contains(TrackBase& track) const
{
- return m_inbandTracks.find(track) != notFound;
+ return m_inbandTracks.find(&track) != notFound;
}
-void TrackListBase::scheduleTrackEvent(const AtomicString& eventName, PassRefPtr<TrackBase> track)
+void TrackListBase::scheduleTrackEvent(const AtomicString& eventName, Ref<TrackBase>&& track)
{
- TrackEventInit initializer;
- initializer.track = track;
- initializer.bubbles = false;
- initializer.cancelable = false;
-
- m_asyncEventQueue.enqueueEvent(TrackEvent::create(eventName, initializer));
+ m_asyncEventQueue.enqueueEvent(TrackEvent::create(eventName, false, false, WTFMove(track)));
}
-void TrackListBase::scheduleAddTrackEvent(PassRefPtr<TrackBase> track)
+void TrackListBase::scheduleAddTrackEvent(Ref<TrackBase>&& track)
{
// 4.8.10.5 Loading the media resource
// ...
@@ -108,10 +117,10 @@ void TrackListBase::scheduleAddTrackEvent(PassRefPtr<TrackBase> track)
// bubble and is not cancelable, and that uses the TrackEvent interface, with
// the track attribute initialized to the text track's TextTrack object, at
// the media element's textTracks attribute's TextTrackList object.
- scheduleTrackEvent(eventNames().addtrackEvent, track);
+ scheduleTrackEvent(eventNames().addtrackEvent, WTFMove(track));
}
-void TrackListBase::scheduleRemoveTrackEvent(PassRefPtr<TrackBase> track)
+void TrackListBase::scheduleRemoveTrackEvent(Ref<TrackBase>&& track)
{
// 4.8.10.6 Offsets into the media resource
// If at any time the user agent learns that an audio or video track has
@@ -135,7 +144,7 @@ void TrackListBase::scheduleRemoveTrackEvent(PassRefPtr<TrackBase> track)
// interface, with the track attribute initialized to the text track's
// TextTrack object, at the media element's textTracks attribute's
// TextTrackList object.
- scheduleTrackEvent(eventNames().removetrackEvent, track);
+ scheduleTrackEvent(eventNames().removetrackEvent, WTFMove(track));
}
void TrackListBase::scheduleChangeEvent()
@@ -148,18 +157,12 @@ void TrackListBase::scheduleChangeEvent()
// Whenever a track in a VideoTrackList that was previously not selected is
// selected, the user agent must queue a task to fire a simple event named
// change at the VideoTrackList object.
-
- EventInit initializer;
- initializer.bubbles = false;
- initializer.cancelable = false;
-
- m_asyncEventQueue.enqueueEvent(Event::create(eventNames().changeEvent, initializer));
+ m_asyncEventQueue.enqueueEvent(Event::create(eventNames().changeEvent, false, false));
}
bool TrackListBase::isAnyTrackEnabled() const
{
- for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
- TrackBase* track = m_inbandTracks[i].get();
+ for (auto& track : m_inbandTracks) {
if (track->enabled())
return true;
}
diff --git a/Source/WebCore/html/track/TrackListBase.h b/Source/WebCore/html/track/TrackListBase.h
index 87c86a479..9573a2131 100644
--- a/Source/WebCore/html/track/TrackListBase.h
+++ b/Source/WebCore/html/track/TrackListBase.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TrackListBase_h
-#define TrackListBase_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
@@ -32,7 +31,6 @@
#include "EventTarget.h"
#include "GenericEventQueue.h"
#include "Timer.h"
-#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
@@ -47,20 +45,16 @@ public:
virtual ~TrackListBase();
virtual unsigned length() const;
- virtual bool contains(TrackBase*) const;
- virtual void remove(TrackBase*);
+ virtual bool contains(TrackBase&) const;
+ virtual void remove(TrackBase&, bool scheduleEvent = true);
// EventTarget
- virtual EventTargetInterface eventTargetInterface() const = 0;
+ EventTargetInterface eventTargetInterface() const override = 0;
using RefCounted<TrackListBase>::ref;
using RefCounted<TrackListBase>::deref;
- virtual ScriptExecutionContext* scriptExecutionContext() const override final { return m_context; }
+ ScriptExecutionContext* scriptExecutionContext() const final { return m_context; }
- DEFINE_ATTRIBUTE_EVENT_LISTENER(addtrack);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(removetrack);
-
- void clearElement() { m_element = 0; }
+ virtual void clearElement();
Element* element() const;
HTMLMediaElement* mediaElement() const { return m_element; }
@@ -72,17 +66,17 @@ public:
protected:
TrackListBase(HTMLMediaElement*, ScriptExecutionContext*);
- void scheduleAddTrackEvent(PassRefPtr<TrackBase>);
- void scheduleRemoveTrackEvent(PassRefPtr<TrackBase>);
+ void scheduleAddTrackEvent(Ref<TrackBase>&&);
+ void scheduleRemoveTrackEvent(Ref<TrackBase>&&);
Vector<RefPtr<TrackBase>> m_inbandTracks;
private:
- void scheduleTrackEvent(const AtomicString& eventName, PassRefPtr<TrackBase>);
+ void scheduleTrackEvent(const AtomicString& eventName, Ref<TrackBase>&&);
// EventTarget
- virtual void refEventTarget() override final { ref(); }
- virtual void derefEventTarget() override final { deref(); }
+ void refEventTarget() final { ref(); }
+ void derefEventTarget() final { deref(); }
ScriptExecutionContext* m_context;
HTMLMediaElement* m_element;
@@ -92,5 +86,4 @@ private:
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/VTTCue.cpp b/Source/WebCore/html/track/VTTCue.cpp
new file mode 100644
index 000000000..4558582b4
--- /dev/null
+++ b/Source/WebCore/html/track/VTTCue.cpp
@@ -0,0 +1,1180 @@
+/*
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2011-2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO_TRACK)
+#include "VTTCue.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "DocumentFragment.h"
+#include "Event.h"
+#include "ExceptionCode.h"
+#include "HTMLDivElement.h"
+#include "HTMLSpanElement.h"
+#include "Logging.h"
+#include "NoEventDispatchAssertion.h"
+#include "NodeTraversal.h"
+#include "RenderVTTCue.h"
+#include "Text.h"
+#include "TextTrack.h"
+#include "TextTrackCueList.h"
+#include "VTTRegionList.h"
+#include "VTTScanner.h"
+#include "WebVTTElement.h"
+#include "WebVTTParser.h"
+#include <wtf/MathExtras.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+// This constant should correspond with the percentage returned by CaptionUserPreferences::captionFontSizeScaleAndImportance.
+const static double DEFAULTCAPTIONFONTSIZEPERCENTAGE = 5;
+
+static const int undefinedPosition = -1;
+
+static const CSSValueID displayWritingModeMap[] = {
+ CSSValueHorizontalTb, CSSValueVerticalRl, CSSValueVerticalLr
+};
+COMPILE_ASSERT(WTF_ARRAY_LENGTH(displayWritingModeMap) == VTTCue::NumberOfWritingDirections, displayWritingModeMap_has_wrong_size);
+
+static const CSSValueID displayAlignmentMap[] = {
+ CSSValueStart, CSSValueCenter, CSSValueEnd, CSSValueLeft, CSSValueRight
+};
+COMPILE_ASSERT(WTF_ARRAY_LENGTH(displayAlignmentMap) == VTTCue::NumberOfAlignments, displayAlignmentMap_has_wrong_size);
+
+static const String& startKeyword()
+{
+ static NeverDestroyed<const String> start(ASCIILiteral("start"));
+ return start;
+}
+
+static const String& middleKeyword()
+{
+ static NeverDestroyed<const String> middle(ASCIILiteral("middle"));
+ return middle;
+}
+
+static const String& endKeyword()
+{
+ static NeverDestroyed<const String> end(ASCIILiteral("end"));
+ return end;
+}
+
+static const String& leftKeyword()
+{
+ static NeverDestroyed<const String> left("left");
+ return left;
+}
+
+static const String& rightKeyword()
+{
+ static NeverDestroyed<const String> right("right");
+ return right;
+}
+
+static const String& horizontalKeyword()
+{
+ return emptyString();
+}
+
+static const String& verticalGrowingLeftKeyword()
+{
+ static NeverDestroyed<const String> verticalrl(ASCIILiteral("rl"));
+ return verticalrl;
+}
+
+static const String& verticalGrowingRightKeyword()
+{
+ static NeverDestroyed<const String> verticallr(ASCIILiteral("lr"));
+ return verticallr;
+}
+
+// ----------------------------
+
+Ref<VTTCueBox> VTTCueBox::create(Document& document, VTTCue& cue)
+{
+ VTTCueBox& cueBox = *new VTTCueBox(document, cue);
+ cueBox.setPseudo(VTTCueBox::vttCueBoxShadowPseudoId());
+ return adoptRef(cueBox);
+}
+
+VTTCueBox::VTTCueBox(Document& document, VTTCue& cue)
+ : HTMLElement(divTag, document)
+ , m_cue(cue)
+{
+ setPseudo(vttCueBoxShadowPseudoId());
+}
+
+VTTCue* VTTCueBox::getCue() const
+{
+ return &m_cue;
+}
+
+void VTTCueBox::applyCSSProperties(const IntSize& videoSize)
+{
+ // FIXME: Apply all the initial CSS positioning properties. http://wkb.ug/79916
+ if (!m_cue.regionId().isEmpty()) {
+ setInlineStyleProperty(CSSPropertyPosition, CSSValueRelative);
+ return;
+ }
+
+ // 3.5.1 On the (root) List of WebVTT Node Objects:
+
+ // the 'position' property must be set to 'absolute'
+ setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute);
+
+ // the 'unicode-bidi' property must be set to 'plaintext'
+ setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext);
+
+ // the 'direction' property must be set to direction
+ setInlineStyleProperty(CSSPropertyDirection, m_cue.getCSSWritingDirection());
+
+ // the 'writing-mode' property must be set to writing-mode
+ setInlineStyleProperty(CSSPropertyWritingMode, m_cue.getCSSWritingMode(), false);
+
+ std::pair<float, float> position = m_cue.getCSSPosition();
+
+ // the 'top' property must be set to top,
+ setInlineStyleProperty(CSSPropertyTop, static_cast<double>(position.second), CSSPrimitiveValue::CSS_PERCENTAGE);
+
+ // the 'left' property must be set to left
+ setInlineStyleProperty(CSSPropertyLeft, static_cast<double>(position.first), CSSPrimitiveValue::CSS_PERCENTAGE);
+
+ double authorFontSize = std::min(videoSize.width(), videoSize.height()) * DEFAULTCAPTIONFONTSIZEPERCENTAGE / 100.0;
+ double multiplier = 1.0;
+ if (authorFontSize)
+ multiplier = m_fontSizeFromCaptionUserPrefs / authorFontSize;
+
+ double textPosition = m_cue.position();
+ double maxSize = 100.0;
+ CSSValueID alignment = m_cue.getCSSAlignment();
+ if (alignment == CSSValueEnd || alignment == CSSValueRight)
+ maxSize = textPosition;
+ else if (alignment == CSSValueStart || alignment == CSSValueLeft)
+ maxSize = 100.0 - textPosition;
+
+ double newCueSize = std::min(m_cue.getCSSSize() * multiplier, 100.0);
+ // the 'width' property must be set to width, and the 'height' property must be set to height
+ if (m_cue.vertical() == horizontalKeyword()) {
+ setInlineStyleProperty(CSSPropertyWidth, newCueSize, CSSPrimitiveValue::CSS_PERCENTAGE);
+ setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto);
+ setInlineStyleProperty(CSSPropertyMinWidth, "-webkit-min-content");
+ setInlineStyleProperty(CSSPropertyMaxWidth, maxSize, CSSPrimitiveValue::CSS_PERCENTAGE);
+ if ((alignment == CSSValueMiddle || alignment == CSSValueCenter) && multiplier != 1.0)
+ setInlineStyleProperty(CSSPropertyLeft, static_cast<double>(position.first - (newCueSize - m_cue.getCSSSize()) / 2), CSSPrimitiveValue::CSS_PERCENTAGE);
+ } else {
+ setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto);
+ setInlineStyleProperty(CSSPropertyHeight, newCueSize, CSSPrimitiveValue::CSS_PERCENTAGE);
+ setInlineStyleProperty(CSSPropertyMinHeight, "-webkit-min-content");
+ setInlineStyleProperty(CSSPropertyMaxHeight, maxSize, CSSPrimitiveValue::CSS_PERCENTAGE);
+ if ((alignment == CSSValueMiddle || alignment == CSSValueCenter) && multiplier != 1.0)
+ setInlineStyleProperty(CSSPropertyTop, static_cast<double>(position.second - (newCueSize - m_cue.getCSSSize()) / 2), CSSPrimitiveValue::CSS_PERCENTAGE);
+ }
+
+ // The 'text-align' property on the (root) List of WebVTT Node Objects must
+ // be set to the value in the second cell of the row of the table below
+ // whose first cell is the value of the corresponding cue's text track cue
+ // alignment:
+ setInlineStyleProperty(CSSPropertyTextAlign, m_cue.getCSSAlignment());
+
+ if (!m_cue.snapToLines()) {
+ // 10.13.1 Set up x and y:
+ // Note: x and y are set through the CSS left and top above.
+
+ // 10.13.2 Position the boxes in boxes such that the point x% along the
+ // width of the bounding box of the boxes in boxes is x% of the way
+ // across the width of the video's rendering area, and the point y%
+ // along the height of the bounding box of the boxes in boxes is y%
+ // of the way across the height of the video's rendering area, while
+ // maintaining the relative positions of the boxes in boxes to each
+ // other.
+ setInlineStyleProperty(CSSPropertyTransform,
+ String::format("translate(-%.2f%%, -%.2f%%)", position.first, position.second));
+
+ setInlineStyleProperty(CSSPropertyWhiteSpace, CSSValuePre);
+ }
+
+ // Make sure shadow or stroke is not clipped.
+ setInlineStyleProperty(CSSPropertyOverflow, CSSValueVisible);
+ m_cue.element().setInlineStyleProperty(CSSPropertyOverflow, CSSValueVisible);
+}
+
+const AtomicString& VTTCueBox::vttCueBoxShadowPseudoId()
+{
+ static NeverDestroyed<const AtomicString> trackDisplayBoxShadowPseudoId("-webkit-media-text-track-display", AtomicString::ConstructFromLiteral);
+ return trackDisplayBoxShadowPseudoId;
+}
+
+RenderPtr<RenderElement> VTTCueBox::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ return createRenderer<RenderVTTCue>(*this, WTFMove(style));
+}
+
+// ----------------------------
+
+const AtomicString& VTTCue::cueBackdropShadowPseudoId()
+{
+ static NeverDestroyed<const AtomicString> cueBackdropShadowPseudoId("-webkit-media-text-track-display-backdrop", AtomicString::ConstructFromLiteral);
+ return cueBackdropShadowPseudoId;
+}
+
+Ref<VTTCue> VTTCue::create(ScriptExecutionContext& context, const WebVTTCueData& data)
+{
+ return adoptRef(*new VTTCue(context, data));
+}
+
+VTTCue::VTTCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const String& content)
+ : TextTrackCue(context, start, end)
+ , m_content(content)
+{
+ initialize(context);
+}
+
+VTTCue::VTTCue(ScriptExecutionContext& context, const WebVTTCueData& cueData)
+ : TextTrackCue(context, MediaTime::zeroTime(), MediaTime::zeroTime())
+{
+ initialize(context);
+ setText(cueData.content());
+ setStartTime(cueData.startTime());
+ setEndTime(cueData.endTime());
+ setId(cueData.id());
+ setCueSettings(cueData.settings());
+ m_originalStartTime = cueData.originalStartTime();
+}
+
+VTTCue::~VTTCue()
+{
+ // FIXME: We should set m_cue in VTTCueBox to nullptr instead.
+ if (m_displayTree && m_displayTree->document().refCount())
+ m_displayTree->remove();
+}
+
+void VTTCue::initialize(ScriptExecutionContext& context)
+{
+ m_linePosition = undefinedPosition;
+ m_computedLinePosition = undefinedPosition;
+ m_textPosition = 50;
+ m_cueSize = 100;
+ m_writingDirection = Horizontal;
+ m_cueAlignment = Middle;
+ m_webVTTNodeTree = nullptr;
+ m_cueBackdropBox = HTMLDivElement::create(downcast<Document>(context));
+ m_cueHighlightBox = HTMLSpanElement::create(spanTag, downcast<Document>(context));
+ m_displayDirection = CSSValueLtr;
+ m_displaySize = 0;
+ m_snapToLines = true;
+ m_displayTreeShouldChange = true;
+ m_notifyRegion = true;
+ m_originalStartTime = MediaTime::zeroTime();
+}
+
+Ref<VTTCueBox> VTTCue::createDisplayTree()
+{
+ return VTTCueBox::create(ownerDocument(), *this);
+}
+
+VTTCueBox& VTTCue::displayTreeInternal()
+{
+ if (!m_displayTree)
+ m_displayTree = createDisplayTree();
+ return *m_displayTree;
+}
+
+void VTTCue::didChange()
+{
+ TextTrackCue::didChange();
+ m_displayTreeShouldChange = true;
+}
+
+const String& VTTCue::vertical() const
+{
+ switch (m_writingDirection) {
+ case Horizontal:
+ return horizontalKeyword();
+ case VerticalGrowingLeft:
+ return verticalGrowingLeftKeyword();
+ case VerticalGrowingRight:
+ return verticalGrowingRightKeyword();
+ default:
+ ASSERT_NOT_REACHED();
+ return emptyString();
+ }
+}
+
+ExceptionOr<void> VTTCue::setVertical(const String& value)
+{
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-vertical
+ // On setting, the text track cue writing direction must be set to the value given
+ // in the first cell of the row in the table above whose second cell is a
+ // case-sensitive match for the new value, if any. If none of the values match, then
+ // the user agent must instead throw a SyntaxError exception.
+
+ WritingDirection direction = m_writingDirection;
+ if (value == horizontalKeyword())
+ direction = Horizontal;
+ else if (value == verticalGrowingLeftKeyword())
+ direction = VerticalGrowingLeft;
+ else if (value == verticalGrowingRightKeyword())
+ direction = VerticalGrowingRight;
+ else
+ return Exception { SYNTAX_ERR };
+
+ if (direction == m_writingDirection)
+ return { };
+
+ willChange();
+ m_writingDirection = direction;
+ didChange();
+
+ return { };
+}
+
+void VTTCue::setSnapToLines(bool value)
+{
+ if (m_snapToLines == value)
+ return;
+
+ willChange();
+ m_snapToLines = value;
+ didChange();
+}
+
+ExceptionOr<void> VTTCue::setLine(double position)
+{
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-line
+ // On setting, if the text track cue snap-to-lines flag is not set, and the new
+ // value is negative or greater than 100, then throw an IndexSizeError exception.
+ if (!m_snapToLines && !(position >= 0 && position <= 100))
+ return Exception { INDEX_SIZE_ERR };
+
+ // Otherwise, set the text track cue line position to the new value.
+ if (m_linePosition == position)
+ return { };
+
+ willChange();
+ m_linePosition = position;
+ m_computedLinePosition = calculateComputedLinePosition();
+ didChange();
+
+ return { };
+}
+
+ExceptionOr<void> VTTCue::setPosition(double position)
+{
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-position
+ // On setting, if the new value is negative or greater than 100, then throw an IndexSizeError exception.
+ // Otherwise, set the text track cue text position to the new value.
+ if (!(position >= 0 && position <= 100))
+ return Exception { INDEX_SIZE_ERR };
+
+ // Otherwise, set the text track cue line position to the new value.
+ if (m_textPosition == position)
+ return { };
+
+ willChange();
+ m_textPosition = position;
+ didChange();
+
+ return { };
+}
+
+ExceptionOr<void> VTTCue::setSize(int size)
+{
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-size
+ // On setting, if the new value is negative or greater than 100, then throw an IndexSizeError
+ // exception. Otherwise, set the text track cue size to the new value.
+ if (!(size >= 0 && size <= 100))
+ return Exception { INDEX_SIZE_ERR };
+
+ // Otherwise, set the text track cue line position to the new value.
+ if (m_cueSize == size)
+ return { };
+
+ willChange();
+ m_cueSize = size;
+ didChange();
+
+ return { };
+}
+
+const String& VTTCue::align() const
+{
+ switch (m_cueAlignment) {
+ case Start:
+ return startKeyword();
+ case Middle:
+ return middleKeyword();
+ case End:
+ return endKeyword();
+ case Left:
+ return leftKeyword();
+ case Right:
+ return rightKeyword();
+ default:
+ ASSERT_NOT_REACHED();
+ return emptyString();
+ }
+}
+
+ExceptionOr<void> VTTCue::setAlign(const String& value)
+{
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-align
+ // On setting, the text track cue alignment must be set to the value given in the
+ // first cell of the row in the table above whose second cell is a case-sensitive
+ // match for the new value, if any. If none of the values match, then the user
+ // agent must instead throw a SyntaxError exception.
+
+ CueAlignment alignment;
+ if (value == startKeyword())
+ alignment = Start;
+ else if (value == middleKeyword())
+ alignment = Middle;
+ else if (value == endKeyword())
+ alignment = End;
+ else if (value == leftKeyword())
+ alignment = Left;
+ else if (value == rightKeyword())
+ alignment = Right;
+ else
+ return Exception { SYNTAX_ERR };
+
+ if (alignment == m_cueAlignment)
+ return { };
+
+ willChange();
+ m_cueAlignment = alignment;
+ didChange();
+
+ return { };
+}
+
+void VTTCue::setText(const String& text)
+{
+ if (m_content == text)
+ return;
+
+ willChange();
+ // Clear the document fragment but don't bother to create it again just yet as we can do that
+ // when it is requested.
+ m_webVTTNodeTree = nullptr;
+ m_content = text;
+ didChange();
+}
+
+void VTTCue::createWebVTTNodeTree()
+{
+ if (!m_webVTTNodeTree)
+ m_webVTTNodeTree = WebVTTParser::createDocumentFragmentFromCueText(ownerDocument(), m_content);
+}
+
+void VTTCue::copyWebVTTNodeToDOMTree(ContainerNode* webVTTNode, ContainerNode* parent)
+{
+ for (Node* node = webVTTNode->firstChild(); node; node = node->nextSibling()) {
+ RefPtr<Node> clonedNode;
+ if (is<WebVTTElement>(*node))
+ clonedNode = downcast<WebVTTElement>(*node).createEquivalentHTMLElement(ownerDocument());
+ else
+ clonedNode = node->cloneNode(false);
+ parent->appendChild(*clonedNode);
+ if (is<ContainerNode>(*node))
+ copyWebVTTNodeToDOMTree(downcast<ContainerNode>(node), downcast<ContainerNode>(clonedNode.get()));
+ }
+}
+
+RefPtr<DocumentFragment> VTTCue::getCueAsHTML()
+{
+ createWebVTTNodeTree();
+ if (!m_webVTTNodeTree)
+ return nullptr;
+
+ auto clonedFragment = DocumentFragment::create(ownerDocument());
+ copyWebVTTNodeToDOMTree(m_webVTTNodeTree.get(), clonedFragment.ptr());
+ return WTFMove(clonedFragment);
+}
+
+RefPtr<DocumentFragment> VTTCue::createCueRenderingTree()
+{
+ createWebVTTNodeTree();
+ if (!m_webVTTNodeTree)
+ return nullptr;
+
+ auto clonedFragment = DocumentFragment::create(ownerDocument());
+
+ // The cloned fragment is never exposed to author scripts so it's safe to dispatch events here.
+ NoEventDispatchAssertion::EventAllowedScope noEventDispatchAssertionDisabledForScope(clonedFragment);
+
+ m_webVTTNodeTree->cloneChildNodes(clonedFragment);
+ return WTFMove(clonedFragment);
+}
+
+void VTTCue::setRegionId(const String& regionId)
+{
+ if (m_regionId == regionId)
+ return;
+
+ willChange();
+ m_regionId = regionId;
+ didChange();
+}
+
+void VTTCue::notifyRegionWhenRemovingDisplayTree(bool notifyRegion)
+{
+ m_notifyRegion = notifyRegion;
+}
+
+void VTTCue::setIsActive(bool active)
+{
+ TextTrackCue::setIsActive(active);
+
+ if (!active) {
+ if (!hasDisplayTree())
+ return;
+
+ // Remove the display tree as soon as the cue becomes inactive.
+ removeDisplayTree();
+ }
+}
+
+int VTTCue::calculateComputedLinePosition()
+{
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-computed-line-position
+
+ // If the text track cue line position is numeric, then that is the text
+ // track cue computed line position.
+ if (m_linePosition != undefinedPosition)
+ return m_linePosition;
+
+ // If the text track cue snap-to-lines flag of the text track cue is not
+ // set, the text track cue computed line position is the value 100;
+ if (!m_snapToLines)
+ return 100;
+
+ // Otherwise, it is the value returned by the following algorithm:
+
+ // If cue is not associated with a text track, return -1 and abort these
+ // steps.
+ if (!track())
+ return -1;
+
+ // Let n be the number of text tracks whose text track mode is showing or
+ // showing by default and that are in the media element's list of text
+ // tracks before track.
+ int n = track()->trackIndexRelativeToRenderedTracks();
+
+ // Increment n by one.
+ n++;
+
+ // Negate n.
+ n = -n;
+
+ return n;
+}
+
+static bool isCueParagraphSeparator(UChar character)
+{
+ // Within a cue, paragraph boundaries are only denoted by Type B characters,
+ // such as U+000A LINE FEED (LF), U+0085 NEXT LINE (NEL), and U+2029 PARAGRAPH SEPARATOR.
+ return u_charType(character) == U_PARAGRAPH_SEPARATOR;
+}
+
+void VTTCue::determineTextDirection()
+{
+ static NeverDestroyed<const String> rtTag(ASCIILiteral("rt"));
+ createWebVTTNodeTree();
+ if (!m_webVTTNodeTree)
+ return;
+
+ // Apply the Unicode Bidirectional Algorithm's Paragraph Level steps to the
+ // concatenation of the values of each WebVTT Text Object in nodes, in a
+ // pre-order, depth-first traversal, excluding WebVTT Ruby Text Objects and
+ // their descendants.
+ StringBuilder paragraphBuilder;
+ for (Node* node = m_webVTTNodeTree->firstChild(); node; node = NodeTraversal::next(*node, m_webVTTNodeTree.get())) {
+ // FIXME: The code does not match the comment above. This does not actually exclude Ruby Text Object descendant.
+ if (!node->isTextNode() || node->localName() == rtTag)
+ continue;
+
+ paragraphBuilder.append(node->nodeValue());
+ }
+
+ String paragraph = paragraphBuilder.toString();
+ if (!paragraph.length())
+ return;
+
+ for (size_t i = 0; i < paragraph.length(); ++i) {
+ UChar current = paragraph[i];
+ if (!current || isCueParagraphSeparator(current))
+ return;
+
+ if (UChar current = paragraph[i]) {
+ UCharDirection charDirection = u_charDirection(current);
+ if (charDirection == U_LEFT_TO_RIGHT) {
+ m_displayDirection = CSSValueLtr;
+ return;
+ }
+ if (charDirection == U_RIGHT_TO_LEFT || charDirection == U_RIGHT_TO_LEFT_ARABIC) {
+ m_displayDirection = CSSValueRtl;
+ return;
+ }
+ }
+ }
+}
+
+void VTTCue::calculateDisplayParameters()
+{
+ // Steps 10.2, 10.3
+ determineTextDirection();
+
+ // 10.4 If the text track cue writing direction is horizontal, then let
+ // block-flow be 'tb'. Otherwise, if the text track cue writing direction is
+ // vertical growing left, then let block-flow be 'lr'. Otherwise, the text
+ // track cue writing direction is vertical growing right; let block-flow be
+ // 'rl'.
+
+ // The above step is done through the writing direction static map.
+
+ // 10.5 Determine the value of maximum size for cue as per the appropriate
+ // rules from the following list:
+ int maximumSize = m_textPosition;
+ if ((m_writingDirection == Horizontal && m_cueAlignment == Start && m_displayDirection == CSSValueLtr)
+ || (m_writingDirection == Horizontal && m_cueAlignment == End && m_displayDirection == CSSValueRtl)
+ || (m_writingDirection == Horizontal && m_cueAlignment == Left)
+ || (m_writingDirection == VerticalGrowingLeft && (m_cueAlignment == Start || m_cueAlignment == Left))
+ || (m_writingDirection == VerticalGrowingRight && (m_cueAlignment == Start || m_cueAlignment == Left))) {
+ maximumSize = 100 - m_textPosition;
+ } else if ((m_writingDirection == Horizontal && m_cueAlignment == End && m_displayDirection == CSSValueLtr)
+ || (m_writingDirection == Horizontal && m_cueAlignment == Start && m_displayDirection == CSSValueRtl)
+ || (m_writingDirection == Horizontal && m_cueAlignment == Right)
+ || (m_writingDirection == VerticalGrowingLeft && (m_cueAlignment == End || m_cueAlignment == Right))
+ || (m_writingDirection == VerticalGrowingRight && (m_cueAlignment == End || m_cueAlignment == Right))) {
+ maximumSize = m_textPosition;
+ } else if (m_cueAlignment == Middle) {
+ maximumSize = m_textPosition <= 50 ? m_textPosition : (100 - m_textPosition);
+ maximumSize = maximumSize * 2;
+ } else
+ ASSERT_NOT_REACHED();
+
+ // 10.6 If the text track cue size is less than maximum size, then let size
+ // be text track cue size. Otherwise, let size be maximum size.
+ m_displaySize = std::min(m_cueSize, maximumSize);
+
+ // FIXME: Understand why step 10.7 is missing (just a copy/paste error?)
+ // Could be done within a spec implementation check - http://crbug.com/301580
+
+ // 10.8 Determine the value of x-position or y-position for cue as per the
+ // appropriate rules from the following list:
+ if (m_writingDirection == Horizontal) {
+ switch (m_cueAlignment) {
+ case Start:
+ if (m_displayDirection == CSSValueLtr)
+ m_displayPosition.first = m_textPosition;
+ else
+ m_displayPosition.first = 100 - m_textPosition - m_displaySize;
+ break;
+ case End:
+ if (m_displayDirection == CSSValueRtl)
+ m_displayPosition.first = 100 - m_textPosition;
+ else
+ m_displayPosition.first = m_textPosition - m_displaySize;
+ break;
+ case Left:
+ if (m_displayDirection == CSSValueLtr)
+ m_displayPosition.first = m_textPosition;
+ else
+ m_displayPosition.first = 100 - m_textPosition;
+ break;
+ case Right:
+ if (m_displayDirection == CSSValueLtr)
+ m_displayPosition.first = m_textPosition - m_displaySize;
+ else
+ m_displayPosition.first = 100 - m_textPosition - m_displaySize;
+ break;
+ case Middle:
+ if (m_displayDirection == CSSValueLtr)
+ m_displayPosition.first = m_textPosition - m_displaySize / 2;
+ else
+ m_displayPosition.first = 100 - m_textPosition - m_displaySize / 2;
+ break;
+ case NumberOfAlignments:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ // A text track cue has a text track cue computed line position whose value
+ // is defined in terms of the other aspects of the cue.
+ m_computedLinePosition = calculateComputedLinePosition();
+
+ // 10.9 Determine the value of whichever of x-position or y-position is not
+ // yet calculated for cue as per the appropriate rules from the following
+ // list:
+ if (m_snapToLines && m_displayPosition.second == undefinedPosition && m_writingDirection == Horizontal)
+ m_displayPosition.second = 0;
+
+ if (!m_snapToLines && m_displayPosition.second == undefinedPosition && m_writingDirection == Horizontal)
+ m_displayPosition.second = m_computedLinePosition;
+
+ if (m_snapToLines && m_displayPosition.first == undefinedPosition
+ && (m_writingDirection == VerticalGrowingLeft || m_writingDirection == VerticalGrowingRight))
+ m_displayPosition.first = 0;
+
+ if (!m_snapToLines && (m_writingDirection == VerticalGrowingLeft || m_writingDirection == VerticalGrowingRight))
+ m_displayPosition.first = m_computedLinePosition;
+}
+
+void VTTCue::markFutureAndPastNodes(ContainerNode* root, const MediaTime& previousTimestamp, const MediaTime& movieTime)
+{
+ static NeverDestroyed<const String> timestampTag(ASCIILiteral("timestamp"));
+
+ bool isPastNode = true;
+ MediaTime currentTimestamp = previousTimestamp;
+ if (currentTimestamp > movieTime)
+ isPastNode = false;
+
+ for (Node* child = root->firstChild(); child; child = NodeTraversal::next(*child, root)) {
+ if (child->nodeName() == timestampTag) {
+ MediaTime currentTimestamp;
+ bool check = WebVTTParser::collectTimeStamp(child->nodeValue(), currentTimestamp);
+ ASSERT_UNUSED(check, check);
+
+ currentTimestamp += m_originalStartTime;
+ if (currentTimestamp > movieTime)
+ isPastNode = false;
+ }
+
+ if (is<WebVTTElement>(*child)) {
+ downcast<WebVTTElement>(*child).setIsPastNode(isPastNode);
+ // Make an elemenet id match a cue id for style matching purposes.
+ if (!id().isEmpty())
+ downcast<WebVTTElement>(*child).setIdAttribute(id());
+ }
+ }
+}
+
+void VTTCue::updateDisplayTree(const MediaTime& movieTime)
+{
+ // The display tree may contain WebVTT timestamp objects representing
+ // timestamps (processing instructions), along with displayable nodes.
+
+ if (!track()->isRendered())
+ return;
+
+ // Mutating the VTT contents is safe because it's never exposed to author scripts.
+ NoEventDispatchAssertion::EventAllowedScope allowedScopeForCueHighlightBox(*m_cueHighlightBox);
+
+ // Clear the contents of the set.
+ m_cueHighlightBox->removeChildren();
+
+ // Update the two sets containing past and future WebVTT objects.
+ RefPtr<DocumentFragment> referenceTree = createCueRenderingTree();
+ if (!referenceTree)
+ return;
+
+ NoEventDispatchAssertion::EventAllowedScope allowedScopeForReferenceTree(*referenceTree);
+
+ markFutureAndPastNodes(referenceTree.get(), startMediaTime(), movieTime);
+ m_cueHighlightBox->appendChild(*referenceTree);
+}
+
+VTTCueBox& VTTCue::getDisplayTree(const IntSize& videoSize, int fontSize)
+{
+ Ref<VTTCueBox> displayTree = displayTreeInternal();
+ if (!m_displayTreeShouldChange || !track()->isRendered())
+ return displayTree.get();
+
+ // 10.1 - 10.10
+ calculateDisplayParameters();
+
+ // 10.11. Apply the terms of the CSS specifications to nodes within the
+ // following constraints, thus obtaining a set of CSS boxes positioned
+ // relative to an initial containing block:
+ displayTree->removeChildren();
+
+ // The document tree is the tree of WebVTT Node Objects rooted at nodes.
+
+ // The children of the nodes must be wrapped in an anonymous box whose
+ // 'display' property has the value 'inline'. This is the WebVTT cue
+ // background box.
+
+ // Note: This is contained by default in m_cueHighlightBox.
+ m_cueHighlightBox->setPseudo(cueShadowPseudoId());
+
+ m_cueBackdropBox->setPseudo(cueBackdropShadowPseudoId());
+ m_cueBackdropBox->appendChild(*m_cueHighlightBox);
+ displayTree->appendChild(*m_cueBackdropBox);
+
+ // FIXME(BUG 79916): Runs of children of WebVTT Ruby Objects that are not
+ // WebVTT Ruby Text Objects must be wrapped in anonymous boxes whose
+ // 'display' property has the value 'ruby-base'.
+
+ displayTree->setFontSizeFromCaptionUserPrefs(fontSize);
+ displayTree->applyCSSProperties(videoSize);
+
+ m_displayTreeShouldChange = false;
+
+ // 10.15. Let cue's text track cue display state have the CSS boxes in
+ // boxes.
+ return displayTree.get();
+}
+
+void VTTCue::removeDisplayTree()
+{
+ // The region needs to be informed about the cue removal.
+ if (m_notifyRegion && track()) {
+ if (VTTRegionList* regions = track()->regions()) {
+ if (VTTRegion* region = regions->getRegionById(m_regionId))
+ if (hasDisplayTree())
+ region->willRemoveTextTrackCueBox(m_displayTree.get());
+ }
+ }
+
+ if (!hasDisplayTree())
+ return;
+ displayTreeInternal().remove();
+}
+
+std::pair<double, double> VTTCue::getPositionCoordinates() const
+{
+ // This method is used for setting x and y when snap to lines is not set.
+ std::pair<double, double> coordinates;
+
+ if (m_writingDirection == Horizontal && m_displayDirection == CSSValueLtr) {
+ coordinates.first = m_textPosition;
+ coordinates.second = m_computedLinePosition;
+
+ return coordinates;
+ }
+
+ if (m_writingDirection == Horizontal && m_displayDirection == CSSValueRtl) {
+ coordinates.first = 100 - m_textPosition;
+ coordinates.second = m_computedLinePosition;
+
+ return coordinates;
+ }
+
+ if (m_writingDirection == VerticalGrowingLeft) {
+ coordinates.first = 100 - m_computedLinePosition;
+ coordinates.second = m_textPosition;
+
+ return coordinates;
+ }
+
+ if (m_writingDirection == VerticalGrowingRight) {
+ coordinates.first = m_computedLinePosition;
+ coordinates.second = m_textPosition;
+
+ return coordinates;
+ }
+
+ ASSERT_NOT_REACHED();
+
+ return coordinates;
+}
+
+VTTCue::CueSetting VTTCue::settingName(VTTScanner& input)
+{
+ CueSetting parsedSetting = None;
+ if (input.scan("vertical"))
+ parsedSetting = Vertical;
+ else if (input.scan("line"))
+ parsedSetting = Line;
+ else if (input.scan("position"))
+ parsedSetting = Position;
+ else if (input.scan("size"))
+ parsedSetting = Size;
+ else if (input.scan("align"))
+ parsedSetting = Align;
+ else if (input.scan("region"))
+ parsedSetting = RegionId;
+
+ // Verify that a ':' follows.
+ if (parsedSetting != None && input.scan(':'))
+ return parsedSetting;
+
+ return None;
+}
+
+void VTTCue::setCueSettings(const String& inputString)
+{
+ if (inputString.isEmpty())
+ return;
+
+ VTTScanner input(inputString);
+
+ while (!input.isAtEnd()) {
+
+ // The WebVTT cue settings part of a WebVTT cue consists of zero or more of the following components, in any order,
+ // separated from each other by one or more U+0020 SPACE characters or U+0009 CHARACTER TABULATION (tab) characters.
+ input.skipWhile<WebVTTParser::isValidSettingDelimiter>();
+ if (input.isAtEnd())
+ break;
+
+ // When the user agent is to parse the WebVTT settings given by a string input for a text track cue cue,
+ // the user agent must run the following steps:
+ // 1. Let settings be the result of splitting input on spaces.
+ // 2. For each token setting in the list settings, run the following substeps:
+ // 1. If setting does not contain a U+003A COLON character (:), or if the first U+003A COLON character (:)
+ // in setting is either the first or last character of setting, then jump to the step labeled next setting.
+ // 2. Let name be the leading substring of setting up to and excluding the first U+003A COLON character (:) in that string.
+ CueSetting name = settingName(input);
+
+ // 3. Let value be the trailing substring of setting starting from the character immediately after the first U+003A COLON character (:) in that string.
+ VTTScanner::Run valueRun = input.collectUntil<WebVTTParser::isValidSettingDelimiter>();
+
+ // 4. Run the appropriate substeps that apply for the value of name, as follows:
+ switch (name) {
+ case Vertical: {
+ // If name is a case-sensitive match for "vertical"
+ // 1. If value is a case-sensitive match for the string "rl", then let cue's text track cue writing direction
+ // be vertical growing left.
+ if (input.scanRun(valueRun, verticalGrowingLeftKeyword()))
+ m_writingDirection = VerticalGrowingLeft;
+
+ // 2. Otherwise, if value is a case-sensitive match for the string "lr", then let cue's text track cue writing
+ // direction be vertical growing right.
+ else if (input.scanRun(valueRun, verticalGrowingRightKeyword()))
+ m_writingDirection = VerticalGrowingRight;
+
+ else
+ LOG(Media, "VTTCue::setCueSettings, invalid Vertical");
+ break;
+ }
+ case Line: {
+ bool isValid = false;
+ do {
+ // 1-2 - Collect chars that are either '-', '%', or a digit.
+ // 1. If value contains any characters other than U+002D HYPHEN-MINUS characters (-), U+0025 PERCENT SIGN
+ // characters (%), and characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump
+ // to the step labeled next setting.
+ float linePosition;
+ bool isNegative;
+ if (!input.scanFloat(linePosition, &isNegative))
+ break;
+
+ bool isPercentage = input.scan('%');
+ if (!input.isAt(valueRun.end()))
+ break;
+
+ // 2. If value does not contain at least one character in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT
+ // NINE (9), then jump to the step labeled next setting.
+ // 3. If any character in value other than the first character is a U+002D HYPHEN-MINUS character (-), then
+ // jump to the step labeled next setting.
+ // 4. If any character in value other than the last character is a U+0025 PERCENT SIGN character (%), then
+ // jump to the step labeled next setting.
+ // 5. If the first character in value is a U+002D HYPHEN-MINUS character (-) and the last character in value is a
+ // U+0025 PERCENT SIGN character (%), then jump to the step labeled next setting.
+ if (isPercentage && isNegative)
+ break;
+
+ // 6. Ignoring the trailing percent sign, if any, interpret value as a (potentially signed) integer, and
+ // let number be that number.
+ // 7. If the last character in value is a U+0025 PERCENT SIGN character (%), but number is not in the range
+ // 0 ≤ number ≤ 100, then jump to the step labeled next setting.
+ // 8. Let cue's text track cue line position be number.
+ // 9. If the last character in value is a U+0025 PERCENT SIGN character (%), then let cue's text track cue
+ // snap-to-lines flag be false. Otherwise, let it be true.
+ if (isPercentage) {
+ if (linePosition < 0 || linePosition > 100)
+ break;
+
+ // 10 - If '%' then set snap-to-lines flag to false.
+ m_snapToLines = false;
+ } else {
+ if (linePosition - static_cast<int>(linePosition))
+ break;
+
+ m_snapToLines = true;
+ }
+
+ m_linePosition = linePosition;
+ isValid = true;
+ } while (0);
+
+ if (!isValid)
+ LOG(Media, "VTTCue::setCueSettings, invalid Line");
+
+ break;
+ }
+ case Position: {
+ float position;
+ if (WebVTTParser::parseFloatPercentageValue(input, position) && input.isAt(valueRun.end()))
+ m_textPosition = position;
+ else
+ LOG(Media, "VTTCue::setCueSettings, invalid Position");
+ break;
+ }
+ case Size: {
+ float cueSize;
+ if (WebVTTParser::parseFloatPercentageValue(input, cueSize) && input.isAt(valueRun.end()))
+ m_cueSize = cueSize;
+ else
+ LOG(Media, "VTTCue::setCueSettings, invalid Size");
+ break;
+ }
+ case Align: {
+ // 1. If value is a case-sensitive match for the string "start", then let cue's text track cue alignment be start alignment.
+ if (input.scanRun(valueRun, startKeyword()))
+ m_cueAlignment = Start;
+
+ // 2. If value is a case-sensitive match for the string "middle", then let cue's text track cue alignment be middle alignment.
+ else if (input.scanRun(valueRun, middleKeyword()))
+ m_cueAlignment = Middle;
+
+ // 3. If value is a case-sensitive match for the string "end", then let cue's text track cue alignment be end alignment.
+ else if (input.scanRun(valueRun, endKeyword()))
+ m_cueAlignment = End;
+
+ // 4. If value is a case-sensitive match for the string "left", then let cue's text track cue alignment be left alignment.
+ else if (input.scanRun(valueRun, leftKeyword()))
+ m_cueAlignment = Left;
+
+ // 5. If value is a case-sensitive match for the string "right", then let cue's text track cue alignment be right alignment.
+ else if (input.scanRun(valueRun, rightKeyword()))
+ m_cueAlignment = Right;
+
+ else
+ LOG(Media, "VTTCue::setCueSettings, invalid Align");
+
+ break;
+ }
+ case RegionId:
+ m_regionId = input.extractString(valueRun);
+ break;
+ case None:
+ break;
+ }
+
+ // Make sure the entire run is consumed.
+ input.skipRun(valueRun);
+ }
+
+ // If cue's line position is not auto or cue's size is not 100 or cue's
+ // writing direction is not horizontal, but cue's region identifier is not
+ // the empty string, let cue's region identifier be the empty string.
+ if (m_regionId.isEmpty())
+ return;
+
+ if (m_linePosition != undefinedPosition || m_cueSize != 100 || m_writingDirection != Horizontal)
+ m_regionId = emptyString();
+}
+
+CSSValueID VTTCue::getCSSAlignment() const
+{
+ return displayAlignmentMap[m_cueAlignment];
+}
+
+CSSValueID VTTCue::getCSSWritingDirection() const
+{
+ return m_displayDirection;
+}
+
+CSSValueID VTTCue::getCSSWritingMode() const
+{
+ return displayWritingModeMap[m_writingDirection];
+}
+
+int VTTCue::getCSSSize() const
+{
+ return m_displaySize;
+}
+
+std::pair<double, double> VTTCue::getCSSPosition() const
+{
+ if (!m_snapToLines)
+ return getPositionCoordinates();
+
+ return m_displayPosition;
+}
+
+bool VTTCue::cueContentsMatch(const TextTrackCue& cue) const
+{
+ const VTTCue* vttCue = toVTTCue(&cue);
+ if (text() != vttCue->text())
+ return false;
+ if (cueSettings() != vttCue->cueSettings())
+ return false;
+ if (position() != vttCue->position())
+ return false;
+ if (line() != vttCue->line())
+ return false;
+ if (size() != vttCue->size())
+ return false;
+ if (align() != vttCue->align())
+ return false;
+
+ return true;
+}
+
+bool VTTCue::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
+{
+ if (!TextTrackCue::isEqual(cue, match))
+ return false;
+
+ if (cue.cueType() != WebVTT)
+ return false;
+
+ return cueContentsMatch(cue);
+}
+
+bool VTTCue::doesExtendCue(const TextTrackCue& cue) const
+{
+ if (!cueContentsMatch(cue))
+ return false;
+
+ return TextTrackCue::doesExtendCue(cue);
+}
+
+void VTTCue::setFontSize(int fontSize, const IntSize&, bool important)
+{
+ if (!hasDisplayTree() || !fontSize)
+ return;
+
+ LOG(Media, "TextTrackCue::setFontSize - setting cue font size to %i", fontSize);
+
+ m_displayTreeShouldChange = true;
+ displayTreeInternal().setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX, important);
+}
+
+VTTCue* toVTTCue(TextTrackCue* cue)
+{
+ return const_cast<VTTCue*>(toVTTCue(const_cast<const TextTrackCue*>(cue)));
+}
+
+const VTTCue* toVTTCue(const TextTrackCue* cue)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(cue->isRenderable());
+ return static_cast<const VTTCue*>(cue);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/VTTCue.h b/Source/WebCore/html/track/VTTCue.h
new file mode 100644
index 000000000..5aa061f43
--- /dev/null
+++ b/Source/WebCore/html/track/VTTCue.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2012-2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "EventTarget.h"
+#include "HTMLElement.h"
+#include "TextTrackCue.h"
+
+namespace WebCore {
+
+class DocumentFragment;
+class HTMLDivElement;
+class HTMLSpanElement;
+class ScriptExecutionContext;
+class VTTCue;
+class VTTScanner;
+class WebVTTCueData;
+
+// ----------------------------
+
+class VTTCueBox : public HTMLElement {
+public:
+ static Ref<VTTCueBox> create(Document&, VTTCue&);
+
+ VTTCue* getCue() const;
+ virtual void applyCSSProperties(const IntSize& videoSize);
+
+ static const AtomicString& vttCueBoxShadowPseudoId();
+ void setFontSizeFromCaptionUserPrefs(int fontSize) { m_fontSizeFromCaptionUserPrefs = fontSize; }
+
+protected:
+ VTTCueBox(Document&, VTTCue&);
+
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+
+ VTTCue& m_cue;
+ int m_fontSizeFromCaptionUserPrefs;
+};
+
+// ----------------------------
+
+class VTTCue : public TextTrackCue {
+public:
+ static Ref<VTTCue> create(ScriptExecutionContext& context, double start, double end, const String& content)
+ {
+ return create(context, MediaTime::createWithDouble(start), MediaTime::createWithDouble(end), content);
+ }
+
+ static Ref<VTTCue> create(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const String& content)
+ {
+ return adoptRef(*new VTTCue(context, start, end, content));
+ }
+
+ static Ref<VTTCue> create(ScriptExecutionContext&, const WebVTTCueData&);
+
+ static const AtomicString& cueBackdropShadowPseudoId();
+
+ virtual ~VTTCue();
+
+ const String& vertical() const;
+ ExceptionOr<void> setVertical(const String&);
+
+ bool snapToLines() const { return m_snapToLines; }
+ void setSnapToLines(bool);
+
+ double line() const { return m_linePosition; }
+ virtual ExceptionOr<void> setLine(double);
+
+ double position() const { return m_textPosition; }
+ virtual ExceptionOr<void> setPosition(double);
+
+ int size() const { return m_cueSize; }
+ ExceptionOr<void> setSize(int);
+
+ const String& align() const;
+ ExceptionOr<void> setAlign(const String&);
+
+ const String& text() const { return m_content; }
+ void setText(const String&);
+
+ const String& cueSettings() const { return m_settings; }
+ void setCueSettings(const String&);
+
+ RefPtr<DocumentFragment> getCueAsHTML();
+ RefPtr<DocumentFragment> createCueRenderingTree();
+
+ const String& regionId() const { return m_regionId; }
+ void setRegionId(const String&);
+ void notifyRegionWhenRemovingDisplayTree(bool);
+
+ void setIsActive(bool) override;
+
+ bool hasDisplayTree() const { return m_displayTree; }
+ VTTCueBox& getDisplayTree(const IntSize& videoSize, int fontSize);
+ HTMLSpanElement& element() const { return *m_cueHighlightBox; }
+
+ void updateDisplayTree(const MediaTime&);
+ void removeDisplayTree();
+ void markFutureAndPastNodes(ContainerNode*, const MediaTime&, const MediaTime&);
+
+ int calculateComputedLinePosition();
+ std::pair<double, double> getPositionCoordinates() const;
+
+ std::pair<double, double> getCSSPosition() const;
+
+ CSSValueID getCSSAlignment() const;
+ int getCSSSize() const;
+ CSSValueID getCSSWritingDirection() const;
+ CSSValueID getCSSWritingMode() const;
+
+ enum WritingDirection {
+ Horizontal = 0,
+ VerticalGrowingLeft,
+ VerticalGrowingRight,
+ NumberOfWritingDirections
+ };
+ WritingDirection getWritingDirection() const { return m_writingDirection; }
+
+ enum CueAlignment {
+ Start = 0,
+ Middle,
+ End,
+ Left,
+ Right,
+ NumberOfAlignments
+ };
+ CueAlignment getAlignment() const { return m_cueAlignment; }
+
+ virtual void setFontSize(int, const IntSize&, bool important);
+
+ bool isEqual(const TextTrackCue&, CueMatchRules) const override;
+ bool cueContentsMatch(const TextTrackCue&) const override;
+ bool doesExtendCue(const TextTrackCue&) const override;
+
+ CueType cueType() const override { return WebVTT; }
+ bool isRenderable() const final { return true; }
+
+ void didChange() override;
+
+protected:
+ VTTCue(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end, const String& content);
+ VTTCue(ScriptExecutionContext&, const WebVTTCueData&);
+
+ virtual Ref<VTTCueBox> createDisplayTree();
+ VTTCueBox& displayTreeInternal();
+
+private:
+ void initialize(ScriptExecutionContext&);
+ void createWebVTTNodeTree();
+ void copyWebVTTNodeToDOMTree(ContainerNode* WebVTTNode, ContainerNode* root);
+
+ void parseSettings(const String&);
+
+ void determineTextDirection();
+ void calculateDisplayParameters();
+
+ enum CueSetting {
+ None,
+ Vertical,
+ Line,
+ Position,
+ Size,
+ Align,
+ RegionId
+ };
+ CueSetting settingName(VTTScanner&);
+
+ String m_content;
+ String m_settings;
+ double m_linePosition;
+ double m_computedLinePosition;
+ double m_textPosition;
+ int m_cueSize;
+
+ WritingDirection m_writingDirection;
+ CueAlignment m_cueAlignment;
+ String m_regionId;
+
+ RefPtr<DocumentFragment> m_webVTTNodeTree;
+ RefPtr<HTMLSpanElement> m_cueHighlightBox;
+ RefPtr<HTMLDivElement> m_cueBackdropBox;
+ RefPtr<VTTCueBox> m_displayTree;
+
+ CSSValueID m_displayDirection;
+ int m_displaySize;
+ std::pair<float, float> m_displayPosition;
+
+ MediaTime m_originalStartTime;
+
+ bool m_snapToLines : 1;
+ bool m_displayTreeShouldChange : 1;
+ bool m_notifyRegion : 1;
+};
+
+VTTCue* toVTTCue(TextTrackCue*);
+const VTTCue* toVTTCue(const TextTrackCue*);
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/VTTCue.idl b/Source/WebCore/html/track/VTTCue.idl
new file mode 100644
index 000000000..9a3b78a7b
--- /dev/null
+++ b/Source/WebCore/html/track/VTTCue.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+ Conditional=VIDEO_TRACK,
+ Constructor(unrestricted double startTime, unrestricted double endTime, DOMString text),
+ ConstructorCallWith=ScriptExecutionContext,
+ JSGenerateToJSObject,
+ JSGenerateToNativeObject,
+] interface VTTCue : TextTrackCue {
+ [SetterMayThrowException] attribute DOMString vertical;
+ attribute boolean snapToLines;
+ [SetterMayThrowException] attribute double line;
+ [SetterMayThrowException] attribute double position;
+ [SetterMayThrowException] attribute double size;
+ [SetterMayThrowException] attribute DOMString align;
+ attribute DOMString text;
+ DocumentFragment getCueAsHTML();
+
+ attribute DOMString regionId;
+};
diff --git a/Source/WebCore/html/track/VTTRegion.cpp b/Source/WebCore/html/track/VTTRegion.cpp
new file mode 100644
index 000000000..0578bf912
--- /dev/null
+++ b/Source/WebCore/html/track/VTTRegion.cpp
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "VTTRegion.h"
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "ClientRect.h"
+#include "DOMTokenList.h"
+#include "ElementChildIterator.h"
+#include "ExceptionCode.h"
+#include "HTMLDivElement.h"
+#include "HTMLParserIdioms.h"
+#include "Logging.h"
+#include "RenderElement.h"
+#include "VTTCue.h"
+#include "VTTScanner.h"
+#include "WebVTTParser.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+// The default values are defined within the WebVTT Regions Spec.
+// https://dvcs.w3.org/hg/text-tracks/raw-file/default/608toVTT/region.html
+
+// Default region line-height (vh units)
+static const float lineHeight = 5.33;
+
+// Default scrolling animation time period (s).
+static const float scrollTime = 0.433;
+
+VTTRegion::VTTRegion(ScriptExecutionContext& context)
+ : ContextDestructionObserver(&context)
+ , m_id(emptyString())
+ , m_scrollTimer(*this, &VTTRegion::scrollTimerFired)
+{
+}
+
+VTTRegion::~VTTRegion()
+{
+}
+
+void VTTRegion::setTrack(TextTrack* track)
+{
+ m_track = track;
+}
+
+void VTTRegion::setId(const String& id)
+{
+ m_id = id;
+}
+
+ExceptionOr<void> VTTRegion::setWidth(double value)
+{
+ if (!(value >= 0 && value <= 100))
+ return Exception { INDEX_SIZE_ERR };
+ m_width = value;
+ return { };
+}
+
+ExceptionOr<void> VTTRegion::setHeight(int value)
+{
+ if (value < 0)
+ return Exception { INDEX_SIZE_ERR };
+ m_heightInLines = value;
+ return { };
+}
+
+ExceptionOr<void> VTTRegion::setRegionAnchorX(double value)
+{
+ if (!(value >= 0 && value <= 100))
+ return Exception { INDEX_SIZE_ERR };
+ m_regionAnchor.setX(value);
+ return { };
+}
+
+ExceptionOr<void> VTTRegion::setRegionAnchorY(double value)
+{
+ if (!(value >= 0 && value <= 100))
+ return Exception { INDEX_SIZE_ERR };
+ m_regionAnchor.setY(value);
+ return { };
+}
+
+ExceptionOr<void> VTTRegion::setViewportAnchorX(double value)
+{
+ if (!(value >= 0 && value <= 100))
+ return Exception { INDEX_SIZE_ERR };
+ m_viewportAnchor.setX(value);
+ return { };
+}
+
+ExceptionOr<void> VTTRegion::setViewportAnchorY(double value)
+{
+ if (!(value >= 0 && value <= 100))
+ return Exception { INDEX_SIZE_ERR };
+ m_viewportAnchor.setY(value);
+ return { };
+}
+
+static const AtomicString& upKeyword()
+{
+ static NeverDestroyed<const AtomicString> upKeyword("up", AtomicString::ConstructFromLiteral);
+ return upKeyword;
+}
+
+const AtomicString& VTTRegion::scroll() const
+{
+ return m_scroll ? upKeyword() : emptyAtom;
+}
+
+ExceptionOr<void> VTTRegion::setScroll(const AtomicString& value)
+{
+ if (value.isEmpty()) {
+ m_scroll = false;
+ return { };
+ }
+ if (value == upKeyword()) {
+ m_scroll = true;
+ return { };
+ }
+ return Exception { SYNTAX_ERR };
+}
+
+void VTTRegion::updateParametersFromRegion(const VTTRegion& other)
+{
+ m_heightInLines = other.m_heightInLines;
+ m_width = other.m_width;
+ m_regionAnchor = other.m_regionAnchor;
+ m_viewportAnchor = other.m_viewportAnchor;
+ m_scroll = other.m_scroll;
+}
+
+void VTTRegion::setRegionSettings(const String& inputString)
+{
+ m_settings = inputString;
+ VTTScanner input(inputString);
+
+ while (!input.isAtEnd()) {
+ input.skipWhile<WebVTTParser::isValidSettingDelimiter>();
+ if (input.isAtEnd())
+ break;
+
+ // Scan the name part.
+ RegionSetting name = scanSettingName(input);
+
+ // Verify that we're looking at a '='.
+ if (name == None || !input.scan('=')) {
+ input.skipUntil<isHTMLSpace<UChar>>();
+ continue;
+ }
+
+ // Scan the value part.
+ parseSettingValue(name, input);
+ }
+}
+
+VTTRegion::RegionSetting VTTRegion::scanSettingName(VTTScanner& input)
+{
+ if (input.scan("id"))
+ return Id;
+ if (input.scan("height"))
+ return Height;
+ if (input.scan("width"))
+ return Width;
+ if (input.scan("viewportanchor"))
+ return ViewportAnchor;
+ if (input.scan("regionanchor"))
+ return RegionAnchor;
+ if (input.scan("scroll"))
+ return Scroll;
+
+ return None;
+}
+
+static inline bool parsedEntireRun(const VTTScanner& input, const VTTScanner::Run& run)
+{
+ return input.isAt(run.end());
+}
+
+void VTTRegion::parseSettingValue(RegionSetting setting, VTTScanner& input)
+{
+ VTTScanner::Run valueRun = input.collectUntil<isHTMLSpace<UChar>>();
+
+ switch (setting) {
+ case Id: {
+ String stringValue = input.extractString(valueRun);
+ if (stringValue.find("-->") == notFound)
+ m_id = stringValue;
+ break;
+ }
+ case Width: {
+ float floatWidth;
+ if (WebVTTParser::parseFloatPercentageValue(input, floatWidth) && parsedEntireRun(input, valueRun))
+ m_width = floatWidth;
+ else
+ LOG(Media, "VTTRegion::parseSettingValue, invalid Width");
+ break;
+ }
+ case Height: {
+ int number;
+ if (input.scanDigits(number) && parsedEntireRun(input, valueRun))
+ m_heightInLines = number;
+ else
+ LOG(Media, "VTTRegion::parseSettingValue, invalid Height");
+ break;
+ }
+ case RegionAnchor: {
+ FloatPoint anchor;
+ if (WebVTTParser::parseFloatPercentageValuePair(input, ',', anchor) && parsedEntireRun(input, valueRun))
+ m_regionAnchor = anchor;
+ else
+ LOG(Media, "VTTRegion::parseSettingValue, invalid RegionAnchor");
+ break;
+ }
+ case ViewportAnchor: {
+ FloatPoint anchor;
+ if (WebVTTParser::parseFloatPercentageValuePair(input, ',', anchor) && parsedEntireRun(input, valueRun))
+ m_viewportAnchor = anchor;
+ else
+ LOG(Media, "VTTRegion::parseSettingValue, invalid ViewportAnchor");
+ break;
+ }
+ case Scroll:
+ if (input.scanRun(valueRun, upKeyword()))
+ m_scroll = true;
+ else
+ LOG(Media, "VTTRegion::parseSettingValue, invalid Scroll");
+ break;
+ case None:
+ break;
+ }
+
+ input.skipRun(valueRun);
+}
+
+const AtomicString& VTTRegion::textTrackCueContainerScrollingClass()
+{
+ static NeverDestroyed<const AtomicString> trackRegionCueContainerScrollingClass("scrolling", AtomicString::ConstructFromLiteral);
+
+ return trackRegionCueContainerScrollingClass;
+}
+
+const AtomicString& VTTRegion::textTrackCueContainerShadowPseudoId()
+{
+ static NeverDestroyed<const AtomicString> trackRegionCueContainerPseudoId("-webkit-media-text-track-region-container", AtomicString::ConstructFromLiteral);
+
+ return trackRegionCueContainerPseudoId;
+}
+
+const AtomicString& VTTRegion::textTrackRegionShadowPseudoId()
+{
+ static NeverDestroyed<const AtomicString> trackRegionShadowPseudoId("-webkit-media-text-track-region", AtomicString::ConstructFromLiteral);
+
+ return trackRegionShadowPseudoId;
+}
+
+void VTTRegion::appendTextTrackCueBox(Ref<VTTCueBox>&& displayBox)
+{
+ ASSERT(m_cueContainer);
+
+ if (m_cueContainer->contains(displayBox.ptr()))
+ return;
+
+ m_cueContainer->appendChild(displayBox);
+ displayLastTextTrackCueBox();
+}
+
+void VTTRegion::displayLastTextTrackCueBox()
+{
+ ASSERT(m_cueContainer);
+
+ // The container needs to be rendered, if it is not empty and the region is not currently scrolling.
+ if (!m_cueContainer->renderer() || !m_cueContainer->hasChildNodes() || m_scrollTimer.isActive())
+ return;
+
+ // If it's a scrolling region, add the scrolling class.
+ if (isScrollingRegion())
+ m_cueContainer->classList().add(textTrackCueContainerScrollingClass());
+
+ float regionBottom = m_regionDisplayTree->getBoundingClientRect()->bottom();
+
+ // Find first cue that is not entirely displayed and scroll it upwards.
+ for (auto& child : childrenOfType<Element>(*m_cueContainer)) {
+ Ref<ClientRect> rect = child.getBoundingClientRect();
+ float childTop = rect->top();
+ float childBottom = rect->bottom();
+
+ if (regionBottom >= childBottom)
+ continue;
+
+ float height = childBottom - childTop;
+
+ m_currentTop -= std::min(height, childBottom - regionBottom);
+ m_cueContainer->setInlineStyleProperty(CSSPropertyTop, m_currentTop, CSSPrimitiveValue::CSS_PX);
+
+ startTimer();
+ break;
+ }
+}
+
+void VTTRegion::willRemoveTextTrackCueBox(VTTCueBox* box)
+{
+ LOG(Media, "VTTRegion::willRemoveTextTrackCueBox");
+ ASSERT(m_cueContainer->contains(box));
+
+ double boxHeight = box->getBoundingClientRect()->bottom() - box->getBoundingClientRect()->top();
+
+ m_cueContainer->classList().remove(textTrackCueContainerScrollingClass());
+
+ m_currentTop += boxHeight;
+ m_cueContainer->setInlineStyleProperty(CSSPropertyTop, m_currentTop, CSSPrimitiveValue::CSS_PX);
+}
+
+HTMLDivElement& VTTRegion::getDisplayTree()
+{
+ if (!m_regionDisplayTree) {
+ m_regionDisplayTree = HTMLDivElement::create(downcast<Document>(*m_scriptExecutionContext));
+ prepareRegionDisplayTree();
+ }
+
+ return *m_regionDisplayTree;
+}
+
+void VTTRegion::prepareRegionDisplayTree()
+{
+ ASSERT(m_regionDisplayTree);
+
+ // 7.2 Prepare region CSS boxes
+
+ // FIXME: Change the code below to use viewport units when
+ // http://crbug/244618 is fixed.
+
+ // Let regionWidth be the text track region width.
+ // Let width be 'regionWidth vw' ('vw' is a CSS unit)
+ m_regionDisplayTree->setInlineStyleProperty(CSSPropertyWidth, m_width, CSSPrimitiveValue::CSS_PERCENTAGE);
+
+ // Let lineHeight be '0.0533vh' ('vh' is a CSS unit) and regionHeight be
+ // the text track region height. Let height be 'lineHeight' multiplied
+ // by regionHeight.
+ double height = lineHeight * m_heightInLines;
+ m_regionDisplayTree->setInlineStyleProperty(CSSPropertyHeight, height, CSSPrimitiveValue::CSS_VH);
+
+ // Let viewportAnchorX be the x dimension of the text track region viewport
+ // anchor and regionAnchorX be the x dimension of the text track region
+ // anchor. Let leftOffset be regionAnchorX multiplied by width divided by
+ // 100.0. Let left be leftOffset subtracted from 'viewportAnchorX vw'.
+ double leftOffset = m_regionAnchor.x() * m_width / 100;
+ m_regionDisplayTree->setInlineStyleProperty(CSSPropertyLeft, m_viewportAnchor.x() - leftOffset, CSSPrimitiveValue::CSS_PERCENTAGE);
+
+ // Let viewportAnchorY be the y dimension of the text track region viewport
+ // anchor and regionAnchorY be the y dimension of the text track region
+ // anchor. Let topOffset be regionAnchorY multiplied by height divided by
+ // 100.0. Let top be topOffset subtracted from 'viewportAnchorY vh'.
+ double topOffset = m_regionAnchor.y() * height / 100;
+ m_regionDisplayTree->setInlineStyleProperty(CSSPropertyTop, m_viewportAnchor.y() - topOffset, CSSPrimitiveValue::CSS_PERCENTAGE);
+
+ // The cue container is used to wrap the cues and it is the object which is
+ // gradually scrolled out as multiple cues are appended to the region.
+ m_cueContainer = HTMLDivElement::create(downcast<Document>(*m_scriptExecutionContext));
+ m_cueContainer->setInlineStyleProperty(CSSPropertyTop, 0.0f, CSSPrimitiveValue::CSS_PX);
+
+ m_cueContainer->setPseudo(textTrackCueContainerShadowPseudoId());
+ m_regionDisplayTree->appendChild(*m_cueContainer);
+
+ // 7.5 Every WebVTT region object is initialised with the following CSS
+ m_regionDisplayTree->setPseudo(textTrackRegionShadowPseudoId());
+}
+
+void VTTRegion::startTimer()
+{
+ LOG(Media, "VTTRegion::startTimer");
+
+ if (m_scrollTimer.isActive())
+ return;
+
+ double duration = isScrollingRegion() ? scrollTime : 0;
+ m_scrollTimer.startOneShot(duration);
+}
+
+void VTTRegion::stopTimer()
+{
+ LOG(Media, "VTTRegion::stopTimer");
+
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+}
+
+void VTTRegion::scrollTimerFired()
+{
+ LOG(Media, "VTTRegion::scrollTimerFired");
+
+ stopTimer();
+ displayLastTextTrackCueBox();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/TextTrackRegion.h b/Source/WebCore/html/track/VTTRegion.h
index 01b64ce4d..99c3e818e 100644
--- a/Source/WebCore/html/track/TextTrackRegion.h
+++ b/Source/WebCore/html/track/VTTRegion.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,26 +29,28 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrackRegion_h
-#define TextTrackRegion_h
+#pragma once
-#if ENABLE(VIDEO_TRACK) && ENABLE(WEBVTT_REGIONS)
+#if ENABLE(VIDEO_TRACK)
+#include "ContextDestructionObserver.h"
#include "FloatPoint.h"
#include "TextTrack.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/RefCounted.h>
namespace WebCore {
-class TextTrackRegion : public RefCounted<TextTrackRegion> {
+class HTMLDivElement;
+class VTTCueBox;
+class VTTScanner;
+
+class VTTRegion final : public RefCounted<VTTRegion>, public ContextDestructionObserver {
public:
- static PassRefPtr<TextTrackRegion> create()
+ static Ref<VTTRegion> create(ScriptExecutionContext& context)
{
- return adoptRef(new TextTrackRegion());
+ return adoptRef(*new VTTRegion(context));
}
- virtual ~TextTrackRegion();
+ virtual ~VTTRegion();
TextTrack* track() const { return m_track; }
void setTrack(TextTrack*);
@@ -56,33 +59,48 @@ public:
void setId(const String&);
double width() const { return m_width; }
- void setWidth(double, ExceptionCode&);
+ ExceptionOr<void> setWidth(double);
- long height() const { return m_heightInLines; }
- void setHeight(long, ExceptionCode&);
+ int height() const { return m_heightInLines; }
+ ExceptionOr<void> setHeight(int);
double regionAnchorX() const { return m_regionAnchor.x(); }
- void setRegionAnchorX(double, ExceptionCode&);
+ ExceptionOr<void> setRegionAnchorX(double);
double regionAnchorY() const { return m_regionAnchor.y(); }
- void setRegionAnchorY(double, ExceptionCode&);
+ ExceptionOr<void> setRegionAnchorY(double);
double viewportAnchorX() const { return m_viewportAnchor.x(); }
- void setViewportAnchorX(double, ExceptionCode&);
+ ExceptionOr<void> setViewportAnchorX(double);
double viewportAnchorY() const { return m_viewportAnchor.y(); }
- void setViewportAnchorY(double, ExceptionCode&);
+ ExceptionOr<void> setViewportAnchorY(double);
- const AtomicString scroll() const;
- void setScroll(const AtomicString&, ExceptionCode&);
+ const AtomicString& scroll() const;
+ ExceptionOr<void> setScroll(const AtomicString&);
- void updateParametersFromRegion(TextTrackRegion*);
+ void updateParametersFromRegion(const VTTRegion&);
const String& regionSettings() const { return m_settings; }
void setRegionSettings(const String&);
+ bool isScrollingRegion() { return m_scroll; }
+
+ HTMLDivElement& getDisplayTree();
+
+ void appendTextTrackCueBox(Ref<VTTCueBox>&&);
+ void displayLastTextTrackCueBox();
+ void willRemoveTextTrackCueBox(VTTCueBox*);
+
private:
- TextTrackRegion();
+ VTTRegion(ScriptExecutionContext&);
+
+ void prepareRegionDisplayTree();
+
+ // The timer is needed to continue processing when cue scrolling ended.
+ void startTimer();
+ void stopTimer();
+ void scrollTimerFired();
enum RegionSetting {
None,
@@ -94,30 +112,47 @@ private:
Scroll
};
- RegionSetting getSettingFromString(const String&);
+ RegionSetting scanSettingName(VTTScanner&);
- void parseSettingValue(RegionSetting, const String&);
- void parseSetting(const String&, unsigned*);
+ void parseSettingValue(RegionSetting, VTTScanner&);
+
+ static const AtomicString& textTrackCueContainerShadowPseudoId();
+ static const AtomicString& textTrackCueContainerScrollingClass();
+ static const AtomicString& textTrackRegionShadowPseudoId();
String m_id;
String m_settings;
- double m_width;
- unsigned m_heightInLines;
+ double m_width { 100 };
+ unsigned m_heightInLines { 3 };
+
+ FloatPoint m_regionAnchor { 0, 100 };
+ FloatPoint m_viewportAnchor { 0, 100 };
- FloatPoint m_regionAnchor;
- FloatPoint m_viewportAnchor;
+ bool m_scroll { false };
- bool m_scroll;
+ // The cue container is the container that is scrolled up to obtain the
+ // effect of scrolling cues when this is enabled for the regions.
+ RefPtr<HTMLDivElement> m_cueContainer;
+ RefPtr<HTMLDivElement> m_regionDisplayTree;
// The member variable track can be a raw pointer as it will never
// reference a destroyed TextTrack, as this member variable
// is cleared in the TextTrack destructor and it is generally
// set/reset within the addRegion and removeRegion methods.
- TextTrack* m_track;
+ TextTrack* m_track { nullptr };
+
+ // Keep track of the current numeric value of the css "top" property.
+ double m_currentTop { 0 };
+
+ // The timer is used to display the next cue line after the current one has
+ // been displayed. It's main use is for scrolling regions and it triggers as
+ // soon as the animation for rolling out one line has finished, but
+ // currently it is used also for non-scrolling regions to use a single
+ // code path.
+ Timer m_scrollTimer;
};
} // namespace WebCore
#endif
-#endif
diff --git a/Source/WebCore/html/track/TextTrackRegion.idl b/Source/WebCore/html/track/VTTRegion.idl
index f8f23b27b..7a24bc2ac 100644
--- a/Source/WebCore/html/track/TextTrackRegion.idl
+++ b/Source/WebCore/html/track/VTTRegion.idl
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,19 +25,19 @@
*/
[
- Conditional=VIDEO_TRACK & WEBVTT_REGIONS,
+ Conditional=VIDEO_TRACK,
+ Constructor(),
+ ConstructorCallWith=ScriptExecutionContext,
JSGenerateToNativeObject,
- Constructor()
-] interface TextTrackRegion {
+] interface VTTRegion {
readonly attribute TextTrack track;
attribute DOMString id;
- [SetterRaisesException] attribute double width;
- [SetterRaisesException] attribute long height;
- [SetterRaisesException] attribute double regionAnchorX;
- [SetterRaisesException] attribute double regionAnchorY;
- [SetterRaisesException] attribute double viewportAnchorX;
- [SetterRaisesException] attribute double viewportAnchorY;
- [SetterRaisesException] attribute DOMString scroll;
+ [SetterMayThrowException] attribute double width;
+ [SetterMayThrowException] attribute long height;
+ [SetterMayThrowException] attribute double regionAnchorX;
+ [SetterMayThrowException] attribute double regionAnchorY;
+ [SetterMayThrowException] attribute double viewportAnchorX;
+ [SetterMayThrowException] attribute double viewportAnchorY;
+ [SetterMayThrowException] attribute DOMString scroll;
};
-
diff --git a/Source/WebCore/html/track/VTTRegionList.cpp b/Source/WebCore/html/track/VTTRegionList.cpp
new file mode 100644
index 000000000..cfc16223f
--- /dev/null
+++ b/Source/WebCore/html/track/VTTRegionList.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "VTTRegionList.h"
+
+#if ENABLE(VIDEO_TRACK)
+
+namespace WebCore {
+
+VTTRegion* VTTRegionList::item(unsigned index) const
+{
+ if (index >= m_vector.size())
+ return nullptr;
+ return const_cast<VTTRegion*>(m_vector[index].ptr());
+}
+
+VTTRegion* VTTRegionList::getRegionById(const String& id) const
+{
+ // FIXME: Why is this special case needed?
+ if (id.isEmpty())
+ return nullptr;
+ for (auto& region : m_vector) {
+ if (region->id() == id)
+ return const_cast<VTTRegion*>(region.ptr());
+ }
+ return nullptr;
+}
+
+void VTTRegionList::add(Ref<VTTRegion>&& region)
+{
+ m_vector.append(WTFMove(region));
+}
+
+void VTTRegionList::remove(VTTRegion& region)
+{
+ for (unsigned i = 0, size = m_vector.size(); i < size; ++i) {
+ if (m_vector[i].ptr() == &region) {
+ m_vector.remove(i);
+ return;
+ }
+ }
+ ASSERT_NOT_REACHED();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/TextTrackRegionList.h b/Source/WebCore/html/track/VTTRegionList.h
index 070e3e56e..7f9fd55dc 100644
--- a/Source/WebCore/html/track/TextTrackRegionList.h
+++ b/Source/WebCore/html/track/VTTRegionList.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,43 +24,48 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrackRegionList_h
-#define TextTrackRegionList_h
+#pragma once
-#if ENABLE(VIDEO_TRACK) && ENABLE(WEBVTT_REGIONS)
+#if ENABLE(VIDEO_TRACK)
-#include "TextTrackRegion.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
+#include "VTTRegion.h"
namespace WebCore {
-class TextTrackRegionList : public RefCounted<TextTrackRegionList> {
+class VTTRegionList : public RefCounted<VTTRegionList> {
public:
- static PassRefPtr<TextTrackRegionList> create()
- {
- return adoptRef(new TextTrackRegionList());
- }
+ static Ref<VTTRegionList> create();
- ~TextTrackRegionList() { }
+ unsigned length() const;
+ VTTRegion* item(unsigned index) const;
+ VTTRegion* getRegionById(const String&) const;
- unsigned long length() const;
-
- TextTrackRegion* item(unsigned index) const;
- TextTrackRegion* getRegionById(const String&) const;
-
- void add(PassRefPtr<TextTrackRegion>);
- bool remove(TextTrackRegion*);
+ void add(Ref<VTTRegion>&&);
+ void remove(VTTRegion&);
private:
- TextTrackRegionList();
+ VTTRegionList() = default;
+
void clear();
- Vector<RefPtr<TextTrackRegion> > m_list;
+ Vector<Ref<VTTRegion>> m_vector;
};
+inline Ref<VTTRegionList> VTTRegionList::create()
+{
+ return adoptRef(*new VTTRegionList);
+}
+
+inline unsigned VTTRegionList::length() const
+{
+ return m_vector.size();
+}
+
+inline void VTTRegionList::clear()
+{
+ m_vector.clear();
+}
+
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/TextTrackRegionList.idl b/Source/WebCore/html/track/VTTRegionList.idl
index 31a0519d1..8431d8b51 100644
--- a/Source/WebCore/html/track/TextTrackRegionList.idl
+++ b/Source/WebCore/html/track/VTTRegionList.idl
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,12 +25,11 @@
*/
[
- NoInterfaceObject,
- Conditional=VIDEO_TRACK & WEBVTT_REGIONS,
+ Conditional=VIDEO_TRACK,
ImplementationLacksVTable,
-] interface TextTrackRegionList {
+ NoInterfaceObject,
+] interface VTTRegionList {
readonly attribute unsigned long length;
- getter TextTrackRegion item(unsigned long index);
- TextTrackRegion getRegionById(DOMString id);
+ getter VTTRegion? item(unsigned long index);
+ VTTRegion? getRegionById(DOMString id);
};
-
diff --git a/Source/WebCore/html/track/VTTScanner.cpp b/Source/WebCore/html/track/VTTScanner.cpp
new file mode 100644
index 000000000..5fd4d060d
--- /dev/null
+++ b/Source/WebCore/html/track/VTTScanner.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2013, Opera Software ASA. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Opera Software ASA nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "VTTScanner.h"
+
+namespace WebCore {
+
+VTTScanner::VTTScanner(const String& line)
+ : m_is8Bit(line.is8Bit())
+{
+ if (m_is8Bit) {
+ m_data.characters8 = line.characters8();
+ m_end.characters8 = m_data.characters8 + line.length();
+ } else {
+ m_data.characters16 = line.characters16();
+ m_end.characters16 = m_data.characters16 + line.length();
+ }
+}
+
+bool VTTScanner::scan(char c)
+{
+ if (!match(c))
+ return false;
+ advance();
+ return true;
+}
+
+bool VTTScanner::scan(const LChar* characters, size_t charactersCount)
+{
+ unsigned matchLength = m_is8Bit ? m_end.characters8 - m_data.characters8 : m_end.characters16 - m_data.characters16;
+ if (matchLength < charactersCount)
+ return false;
+ bool matched;
+ if (m_is8Bit)
+ matched = WTF::equal(m_data.characters8, characters, charactersCount);
+ else
+ matched = WTF::equal(m_data.characters16, characters, charactersCount);
+ if (matched)
+ advance(charactersCount);
+ return matched;
+}
+
+bool VTTScanner::scanRun(const Run& run, const String& toMatch)
+{
+ ASSERT(run.start() == position());
+ ASSERT(run.start() <= end());
+ ASSERT(run.end() >= run.start());
+ ASSERT(run.end() <= end());
+ size_t matchLength = run.length();
+ if (toMatch.length() > matchLength)
+ return false;
+ bool matched;
+ if (m_is8Bit)
+ matched = WTF::equal(toMatch.impl(), m_data.characters8, matchLength);
+ else
+ matched = WTF::equal(toMatch.impl(), m_data.characters16, matchLength);
+ if (matched)
+ seekTo(run.end());
+ return matched;
+}
+
+void VTTScanner::skipRun(const Run& run)
+{
+ ASSERT(run.start() <= end());
+ ASSERT(run.end() >= run.start());
+ ASSERT(run.end() <= end());
+ seekTo(run.end());
+}
+
+String VTTScanner::extractString(const Run& run)
+{
+ ASSERT(run.start() == position());
+ ASSERT(run.start() <= end());
+ ASSERT(run.end() >= run.start());
+ ASSERT(run.end() <= end());
+ String s;
+ if (m_is8Bit)
+ s = String(m_data.characters8, run.length());
+ else
+ s = String(m_data.characters16, run.length());
+ seekTo(run.end());
+ return s;
+}
+
+String VTTScanner::restOfInputAsString()
+{
+ Run rest(position(), end(), m_is8Bit);
+ return extractString(rest);
+}
+
+unsigned VTTScanner::scanDigits(int& number)
+{
+ Run runOfDigits = collectWhile<isASCIIDigit>();
+ if (runOfDigits.isEmpty()) {
+ number = 0;
+ return 0;
+ }
+ bool validNumber;
+ size_t numDigits = runOfDigits.length();
+ if (m_is8Bit)
+ number = charactersToIntStrict(m_data.characters8, numDigits, &validNumber);
+ else
+ number = charactersToIntStrict(m_data.characters16, numDigits, &validNumber);
+
+ // Since we know that scanDigits only scanned valid (ASCII) digits (and
+ // hence that's what got passed to charactersToInt()), the remaining
+ // failure mode for charactersToInt() is overflow, so if |validNumber| is
+ // not true, then set |number| to the maximum int value.
+ if (!validNumber)
+ number = std::numeric_limits<int>::max();
+ // Consume the digits.
+ seekTo(runOfDigits.end());
+ return numDigits;
+}
+
+bool VTTScanner::scanFloat(float& number, bool* isNegative)
+{
+ bool negative = scan('-');
+ Run integerRun = collectWhile<isASCIIDigit>();
+
+ seekTo(integerRun.end());
+ Run decimalRun(position(), position(), m_is8Bit);
+ if (scan('.')) {
+ decimalRun = collectWhile<isASCIIDigit>();
+ seekTo(decimalRun.end());
+ }
+
+ // At least one digit required.
+ if (integerRun.isEmpty() && decimalRun.isEmpty()) {
+ // Restore to starting position.
+ seekTo(integerRun.start());
+ return false;
+ }
+
+ size_t lengthOfFloat = Run(integerRun.start(), position(), m_is8Bit).length();
+ bool validNumber;
+ if (m_is8Bit)
+ number = charactersToFloat(integerRun.start(), lengthOfFloat, &validNumber);
+ else
+ number = charactersToFloat(reinterpret_cast<const UChar*>(integerRun.start()), lengthOfFloat, &validNumber);
+
+ if (!validNumber)
+ number = std::numeric_limits<float>::max();
+ else if (negative)
+ number = -number;
+
+ if (isNegative)
+ *isNegative = negative;
+
+ return true;
+}
+
+}
diff --git a/Source/WebCore/html/track/VTTScanner.h b/Source/WebCore/html/track/VTTScanner.h
new file mode 100644
index 000000000..c4ae32a01
--- /dev/null
+++ b/Source/WebCore/html/track/VTTScanner.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2013, Opera Software ASA. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Opera Software ASA nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ParsingUtilities.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+// Helper class for "scanning" an input string and performing parsing of
+// "micro-syntax"-like constructs.
+//
+// There's two primary operations: match and scan.
+//
+// The 'match' operation matches an explicitly or implicitly specified sequence
+// against the characters ahead of the current input pointer, and returns true
+// if the sequence can be matched.
+//
+// The 'scan' operation performs a 'match', and if the match is successful it
+// advance the input pointer past the matched sequence.
+class VTTScanner {
+ WTF_MAKE_NONCOPYABLE(VTTScanner);
+public:
+ explicit VTTScanner(const String& line);
+
+ typedef const LChar* Position;
+
+ class Run {
+ public:
+ Run(Position start, Position end, bool is8Bit)
+ : m_start(start), m_end(end), m_is8Bit(is8Bit) { }
+
+ Position start() const { return m_start; }
+ Position end() const { return m_end; }
+
+ bool isEmpty() const { return m_start == m_end; }
+ size_t length() const;
+
+ private:
+ Position m_start;
+ Position m_end;
+ bool m_is8Bit;
+ };
+
+ // Check if the input pointer points at the specified position.
+ bool isAt(Position checkPosition) const { return position() == checkPosition; }
+ // Check if the input pointer points at the end of the input.
+ bool isAtEnd() const { return position() == end(); }
+ // Match the character |c| against the character at the input pointer (~lookahead).
+ bool match(char c) const { return !isAtEnd() && currentChar() == c; }
+ // Scan the character |c|.
+ bool scan(char);
+ // Scan the first |charactersCount| characters of the string |characters|.
+ bool scan(const LChar* characters, size_t charactersCount);
+
+ // Scan the literal |characters|.
+ template<unsigned charactersCount>
+ bool scan(const char (&characters)[charactersCount]);
+
+ // Skip (advance the input pointer) as long as the specified
+ // |characterPredicate| returns true, and the input pointer is not passed
+ // the end of the input.
+ template<bool characterPredicate(UChar)>
+ void skipWhile();
+
+ // Like skipWhile, but using a negated predicate.
+ template<bool characterPredicate(UChar)>
+ void skipUntil();
+
+ // Return the run of characters for which the specified
+ // |characterPredicate| returns true. The start of the run will be the
+ // current input pointer.
+ template<bool characterPredicate(UChar)>
+ Run collectWhile();
+
+ // Like collectWhile, but using a negated predicate.
+ template<bool characterPredicate(UChar)>
+ Run collectUntil();
+
+ // Scan the string |toMatch|, using the specified |run| as the sequence to
+ // match against.
+ bool scanRun(const Run&, const String& toMatch);
+
+ // Skip to the end of the specified |run|.
+ void skipRun(const Run&);
+
+ // Return the String made up of the characters in |run|, and advance the
+ // input pointer to the end of the run.
+ String extractString(const Run&);
+
+ // Return a String constructed from the rest of the input (between input
+ // pointer and end of input), and advance the input pointer accordingly.
+ String restOfInputAsString();
+
+ // Scan a set of ASCII digits from the input. Return the number of digits
+ // scanned, and set |number| to the computed value. If the digits make up a
+ // number that does not fit the 'int' type, |number| is set to INT_MAX.
+ // Note: Does not handle sign.
+ unsigned scanDigits(int& number);
+
+ // Scan a floating point value on one of the forms: \d+\.? \d+\.\d+ \.\d+
+ bool scanFloat(float& number, bool* isNegative = nullptr);
+
+protected:
+ Position position() const { return m_data.characters8; }
+ Position end() const { return m_end.characters8; }
+ void seekTo(Position);
+ UChar currentChar() const;
+ void advance(unsigned amount = 1);
+ // Adapt a UChar-predicate to an LChar-predicate.
+ // (For use with skipWhile/Until from ParsingUtilities.h).
+ template<bool characterPredicate(UChar)>
+ static inline bool LCharPredicateAdapter(LChar c) { return characterPredicate(c); }
+ union {
+ const LChar* characters8;
+ const UChar* characters16;
+ } m_data;
+ union {
+ const LChar* characters8;
+ const UChar* characters16;
+ } m_end;
+ bool m_is8Bit;
+};
+
+inline size_t VTTScanner::Run::length() const
+{
+ if (m_is8Bit)
+ return m_end - m_start;
+ return reinterpret_cast<const UChar*>(m_end) - reinterpret_cast<const UChar*>(m_start);
+}
+
+template<unsigned charactersCount>
+inline bool VTTScanner::scan(const char (&characters)[charactersCount])
+{
+ return scan(reinterpret_cast<const LChar*>(characters), charactersCount - 1);
+}
+
+template<bool characterPredicate(UChar)>
+inline void VTTScanner::skipWhile()
+{
+ if (m_is8Bit)
+ WebCore::skipWhile<LChar, LCharPredicateAdapter<characterPredicate> >(m_data.characters8, m_end.characters8);
+ else
+ WebCore::skipWhile<UChar, characterPredicate>(m_data.characters16, m_end.characters16);
+}
+
+template<bool characterPredicate(UChar)>
+inline void VTTScanner::skipUntil()
+{
+ if (m_is8Bit)
+ WebCore::skipUntil<LChar, LCharPredicateAdapter<characterPredicate> >(m_data.characters8, m_end.characters8);
+ else
+ WebCore::skipUntil<UChar, characterPredicate>(m_data.characters16, m_end.characters16);
+}
+
+template<bool characterPredicate(UChar)>
+inline VTTScanner::Run VTTScanner::collectWhile()
+{
+ if (m_is8Bit) {
+ const LChar* current = m_data.characters8;
+ WebCore::skipWhile<LChar, LCharPredicateAdapter<characterPredicate> >(current, m_end.characters8);
+ return Run(position(), current, m_is8Bit);
+ }
+ const UChar* current = m_data.characters16;
+ WebCore::skipWhile<UChar, characterPredicate>(current, m_end.characters16);
+ return Run(position(), reinterpret_cast<Position>(current), m_is8Bit);
+}
+
+template<bool characterPredicate(UChar)>
+inline VTTScanner::Run VTTScanner::collectUntil()
+{
+ if (m_is8Bit) {
+ const LChar* current = m_data.characters8;
+ WebCore::skipUntil<LChar, LCharPredicateAdapter<characterPredicate> >(current, m_end.characters8);
+ return Run(position(), current, m_is8Bit);
+ }
+ const UChar* current = m_data.characters16;
+ WebCore::skipUntil<UChar, characterPredicate>(current, m_end.characters16);
+ return Run(position(), reinterpret_cast<Position>(current), m_is8Bit);
+}
+
+inline void VTTScanner::seekTo(Position position)
+{
+ ASSERT(position <= end());
+ m_data.characters8 = position;
+}
+
+inline UChar VTTScanner::currentChar() const
+{
+ ASSERT(position() < end());
+ return m_is8Bit ? *m_data.characters8 : *m_data.characters16;
+}
+
+inline void VTTScanner::advance(unsigned amount)
+{
+ ASSERT(position() < end());
+ if (m_is8Bit)
+ m_data.characters8 += amount;
+ else
+ m_data.characters16 += amount;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/track/VideoTrack.cpp b/Source/WebCore/html/track/VideoTrack.cpp
index c0480fee2..f662dae3a 100644
--- a/Source/WebCore/html/track/VideoTrack.cpp
+++ b/Source/WebCore/html/track/VideoTrack.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -30,12 +30,10 @@
*/
#include "config.h"
+#include "VideoTrack.h"
#if ENABLE(VIDEO_TRACK)
-#include "VideoTrack.h"
-
-#include "Event.h"
#include "HTMLMediaElement.h"
#include "VideoTrackList.h"
@@ -47,97 +45,76 @@ namespace WebCore {
const AtomicString& VideoTrack::alternativeKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, alternative, ("alternative", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> alternative("alternative", AtomicString::ConstructFromLiteral);
return alternative;
}
const AtomicString& VideoTrack::captionsKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, captions, ("captions", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> captions("captions", AtomicString::ConstructFromLiteral);
return captions;
}
const AtomicString& VideoTrack::mainKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, captions, ("main", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> captions("main", AtomicString::ConstructFromLiteral);
return captions;
}
const AtomicString& VideoTrack::signKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, sign, ("sign", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> sign("sign", AtomicString::ConstructFromLiteral);
return sign;
}
const AtomicString& VideoTrack::subtitlesKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, subtitles, ("subtitles", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> subtitles("subtitles", AtomicString::ConstructFromLiteral);
return subtitles;
}
const AtomicString& VideoTrack::commentaryKeyword()
{
- DEFINE_STATIC_LOCAL(const AtomicString, commentary, ("commentary", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<const AtomicString> commentary("commentary", AtomicString::ConstructFromLiteral);
return commentary;
}
-VideoTrack::VideoTrack(VideoTrackClient* client, PassRefPtr<VideoTrackPrivate> trackPrivate)
- : TrackBase(TrackBase::VideoTrack, trackPrivate->id(), trackPrivate->label(), trackPrivate->language())
- , m_selected(trackPrivate->selected())
- , m_client(client)
+VideoTrack::VideoTrack(VideoTrackClient& client, VideoTrackPrivate& trackPrivate)
+ : MediaTrackBase(MediaTrackBase::VideoTrack, trackPrivate.id(), trackPrivate.label(), trackPrivate.language())
+ , m_selected(trackPrivate.selected())
+ , m_client(&client)
, m_private(trackPrivate)
{
m_private->setClient(this);
-
- switch (m_private->kind()) {
- case VideoTrackPrivate::Alternative:
- setKindInternal(VideoTrack::alternativeKeyword());
- break;
- case VideoTrackPrivate::Captions:
- setKindInternal(VideoTrack::captionsKeyword());
- break;
- case VideoTrackPrivate::Main:
- setKindInternal(VideoTrack::mainKeyword());
- break;
- case VideoTrackPrivate::Sign:
- setKindInternal(VideoTrack::signKeyword());
- break;
- case VideoTrackPrivate::Subtitles:
- setKindInternal(VideoTrack::subtitlesKeyword());
- break;
- case VideoTrackPrivate::Commentary:
- setKindInternal(VideoTrack::commentaryKeyword());
- break;
- case VideoTrackPrivate::None:
- setKindInternal(emptyString());
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
+ updateKindFromPrivate();
}
VideoTrack::~VideoTrack()
{
- m_private->setClient(0);
+ m_private->setClient(nullptr);
}
-bool VideoTrack::isValidKind(const AtomicString& value) const
+void VideoTrack::setPrivate(VideoTrackPrivate& trackPrivate)
{
- if (value == alternativeKeyword())
- return true;
- if (value == captionsKeyword())
- return true;
- if (value == mainKeyword())
- return true;
- if (value == signKeyword())
- return true;
- if (value == subtitlesKeyword())
- return true;
- if (value == commentaryKeyword())
- return true;
+ if (m_private.ptr() == &trackPrivate)
+ return;
- return false;
+ m_private->setClient(nullptr);
+ m_private = trackPrivate;
+ m_private->setClient(this);
+
+ m_private->setSelected(m_selected);
+ updateKindFromPrivate();
+}
+
+bool VideoTrack::isValidKind(const AtomicString& value) const
+{
+ return value == alternativeKeyword()
+ || value == commentaryKeyword()
+ || value == captionsKeyword()
+ || value == mainKeyword()
+ || value == signKeyword()
+ || value == subtitlesKeyword();
}
void VideoTrack::setSelected(const bool selected)
@@ -149,46 +126,44 @@ void VideoTrack::setSelected(const bool selected)
m_private->setSelected(selected);
if (m_client)
- m_client->videoTrackSelectedChanged(this);
+ m_client->videoTrackSelectedChanged(*this);
}
size_t VideoTrack::inbandTrackIndex()
{
- ASSERT(m_private);
return m_private->trackIndex();
}
-void VideoTrack::selectedChanged(VideoTrackPrivate* trackPrivate, bool selected)
+void VideoTrack::selectedChanged(bool selected)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setSelected(selected);
}
-void VideoTrack::idChanged(TrackPrivateBase* trackPrivate, const String& id)
+void VideoTrack::idChanged(const AtomicString& id)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setId(id);
}
-void VideoTrack::labelChanged(TrackPrivateBase* trackPrivate, const String& label)
+void VideoTrack::labelChanged(const AtomicString& label)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setLabel(label);
}
-void VideoTrack::languageChanged(TrackPrivateBase* trackPrivate, const String& language)
+void VideoTrack::languageChanged(const AtomicString& language)
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
setLanguage(language);
}
-void VideoTrack::willRemove(TrackPrivateBase* trackPrivate)
+void VideoTrack::willRemove()
{
- ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
- mediaElement()->removeVideoTrack(this);
+ auto* element = mediaElement();
+ if (!element)
+ return;
+ element->removeVideoTrack(*this);
}
#if ENABLE(MEDIA_SOURCE)
+
void VideoTrack::setKind(const AtomicString& kind)
{
// 10.1 kind, on setting:
@@ -203,11 +178,11 @@ void VideoTrack::setKind(const AtomicString& kind)
// 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
// event named change at sourceBuffer.videoTracks.
if (m_sourceBuffer)
- m_sourceBuffer->videoTracks()->scheduleChangeEvent();
+ m_sourceBuffer->videoTracks().scheduleChangeEvent();
// 4. Queue a task to fire a simple event named change at the VideoTrackList object referenced by
// the videoTracks attribute on the HTMLMediaElement.
- mediaElement()->videoTracks()->scheduleChangeEvent();
+ mediaElement()->videoTracks().scheduleChangeEvent();
}
void VideoTrack::setLanguage(const AtomicString& language)
@@ -215,22 +190,52 @@ void VideoTrack::setLanguage(const AtomicString& language)
// 10.1 language, on setting:
// 1. If the value being assigned to this attribute is not an empty string or a BCP 47 language
// tag[BCP47], then abort these steps.
- // FIXME(123926): Validate the BCP47-ness of langague.
+ // BCP 47 validation is done in TrackBase::setLanguage() which is
+ // shared between all tracks that support setting language.
// 2. Update this attribute to the new value.
- TrackBase::setLanguage(language);
+ MediaTrackBase::setLanguage(language);
// 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
// event named change at sourceBuffer.videoTracks.
if (m_sourceBuffer)
- m_sourceBuffer->videoTracks()->scheduleChangeEvent();
+ m_sourceBuffer->videoTracks().scheduleChangeEvent();
// 4. Queue a task to fire a simple event named change at the VideoTrackList object referenced by
// the videoTracks attribute on the HTMLMediaElement.
- mediaElement()->videoTracks()->scheduleChangeEvent();
+ mediaElement()->videoTracks().scheduleChangeEvent();
}
+
#endif
+void VideoTrack::updateKindFromPrivate()
+{
+ switch (m_private->kind()) {
+ case VideoTrackPrivate::Alternative:
+ setKindInternal(VideoTrack::alternativeKeyword());
+ return;
+ case VideoTrackPrivate::Captions:
+ setKindInternal(VideoTrack::captionsKeyword());
+ return;
+ case VideoTrackPrivate::Main:
+ setKindInternal(VideoTrack::mainKeyword());
+ return;
+ case VideoTrackPrivate::Sign:
+ setKindInternal(VideoTrack::signKeyword());
+ return;
+ case VideoTrackPrivate::Subtitles:
+ setKindInternal(VideoTrack::subtitlesKeyword());
+ return;
+ case VideoTrackPrivate::Commentary:
+ setKindInternal(VideoTrack::commentaryKeyword());
+ return;
+ case VideoTrackPrivate::None:
+ setKindInternal(emptyString());
+ return;
+ }
+ ASSERT_NOT_REACHED();
+}
+
} // namespace WebCore
#endif
diff --git a/Source/WebCore/html/track/VideoTrack.h b/Source/WebCore/html/track/VideoTrack.h
index 6343a0743..ebee829e1 100644
--- a/Source/WebCore/html/track/VideoTrack.h
+++ b/Source/WebCore/html/track/VideoTrack.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,17 +24,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef VideoTrack_h
-#define VideoTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
-#include "ExceptionCode.h"
#include "TrackBase.h"
#include "VideoTrackPrivate.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -44,14 +39,14 @@ class VideoTrack;
class VideoTrackClient {
public:
virtual ~VideoTrackClient() { }
- virtual void videoTrackSelectedChanged(VideoTrack*) = 0;
+ virtual void videoTrackSelectedChanged(VideoTrack&) = 0;
};
-class VideoTrack : public TrackBase, public VideoTrackPrivateClient {
+class VideoTrack final : public MediaTrackBase, private VideoTrackPrivateClient {
public:
- static PassRefPtr<VideoTrack> create(VideoTrackClient* client, PassRefPtr<VideoTrackPrivate> trackPrivate)
+ static Ref<VideoTrack> create(VideoTrackClient& client, VideoTrackPrivate& trackPrivate)
{
- return adoptRef(new VideoTrack(client, trackPrivate));
+ return adoptRef(*new VideoTrack(client, trackPrivate));
}
virtual ~VideoTrack();
@@ -61,50 +56,52 @@ public:
static const AtomicString& signKeyword();
static const AtomicString& subtitlesKeyword();
static const AtomicString& commentaryKeyword();
- virtual const AtomicString& defaultKindKeyword() const override { return emptyAtom; }
bool selected() const { return m_selected; }
virtual void setSelected(const bool);
- virtual void clearClient() override { m_client = 0; }
+ void clearClient() final { m_client = nullptr; }
VideoTrackClient* client() const { return m_client; }
size_t inbandTrackIndex();
#if ENABLE(MEDIA_SOURCE)
- virtual void setKind(const AtomicString&) override;
- virtual void setLanguage(const AtomicString&) override;
+ void setKind(const AtomicString&) final;
+ void setLanguage(const AtomicString&) final;
#endif
const MediaDescription& description() const;
-protected:
- VideoTrack(VideoTrackClient*, PassRefPtr<VideoTrackPrivate> privateTrack);
+ void setPrivate(VideoTrackPrivate&);
private:
- virtual bool isValidKind(const AtomicString&) const override;
+ VideoTrack(VideoTrackClient&, VideoTrackPrivate&);
- virtual void selectedChanged(VideoTrackPrivate*, bool) override;
- virtual void idChanged(TrackPrivateBase*, const String&) override;
- virtual void labelChanged(TrackPrivateBase*, const String&) override;
- virtual void languageChanged(TrackPrivateBase*, const String&) override;
- virtual void willRemove(TrackPrivateBase*) override;
+ bool isValidKind(const AtomicString&) const final;
- virtual bool enabled() const override { return selected(); }
+ // VideoTrackPrivateClient
+ void selectedChanged(bool) final;
+
+ // TrackPrivateBaseClient
+ void idChanged(const AtomicString&) final;
+ void labelChanged(const AtomicString&) final;
+ void languageChanged(const AtomicString&) final;
+ void willRemove() final;
+
+ bool enabled() const final { return selected(); }
+
+ void updateKindFromPrivate();
bool m_selected;
VideoTrackClient* m_client;
- RefPtr<VideoTrackPrivate> m_private;
+ Ref<VideoTrackPrivate> m_private;
};
-inline VideoTrack* toVideoTrack(TrackBase* track)
-{
- ASSERT_WITH_SECURITY_IMPLICATION(track->type() == TrackBase::VideoTrack);
- return static_cast<VideoTrack*>(track);
-}
-
} // namespace WebCore
-#endif
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::VideoTrack)
+ static bool isType(const WebCore::TrackBase& track) { return track.type() == WebCore::TrackBase::VideoTrack; }
+SPECIALIZE_TYPE_TRAITS_END()
+
#endif
diff --git a/Source/WebCore/html/track/VideoTrack.idl b/Source/WebCore/html/track/VideoTrack.idl
index 53e0da62f..5627d95e7 100644
--- a/Source/WebCore/html/track/VideoTrack.idl
+++ b/Source/WebCore/html/track/VideoTrack.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,7 +24,6 @@
*/
[
- NoInterfaceObject,
Conditional=VIDEO_TRACK,
GenerateIsReachable=ImplElementRoot,
JSCustomMarkFunction
diff --git a/Source/WebCore/html/track/VideoTrackList.cpp b/Source/WebCore/html/track/VideoTrackList.cpp
index 594ca1b3a..304c601b8 100644
--- a/Source/WebCore/html/track/VideoTrackList.cpp
+++ b/Source/WebCore/html/track/VideoTrackList.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -29,7 +29,6 @@
#include "VideoTrackList.h"
-#include "EventNames.h"
#include "VideoTrack.h"
using namespace WebCore;
@@ -43,48 +42,50 @@ VideoTrackList::~VideoTrackList()
{
}
-void VideoTrackList::append(PassRefPtr<VideoTrack> prpTrack)
+void VideoTrackList::append(Ref<VideoTrack>&& track)
{
- RefPtr<VideoTrack> track = prpTrack;
-
// Insert tracks in the media file order.
size_t index = track->inbandTrackIndex();
- m_inbandTracks.insert(index, track);
+ size_t insertionIndex;
+ for (insertionIndex = 0; insertionIndex < m_inbandTracks.size(); ++insertionIndex) {
+ auto& otherTrack = downcast<VideoTrack>(*m_inbandTracks[insertionIndex]);
+ if (otherTrack.inbandTrackIndex() > index)
+ break;
+ }
+ m_inbandTracks.insert(insertionIndex, track.ptr());
ASSERT(!track->mediaElement() || track->mediaElement() == mediaElement());
track->setMediaElement(mediaElement());
- scheduleAddTrackEvent(track.release());
+ scheduleAddTrackEvent(WTFMove(track));
}
VideoTrack* VideoTrackList::item(unsigned index) const
{
if (index < m_inbandTracks.size())
- return toVideoTrack(m_inbandTracks[index].get());
-
- return 0;
+ return downcast<VideoTrack>(m_inbandTracks[index].get());
+ return nullptr;
}
VideoTrack* VideoTrackList::getTrackById(const AtomicString& id) const
{
- for (size_t i = 0; i < length(); ++i) {
- VideoTrack* track = toVideoTrack(m_inbandTracks[i].get());
- if (track->id() == id)
- return track;
+ for (auto& inbandTracks : m_inbandTracks) {
+ auto& track = downcast<VideoTrack>(*inbandTracks);
+ if (track.id() == id)
+ return &track;
}
- return 0;
+ return nullptr;
}
-long VideoTrackList::selectedIndex() const
+int VideoTrackList::selectedIndex() const
{
// 4.8.10.10.1 AudioTrackList and VideoTrackList objects
// The VideoTrackList.selectedIndex attribute must return the index of the
// currently selected track, if any. If the VideoTrackList object does not
// currently represent any tracks, or if none of the tracks are selected,
// it must instead return −1.
- for (size_t i = 0; i < length(); ++i) {
- VideoTrack* track = toVideoTrack(m_inbandTracks[i].get());
- if (track->selected())
+ for (unsigned i = 0; i < length(); ++i) {
+ if (downcast<VideoTrack>(*m_inbandTracks[i]).selected())
return i;
}
return -1;
diff --git a/Source/WebCore/html/track/VideoTrackList.h b/Source/WebCore/html/track/VideoTrackList.h
index de7b845a1..6b5be25b4 100644
--- a/Source/WebCore/html/track/VideoTrackList.h
+++ b/Source/WebCore/html/track/VideoTrackList.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef VideoTrackList_h
-#define VideoTrackList_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
@@ -34,30 +33,28 @@ namespace WebCore {
class VideoTrack;
-class VideoTrackList : public TrackListBase {
+class VideoTrackList final : public TrackListBase {
public:
- static PassRefPtr<VideoTrackList> create(HTMLMediaElement* owner, ScriptExecutionContext* context)
+ static Ref<VideoTrackList> create(HTMLMediaElement* owner, ScriptExecutionContext* context)
{
- return adoptRef(new VideoTrackList(owner, context));
+ return adoptRef(*new VideoTrackList(owner, context));
}
- ~VideoTrackList();
+ virtual ~VideoTrackList();
VideoTrack* getTrackById(const AtomicString&) const;
- long selectedIndex() const;
+ int selectedIndex() const;
VideoTrack* item(unsigned) const;
VideoTrack* lastItem() const { return item(length() - 1); }
- void append(PassRefPtr<VideoTrack>);
+ void append(Ref<VideoTrack>&&);
// EventTarget
- virtual EventTargetInterface eventTargetInterface() const override;
+ EventTargetInterface eventTargetInterface() const override;
private:
VideoTrackList(HTMLMediaElement*, ScriptExecutionContext*);
-
};
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/VideoTrackList.idl b/Source/WebCore/html/track/VideoTrackList.idl
index 1058bd97b..9c43fcd18 100644
--- a/Source/WebCore/html/track/VideoTrackList.idl
+++ b/Source/WebCore/html/track/VideoTrackList.idl
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,26 +24,17 @@
*/
[
- NoInterfaceObject,
Conditional=VIDEO_TRACK,
GenerateIsReachable=ImplElementRoot,
- EventTarget,
JSCustomMarkFunction,
-] interface VideoTrackList {
+] interface VideoTrackList : EventTarget {
readonly attribute unsigned long length;
getter VideoTrack item(unsigned long index);
VideoTrack getTrackById(DOMString id);
+ readonly attribute long selectedIndex;
- attribute EventListener onchange;
- attribute EventListener onaddtrack;
- attribute EventListener onremovetrack;
-
- void addEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- void removeEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- [RaisesException] boolean dispatchEvent(Event evt);
+ attribute EventHandler onchange;
+ attribute EventHandler onaddtrack;
+ attribute EventHandler onremovetrack;
};
diff --git a/Source/WebCore/html/track/WebVTTElement.cpp b/Source/WebCore/html/track/WebVTTElement.cpp
index 6a76d6078..f43403269 100644
--- a/Source/WebCore/html/track/WebVTTElement.cpp
+++ b/Source/WebCore/html/track/WebVTTElement.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,26 +24,27 @@
*/
#include "config.h"
+#include "WebVTTElement.h"
#if ENABLE(VIDEO_TRACK)
-#include "WebVTTElement.h"
-
-#include "HTMLElementFactory.h"
+#include "HTMLSpanElement.h"
+#include "RubyElement.h"
+#include "RubyTextElement.h"
#include "TextTrack.h"
namespace WebCore {
static const QualifiedName& nodeTypeToTagName(WebVTTNodeType nodeType)
{
- DEFINE_STATIC_LOCAL(QualifiedName, cTag, (nullAtom, "c", nullAtom));
- DEFINE_STATIC_LOCAL(QualifiedName, vTag, (nullAtom, "v", nullAtom));
- DEFINE_STATIC_LOCAL(QualifiedName, langTag, (nullAtom, "lang", nullAtom));
- DEFINE_STATIC_LOCAL(QualifiedName, bTag, (nullAtom, "b", nullAtom));
- DEFINE_STATIC_LOCAL(QualifiedName, uTag, (nullAtom, "u", nullAtom));
- DEFINE_STATIC_LOCAL(QualifiedName, iTag, (nullAtom, "i", nullAtom));
- DEFINE_STATIC_LOCAL(QualifiedName, rubyTag, (nullAtom, "ruby", nullAtom));
- DEFINE_STATIC_LOCAL(QualifiedName, rtTag, (nullAtom, "rt", nullAtom));
+ static NeverDestroyed<QualifiedName> cTag(nullAtom, "c", nullAtom);
+ static NeverDestroyed<QualifiedName> vTag(nullAtom, "v", nullAtom);
+ static NeverDestroyed<QualifiedName> langTag(nullAtom, "lang", nullAtom);
+ static NeverDestroyed<QualifiedName> bTag(nullAtom, "b", nullAtom);
+ static NeverDestroyed<QualifiedName> uTag(nullAtom, "u", nullAtom);
+ static NeverDestroyed<QualifiedName> iTag(nullAtom, "i", nullAtom);
+ static NeverDestroyed<QualifiedName> rubyTag(nullAtom, "ruby", nullAtom);
+ static NeverDestroyed<QualifiedName> rtTag(nullAtom, "rt", nullAtom);
switch (nodeType) {
case WebVTTNodeTypeClass:
return cTag;
@@ -75,19 +76,19 @@ WebVTTElement::WebVTTElement(WebVTTNodeType nodeType, Document& document)
{
}
-PassRefPtr<WebVTTElement> WebVTTElement::create(WebVTTNodeType nodeType, Document& document)
+Ref<WebVTTElement> WebVTTElement::create(WebVTTNodeType nodeType, Document& document)
{
- return adoptRef(new WebVTTElement(nodeType, document));
+ return adoptRef(*new WebVTTElement(nodeType, document));
}
-PassRefPtr<Element> WebVTTElement::cloneElementWithoutAttributesAndChildren()
+Ref<Element> WebVTTElement::cloneElementWithoutAttributesAndChildren(Document& targetDocument)
{
- RefPtr<WebVTTElement> clone = create(static_cast<WebVTTNodeType>(m_webVTTNodeType), document());
+ Ref<WebVTTElement> clone = create(static_cast<WebVTTNodeType>(m_webVTTNodeType), targetDocument);
clone->setLanguage(m_language);
- return clone;
+ return WTFMove(clone);
}
-PassRefPtr<HTMLElement> WebVTTElement::createEquivalentHTMLElement(Document& document)
+Ref<HTMLElement> WebVTTElement::createEquivalentHTMLElement(Document& document)
{
RefPtr<HTMLElement> htmlElement;
@@ -95,31 +96,31 @@ PassRefPtr<HTMLElement> WebVTTElement::createEquivalentHTMLElement(Document& doc
case WebVTTNodeTypeClass:
case WebVTTNodeTypeLanguage:
case WebVTTNodeTypeVoice:
- htmlElement = HTMLElementFactory::createElement(HTMLNames::spanTag, document);
- htmlElement->setAttribute(HTMLNames::titleAttr, getAttribute(voiceAttributeName()));
- htmlElement->setAttribute(HTMLNames::langAttr, getAttribute(langAttributeName()));
+ htmlElement = HTMLSpanElement::create(document);
+ htmlElement->setAttributeWithoutSynchronization(HTMLNames::titleAttr, attributeWithoutSynchronization(voiceAttributeName()));
+ htmlElement->setAttributeWithoutSynchronization(HTMLNames::langAttr, attributeWithoutSynchronization(langAttributeName()));
break;
case WebVTTNodeTypeItalic:
- htmlElement = HTMLElementFactory::createElement(HTMLNames::iTag, document);
+ htmlElement = HTMLElement::create(HTMLNames::iTag, document);
break;
case WebVTTNodeTypeBold:
- htmlElement = HTMLElementFactory::createElement(HTMLNames::bTag, document);
+ htmlElement = HTMLElement::create(HTMLNames::bTag, document);
break;
case WebVTTNodeTypeUnderline:
- htmlElement = HTMLElementFactory::createElement(HTMLNames::uTag, document);
+ htmlElement = HTMLElement::create(HTMLNames::uTag, document);
break;
case WebVTTNodeTypeRuby:
- htmlElement = HTMLElementFactory::createElement(HTMLNames::rubyTag, document);
+ htmlElement = RubyElement::create(document);
break;
case WebVTTNodeTypeRubyText:
- htmlElement = HTMLElementFactory::createElement(HTMLNames::rtTag, document);
+ htmlElement = RubyTextElement::create(document);
break;
}
ASSERT(htmlElement);
if (htmlElement)
- htmlElement->setAttribute(HTMLNames::classAttr, fastGetAttribute(HTMLNames::classAttr));
- return htmlElement.release();
+ htmlElement->setAttributeWithoutSynchronization(HTMLNames::classAttr, attributeWithoutSynchronization(HTMLNames::classAttr));
+ return htmlElement.releaseNonNull();
}
} // namespace WebCore
diff --git a/Source/WebCore/html/track/WebVTTElement.h b/Source/WebCore/html/track/WebVTTElement.h
index f49412c26..a08f42410 100644
--- a/Source/WebCore/html/track/WebVTTElement.h
+++ b/Source/WebCore/html/track/WebVTTElement.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,9 +23,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#pragma once
+
#if ENABLE(VIDEO_TRACK)
#include "HTMLElement.h"
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
@@ -43,10 +46,10 @@ enum WebVTTNodeType {
class WebVTTElement final : public Element {
public:
- static PassRefPtr<WebVTTElement> create(const WebVTTNodeType, Document&);
- PassRefPtr<HTMLElement> createEquivalentHTMLElement(Document&);
+ static Ref<WebVTTElement> create(const WebVTTNodeType, Document&);
+ Ref<HTMLElement> createEquivalentHTMLElement(Document&);
- virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() override;
+ Ref<Element> cloneElementWithoutAttributesAndChildren(Document&) override;
void setWebVTTNodeType(WebVTTNodeType type) { m_webVTTNodeType = static_cast<unsigned>(type); }
WebVTTNodeType webVTTNodeType() const { return static_cast<WebVTTNodeType>(m_webVTTNodeType); }
@@ -59,20 +62,20 @@ public:
static const QualifiedName& voiceAttributeName()
{
- DEFINE_STATIC_LOCAL(QualifiedName, voiceAttr, (nullAtom, "voice", nullAtom));
+ static NeverDestroyed<QualifiedName> voiceAttr(nullAtom, "voice", nullAtom);
return voiceAttr;
}
static const QualifiedName& langAttributeName()
{
- DEFINE_STATIC_LOCAL(QualifiedName, voiceAttr, (nullAtom, "lang", nullAtom));
+ static NeverDestroyed<QualifiedName> voiceAttr(nullAtom, "lang", nullAtom);
return voiceAttr;
}
private:
WebVTTElement(WebVTTNodeType, Document&);
- virtual bool isWebVTTElement() const override { return true; }
+ bool isWebVTTElement() const override { return true; }
unsigned m_isPastNode : 1;
unsigned m_webVTTNodeType : 4;
@@ -80,10 +83,10 @@ private:
AtomicString m_language;
};
-void isWebVTTElement(const WebVTTElement&); // Catch unnecessary runtime check of type known at compile time.
-inline bool isWebVTTElement(const Node& node) { return node.isWebVTTElement(); }
-NODE_TYPE_CASTS(WebVTTElement)
-
} // namespace WebCore
-#endif
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::WebVTTElement)
+ static bool isType(const WebCore::Node& node) { return node.isWebVTTElement(); }
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/WebVTTParser.cpp b/Source/WebCore/html/track/WebVTTParser.cpp
index 48d729fb6..646110180 100644
--- a/Source/WebCore/html/track/WebVTTParser.cpp
+++ b/Source/WebCore/html/track/WebVTTParser.cpp
@@ -1,6 +1,7 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
* Copyright (C) 2013 Cable Television Labs, Inc.
+ * Copyright (C) 2011-2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -35,8 +36,11 @@
#include "WebVTTParser.h"
+#include "HTMLParserIdioms.h"
+#include "ISOVTTCue.h"
#include "ProcessingInstruction.h"
#include "Text.h"
+#include "VTTScanner.h"
#include "WebVTTElement.h"
namespace WebCore {
@@ -44,83 +48,46 @@ namespace WebCore {
const double secondsPerHour = 3600;
const double secondsPerMinute = 60;
const double secondsPerMillisecond = 0.001;
-const double malformedTime = -1;
-const UChar bom = 0xFEFF;
const char* fileIdentifier = "WEBVTT";
const unsigned fileIdentifierLength = 6;
-String WebVTTParser::collectDigits(const String& input, unsigned* position)
-{
- StringBuilder digits;
- while (*position < input.length() && isASCIIDigit(input[*position]))
- digits.append(input[(*position)++]);
- return digits.toString();
-}
-
-String WebVTTParser::collectWord(const String& input, unsigned* position)
-{
- StringBuilder string;
- while (*position < input.length() && !isASpace(input[*position]))
- string.append(input[(*position)++]);
- return string.toString();
-}
-
-#if ENABLE(WEBVTT_REGIONS)
-float WebVTTParser::parseFloatPercentageValue(const String& value, bool& isValidSetting)
+bool WebVTTParser::parseFloatPercentageValue(VTTScanner& valueScanner, float& percentage)
{
+ float number;
+ if (!valueScanner.scanFloat(number))
+ return false;
// '%' must be present and at the end of the setting value.
- if (value.find('%', 1) != value.length() - 1) {
- isValidSetting = false;
- return 0;
- }
-
- unsigned position = 0;
-
- StringBuilder floatNumberAsString;
- floatNumberAsString.append(WebVTTParser::collectDigits(value, &position));
-
- if (value[position] == '.') {
- floatNumberAsString.append(".");
- position++;
-
- floatNumberAsString.append(WebVTTParser::collectDigits(value, &position));
- }
- float number = floatNumberAsString.toString().toFloat(&isValidSetting);
+ if (!valueScanner.scan('%'))
+ return false;
- if (isValidSetting && (number <= 0 || number >= 100))
- isValidSetting = false;
+ if (number < 0 || number > 100)
+ return false;
- return number;
+ percentage = number;
+ return true;
}
-FloatPoint WebVTTParser::parseFloatPercentageValuePair(const String& value, char delimiter, bool& isValidSetting)
+bool WebVTTParser::parseFloatPercentageValuePair(VTTScanner& valueScanner, char delimiter, FloatPoint& valuePair)
{
- // The delimiter can't be the first or second value because a pair of
- // percentages (x%,y%) implies that at least the first two characters
- // are the first percentage value.
- size_t delimiterOffset = value.find(delimiter, 2);
- if (delimiterOffset == notFound || delimiterOffset == value.length() - 1) {
- isValidSetting = false;
- return FloatPoint(0, 0);
- }
+ float firstCoord;
+ if (!parseFloatPercentageValue(valueScanner, firstCoord))
+ return false;
- bool isFirstValueValid;
- float firstCoord = parseFloatPercentageValue(value.substring(0, delimiterOffset), isFirstValueValid);
+ if (!valueScanner.scan(delimiter))
+ return false;
- bool isSecondValueValid;
- float secondCoord = parseFloatPercentageValue(value.substring(delimiterOffset + 1, value.length() - 1), isSecondValueValid);
+ float secondCoord;
+ if (!parseFloatPercentageValue(valueScanner, secondCoord))
+ return false;
- isValidSetting = isFirstValueValid && isSecondValueValid;
- return FloatPoint(firstCoord, secondCoord);
+ valuePair = FloatPoint(firstCoord, secondCoord);
+ return true;
}
-#endif
WebVTTParser::WebVTTParser(WebVTTParserClient* client, ScriptExecutionContext* context)
: m_scriptExecutionContext(context)
, m_state(Initial)
- , m_currentStartTime(0)
- , m_currentEndTime(0)
- , m_tokenizer(WebVTTTokenizer::create())
+ , m_decoder(TextResourceDecoder::create("text/plain", UTF8Encoding()))
, m_client(client)
{
}
@@ -131,32 +98,64 @@ void WebVTTParser::getNewCues(Vector<RefPtr<WebVTTCueData>>& outputCues)
m_cuelist.clear();
}
-#if ENABLE(WEBVTT_REGIONS)
-void WebVTTParser::getNewRegions(Vector<RefPtr<TextTrackRegion>>& outputRegions)
+void WebVTTParser::getNewRegions(Vector<RefPtr<VTTRegion>>& outputRegions)
{
outputRegions = m_regionList;
m_regionList.clear();
}
-#endif
+
+void WebVTTParser::parseFileHeader(String&& data)
+{
+ m_state = Initial;
+ m_lineReader.reset();
+ m_lineReader.append(WTFMove(data));
+ parse();
+}
void WebVTTParser::parseBytes(const char* data, unsigned length)
{
- // 4.8.10.13.3 WHATWG WebVTT Parser algorithm.
- // 1-3 - Initial setup.
- unsigned position = 0;
-
- while (position < length) {
- String line = collectNextLine(data, length, &position);
- if (line.isNull()) {
- m_buffer.append(data + position, length - position);
- return;
- }
+ m_lineReader.append(m_decoder->decode(data, length));
+ parse();
+}
+
+void WebVTTParser::parseCueData(const ISOWebVTTCue& data)
+{
+ auto cue = WebVTTCueData::create();
+
+ MediaTime startTime = data.presentationTime();
+ cue->setStartTime(startTime);
+ cue->setEndTime(startTime + data.duration());
+
+ cue->setContent(data.cueText());
+ cue->setId(data.id());
+ cue->setSettings(data.settings());
+
+ MediaTime originalStartTime;
+ if (WebVTTParser::collectTimeStamp(data.originalStartTime(), originalStartTime))
+ cue->setOriginalStartTime(originalStartTime);
+
+ m_cuelist.append(WTFMove(cue));
+ if (m_client)
+ m_client->newCuesParsed();
+}
+void WebVTTParser::flush()
+{
+ m_lineReader.append(m_decoder->flush());
+ m_lineReader.appendEndOfStream();
+ parse();
+ flushPendingCue();
+}
+
+void WebVTTParser::parse()
+{
+ // WebVTT parser algorithm. (5.1 WebVTT file parsing.)
+ // Steps 1 - 3 - Initial setup.
+ while (auto line = m_lineReader.nextLine()) {
switch (m_state) {
case Initial:
-
- // 4-12 - Collect the first line and check for "WEBVTT".
- if (!hasRequiredFileIdentifier(line)) {
+ // Steps 4 - 9 - Check for a valid WebVTT signature.
+ if (!hasRequiredFileIdentifier(*line)) {
if (m_client)
m_client->fileFailedToParse();
return;
@@ -166,48 +165,53 @@ void WebVTTParser::parseBytes(const char* data, unsigned length)
break;
case Header:
- // 13-18 - Allow a header (comment area) under the WEBVTT line.
-#if ENABLE(WEBVTT_REGIONS)
- if (line.isEmpty()) {
+ collectMetadataHeader(*line);
+
+ if (line->isEmpty()) {
+ // Steps 10-14 - Allow a header (comment area) under the WEBVTT line.
if (m_client && m_regionList.size())
m_client->newRegionsParsed();
-
m_state = Id;
break;
}
- collectHeader(line);
+ // Step 15 - Break out of header loop if the line could be a timestamp line.
+ if (line->contains("-->"))
+ m_state = recoverCue(*line);
- break;
-
- case Metadata:
-#endif
- if (line.isEmpty())
- m_state = Id;
+ // Step 16 - Line is not the empty string and does not contain "-->".
break;
case Id:
- // 19-29 - Allow any number of line terminators, then initialize new cue values.
- if (line.isEmpty())
+ // Steps 17 - 20 - Allow any number of line terminators, then initialize new cue values.
+ if (line->isEmpty())
break;
+
+ // Step 21 - Cue creation (start a new cue).
resetCueValues();
- // 30-39 - Check if this line contains an optional identifier or timing data.
- m_state = collectCueId(line);
+ // Steps 22 - 25 - Check if this line contains an optional identifier or timing data.
+ m_state = collectCueId(*line);
break;
case TimingsAndSettings:
- // 40 - Collect cue timings and settings.
- m_state = collectTimingsAndSettings(line);
+ // Steps 26 - 27 - Discard current cue if the line is empty.
+ if (line->isEmpty()) {
+ m_state = Id;
+ break;
+ }
+
+ // Steps 28 - 29 - Collect cue timings and settings.
+ m_state = collectTimingsAndSettings(*line);
break;
case CueText:
- // 41-53 - Collect the cue text, create a cue, and add it to the output.
- m_state = collectCueText(line);
+ // Steps 31 - 41 - Collect the cue text, create a cue, and add it to the output.
+ m_state = collectCueText(*line);
break;
case BadCue:
- // 54-62 - Collect and discard the remaining cue.
- m_state = ignoreBadCue(line);
+ // Steps 42 - 48 - Discard lines until an empty line or a potential timing line is seen.
+ m_state = ignoreBadCue(*line);
break;
case Finished:
@@ -224,55 +228,47 @@ void WebVTTParser::fileFinished()
m_state = Finished;
}
+void WebVTTParser::flushPendingCue()
+{
+ ASSERT(m_lineReader.isAtEndOfStream());
+ // If we're in the CueText state when we run out of data, we emit the pending cue.
+ if (m_state == CueText)
+ createNewCue();
+}
+
bool WebVTTParser::hasRequiredFileIdentifier(const String& line)
{
// A WebVTT file identifier consists of an optional BOM character,
// the string "WEBVTT" followed by an optional space or tab character,
// and any number of characters that are not line terminators ...
- unsigned linePos = 0;
-
- if (line.isEmpty())
+ if (!line.startsWith(fileIdentifier, fileIdentifierLength))
return false;
-
- if (line[0] == bom)
- ++linePos;
-
- if (line.length() < fileIdentifierLength + linePos)
- return false;
-
- for (unsigned i = 0; i < fileIdentifierLength; ++i, ++linePos) {
- if (line[linePos] != fileIdentifier[i])
- return false;
- }
-
- if (linePos < line.length() && line[linePos] != ' ' && line[linePos] != '\t')
+ if (line.length() > fileIdentifierLength && !isHTMLSpace(line[fileIdentifierLength]))
return false;
return true;
}
-#if ENABLE(WEBVTT_REGIONS)
-void WebVTTParser::collectHeader(const String& line)
+void WebVTTParser::collectMetadataHeader(const String& line)
{
- // 4.1 Extension of WebVTT header parsing (11 - 15)
- DEFINE_STATIC_LOCAL(const AtomicString, regionHeaderName, ("Region", AtomicString::ConstructFromLiteral));
+ // WebVTT header parsing (WebVTT parser algorithm step 12)
+ static NeverDestroyed<const AtomicString> regionHeaderName("Region", AtomicString::ConstructFromLiteral);
- // 15.4 If line contains the character ":" (A U+003A COLON), then set metadata's
+ // Step 12.4 If line contains the character ":" (A U+003A COLON), then set metadata's
// name to the substring of line before the first ":" character and
// metadata's value to the substring after this character.
- if (!line.contains(":"))
+ size_t colonPosition = line.find(':');
+ if (colonPosition == notFound)
return;
- unsigned colonPosition = line.find(":");
- m_currentHeaderName = line.substring(0, colonPosition);
+ String headerName = line.substring(0, colonPosition);
- // 15.5 If metadata's name equals "Region":
- if (m_currentHeaderName == regionHeaderName) {
- m_currentHeaderValue = line.substring(colonPosition + 1, line.length() - 1);
- // 15.5.1 - 15.5.8 Region creation: Let region be a new text track region [...]
- createNewRegion();
+ // Step 12.5 If metadata's name equals "Region":
+ if (headerName == regionHeaderName) {
+ String headerValue = line.substring(colonPosition + 1, line.length() - 1);
+ // Steps 12.5.1 - 12.5.11 Region creation: Let region be a new text track region [...]
+ createNewRegion(headerValue);
}
}
-#endif
WebVTTParser::ParseState WebVTTParser::collectCueId(const String& line)
{
@@ -284,97 +280,126 @@ WebVTTParser::ParseState WebVTTParser::collectCueId(const String& line)
WebVTTParser::ParseState WebVTTParser::collectTimingsAndSettings(const String& line)
{
- // 4.8.10.13.3 Collect WebVTT cue timings and settings.
- // 1-3 - Let input be the string being parsed and position be a pointer into input
- unsigned position = 0;
- skipWhiteSpace(line, &position);
-
- // 4-5 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue start time be the collected time.
- m_currentStartTime = collectTimeStamp(line, &position);
- if (m_currentStartTime == malformedTime)
- return BadCue;
- if (position >= line.length())
- return BadCue;
- char nextChar = line[position++];
- if (nextChar != ' ' && nextChar != '\t')
+ if (line.isEmpty())
return BadCue;
- skipWhiteSpace(line, &position);
- // 6-9 - If the next three characters are not "-->", abort and return failure.
- if (line.find("-->", position) == notFound)
- return BadCue;
- position += 3;
- if (position >= line.length())
+ VTTScanner input(line);
+
+ // Collect WebVTT cue timings and settings. (5.3 WebVTT cue timings and settings parsing.)
+ // Steps 1 - 3 - Let input be the string being parsed and position be a pointer into input
+ input.skipWhile<isHTMLSpace<UChar>>();
+
+ // Steps 4 - 5 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue start time be the collected time.
+ if (!collectTimeStamp(input, m_currentStartTime))
return BadCue;
- nextChar = line[position++];
- if (nextChar != ' ' && nextChar != '\t')
+
+ input.skipWhile<isHTMLSpace<UChar>>();
+
+ // Steps 6 - 9 - If the next three characters are not "-->", abort and return failure.
+ if (!input.scan("-->"))
return BadCue;
- skipWhiteSpace(line, &position);
+
+ input.skipWhile<isHTMLSpace<UChar>>();
- // 10-11 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue end time be the collected time.
- m_currentEndTime = collectTimeStamp(line, &position);
- if (m_currentEndTime == malformedTime)
+ // Steps 10 - 11 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue end time be the collected time.
+ if (!collectTimeStamp(input, m_currentEndTime))
return BadCue;
- skipWhiteSpace(line, &position);
- // 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCue).
- m_currentSettings = line.substring(position, line.length()-1);
+ input.skipWhile<isHTMLSpace<UChar>>();
+
+ // Step 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCue).
+ m_currentSettings = input.restOfInputAsString();
return CueText;
}
WebVTTParser::ParseState WebVTTParser::collectCueText(const String& line)
{
+ // Step 34.
if (line.isEmpty()) {
createNewCue();
return Id;
}
+ // Step 35.
+ if (line.contains("-->")) {
+ // Step 39-40.
+ createNewCue();
+
+ // Step 41 - New iteration of the cue loop.
+ return recoverCue(line);
+ }
if (!m_currentContent.isEmpty())
- m_currentContent.append("\n");
+ m_currentContent.append('\n');
m_currentContent.append(line);
-
+
return CueText;
}
+WebVTTParser::ParseState WebVTTParser::recoverCue(const String& line)
+{
+ // Step 17 and 21.
+ resetCueValues();
+
+ // Step 22.
+ return collectTimingsAndSettings(line);
+}
+
WebVTTParser::ParseState WebVTTParser::ignoreBadCue(const String& line)
{
- if (!line.isEmpty())
- return BadCue;
- return Id;
+ if (line.isEmpty())
+ return Id;
+ if (line.contains("-->"))
+ return recoverCue(line);
+ return BadCue;
}
-PassRefPtr<DocumentFragment> WebVTTParser::createDocumentFragmentFromCueText(const String& text)
+// A helper class for the construction of a "cue fragment" from the cue text.
+class WebVTTTreeBuilder {
+public:
+ WebVTTTreeBuilder(Document& document)
+ : m_document(document) { }
+
+ Ref<DocumentFragment> buildFromString(const String& cueText);
+
+private:
+ void constructTreeFromToken(Document&);
+
+ WebVTTToken m_token;
+ RefPtr<ContainerNode> m_currentNode;
+ Vector<AtomicString> m_languageStack;
+ Document& m_document;
+};
+
+Ref<DocumentFragment> WebVTTTreeBuilder::buildFromString(const String& cueText)
{
// Cue text processing based on
- // 4.8.10.13.4 WebVTT cue text parsing rules and
- // 4.8.10.13.5 WebVTT cue text DOM construction rules.
-
- ASSERT(m_scriptExecutionContext->isDocument());
- Document* document = toDocument(m_scriptExecutionContext);
-
- RefPtr<DocumentFragment> fragment = DocumentFragment::create(*document);
+ // 5.4 WebVTT cue text parsing rules, and
+ // 5.5 WebVTT cue text DOM construction rules.
+ auto fragment = DocumentFragment::create(m_document);
- if (text.isEmpty()) {
- fragment->parserAppendChild(Text::create(*document, emptyString()));
- return fragment.release();
+ if (cueText.isEmpty()) {
+ fragment->parserAppendChild(Text::create(m_document, emptyString()));
+ return fragment;
}
- m_currentNode = fragment;
- m_tokenizer->reset();
- m_token.clear();
-
+ m_currentNode = fragment.ptr();
+
+ WebVTTTokenizer tokenizer(cueText);
m_languageStack.clear();
- SegmentedString content(text);
- while (m_tokenizer->nextToken(content, m_token))
- constructTreeFromToken(document);
+
+ while (tokenizer.nextToken(m_token))
+ constructTreeFromToken(m_document);
- return fragment.release();
+ return fragment;
}
-void WebVTTParser::createNewCue()
+Ref<DocumentFragment> WebVTTParser::createDocumentFragmentFromCueText(Document& document, const String& cueText)
{
- if (!m_currentContent.length())
- return;
+ WebVTTTreeBuilder treeBuilder(document);
+ return treeBuilder.buildFromString(cueText);
+}
+void WebVTTParser::createNewCue()
+{
RefPtr<WebVTTCueData> cue = WebVTTCueData::create();
cue->setStartTime(m_currentStartTime);
cue->setEndTime(m_currentEndTime);
@@ -391,21 +416,21 @@ void WebVTTParser::resetCueValues()
{
m_currentId = emptyString();
m_currentSettings = emptyString();
- m_currentStartTime = 0;
- m_currentEndTime = 0;
+ m_currentStartTime = MediaTime::zeroTime();
+ m_currentEndTime = MediaTime::zeroTime();
m_currentContent.clear();
}
-#if ENABLE(WEBVTT_REGIONS)
-void WebVTTParser::createNewRegion()
+void WebVTTParser::createNewRegion(const String& headerValue)
{
- if (!m_currentHeaderValue.length())
+ if (headerValue.isEmpty())
return;
- RefPtr<TextTrackRegion> region = TextTrackRegion::create();
- region->setRegionSettings(m_currentHeaderValue);
+ // Steps 12.5.1 - 12.5.9 - Construct and initialize a WebVTT Region object.
+ RefPtr<VTTRegion> region = VTTRegion::create(*m_scriptExecutionContext);
+ region->setRegionSettings(headerValue);
- // 15.5.10 If the text track list of regions regions contains a region
+ // Step 12.5.10 If the text track list of regions regions contains a region
// with the same region identifier value as region, remove that region.
for (size_t i = 0; i < m_regionList.size(); ++i)
if (m_regionList[i]->id() == region->id()) {
@@ -413,73 +438,66 @@ void WebVTTParser::createNewRegion()
break;
}
+ // Step 12.5.11
m_regionList.append(region);
}
-#endif
-double WebVTTParser::collectTimeStamp(const String& line, unsigned* position)
+bool WebVTTParser::collectTimeStamp(const String& line, MediaTime& timeStamp)
{
- // 4.8.10.13.3 Collect a WebVTT timestamp.
- // 1-4 - Initial checks, let most significant units be minutes.
+ if (line.isEmpty())
+ return false;
+
+ VTTScanner input(line);
+ return collectTimeStamp(input, timeStamp);
+}
+
+bool WebVTTParser::collectTimeStamp(VTTScanner& input, MediaTime& timeStamp)
+{
+ // Collect a WebVTT timestamp (5.3 WebVTT cue timings and settings parsing.)
+ // Steps 1 - 4 - Initial checks, let most significant units be minutes.
enum Mode { minutes, hours };
Mode mode = minutes;
- if (*position >= line.length() || !isASCIIDigit(line[*position]))
- return malformedTime;
- // 5-6 - Collect a sequence of characters that are 0-9.
- String digits1 = collectDigits(line, position);
- int value1 = digits1.toInt();
-
- // 7 - If not 2 characters or value is greater than 59, interpret as hours.
- if (digits1.length() != 2 || value1 > 59)
+ // Steps 5 - 7 - Collect a sequence of characters that are 0-9.
+ // If not 2 characters or value is greater than 59, interpret as hours.
+ int value1;
+ unsigned value1Digits = input.scanDigits(value1);
+ if (!value1Digits)
+ return false;
+ if (value1Digits != 2 || value1 > 59)
mode = hours;
- // 8-12 - Collect the next sequence of 0-9 after ':' (must be 2 chars).
- if (*position >= line.length() || line[(*position)++] != ':')
- return malformedTime;
- if (*position >= line.length() || !isASCIIDigit(line[(*position)]))
- return malformedTime;
- String digits2 = collectDigits(line, position);
- int value2 = digits2.toInt();
- if (digits2.length() != 2)
- return malformedTime;
-
- // 13 - Detect whether this timestamp includes hours.
+ // Steps 8 - 11 - Collect the next sequence of 0-9 after ':' (must be 2 chars).
+ int value2;
+ if (!input.scan(':') || input.scanDigits(value2) != 2)
+ return false;
+
+ // Step 12 - Detect whether this timestamp includes hours.
int value3;
- if (mode == hours || (*position < line.length() && line[*position] == ':')) {
- if (*position >= line.length() || line[(*position)++] != ':')
- return malformedTime;
- if (*position >= line.length() || !isASCIIDigit(line[*position]))
- return malformedTime;
- String digits3 = collectDigits(line, position);
- if (digits3.length() != 2)
- return malformedTime;
- value3 = digits3.toInt();
+ if (mode == hours || input.match(':')) {
+ if (!input.scan(':') || input.scanDigits(value3) != 2)
+ return false;
} else {
value3 = value2;
value2 = value1;
value1 = 0;
}
- // 14-19 - Collect next sequence of 0-9 after '.' (must be 3 chars).
- if (*position >= line.length() || line[(*position)++] != '.')
- return malformedTime;
- if (*position >= line.length() || !isASCIIDigit(line[*position]))
- return malformedTime;
- String digits4 = collectDigits(line, position);
- if (digits4.length() != 3)
- return malformedTime;
- int value4 = digits4.toInt();
+ // Steps 13 - 17 - Collect next sequence of 0-9 after '.' (must be 3 chars).
+ int value4;
+ if (!input.scan('.') || input.scanDigits(value4) != 3)
+ return false;
if (value2 > 59 || value3 > 59)
- return malformedTime;
+ return false;
- // 20-21 - Calculate result.
- return (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + (value4 * secondsPerMillisecond);
+ // Steps 18 - 19 - Calculate result.
+ timeStamp = MediaTime::createWithDouble((value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + (value4 * secondsPerMillisecond));
+ return true;
}
static WebVTTNodeType tokenToNodeType(WebVTTToken& token)
{
- switch (token.name().size()) {
+ switch (token.name().length()) {
case 1:
if (token.name()[0] == 'c')
return WebVTTNodeTypeClass;
@@ -506,91 +524,77 @@ static WebVTTNodeType tokenToNodeType(WebVTTToken& token)
return WebVTTNodeTypeNone;
}
-void WebVTTParser::constructTreeFromToken(Document* document)
+void WebVTTTreeBuilder::constructTreeFromToken(Document& document)
{
- QualifiedName tagName(nullAtom, AtomicString(m_token.name()), xhtmlNamespaceURI);
-
// http://dev.w3.org/html5/webvtt/#webvtt-cue-text-dom-construction-rules
switch (m_token.type()) {
case WebVTTTokenTypes::Character: {
- String content(m_token.characters()); // FIXME: This should be 8bit if possible.
- RefPtr<Text> child = Text::create(*document, content);
- m_currentNode->parserAppendChild(child);
+ m_currentNode->parserAppendChild(Text::create(document, m_token.characters()));
break;
}
case WebVTTTokenTypes::StartTag: {
- RefPtr<WebVTTElement> child;
WebVTTNodeType nodeType = tokenToNodeType(m_token);
- if (nodeType != WebVTTNodeTypeNone)
- child = WebVTTElement::create(nodeType, *document);
- if (child) {
- if (m_token.classes().size() > 0)
- child->setAttribute(classAttr, AtomicString(m_token.classes()));
-
- if (child->webVTTNodeType() == WebVTTNodeTypeVoice)
- child->setAttribute(WebVTTElement::voiceAttributeName(), AtomicString(m_token.annotation()));
- else if (child->webVTTNodeType() == WebVTTNodeTypeLanguage) {
- m_languageStack.append(AtomicString(m_token.annotation()));
- child->setAttribute(WebVTTElement::langAttributeName(), m_languageStack.last());
- }
- if (!m_languageStack.isEmpty())
- child->setLanguage(m_languageStack.last());
- m_currentNode->parserAppendChild(child);
- m_currentNode = child;
+ if (nodeType == WebVTTNodeTypeNone)
+ break;
+
+ WebVTTNodeType currentType = is<WebVTTElement>(*m_currentNode) ? downcast<WebVTTElement>(*m_currentNode).webVTTNodeType() : WebVTTNodeTypeNone;
+ // <rt> is only allowed if the current node is <ruby>.
+ if (nodeType == WebVTTNodeTypeRubyText && currentType != WebVTTNodeTypeRuby)
+ break;
+
+ auto child = WebVTTElement::create(nodeType, document);
+ if (!m_token.classes().isEmpty())
+ child->setAttributeWithoutSynchronization(classAttr, m_token.classes());
+
+ if (nodeType == WebVTTNodeTypeVoice)
+ child->setAttributeWithoutSynchronization(WebVTTElement::voiceAttributeName(), m_token.annotation());
+ else if (nodeType == WebVTTNodeTypeLanguage) {
+ m_languageStack.append(m_token.annotation());
+ child->setAttributeWithoutSynchronization(WebVTTElement::langAttributeName(), m_languageStack.last());
}
+ if (!m_languageStack.isEmpty())
+ child->setLanguage(m_languageStack.last());
+ m_currentNode->parserAppendChild(child);
+ m_currentNode = WTFMove(child);
break;
}
case WebVTTTokenTypes::EndTag: {
WebVTTNodeType nodeType = tokenToNodeType(m_token);
- if (nodeType != WebVTTNodeTypeNone) {
- if (nodeType == WebVTTNodeTypeLanguage && m_currentNode->isWebVTTElement() && toWebVTTElement(m_currentNode.get())->webVTTNodeType() == WebVTTNodeTypeLanguage)
- m_languageStack.removeLast();
- if (m_currentNode->parentNode())
- m_currentNode = m_currentNode->parentNode();
+ if (nodeType == WebVTTNodeTypeNone)
+ break;
+
+ // The only non-VTTElement would be the DocumentFragment root. (Text
+ // nodes and PIs will never appear as m_currentNode.)
+ if (!is<WebVTTElement>(*m_currentNode))
+ break;
+
+ WebVTTNodeType currentType = downcast<WebVTTElement>(*m_currentNode).webVTTNodeType();
+ bool matchesCurrent = nodeType == currentType;
+ if (!matchesCurrent) {
+ // </ruby> auto-closes <rt>
+ if (currentType == WebVTTNodeTypeRubyText && nodeType == WebVTTNodeTypeRuby) {
+ if (m_currentNode->parentNode())
+ m_currentNode = m_currentNode->parentNode();
+ } else
+ break;
}
+ if (nodeType == WebVTTNodeTypeLanguage)
+ m_languageStack.removeLast();
+ if (m_currentNode->parentNode())
+ m_currentNode = m_currentNode->parentNode();
break;
}
case WebVTTTokenTypes::TimestampTag: {
- unsigned position = 0;
- String charactersString(StringImpl::create8BitIfPossible(m_token.characters()));
- double time = collectTimeStamp(charactersString, &position);
- if (time != malformedTime)
- m_currentNode->parserAppendChild(ProcessingInstruction::create(*document, "timestamp", charactersString));
+ String charactersString = m_token.characters();
+ MediaTime parsedTimeStamp;
+ if (WebVTTParser::collectTimeStamp(charactersString, parsedTimeStamp))
+ m_currentNode->parserAppendChild(ProcessingInstruction::create(document, "timestamp", charactersString));
break;
}
default:
break;
}
- m_token.clear();
-}
-
-void WebVTTParser::skipWhiteSpace(const String& line, unsigned* position)
-{
- while (*position < line.length() && isASpace(line[*position]))
- (*position)++;
-}
-
-String WebVTTParser::collectNextLine(const char* data, unsigned length, unsigned* position)
-{
- unsigned currentPosition = *position;
- while (currentPosition < length && data[currentPosition] != '\r' && data[currentPosition] != '\n')
- currentPosition++;
- if (currentPosition >= length)
- return String();
- String line = String::fromUTF8(data + *position , currentPosition - *position);
- if (data[currentPosition] == '\r')
- currentPosition++;
- if (currentPosition < length && data[currentPosition] == '\n')
- currentPosition++;
- *position = currentPosition;
- if (m_buffer.isEmpty())
- return line;
-
- String lineWithBuffer = String::fromUTF8(m_buffer.data(), m_buffer.size());
- lineWithBuffer.append(line);
- m_buffer.clear();
- return lineWithBuffer;
}
}
diff --git a/Source/WebCore/html/track/WebVTTParser.h b/Source/WebCore/html/track/WebVTTParser.h
index eb27d7930..69ac0552a 100644
--- a/Source/WebCore/html/track/WebVTTParser.h
+++ b/Source/WebCore/html/track/WebVTTParser.h
@@ -1,6 +1,7 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
* Copyright (C) 2013 Cable Television Labs, Inc.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -29,16 +30,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef WebVTTParser_h
-#define WebVTTParser_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
+#include "BufferedLineReader.h"
#include "DocumentFragment.h"
#include "HTMLNames.h"
-#include "TextTrackRegion.h"
+#include "TextResourceDecoder.h"
+#include "VTTRegion.h"
#include "WebVTTTokenizer.h"
-#include <wtf/PassOwnPtr.h>
+#include <memory>
+#include <wtf/MediaTime.h>
#include <wtf/text/StringBuilder.h>
namespace WebCore {
@@ -46,29 +49,29 @@ namespace WebCore {
using namespace HTMLNames;
class Document;
+class ISOWebVTTCue;
+class VTTScanner;
class WebVTTParserClient {
public:
virtual ~WebVTTParserClient() { }
virtual void newCuesParsed() = 0;
-#if ENABLE(WEBVTT_REGIONS)
virtual void newRegionsParsed() = 0;
-#endif
virtual void fileFailedToParse() = 0;
};
-class WebVTTCueData : public RefCounted<WebVTTCueData> {
+class WebVTTCueData final : public RefCounted<WebVTTCueData> {
public:
- static PassRefPtr<WebVTTCueData> create() { return adoptRef(new WebVTTCueData()); }
- virtual ~WebVTTCueData() { }
+ static Ref<WebVTTCueData> create() { return adoptRef(*new WebVTTCueData()); }
+ ~WebVTTCueData() { }
- double startTime() const { return m_startTime; }
- void setStartTime(double startTime) { m_startTime = startTime; }
+ MediaTime startTime() const { return m_startTime; }
+ void setStartTime(const MediaTime& startTime) { m_startTime = startTime; }
- double endTime() const { return m_endTime; }
- void setEndTime(double endTime) { m_endTime = endTime; }
+ MediaTime endTime() const { return m_endTime; }
+ void setEndTime(const MediaTime& endTime) { m_endTime = endTime; }
String id() const { return m_id; }
void setId(String id) { m_id = id; }
@@ -79,30 +82,25 @@ public:
String settings() const { return m_settings; }
void setSettings(String settings) { m_settings = settings; }
+ MediaTime originalStartTime() const { return m_originalStartTime; }
+ void setOriginalStartTime(const MediaTime& time) { m_originalStartTime = time; }
+
private:
- WebVTTCueData()
- : m_startTime(0)
- , m_endTime(0)
- {
- }
+ WebVTTCueData() { }
- double m_startTime;
- double m_endTime;
+ MediaTime m_startTime;
+ MediaTime m_endTime;
+ MediaTime m_originalStartTime;
String m_id;
String m_content;
String m_settings;
};
-class WebVTTParser {
+class WebVTTParser final {
public:
- virtual ~WebVTTParser() { }
-
enum ParseState {
Initial,
Header,
-#if ENABLE(WEBVTT_REGIONS)
- Metadata,
-#endif
Id,
TimingsAndSettings,
CueText,
@@ -110,11 +108,8 @@ public:
Finished
};
- static OwnPtr<WebVTTParser> create(WebVTTParserClient* client, ScriptExecutionContext* context)
- {
- return adoptPtr(new WebVTTParser(client, context));
- }
-
+ WebVTTParser(WebVTTParserClient*, ScriptExecutionContext*);
+
static inline bool isRecognizedTag(const AtomicString& tagName)
{
return tagName == iTag
@@ -124,91 +119,68 @@ public:
|| tagName == rtTag;
}
- static inline bool isASpace(char c)
- {
- // WebVTT space characters are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), U+000C FORM FEED (FF), and U+000D CARRIAGE RETURN (CR).
- return c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r';
- }
- static inline bool isValidSettingDelimiter(char c)
+ static inline bool isValidSettingDelimiter(UChar c)
{
// ... a WebVTT cue consists of zero or more of the following components, in any order, separated from each other by one or more
// U+0020 SPACE characters or U+0009 CHARACTER TABULATION (tab) characters.
return c == ' ' || c == '\t';
}
- static String collectDigits(const String&, unsigned*);
- static String collectWord(const String&, unsigned*);
+ static bool collectTimeStamp(const String&, MediaTime&);
-#if ENABLE(WEBVTT_REGIONS)
// Useful functions for parsing percentage settings.
- static float parseFloatPercentageValue(const String&, bool&);
- static FloatPoint parseFloatPercentageValuePair(const String&, char, bool&);
-#endif
+ static bool parseFloatPercentageValue(VTTScanner& valueScanner, float&);
+ static bool parseFloatPercentageValuePair(VTTScanner& valueScanner, char, FloatPoint&);
// Input data to the parser to parse.
- void parseBytes(const char* data, unsigned length);
+ void parseBytes(const char*, unsigned);
+ void parseFileHeader(String&&);
+ void parseCueData(const ISOWebVTTCue&);
+ void flush();
void fileFinished();
// Transfers ownership of last parsed cues to caller.
void getNewCues(Vector<RefPtr<WebVTTCueData>>&);
-#if ENABLE(WEBVTT_REGIONS)
- void getNewRegions(Vector<RefPtr<TextTrackRegion>>&);
-#endif
+ void getNewRegions(Vector<RefPtr<VTTRegion>>&);
- PassRefPtr<DocumentFragment> createDocumentFragmentFromCueText(const String&);
- double collectTimeStamp(const String&, unsigned*);
+ // Create the DocumentFragment representation of the WebVTT cue text.
+ static Ref<DocumentFragment> createDocumentFragmentFromCueText(Document&, const String&);
protected:
- WebVTTParser(WebVTTParserClient*, ScriptExecutionContext*);
-
ScriptExecutionContext* m_scriptExecutionContext;
ParseState m_state;
private:
+ void parse();
+ void flushPendingCue();
bool hasRequiredFileIdentifier(const String&);
ParseState collectCueId(const String&);
ParseState collectTimingsAndSettings(const String&);
ParseState collectCueText(const String&);
+ ParseState recoverCue(const String&);
ParseState ignoreBadCue(const String&);
void createNewCue();
void resetCueValues();
-#if ENABLE(WEBVTT_REGIONS)
- void collectHeader(const String&);
- void createNewRegion();
-#endif
+ void collectMetadataHeader(const String&);
+ void createNewRegion(const String& headerValue);
- void skipWhiteSpace(const String&, unsigned*);
- String collectNextLine(const char* data, unsigned length, unsigned*);
+ static bool collectTimeStamp(VTTScanner& input, MediaTime& timeStamp);
- void constructTreeFromToken(Document*);
-
- String m_currentHeaderName;
- String m_currentHeaderValue;
-
- Vector<char> m_buffer;
+ BufferedLineReader m_lineReader;
+ RefPtr<TextResourceDecoder> m_decoder;
String m_currentId;
- double m_currentStartTime;
- double m_currentEndTime;
+ MediaTime m_currentStartTime;
+ MediaTime m_currentEndTime;
StringBuilder m_currentContent;
String m_currentSettings;
-
- WebVTTToken m_token;
- OwnPtr<WebVTTTokenizer> m_tokenizer;
-
- RefPtr<ContainerNode> m_currentNode;
WebVTTParserClient* m_client;
- Vector<AtomicString> m_languageStack;
Vector<RefPtr<WebVTTCueData>> m_cuelist;
-
-#if ENABLE(WEBVTT_REGIONS)
- Vector<RefPtr<TextTrackRegion>> m_regionList;
-#endif
+ Vector<RefPtr<VTTRegion>> m_regionList;
};
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/WebVTTToken.h b/Source/WebCore/html/track/WebVTTToken.h
index 7cf1a27d3..317e1006d 100644
--- a/Source/WebCore/html/track/WebVTTToken.h
+++ b/Source/WebCore/html/track/WebVTTToken.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,8 +29,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef WebVTTToken_h
-#define WebVTTToken_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
@@ -43,170 +43,56 @@ public:
StartTag,
EndTag,
TimestampTag,
- EndOfFile,
};
};
class WebVTTToken {
- WTF_MAKE_NONCOPYABLE(WebVTTToken);
- WTF_MAKE_FAST_ALLOCATED;
public:
typedef WebVTTTokenTypes Type;
- typedef WTF::Vector<UChar, 1024> DataVector; // FIXME: Is this too large for WebVTT?
- WebVTTToken() { clear(); }
+ WebVTTToken()
+ : m_type(Type::Uninitialized) { }
- void appendToName(UChar character)
+ static WebVTTToken StringToken(const String& characterData)
{
- ASSERT(m_type == WebVTTTokenTypes::StartTag || m_type == WebVTTTokenTypes::EndTag);
- ASSERT(character);
- m_data.append(character);
+ return WebVTTToken(Type::Character, characterData);
}
- Type::Type type() const { return m_type; }
-
- const DataVector& name() const
- {
- return m_data;
- }
-
- const DataVector& characters() const
- {
- ASSERT(m_type == Type::Character || m_type == Type::TimestampTag);
- return m_data;
- }
-
- // Starting a character token works slightly differently than starting
- // other types of tokens because we want to save a per-character branch.
- void ensureIsCharacterToken()
- {
- ASSERT(m_type == Type::Uninitialized || m_type == Type::Character);
- m_type = Type::Character;
- }
-
- void appendToCharacter(char character)
- {
- ASSERT(m_type == Type::Character);
- m_data.append(character);
- }
-
- void appendToCharacter(UChar character)
- {
- ASSERT(m_type == Type::Character);
- m_data.append(character);
- }
-
- void appendToCharacter(const Vector<LChar, 32>& characters)
- {
- ASSERT(m_type == Type::Character);
- m_data.appendVector(characters);
- }
-
- void beginEmptyStartTag()
- {
- ASSERT(m_type == Type::Uninitialized);
- m_type = Type::StartTag;
- m_data.clear();
- }
-
- void beginStartTag(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == Type::Uninitialized);
- m_type = Type::StartTag;
- m_data.append(character);
- }
-
- void beginEndTag(LChar character)
- {
- ASSERT(m_type == Type::Uninitialized);
- m_type = Type::EndTag;
- m_data.append(character);
- }
-
- void beginTimestampTag(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == Type::Uninitialized);
- m_type = Type::TimestampTag;
- m_data.append(character);
- }
-
- void appendToTimestamp(UChar character)
+ static WebVTTToken StartTag(const String& tagName, const AtomicString& classes = emptyAtom, const AtomicString& annotation = emptyAtom)
{
- ASSERT(character);
- ASSERT(m_type == Type::TimestampTag);
- m_data.append(character);
+ WebVTTToken token(Type::StartTag, tagName);
+ token.m_classes = classes;
+ token.m_annotation = annotation;
+ return token;
}
- void appendToClass(UChar character)
+ static WebVTTToken EndTag(const String& tagName)
{
- appendToStartType(character);
+ return WebVTTToken(Type::EndTag, tagName);
}
- void addNewClass()
- {
- ASSERT(m_type == Type::StartTag);
- if (!m_classes.isEmpty())
- m_classes.append(' ');
- m_classes.appendVector(m_currentBuffer);
- m_currentBuffer.clear();
- }
-
- const DataVector& classes() const
+ static WebVTTToken TimestampTag(const String& timestampData)
{
- return m_classes;
+ return WebVTTToken(Type::TimestampTag, timestampData);
}
- void appendToAnnotation(UChar character)
- {
- appendToStartType(character);
- }
-
- void addNewAnnotation()
- {
- ASSERT(m_type == Type::StartTag);
- m_annotation.clear();
- m_annotation.appendVector(m_currentBuffer);
- m_currentBuffer.clear();
- }
-
- const DataVector& annotation() const
- {
- return m_annotation;
- }
-
- void makeEndOfFile()
- {
- ASSERT(m_type == Type::Uninitialized);
- m_type = Type::EndOfFile;
- }
-
- void clear()
- {
- m_type = Type::Uninitialized;
- m_data.clear();
- m_annotation.clear();
- m_classes.clear();
- m_currentBuffer.clear();
- }
+ Type::Type type() const { return m_type; }
+ const String& name() const { return m_data; }
+ const String& characters() const { return m_data; }
+ const AtomicString& classes() const { return m_classes; }
+ const AtomicString& annotation() const { return m_annotation; }
private:
- void appendToStartType(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == Type::StartTag);
- m_currentBuffer.append(character);
- }
+ WebVTTToken(Type::Type type, const String& data)
+ : m_type(type)
+ , m_data(data) { }
Type::Type m_type;
- DataVector m_data;
- DataVector m_annotation;
- DataVector m_classes;
- DataVector m_currentBuffer;
+ String m_data;
+ AtomicString m_annotation;
+ AtomicString m_classes;
};
-}
+} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/html/track/WebVTTTokenizer.cpp b/Source/WebCore/html/track/WebVTTTokenizer.cpp
index 9bde924c8..024c04a09 100644
--- a/Source/WebCore/html/track/WebVTTTokenizer.cpp
+++ b/Source/WebCore/html/track/WebVTTTokenizer.cpp
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -29,206 +30,201 @@
*/
#include "config.h"
+#include "WebVTTTokenizer.h"
#if ENABLE(VIDEO_TRACK)
-#include "WebVTTTokenizer.h"
-
#include "MarkupTokenizerInlines.h"
+#include <wtf/text/StringBuilder.h>
#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
-#define WEBVTT_BEGIN_STATE(stateName) BEGIN_STATE(WebVTTTokenizerState, stateName)
-#define WEBVTT_ADVANCE_TO(stateName) ADVANCE_TO(WebVTTTokenizerState, stateName)
+#define WEBVTT_ADVANCE_TO(stateName) \
+ do { \
+ ASSERT(!m_input.isEmpty()); \
+ m_preprocessor.advance(m_input); \
+ character = m_preprocessor.nextInputCharacter(); \
+ goto stateName; \
+ } while (false)
-WebVTTTokenizer::WebVTTTokenizer()
- : m_inputStreamPreprocessor(this)
+template<unsigned charactersCount> ALWAYS_INLINE bool equalLiteral(const StringBuilder& s, const char (&characters)[charactersCount])
{
- reset();
+ return WTF::equal(s, reinterpret_cast<const LChar*>(characters), charactersCount - 1);
}
-template <typename CharacterType>
-inline bool vectorEqualsString(const Vector<CharacterType, 32>& vector, const String& string)
+static void addNewClass(StringBuilder& classes, const StringBuilder& newClass)
{
- if (vector.size() != string.length())
- return false;
-
- if (!string.length())
- return true;
+ if (!classes.isEmpty())
+ classes.append(' ');
+ classes.append(newClass);
+}
- return equal(string.impl(), vector.data(), vector.size());
+inline bool emitToken(WebVTTToken& resultToken, const WebVTTToken& token)
+{
+ resultToken = token;
+ return true;
}
-void WebVTTTokenizer::reset()
+inline bool advanceAndEmitToken(SegmentedString& source, WebVTTToken& resultToken, const WebVTTToken& token)
{
- m_state = WebVTTTokenizerState::DataState;
- m_token = 0;
- m_buffer.clear();
+ source.advance();
+ return emitToken(resultToken, token);
}
-
-bool WebVTTTokenizer::nextToken(SegmentedString& source, WebVTTToken& token)
+
+WebVTTTokenizer::WebVTTTokenizer(const String& input)
+ : m_input(input)
+ , m_preprocessor(*this)
{
- // If we have a token in progress, then we're supposed to be called back
- // with the same token so we can finish it.
- ASSERT(!m_token || m_token == &token || token.type() == WebVTTTokenTypes::Uninitialized);
- m_token = &token;
+ // Append an EOF marker and close the input "stream".
+ ASSERT(!m_input.isClosed());
+ m_input.append(String { &kEndOfFileMarker, 1 });
+ m_input.close();
+}
- if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source))
- return haveBufferedCharacterToken();
+bool WebVTTTokenizer::nextToken(WebVTTToken& token)
+{
+ if (m_input.isEmpty() || !m_preprocessor.peek(m_input))
+ return false;
- UChar cc = m_inputStreamPreprocessor.nextInputCharacter();
+ UChar character = m_preprocessor.nextInputCharacter();
+ if (character == kEndOfFileMarker) {
+ m_preprocessor.advance(m_input);
+ return false;
+ }
- // 4.8.10.13.4 WebVTT cue text tokenizer
- switch (m_state) {
- WEBVTT_BEGIN_STATE(DataState) {
- if (cc == '&') {
- m_buffer.append(static_cast<LChar>(cc));
- WEBVTT_ADVANCE_TO(EscapeState);
- } else if (cc == '<') {
- if (m_token->type() == WebVTTTokenTypes::Uninitialized
- || vectorEqualsString<UChar>(m_token->characters(), emptyString()))
- WEBVTT_ADVANCE_TO(TagState);
- else
- return emitAndResumeIn(source, WebVTTTokenizerState::TagState);
- } else if (cc == kEndOfFileMarker)
- return emitEndOfFile(source);
+ StringBuilder buffer;
+ StringBuilder result;
+ StringBuilder classes;
+
+// 4.8.10.13.4 WebVTT cue text tokenizer
+DataState:
+ if (character == '&') {
+ buffer.append('&');
+ WEBVTT_ADVANCE_TO(EscapeState);
+ } else if (character == '<') {
+ if (result.isEmpty())
+ WEBVTT_ADVANCE_TO(TagState);
else {
- bufferCharacter(cc);
- WEBVTT_ADVANCE_TO(DataState);
- }
- }
- END_STATE()
-
- WEBVTT_BEGIN_STATE(EscapeState) {
- if (cc == ';') {
- if (vectorEqualsString(m_buffer, "&amp"))
- bufferCharacter('&');
- else if (vectorEqualsString(m_buffer, "&lt"))
- bufferCharacter('<');
- else if (vectorEqualsString(m_buffer, "&gt"))
- bufferCharacter('>');
- else if (vectorEqualsString(m_buffer, "&lrm"))
- bufferCharacter(leftToRightMark);
- else if (vectorEqualsString(m_buffer, "&rlm"))
- bufferCharacter(rightToLeftMark);
- else if (vectorEqualsString(m_buffer, "&nbsp"))
- bufferCharacter(noBreakSpace);
- else {
- m_buffer.append(static_cast<LChar>(cc));
- m_token->appendToCharacter(m_buffer);
- }
- m_buffer.clear();
- WEBVTT_ADVANCE_TO(DataState);
- } else if (isASCIIAlphanumeric(cc)) {
- m_buffer.append(static_cast<LChar>(cc));
- WEBVTT_ADVANCE_TO(EscapeState);
- } else if (cc == kEndOfFileMarker) {
- m_token->appendToCharacter(m_buffer);
- return emitEndOfFile(source);
- } else {
- if (!vectorEqualsString(m_buffer, "&"))
- m_token->appendToCharacter(m_buffer);
- m_buffer.clear();
- WEBVTT_ADVANCE_TO(DataState);
+ // We don't want to advance input or perform a state transition - just return a (new) token.
+ // (On the next call to nextToken we will see '<' again, but take the other branch in this if instead.)
+ return emitToken(token, WebVTTToken::StringToken(result.toString()));
}
+ } else if (character == kEndOfFileMarker)
+ return advanceAndEmitToken(m_input, token, WebVTTToken::StringToken(result.toString()));
+ else {
+ result.append(character);
+ WEBVTT_ADVANCE_TO(DataState);
}
- END_STATE()
-
- WEBVTT_BEGIN_STATE(TagState) {
- if (isTokenizerWhitespace(cc)) {
- m_token->beginEmptyStartTag();
- WEBVTT_ADVANCE_TO(StartTagAnnotationState);
- } else if (cc == '.') {
- m_token->beginEmptyStartTag();
- WEBVTT_ADVANCE_TO(StartTagClassState);
- } else if (cc == '/') {
- WEBVTT_ADVANCE_TO(EndTagOpenState);
- } else if (WTF::isASCIIDigit(cc)) {
- m_token->beginTimestampTag(cc);
- WEBVTT_ADVANCE_TO(TimestampTagState);
- } else if (cc == '>' || cc == kEndOfFileMarker) {
- m_token->beginEmptyStartTag();
- return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
- } else {
- m_token->beginStartTag(cc);
- WEBVTT_ADVANCE_TO(StartTagState);
- }
- }
- END_STATE()
-
- WEBVTT_BEGIN_STATE(StartTagState) {
- if (isTokenizerWhitespace(cc))
- WEBVTT_ADVANCE_TO(StartTagAnnotationState);
- else if (cc == '.')
- WEBVTT_ADVANCE_TO(StartTagClassState);
- else if (cc == '>' || cc == kEndOfFileMarker)
- return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+
+EscapeState:
+ if (character == ';') {
+ if (equalLiteral(buffer, "&amp"))
+ result.append('&');
+ else if (equalLiteral(buffer, "&lt"))
+ result.append('<');
+ else if (equalLiteral(buffer, "&gt"))
+ result.append('>');
+ else if (equalLiteral(buffer, "&lrm"))
+ result.append(leftToRightMark);
+ else if (equalLiteral(buffer, "&rlm"))
+ result.append(rightToLeftMark);
+ else if (equalLiteral(buffer, "&nbsp"))
+ result.append(noBreakSpace);
else {
- m_token->appendToName(cc);
- WEBVTT_ADVANCE_TO(StartTagState);
+ buffer.append(character);
+ result.append(buffer);
}
- }
- END_STATE()
-
- WEBVTT_BEGIN_STATE(StartTagClassState) {
- if (isTokenizerWhitespace(cc)) {
- m_token->addNewClass();
- WEBVTT_ADVANCE_TO(StartTagAnnotationState);
- } else if (cc == '.') {
- m_token->addNewClass();
- WEBVTT_ADVANCE_TO(StartTagClassState);
- } else if (cc == '>' || cc == kEndOfFileMarker) {
- m_token->addNewClass();
- return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
- } else {
- m_token->appendToClass(cc);
- WEBVTT_ADVANCE_TO(StartTagClassState);
+ buffer.clear();
+ WEBVTT_ADVANCE_TO(DataState);
+ } else if (isASCIIAlphanumeric(character)) {
+ buffer.append(character);
+ WEBVTT_ADVANCE_TO(EscapeState);
+ } else if (character == '<') {
+ result.append(buffer);
+ return emitToken(token, WebVTTToken::StringToken(result.toString()));
+ } else if (character == kEndOfFileMarker) {
+ result.append(buffer);
+ return advanceAndEmitToken(m_input, token, WebVTTToken::StringToken(result.toString()));
+ } else {
+ result.append(buffer);
+ buffer.clear();
+
+ if (character == '&') {
+ buffer.append('&');
+ WEBVTT_ADVANCE_TO(EscapeState);
}
-
+ result.append(character);
+ WEBVTT_ADVANCE_TO(DataState);
}
- END_STATE()
- WEBVTT_BEGIN_STATE(StartTagAnnotationState) {
- if (cc == '>' || cc == kEndOfFileMarker) {
- m_token->addNewAnnotation();
- return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
- }
- m_token->appendToAnnotation(cc);
+TagState:
+ if (isTokenizerWhitespace(character)) {
+ ASSERT(result.isEmpty());
WEBVTT_ADVANCE_TO(StartTagAnnotationState);
- }
- END_STATE()
-
- WEBVTT_BEGIN_STATE(EndTagOpenState) {
- if (cc == '>' || cc == kEndOfFileMarker) {
- m_token->beginEndTag('\0');
- return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
- }
- m_token->beginEndTag(cc);
- WEBVTT_ADVANCE_TO(EndTagState);
- }
- END_STATE()
-
- WEBVTT_BEGIN_STATE(EndTagState) {
- if (cc == '>' || cc == kEndOfFileMarker)
- return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
- m_token->appendToName(cc);
+ } else if (character == '.') {
+ ASSERT(result.isEmpty());
+ WEBVTT_ADVANCE_TO(StartTagClassState);
+ } else if (character == '/') {
WEBVTT_ADVANCE_TO(EndTagState);
+ } else if (WTF::isASCIIDigit(character)) {
+ result.append(character);
+ WEBVTT_ADVANCE_TO(TimestampTagState);
+ } else if (character == '>' || character == kEndOfFileMarker) {
+ ASSERT(result.isEmpty());
+ return advanceAndEmitToken(m_input, token, WebVTTToken::StartTag(result.toString()));
+ } else {
+ result.append(character);
+ WEBVTT_ADVANCE_TO(StartTagState);
}
- END_STATE()
- WEBVTT_BEGIN_STATE(TimestampTagState) {
- if (cc == '>' || cc == kEndOfFileMarker)
- return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
- m_token->appendToTimestamp(cc);
- WEBVTT_ADVANCE_TO(TimestampTagState);
+StartTagState:
+ if (isTokenizerWhitespace(character))
+ WEBVTT_ADVANCE_TO(StartTagAnnotationState);
+ else if (character == '.')
+ WEBVTT_ADVANCE_TO(StartTagClassState);
+ else if (character == '>' || character == kEndOfFileMarker)
+ return advanceAndEmitToken(m_input, token, WebVTTToken::StartTag(result.toString()));
+ else {
+ result.append(character);
+ WEBVTT_ADVANCE_TO(StartTagState);
}
- END_STATE()
+StartTagClassState:
+ if (isTokenizerWhitespace(character)) {
+ addNewClass(classes, buffer);
+ buffer.clear();
+ WEBVTT_ADVANCE_TO(StartTagAnnotationState);
+ } else if (character == '.') {
+ addNewClass(classes, buffer);
+ buffer.clear();
+ WEBVTT_ADVANCE_TO(StartTagClassState);
+ } else if (character == '>' || character == kEndOfFileMarker) {
+ addNewClass(classes, buffer);
+ buffer.clear();
+ return advanceAndEmitToken(m_input, token, WebVTTToken::StartTag(result.toString(), classes.toAtomicString()));
+ } else {
+ buffer.append(character);
+ WEBVTT_ADVANCE_TO(StartTagClassState);
}
- ASSERT_NOT_REACHED();
- return false;
+StartTagAnnotationState:
+ if (character == '>' || character == kEndOfFileMarker)
+ return advanceAndEmitToken(m_input, token, WebVTTToken::StartTag(result.toString(), classes.toAtomicString(), buffer.toAtomicString()));
+ buffer.append(character);
+ WEBVTT_ADVANCE_TO(StartTagAnnotationState);
+
+EndTagState:
+ if (character == '>' || character == kEndOfFileMarker)
+ return advanceAndEmitToken(m_input, token, WebVTTToken::EndTag(result.toString()));
+ result.append(character);
+ WEBVTT_ADVANCE_TO(EndTagState);
+
+TimestampTagState:
+ if (character == '>' || character == kEndOfFileMarker)
+ return advanceAndEmitToken(m_input, token, WebVTTToken::TimestampTag(result.toString()));
+ result.append(character);
+ WEBVTT_ADVANCE_TO(TimestampTagState);
}
}
diff --git a/Source/WebCore/html/track/WebVTTTokenizer.h b/Source/WebCore/html/track/WebVTTTokenizer.h
index 79ee06b26..2b0c0c02d 100644
--- a/Source/WebCore/html/track/WebVTTTokenizer.h
+++ b/Source/WebCore/html/track/WebVTTTokenizer.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,91 +29,27 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef WebVTTTokenizer_h
-#define WebVTTTokenizer_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "InputStreamPreprocessor.h"
#include "WebVTTToken.h"
-#include <wtf/PassOwnPtr.h>
namespace WebCore {
-class WebVTTTokenizerState {
-public:
- enum State {
- DataState,
- EscapeState,
- TagState,
- StartTagState,
- StartTagClassState,
- StartTagAnnotationState,
- EndTagState,
- EndTagOpenState,
- TimestampTagState,
- };
-};
-
class WebVTTTokenizer {
- WTF_MAKE_NONCOPYABLE(WebVTTTokenizer);
- WTF_MAKE_FAST_ALLOCATED;
public:
- static OwnPtr<WebVTTTokenizer> create() { return adoptPtr(new WebVTTTokenizer); }
-
- typedef WebVTTTokenizerState State;
-
- void reset();
-
- bool nextToken(SegmentedString&, WebVTTToken&);
-
- inline bool haveBufferedCharacterToken()
- {
- return m_token->type() == WebVTTToken::Type::Character;
- }
+ explicit WebVTTTokenizer(const String&);
+ bool nextToken(WebVTTToken&);
- inline void bufferCharacter(UChar character)
- {
- ASSERT(character != kEndOfFileMarker);
- m_token->ensureIsCharacterToken();
- m_token->appendToCharacter(character);
- }
-
- inline bool emitAndResumeIn(SegmentedString& source, State::State state)
- {
- m_state = state;
- source.advanceAndUpdateLineNumber();
- return true;
- }
-
- inline bool emitEndOfFile(SegmentedString& source)
- {
- if (haveBufferedCharacterToken())
- return true;
- m_state = State::DataState;
- source.advanceAndUpdateLineNumber();
- m_token->clear();
- m_token->makeEndOfFile();
- return true;
- }
-
- bool shouldSkipNullCharacters() const { return true; }
+ static bool neverSkipNullCharacters() { return false; }
private:
- WebVTTTokenizer();
-
- // m_token is owned by the caller. If nextToken is not on the stack,
- // this member might be pointing to unallocated memory.
- WebVTTToken* m_token;
- WebVTTTokenizerState::State m_state;
-
- Vector<LChar, 32> m_buffer;
-
- // ://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream
- InputStreamPreprocessor<WebVTTTokenizer> m_inputStreamPreprocessor;
+ SegmentedString m_input;
+ InputStreamPreprocessor<WebVTTTokenizer> m_preprocessor;
};
-}
+} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)