1/*
2 * Copyright (C) 2012-2017 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 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 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#include "InbandGenericTextTrack.h"
28
29#if ENABLE(VIDEO_TRACK)
30
31#include "DataCue.h"
32#include "HTMLMediaElement.h"
33#include "InbandTextTrackPrivate.h"
34#include "Logging.h"
35#include "VTTRegionList.h"
36#include <math.h>
37#include <wtf/IsoMallocInlines.h>
38#include <wtf/text/CString.h>
39
40namespace WebCore {
41
42WTF_MAKE_ISO_ALLOCATED_IMPL(InbandGenericTextTrack);
43
44void GenericTextTrackCueMap::add(GenericCueData& cueData, TextTrackCueGeneric& cue)
45{
46 m_dataToCueMap.add(&cueData, &cue);
47 m_cueToDataMap.add(&cue, &cueData);
48}
49
50TextTrackCueGeneric* GenericTextTrackCueMap::find(GenericCueData& cueData)
51{
52 return m_dataToCueMap.get(&cueData);
53}
54
55GenericCueData* GenericTextTrackCueMap::find(TextTrackCue& cue)
56{
57 return m_cueToDataMap.get(&cue);
58}
59
60void GenericTextTrackCueMap::remove(GenericCueData& cueData)
61{
62 if (auto cue = m_dataToCueMap.take(&cueData))
63 m_cueToDataMap.remove(cue);
64}
65
66void GenericTextTrackCueMap::remove(TextTrackCue& cue)
67{
68 if (auto data = m_cueToDataMap.take(&cue))
69 m_dataToCueMap.remove(data);
70}
71
72inline InbandGenericTextTrack::InbandGenericTextTrack(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
73 : InbandTextTrack(context, client, trackPrivate)
74{
75}
76
77Ref<InbandGenericTextTrack> InbandGenericTextTrack::create(ScriptExecutionContext& context, TextTrackClient& client, InbandTextTrackPrivate& trackPrivate)
78{
79 return adoptRef(*new InbandGenericTextTrack(context, client, trackPrivate));
80}
81
82InbandGenericTextTrack::~InbandGenericTextTrack() = default;
83
84void InbandGenericTextTrack::updateCueFromCueData(TextTrackCueGeneric& cue, GenericCueData& cueData)
85{
86 cue.willChange();
87
88 cue.setStartTime(cueData.startTime());
89 MediaTime endTime = cueData.endTime();
90 if (endTime.isPositiveInfinite() && mediaElement())
91 endTime = mediaElement()->durationMediaTime();
92 cue.setEndTime(endTime);
93 cue.setText(cueData.content());
94 cue.setId(cueData.id());
95 cue.setBaseFontSizeRelativeToVideoHeight(cueData.baseFontSize());
96 cue.setFontSizeMultiplier(cueData.relativeFontSize());
97 cue.setFontName(cueData.fontName());
98
99 if (cueData.position() > 0)
100 cue.setPosition(std::round(cueData.position()));
101 if (cueData.line() > 0)
102 cue.setLine(std::round(cueData.line()));
103 if (cueData.size() > 0)
104 cue.setSize(std::round(cueData.size()));
105 if (cueData.backgroundColor().isValid())
106 cue.setBackgroundColor(cueData.backgroundColor().rgb());
107 if (cueData.foregroundColor().isValid())
108 cue.setForegroundColor(cueData.foregroundColor().rgb());
109 if (cueData.highlightColor().isValid())
110 cue.setHighlightColor(cueData.highlightColor().rgb());
111
112 if (cueData.align() == GenericCueData::Start)
113 cue.setAlign("start"_s);
114 else if (cueData.align() == GenericCueData::Middle)
115 cue.setAlign("middle"_s);
116 else if (cueData.align() == GenericCueData::End)
117 cue.setAlign("end"_s);
118 cue.setSnapToLines(false);
119
120 cue.didChange();
121}
122
123void InbandGenericTextTrack::addGenericCue(GenericCueData& cueData)
124{
125 if (m_cueMap.find(cueData))
126 return;
127
128 auto cue = TextTrackCueGeneric::create(*scriptExecutionContext(), cueData.startTime(), cueData.endTime(), cueData.content());
129 updateCueFromCueData(cue.get(), cueData);
130 if (hasCue(cue.ptr(), TextTrackCue::IgnoreDuration)) {
131 INFO_LOG(LOGIDENTIFIER, "ignoring already added cue: ", cue.get());
132 return;
133 }
134
135 INFO_LOG(LOGIDENTIFIER, "added cue: ", cue.get());
136
137 if (cueData.status() != GenericCueData::Complete)
138 m_cueMap.add(cueData, cue);
139
140 addCue(WTFMove(cue));
141}
142
143void InbandGenericTextTrack::updateGenericCue(GenericCueData& cueData)
144{
145 auto cue = makeRefPtr(m_cueMap.find(cueData));
146 if (!cue)
147 return;
148
149 updateCueFromCueData(*cue, cueData);
150
151 if (cueData.status() == GenericCueData::Complete)
152 m_cueMap.remove(cueData);
153}
154
155void InbandGenericTextTrack::removeGenericCue(GenericCueData& cueData)
156{
157 auto cue = makeRefPtr(m_cueMap.find(cueData));
158 if (cue) {
159 INFO_LOG(LOGIDENTIFIER, *cue);
160 removeCue(*cue);
161 } else
162 INFO_LOG(LOGIDENTIFIER, "UNABLE to find cue: ", cueData);
163
164}
165
166ExceptionOr<void> InbandGenericTextTrack::removeCue(TextTrackCue& cue)
167{
168 auto result = TextTrack::removeCue(cue);
169 if (!result.hasException())
170 m_cueMap.remove(cue);
171 return result;
172}
173
174WebVTTParser& InbandGenericTextTrack::parser()
175{
176 if (!m_webVTTParser)
177 m_webVTTParser = std::make_unique<WebVTTParser>(static_cast<WebVTTParserClient*>(this), scriptExecutionContext());
178 return *m_webVTTParser;
179}
180
181void InbandGenericTextTrack::parseWebVTTCueData(const ISOWebVTTCue& cueData)
182{
183 parser().parseCueData(cueData);
184}
185
186void InbandGenericTextTrack::parseWebVTTFileHeader(String&& header)
187{
188 parser().parseFileHeader(WTFMove(header));
189}
190
191void InbandGenericTextTrack::newCuesParsed()
192{
193 Vector<RefPtr<WebVTTCueData>> cues;
194 parser().getNewCues(cues);
195
196 for (auto& cueData : cues) {
197 auto vttCue = VTTCue::create(*scriptExecutionContext(), *cueData);
198
199 if (hasCue(vttCue.ptr(), TextTrackCue::IgnoreDuration)) {
200 INFO_LOG(LOGIDENTIFIER, "ignoring already added cue: ", vttCue.get());
201 return;
202 }
203
204 INFO_LOG(LOGIDENTIFIER, vttCue.get());
205
206 addCue(WTFMove(vttCue));
207 }
208}
209
210void InbandGenericTextTrack::newRegionsParsed()
211{
212 Vector<RefPtr<VTTRegion>> newRegions;
213 parser().getNewRegions(newRegions);
214
215 for (auto& region : newRegions) {
216 region->setTrack(this);
217 regions()->add(region.releaseNonNull());
218 }
219}
220
221void InbandGenericTextTrack::newStyleSheetsParsed()
222{
223}
224
225void InbandGenericTextTrack::fileFailedToParse()
226{
227 ERROR_LOG(LOGIDENTIFIER);
228}
229
230} // namespace WebCore
231
232#endif
233