2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "core/html/HTMLTrackElement.h"
29 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
30 #include "core/HTMLNames.h"
31 #include "core/dom/Document.h"
32 #include "core/events/Event.h"
33 #include "core/frame/csp/ContentSecurityPolicy.h"
34 #include "core/html/HTMLMediaElement.h"
35 #include "platform/Logging.h"
39 using namespace HTMLNames;
42 static String urlForLoggingTrack(const KURL& url)
44 static const unsigned maximumURLLengthForLogging = 128;
46 if (url.string().length() < maximumURLLengthForLogging)
48 return url.string().substring(0, maximumURLLengthForLogging) + "...";
52 inline HTMLTrackElement::HTMLTrackElement(Document& document)
53 : HTMLElement(trackTag, document)
54 , m_loadTimer(this, &HTMLTrackElement::loadTimerFired)
56 WTF_LOG(Media, "HTMLTrackElement::HTMLTrackElement - %p", this);
59 DEFINE_NODE_FACTORY(HTMLTrackElement)
61 HTMLTrackElement::~HTMLTrackElement()
65 m_track->clearTrackElement();
69 Node::InsertionNotificationRequest HTMLTrackElement::insertedInto(ContainerNode* insertionPoint)
71 WTF_LOG(Media, "HTMLTrackElement::insertedInto");
73 // Since we've moved to a new parent, we may now be able to load.
76 HTMLElement::insertedInto(insertionPoint);
77 HTMLMediaElement* parent = mediaElement();
78 if (insertionPoint == parent)
79 parent->didAddTrackElement(this);
83 void HTMLTrackElement::removedFrom(ContainerNode* insertionPoint)
85 if (!parentNode() && isHTMLMediaElement(*insertionPoint))
86 toHTMLMediaElement(insertionPoint)->didRemoveTrackElement(this);
87 HTMLElement::removedFrom(insertionPoint);
90 void HTMLTrackElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
92 if (name == srcAttr) {
96 m_track->removeAllCues();
98 // 4.8.10.12.3 Sourcing out-of-band text tracks
99 // As the kind, label, and srclang attributes are set, changed, or removed, the text track must update accordingly...
100 } else if (name == kindAttr) {
101 track()->setKind(value.lower());
102 } else if (name == labelAttr) {
103 track()->setLabel(value);
104 } else if (name == srclangAttr) {
105 track()->setLanguage(value);
106 } else if (name == idAttr) {
107 track()->setId(value);
108 } else if (name == defaultAttr) {
109 track()->setIsDefault(!value.isNull());
112 HTMLElement::parseAttribute(name, value);
115 const AtomicString& HTMLTrackElement::kind()
117 return track()->kind();
120 void HTMLTrackElement::setKind(const AtomicString& kind)
122 setAttribute(kindAttr, kind);
125 LoadableTextTrack* HTMLTrackElement::ensureTrack()
128 // kind, label and language are updated by parseAttribute
129 m_track = LoadableTextTrack::create(this);
131 return m_track.get();
134 TextTrack* HTMLTrackElement::track()
136 return ensureTrack();
139 bool HTMLTrackElement::isURLAttribute(const Attribute& attribute) const
141 return attribute.name() == srcAttr || HTMLElement::isURLAttribute(attribute);
144 void HTMLTrackElement::scheduleLoad()
146 WTF_LOG(Media, "HTMLTrackElement::scheduleLoad");
148 // 1. If another occurrence of this algorithm is already running for this text track and its track element,
149 // abort these steps, letting that other algorithm take care of this element.
150 if (m_loadTimer.isActive())
153 // 2. If the text track's text track mode is not set to one of hidden or showing, abort these steps.
154 if (ensureTrack()->mode() != TextTrack::hiddenKeyword() && ensureTrack()->mode() != TextTrack::showingKeyword())
157 // 3. If the text track's track element does not have a media element as a parent, abort these steps.
161 // 4. Run the remainder of these steps asynchronously, allowing whatever caused these steps to run to continue.
162 m_loadTimer.startOneShot(0, FROM_HERE);
165 void HTMLTrackElement::loadTimerFired(Timer<HTMLTrackElement>*)
167 if (!fastHasAttribute(srcAttr))
170 WTF_LOG(Media, "HTMLTrackElement::loadTimerFired");
172 // 6. Set the text track readiness state to loading.
173 setReadyState(HTMLTrackElement::LOADING);
175 // 7. Let URL be the track URL of the track element.
176 KURL url = getNonEmptyURLAttribute(srcAttr);
178 // 8. If the track element's parent is a media element then let CORS mode be the state of the parent media
179 // element's crossorigin content attribute. Otherwise, let CORS mode be No CORS.
180 if (!canLoadUrl(url)) {
181 didCompleteLoad(HTMLTrackElement::Failure);
185 ensureTrack()->scheduleLoad(url);
188 bool HTMLTrackElement::canLoadUrl(const KURL& url)
190 HTMLMediaElement* parent = mediaElement();
194 // 4.8.10.12.3 Sourcing out-of-band text tracks
196 // 4. Download: If URL is not the empty string, perform a potentially CORS-enabled fetch of URL, with the
197 // mode being the state of the media element's crossorigin content attribute, the origin being the
198 // origin of the media element's Document, and the default origin behaviour set to fail.
202 if (!document().contentSecurityPolicy()->allowMediaFromSource(url)) {
203 WTF_LOG(Media, "HTMLTrackElement::canLoadUrl(%s) -> rejected by Content Security Policy", urlForLoggingTrack(url).utf8().data());
210 void HTMLTrackElement::didCompleteLoad(LoadStatus status)
212 // 4.8.10.12.3 Sourcing out-of-band text tracks (continued)
215 // If the fetching algorithm fails for any reason (network error, the server returns an error
216 // code, a cross-origin check fails, etc), or if URL is the empty string or has the wrong origin
217 // as determined by the condition at the start of this step, or if the fetched resource is not in
218 // a supported format, then queue a task to first change the text track readiness state to failed
219 // to load and then fire a simple event named error at the track element; and then, once that task
220 // is queued, move on to the step below labeled monitoring.
222 if (status == Failure) {
223 setReadyState(HTMLTrackElement::TRACK_ERROR);
224 dispatchEvent(Event::create(EventTypeNames::error), IGNORE_EXCEPTION);
228 // If the fetching algorithm does not fail, then the final task that is queued by the networking
229 // task source must run the following steps:
230 // 1. Change the text track readiness state to loaded.
231 setReadyState(HTMLTrackElement::LOADED);
233 // 2. If the file was successfully processed, fire a simple event named load at the
235 dispatchEvent(Event::create(EventTypeNames::load), IGNORE_EXCEPTION);
238 // NOTE: The values in the TextTrack::ReadinessState enum must stay in sync with those in HTMLTrackElement::ReadyState.
239 COMPILE_ASSERT(HTMLTrackElement::NONE == static_cast<HTMLTrackElement::ReadyState>(TextTrack::NotLoaded), TextTrackEnumNotLoaded_Is_Wrong_Should_Be_HTMLTrackElementEnumNONE);
240 COMPILE_ASSERT(HTMLTrackElement::LOADING == static_cast<HTMLTrackElement::ReadyState>(TextTrack::Loading), TextTrackEnumLoadingIsWrong_ShouldBe_HTMLTrackElementEnumLOADING);
241 COMPILE_ASSERT(HTMLTrackElement::LOADED == static_cast<HTMLTrackElement::ReadyState>(TextTrack::Loaded), TextTrackEnumLoaded_Is_Wrong_Should_Be_HTMLTrackElementEnumLOADED);
242 COMPILE_ASSERT(HTMLTrackElement::TRACK_ERROR == static_cast<HTMLTrackElement::ReadyState>(TextTrack::FailedToLoad), TextTrackEnumFailedToLoad_Is_Wrong_Should_Be_HTMLTrackElementEnumTRACK_ERROR);
244 void HTMLTrackElement::setReadyState(ReadyState state)
246 ensureTrack()->setReadinessState(static_cast<TextTrack::ReadinessState>(state));
247 if (HTMLMediaElement* parent = mediaElement())
248 return parent->textTrackReadyStateChanged(m_track.get());
251 HTMLTrackElement::ReadyState HTMLTrackElement::readyState()
253 return static_cast<ReadyState>(ensureTrack()->readinessState());
256 const AtomicString& HTMLTrackElement::mediaElementCrossOriginAttribute() const
258 if (HTMLMediaElement* parent = mediaElement())
259 return parent->fastGetAttribute(HTMLNames::crossoriginAttr);
264 HTMLMediaElement* HTMLTrackElement::mediaElement() const
266 Element* parent = parentElement();
267 if (isHTMLMediaElement(parent))
268 return toHTMLMediaElement(parent);
272 void HTMLTrackElement::trace(Visitor* visitor)
274 visitor->trace(m_track);
275 HTMLElement::trace(visitor);