6d7e379ab7449f53c5851356361f1ce54afd5f99
[WebKit-https.git] / Source / WebCore / html / track / InbandTextTrack.cpp
1 /*
2  * Copyright (C) 2012 Apple 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
30 #include "InbandTextTrack.h"
31
32 #include "Document.h"
33 #include "Event.h"
34 #include "ExceptionCodePlaceholder.h"
35 #include "HTMLMediaElement.h"
36 #include "InbandTextTrackPrivate.h"
37 #include "Logging.h"
38 #include "TextTrackCueGeneric.h"
39 #include "TextTrackCueList.h"
40 #include <math.h>
41 #include <wtf/UnusedParam.h>
42
43 namespace WebCore {
44
45 void TextTrackCueMap::add(GenericCueData* cueData, TextTrackCueGeneric* cue)
46 {
47     m_dataToCueMap.add(cueData, cue);
48     m_cueToDataMap.add(cue, cueData);
49 }
50
51 PassRefPtr<TextTrackCueGeneric> TextTrackCueMap::find(GenericCueData* cueData)
52 {
53     GenericCueDataToCueMap::iterator iter = m_dataToCueMap.find(cueData);
54     if (iter == m_dataToCueMap.end())
55         return 0;
56     
57     return iter->value;
58 }
59
60 PassRefPtr<GenericCueData> TextTrackCueMap::find(TextTrackCueGeneric* cue)
61 {
62     GenericCueToCueDataMap::iterator iter = m_cueToDataMap.find(cue);
63     if (iter == m_cueToDataMap.end())
64         return 0;
65     
66     return iter->value;
67 }
68
69 void TextTrackCueMap::remove(GenericCueData* cueData)
70 {
71     RefPtr<TextTrackCueGeneric> cue = find(cueData);
72
73     if (cue)
74         m_cueToDataMap.remove(cue);
75     m_dataToCueMap.remove(cueData);
76 }
77
78 void TextTrackCueMap::remove(TextTrackCueGeneric* cue)
79 {
80     RefPtr<GenericCueData> cueData = find(cue);
81
82     if (cueData)
83         m_dataToCueMap.remove(cueData);
84     m_cueToDataMap.remove(cue);
85 }
86
87
88 PassRefPtr<InbandTextTrack> InbandTextTrack::create(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> playerPrivate)
89 {
90     return adoptRef(new InbandTextTrack(context, client, playerPrivate));
91 }
92
93 InbandTextTrack::InbandTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> tracksPrivate)
94     : TextTrack(context, client, emptyString(), tracksPrivate->label(), tracksPrivate->language(), InBand)
95     , m_private(tracksPrivate)
96 {
97     m_private->setClient(this);
98     
99     switch (m_private->kind()) {
100     case InbandTextTrackPrivate::Subtitles:
101         setKind(TextTrack::subtitlesKeyword());
102         break;
103     case InbandTextTrackPrivate::Captions:
104         setKind(TextTrack::captionsKeyword());
105         break;
106     case InbandTextTrackPrivate::Descriptions:
107         setKind(TextTrack::descriptionsKeyword());
108         break;
109     case InbandTextTrackPrivate::Chapters:
110         setKind(TextTrack::chaptersKeyword());
111         break;
112     case InbandTextTrackPrivate::Metadata:
113         setKind(TextTrack::metadataKeyword());
114         break;
115     case InbandTextTrackPrivate::Forced:
116         setKind(TextTrack::forcedKeyword());
117         break;
118     case InbandTextTrackPrivate::None:
119     default:
120         ASSERT_NOT_REACHED();
121         break;
122     }
123 }
124
125 InbandTextTrack::~InbandTextTrack()
126 {
127     m_private->setClient(0);
128 }
129
130 void InbandTextTrack::setMode(const AtomicString& mode)
131 {
132     TextTrack::setMode(mode);
133
134     if (mode == TextTrack::disabledKeyword())
135         m_private->setMode(InbandTextTrackPrivate::Disabled);
136     else if (mode == TextTrack::hiddenKeyword())
137         m_private->setMode(InbandTextTrackPrivate::Hidden);
138     else if (mode == TextTrack::showingKeyword())
139         m_private->setMode(InbandTextTrackPrivate::Showing);
140     else
141         ASSERT_NOT_REACHED();
142 }
143
144 bool InbandTextTrack::isClosedCaptions() const
145 {
146     if (!m_private)
147         return false;
148
149     return m_private->isClosedCaptions();
150 }
151
152 bool InbandTextTrack::containsOnlyForcedSubtitles() const
153 {
154     if (!m_private)
155         return false;
156     
157     return m_private->containsOnlyForcedSubtitles();
158 }
159
160 bool InbandTextTrack::isMainProgramContent() const
161 {
162     if (!m_private)
163         return false;
164     
165     return m_private->isMainProgramContent();
166 }
167
168 bool InbandTextTrack::isEasyToRead() const
169 {
170     if (!m_private)
171         return false;
172     
173     return m_private->isEasyToRead();
174 }
175     
176 size_t InbandTextTrack::inbandTrackIndex()
177 {
178     ASSERT(m_private);
179     return m_private->textTrackIndex();
180 }
181
182 void InbandTextTrack::updateCueFromCueData(TextTrackCueGeneric* cue, GenericCueData* cueData)
183 {
184     cue->willChange();
185
186     cue->setStartTime(cueData->startTime(), IGNORE_EXCEPTION);
187     double endTime = cueData->endTime();
188     if (std::isinf(endTime) && mediaElement())
189         endTime = mediaElement()->duration();
190     cue->setEndTime(endTime, IGNORE_EXCEPTION);
191     cue->setText(cueData->content());
192     cue->setId(cueData->id());
193     cue->setBaseFontSizeRelativeToVideoHeight(cueData->baseFontSize());
194     cue->setFontSizeMultiplier(cueData->relativeFontSize());
195     cue->setFontName(cueData->fontName());
196
197     if (cueData->position() > 0)
198         cue->setPosition(lround(cueData->position()), IGNORE_EXCEPTION);
199     if (cueData->line() > 0)
200         cue->setLine(lround(cueData->line()), IGNORE_EXCEPTION);
201     if (cueData->size() > 0)
202         cue->setSize(lround(cueData->size()), IGNORE_EXCEPTION);
203     if (cueData->backgroundColor().isValid())
204         cue->setBackgroundColor(cueData->backgroundColor().rgb());
205     if (cueData->foregroundColor().isValid())
206         cue->setForegroundColor(cueData->foregroundColor().rgb());
207
208     if (cueData->align() == GenericCueData::Start)
209         cue->setAlign(ASCIILiteral("start"), IGNORE_EXCEPTION);
210     else if (cueData->align() == GenericCueData::Middle)
211         cue->setAlign(ASCIILiteral("middle"), IGNORE_EXCEPTION);
212     else if (cueData->align() == GenericCueData::End)
213         cue->setAlign(ASCIILiteral("end"), IGNORE_EXCEPTION);
214     cue->setSnapToLines(false);
215
216     cue->didChange();
217 }
218     
219 void InbandTextTrack::addGenericCue(InbandTextTrackPrivate* trackPrivate, PassRefPtr<GenericCueData> prpCueData)
220 {
221     UNUSED_PARAM(trackPrivate);
222     ASSERT(trackPrivate == m_private);
223
224     RefPtr<GenericCueData> cueData = prpCueData;
225     if (m_cueMap.find(cueData.get()))
226         return;
227
228     RefPtr<TextTrackCueGeneric> cue = TextTrackCueGeneric::create(scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
229     updateCueFromCueData(cue.get(), cueData.get());
230     if (hasCue(cue.get(), TextTrackCue::IgnoreDuration)) {
231         LOG(Media, "InbandTextTrack::addGenericCue ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
232         return;
233     }
234
235     m_cueMap.add(cueData.get(), cue.get());
236
237     addCue(cue);
238 }
239
240 void InbandTextTrack::updateGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
241 {
242     RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
243     if (!cue)
244         return;
245
246     updateCueFromCueData(cue.get(), cueData);
247     
248     if (cueData->status() == GenericCueData::Complete)
249         m_cueMap.remove(cueData);
250 }
251
252 void InbandTextTrack::removeGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
253 {
254     RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
255     if (cue)
256         removeCue(cue.get(), IGNORE_EXCEPTION);
257     else
258         m_cueMap.remove(cueData);
259 }
260
261 void InbandTextTrack::removeCue(TextTrackCue* cue, ExceptionCode& ec)
262 {
263     m_cueMap.remove(static_cast<TextTrackCueGeneric*>(cue));
264     TextTrack::removeCue(cue, ec);
265 }
266     
267 } // namespace WebCore
268
269 #endif