Implement TextTrackList and the textTracks attribute of HTMLMediaElement
[WebKit-https.git] / Source / WebCore / html / HTMLTrackElement.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(VIDEO_TRACK)
29 #include "HTMLTrackElement.h"
30
31 #include "Event.h"
32 #include "HTMLMediaElement.h"
33 #include "HTMLNames.h"
34 #include "Logging.h"
35 #include "RuntimeEnabledFeatures.h"
36 #include "ScriptEventListener.h"
37
38 using namespace std;
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
44 inline HTMLTrackElement::HTMLTrackElement(const QualifiedName& tagName, Document* document)
45     : HTMLElement(tagName, document)
46 {
47     LOG(Media, "HTMLTrackElement::HTMLTrackElement - %p", this);
48     ASSERT(hasTagName(trackTag));
49 }
50
51 HTMLTrackElement::~HTMLTrackElement()
52 {
53     if (m_track)
54         m_track->clearClient();
55 }
56
57 PassRefPtr<HTMLTrackElement> HTMLTrackElement::create(const QualifiedName& tagName, Document* document)
58 {
59     return adoptRef(new HTMLTrackElement(tagName, document));
60 }
61
62 void HTMLTrackElement::insertedIntoTree(bool deep)
63 {
64     HTMLElement::insertedIntoTree(deep);
65
66     if (HTMLMediaElement* parent = mediaElement())
67         parent->trackWasAdded(this);
68 }
69
70 void HTMLTrackElement::willRemove()
71 {
72     if (HTMLMediaElement* parent = mediaElement())
73         parent->trackWillBeRemoved(this);
74
75     HTMLElement::willRemove();
76 }
77
78 void HTMLTrackElement::parseMappedAttribute(Attribute* attribute)
79 {
80     const QualifiedName& attrName = attribute->name();
81
82     if (attrName == onloadAttr)
83         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attribute));
84     else if (attrName == onerrorAttr)
85         setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attribute));
86     else
87         HTMLElement::parseMappedAttribute(attribute);
88 }
89
90 void HTMLTrackElement::attributeChanged(Attribute* attr, bool preserveDecls)
91 {
92     HTMLElement::attributeChanged(attr, preserveDecls);
93
94     const QualifiedName& attrName = attr->name();
95     if (attrName == srcAttr) {
96         if (!getAttribute(srcAttr).isEmpty() && mediaElement())
97             scheduleLoad();
98     }
99 }
100
101 KURL HTMLTrackElement::src() const
102 {
103     return document()->completeURL(getAttribute(srcAttr));
104 }
105
106 void HTMLTrackElement::setSrc(const String& url)
107 {
108     setAttribute(srcAttr, url);
109 }
110
111 String HTMLTrackElement::kind() const
112 {
113     return getAttribute(kindAttr);
114 }
115
116 void HTMLTrackElement::setKind(const String& kind)
117 {
118     setAttribute(kindAttr, kind);
119 }
120
121 String HTMLTrackElement::srclang() const
122 {
123     return getAttribute(srclangAttr);
124 }
125
126 void HTMLTrackElement::setSrclang(const String& srclang)
127 {
128     setAttribute(srclangAttr, srclang);
129 }
130
131 String HTMLTrackElement::label() const
132 {
133     return getAttribute(labelAttr);
134 }
135
136 void HTMLTrackElement::setLabel(const String& label)
137 {
138     setAttribute(labelAttr, label);
139 }
140
141 bool HTMLTrackElement::isDefault() const
142 {
143     return fastHasAttribute(defaultAttr);
144 }
145
146 void HTMLTrackElement::setIsDefault(bool isDefault)
147 {
148     setBooleanAttribute(defaultAttr, isDefault);
149 }
150
151 LoadableTextTrack* HTMLTrackElement::ensureTrack()
152 {
153     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
154         return 0;
155
156     if (!m_track)
157         m_track = LoadableTextTrack::create(this, kind(), label(), srclang(), isDefault());
158     return m_track.get();
159 }
160
161 TextTrack* HTMLTrackElement::track()
162 {
163     return ensureTrack();
164 }
165
166 bool HTMLTrackElement::isURLAttribute(Attribute* attribute) const
167 {
168     return attribute->name() == srcAttr || HTMLElement::isURLAttribute(attribute);
169 }
170
171 void HTMLTrackElement::scheduleLoad()
172 {
173     if (!mediaElement())
174         return;
175
176     if (!fastHasAttribute(srcAttr))
177         return;
178
179     ensureTrack()->scheduleLoad(getNonEmptyURLAttribute(srcAttr));
180 }
181
182 bool HTMLTrackElement::canLoadUrl(LoadableTextTrack*, const KURL& url)
183 {
184     HTMLMediaElement* parent = mediaElement();
185     if (!parent)
186         return false;
187
188     if (!parent->isSafeToLoadURL(url, HTMLMediaElement::Complain))
189         return false;
190     
191     return dispatchBeforeLoadEvent(url.string());
192 }
193
194 void HTMLTrackElement::didCompleteLoad(LoadableTextTrack*, bool loadingFailed)
195 {
196     ExceptionCode ec = 0;
197     dispatchEvent(Event::create(loadingFailed ? eventNames().errorEvent : eventNames().loadEvent, false, false), ec);
198 }
199     
200 void HTMLTrackElement::textTrackReadyStateChanged(TextTrack* track)
201 {
202     if (HTMLMediaElement* parent = mediaElement())
203         return parent->textTrackReadyStateChanged(track);
204 }
205     
206 void HTMLTrackElement::textTrackModeChanged(TextTrack* track)
207 {
208     if (HTMLMediaElement* parent = mediaElement())
209         return parent->textTrackModeChanged(track);
210 }
211     
212 void HTMLTrackElement::textTrackAddCues(TextTrack* track, const TextTrackCueList* cues)
213 {
214     if (HTMLMediaElement* parent = mediaElement())
215         return parent->textTrackAddCues(track, cues);
216 }
217     
218 void HTMLTrackElement::textTrackRemoveCues(TextTrack* track, const TextTrackCueList* cues)
219 {
220     if (HTMLMediaElement* parent = mediaElement())
221         return parent->textTrackAddCues(track, cues);
222 }
223     
224 void HTMLTrackElement::textTrackAddCue(TextTrack* track, PassRefPtr<TextTrackCue> cue)
225 {
226     if (HTMLMediaElement* parent = mediaElement())
227         return parent->textTrackAddCue(track, cue);
228 }
229     
230 void HTMLTrackElement::textTrackRemoveCue(TextTrack* track, PassRefPtr<TextTrackCue> cue)
231 {
232     if (HTMLMediaElement* parent = mediaElement())
233         return parent->textTrackRemoveCue(track, cue);
234 }
235
236 HTMLMediaElement* HTMLTrackElement::mediaElement() const
237 {
238     Element* parent = parentElement();
239     if (parent && parent->isMediaElement())
240         return static_cast<HTMLMediaElement*>(parentNode());
241
242     return 0;
243 }
244
245 #if ENABLE(MICRODATA)
246 String HTMLTrackElement::itemValueText() const
247 {
248     return getURLAttribute(srcAttr);
249 }
250
251 void HTMLTrackElement::setItemValueText(const String& value, ExceptionCode& ec)
252 {
253     setAttribute(srcAttr, value, ec);
254 }
255 #endif
256
257 }
258
259 #endif